Added missing changes to the OpenAL-Soft update.

This commit is contained in:
Alex Szpakowski
2015-12-01 13:40:34 -04:00
parent f8dae3ea09
commit e9d77ef766
94 changed files with 9219 additions and 6099 deletions
+1 -1
View File
@@ -138,7 +138,7 @@ set(MEGA_LIBTHEORA_VER "1.1")
set(MEGA_MPG123_VER "1.15.3")
set(MEGA_FREETYPE_VER "2.5.0.1")
set(MEGA_SDL2_VER "2.0.3-dba168c67bea")
set(MEGA_OPENAL_VER "1.16.0")
set(MEGA_OPENAL_VER "1.17.0")
set(MEGA_MODPLUG_VER "0.8.8.4")
set(SKIP_INSTALL_ALL TRUE)
+781 -511
View File
File diff suppressed because it is too large Load Diff
+837 -567
View File
File diff suppressed because it is too large Load Diff
+86 -35
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -33,11 +33,13 @@
#include <ctype.h>
#include <string.h>
#ifdef _WIN32_IE
#include <windows.h>
#include <shlobj.h>
#endif
#include "alMain.h"
#include "compat.h"
#include "bool.h"
typedef struct ConfigEntry {
@@ -137,13 +139,21 @@ static char *expdup(const char *str)
}
else
{
bool hasbraces;
char envname[1024];
size_t k = 0;
hasbraces = (*str == '{');
if(hasbraces) str++;
while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1)
envname[k++] = *(str++);
envname[k++] = '\0';
if(hasbraces && *str != '}')
continue;
if(hasbraces) str++;
if((addstr=getenv(envname)) == NULL)
continue;
addstrlen = strlen(addstr);
@@ -192,12 +202,8 @@ static void LoadConfigFromFile(FILE *f)
char key[256] = "";
char value[256] = "";
comment = strchr(buffer, '#');
if(comment) *(comment++) = 0;
line = rstrip(lstrip(buffer));
if(!line[0])
continue;
if(!line[0]) continue;
if(line[0] == '[')
{
@@ -205,10 +211,21 @@ static void LoadConfigFromFile(FILE *f)
char *endsection;
endsection = strchr(section, ']');
if(!endsection || section == endsection || endsection[1] != 0)
if(!endsection || section == endsection)
{
ERR("config parse error: bad line \"%s\"\n", line);
continue;
ERR("config parse error: bad line \"%s\"\n", line);
continue;
}
if(endsection[1] != 0)
{
char *end = endsection+1;
while(isspace(*end))
++end;
if(*end != 0 && *end != '#')
{
ERR("config parse error: bad line \"%s\"\n", line);
continue;
}
}
*endsection = 0;
@@ -223,6 +240,10 @@ static void LoadConfigFromFile(FILE *f)
continue;
}
comment = strchr(line, '#');
if(comment) *(comment++) = 0;
if(!line[0]) continue;
if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 ||
sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 ||
sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2)
@@ -296,27 +317,33 @@ void ReadALConfig(void)
if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
{
size_t p = lstrlenW(buffer);
_snwprintf(buffer+p, PATH_MAX-p, L"\\alsoft.ini");
al_string filepath = AL_STRING_INIT_STATIC();
al_string_copy_wcstr(&filepath, buffer);
al_string_append_cstr(&filepath, "\\alsoft.ini");
TRACE("Loading config %ls...\n", buffer);
f = _wfopen(buffer, L"rt");
TRACE("Loading config %s...\n", al_string_get_cstr(filepath));
f = al_fopen(al_string_get_cstr(filepath), "rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
al_string_deinit(&filepath);
}
if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str)
{
TRACE("Loading config %ls...\n", str);
f = _wfopen(str, L"rt");
al_string filepath = AL_STRING_INIT_STATIC();
al_string_copy_wcstr(&filepath, str);
TRACE("Loading config %s...\n", al_string_get_cstr(filepath));
f = al_fopen(al_string_get_cstr(filepath), "rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
al_string_deinit(&filepath);
}
}
#else
@@ -428,7 +455,7 @@ void FreeALConfig(void)
free(cfgBlock.entries);
}
const char *GetConfigValue(const char *blockName, const char *keyName, const char *def)
const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def)
{
unsigned int i;
char key[256];
@@ -437,16 +464,26 @@ const char *GetConfigValue(const char *blockName, const char *keyName, const cha
return def;
if(blockName && strcasecmp(blockName, "general") != 0)
snprintf(key, sizeof(key), "%s/%s", blockName, keyName);
{
if(devName)
snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName);
else
snprintf(key, sizeof(key), "%s/%s", blockName, keyName);
}
else
{
strncpy(key, keyName, sizeof(key)-1);
key[sizeof(key)-1] = 0;
if(devName)
snprintf(key, sizeof(key), "%s/%s", devName, keyName);
else
{
strncpy(key, keyName, sizeof(key)-1);
key[sizeof(key)-1] = 0;
}
}
for(i = 0;i < cfgBlock.entryCount;i++)
{
if(strcasecmp(cfgBlock.entries[i].key, key) == 0)
if(strcmp(cfgBlock.entries[i].key, key) == 0)
{
TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value);
if(cfgBlock.entries[i].value[0])
@@ -455,46 +492,50 @@ const char *GetConfigValue(const char *blockName, const char *keyName, const cha
}
}
TRACE("Key %s not found\n", key);
return def;
if(!devName)
{
TRACE("Key %s not found\n", key);
return def;
}
return GetConfigValue(NULL, blockName, keyName, def);
}
int ConfigValueExists(const char *blockName, const char *keyName)
int ConfigValueExists(const char *devName, const char *blockName, const char *keyName)
{
const char *val = GetConfigValue(blockName, keyName, "");
const char *val = GetConfigValue(devName, blockName, keyName, "");
return !!val[0];
}
int ConfigValueStr(const char *blockName, const char *keyName, const char **ret)
int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret)
{
const char *val = GetConfigValue(blockName, keyName, "");
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = val;
return 1;
}
int ConfigValueInt(const char *blockName, const char *keyName, int *ret)
int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret)
{
const char *val = GetConfigValue(blockName, keyName, "");
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = strtol(val, NULL, 0);
return 1;
}
int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret)
int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret)
{
const char *val = GetConfigValue(blockName, keyName, "");
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = strtoul(val, NULL, 0);
return 1;
}
int ConfigValueFloat(const char *blockName, const char *keyName, float *ret)
int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret)
{
const char *val = GetConfigValue(blockName, keyName, "");
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
#ifdef HAVE_STRTOF
@@ -505,9 +546,19 @@ int ConfigValueFloat(const char *blockName, const char *keyName, float *ret)
return 1;
}
int GetConfigValueBool(const char *blockName, const char *keyName, int def)
int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret)
{
const char *val = GetConfigValue(blockName, keyName, "");
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
strcasecmp(val, "on") == 0 || atoi(val) != 0);
return 1;
}
int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def)
{
const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return !!def;
return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
+274 -2
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -127,3 +127,275 @@ void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
almtx_unlock(&ring->mtx);
}
/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended
* to include an element size. Consequently, parameters and return values for a
* size or count is in 'elements', not bytes. Additionally, it only supports
* single-consumer/single-provider operation. */
struct ll_ringbuffer {
volatile size_t write_ptr;
volatile size_t read_ptr;
size_t size;
size_t size_mask;
size_t elem_size;
int mlocked;
alignas(16) char buf[];
};
/* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes.
* The number of elements is rounded up to the next power of two. */
ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz)
{
ll_ringbuffer_t *rb;
ALuint power_of_two;
power_of_two = NextPowerOf2(sz);
if(power_of_two < sz)
return NULL;
rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz);
if(!rb) return NULL;
rb->size = power_of_two;
rb->size_mask = rb->size - 1;
rb->elem_size = elem_sz;
rb->write_ptr = 0;
rb->read_ptr = 0;
rb->mlocked = 0;
return rb;
}
/* Free all data associated with the ringbuffer `rb'. */
void ll_ringbuffer_free(ll_ringbuffer_t *rb)
{
if(rb)
{
#ifdef USE_MLOCK
if(rb->mlocked)
munlock(rb, sizeof(*rb) + rb->size*rb->elem_size);
#endif /* USE_MLOCK */
al_free(rb);
}
}
/* Lock the data block of `rb' using the system call 'mlock'. */
int ll_ringbuffer_mlock(ll_ringbuffer_t *rb)
{
#ifdef USE_MLOCK
if(!rb->locked && 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)
{
rb->read_ptr = 0;
rb->write_ptr = 0;
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 = rb->write_ptr;
size_t r = rb->read_ptr;
return (rb->size+w-r) & rb->size_mask;
}
/* Return the number of elements available for writing. This is the number of
* elements in front of the write pointer and behind the read pointer. */
size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb)
{
size_t w = rb->write_ptr;
size_t r = rb->read_ptr;
return (rb->size+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 free_cnt;
size_t cnt2;
size_t to_read;
size_t n1, n2;
free_cnt = ll_ringbuffer_read_space(rb);
if(free_cnt == 0) return 0;
to_read = (cnt > free_cnt) ? free_cnt : cnt;
cnt2 = rb->read_ptr + to_read;
if(cnt2 > rb->size)
{
n1 = rb->size - rb->read_ptr;
n2 = cnt2 & rb->size_mask;
}
else
{
n1 = to_read;
n2 = 0;
}
memcpy(dest, &(rb->buf[rb->read_ptr*rb->elem_size]), n1*rb->elem_size);
rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
if(n2)
{
memcpy(dest + n1*rb->elem_size, &(rb->buf[rb->read_ptr*rb->elem_size]), n2*rb->elem_size);
rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
}
return to_read;
}
/* The copying data reader w/o read pointer advance. Copy at most `cnt'
* elements from `rb' to `dest'. Returns the actual number of elements copied.
*/
size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt)
{
size_t free_cnt;
size_t cnt2;
size_t to_read;
size_t n1, n2;
size_t tmp_read_ptr;
tmp_read_ptr = rb->read_ptr;
free_cnt = ll_ringbuffer_read_space(rb);
if(free_cnt == 0) return 0;
to_read = (cnt > free_cnt) ? free_cnt : cnt;
cnt2 = tmp_read_ptr + to_read;
if(cnt2 > rb->size)
{
n1 = rb->size - tmp_read_ptr;
n2 = cnt2 & rb->size_mask;
}
else
{
n1 = to_read;
n2 = 0;
}
memcpy(dest, &(rb->buf[tmp_read_ptr*rb->elem_size]), n1*rb->elem_size);
tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
if(n2)
memcpy(dest + n1*rb->elem_size, &(rb->buf[tmp_read_ptr*rb->elem_size]), n2*rb->elem_size);
return to_read;
}
/* The copying data writer. Copy at most `cnt' elements to `rb' from `src'.
* Returns the actual number of elements copied. */
size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt)
{
size_t free_cnt;
size_t cnt2;
size_t to_write;
size_t n1, n2;
free_cnt = ll_ringbuffer_write_space(rb);
if(free_cnt == 0) return 0;
to_write = (cnt > free_cnt) ? free_cnt : cnt;
cnt2 = rb->write_ptr + to_write;
if(cnt2 > rb->size)
{
n1 = rb->size - rb->write_ptr;
n2 = cnt2 & rb->size_mask;
}
else
{
n1 = to_write;
n2 = 0;
}
memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src, n1*rb->elem_size);
rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
if(n2)
{
memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src + n1*rb->elem_size, n2*rb->elem_size);
rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
}
return to_write;
}
/* Advance the read pointer `cnt' places. */
void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt)
{
size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
rb->read_ptr = tmp;
}
/* Advance the write pointer `cnt' places. */
void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt)
{
size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
rb->write_ptr = tmp;
}
/* The non-copying data reader. `vec' is an array of two places. Set the values
* at `vec' to hold the current readable data at `rb'. If the readable data is
* in one segment the second segment has zero length. */
void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t * vec)
{
size_t free_cnt;
size_t cnt2;
size_t w, r;
w = rb->write_ptr;
r = rb->read_ptr;
free_cnt = (rb->size+w-r) & rb->size_mask;
cnt2 = r + free_cnt;
if(cnt2 > rb->size)
{
/* Two part vector: the rest of the buffer after the current write ptr,
* plus some from the start of the buffer. */
vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]);
vec[0].len = rb->size - r;
vec[1].buf = (char*)rb->buf;
vec[1].len = cnt2 & rb->size_mask;
}
else
{
/* Single part vector: just the rest of the buffer */
vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]);
vec[0].len = free_cnt;
vec[1].buf = NULL;
vec[1].len = 0;
}
}
/* The non-copying data writer. `vec' is an array of two places. Set the values
* at `vec' to hold the current writeable data at `rb'. If the writeable data
* is in one segment the second segment has zero length. */
void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec)
{
size_t free_cnt;
size_t cnt2;
size_t w, r;
w = rb->write_ptr;
r = rb->read_ptr;
free_cnt = (rb->size+r-w-1) & rb->size_mask;
cnt2 = w + free_cnt;
if(cnt2 > rb->size)
{
/* Two part vector: the rest of the buffer after the current write ptr,
* plus some from the start of the buffer. */
vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]);
vec[0].len = rb->size - w;
vec[1].buf = (char*)rb->buf;
vec[1].len = cnt2 & rb->size_mask;
}
else
{
vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]);
vec[0].len = free_cnt;
vec[1].buf = NULL;
vec[1].len = 0;
}
}
+4 -1
View File
@@ -8,6 +8,7 @@
typedef char al_string_char_type;
TYPEDEF_VECTOR(al_string_char_type, al_string)
TYPEDEF_VECTOR(al_string, vector_al_string)
inline void al_string_deinit(al_string *str)
{ VECTOR_DEINIT(*str); }
@@ -15,7 +16,7 @@ inline void al_string_deinit(al_string *str)
#define AL_STRING_INIT_STATIC() ((al_string)NULL)
#define AL_STRING_DEINIT(_x) al_string_deinit(&(_x))
inline ALsizei al_string_length(const_al_string str)
inline size_t al_string_length(const_al_string str)
{ return VECTOR_SIZE(str); }
inline ALboolean al_string_empty(const_al_string str)
@@ -40,6 +41,8 @@ void al_string_append_range(al_string *str, const al_string_char_type *from, con
#include <wchar.h>
/* Windows-only methods to deal with WideChar strings. */
void al_string_copy_wcstr(al_string *str, const wchar_t *from);
void al_string_append_wcstr(al_string *str, const wchar_t *from);
void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to);
#endif
#endif /* ALSTRING_H */
+16 -23
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -273,14 +273,14 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
al_string_copy_cstr(&entry.name, alsaDevice);
al_string_copy_cstr(&entry.device_name, GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
al_string_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
"device" : "capture", "default"));
VECTOR_PUSH_BACK(*DeviceList, entry);
card = -1;
if((err=snd_card_next(&card)) < 0)
ERR("Failed to find a card: %s\n", snd_strerror(err));
ConfigValueStr("alsa", prefix_name(stream), &main_prefix);
ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix);
while(card >= 0)
{
const char *card_prefix = main_prefix;
@@ -304,7 +304,7 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
cardid = snd_ctl_card_info_get_id(info);
snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
ConfigValueStr("alsa", name, &card_prefix);
ConfigValueStr(NULL, "alsa", name, &card_prefix);
dev = -1;
while(1)
@@ -330,7 +330,7 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
devname = snd_pcm_info_get_name(pcminfo);
snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
ConfigValueStr("alsa", name, &device_prefix);
ConfigValueStr(NULL, "alsa", name, &device_prefix);
snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
cardname, devname, cardid, dev);
@@ -640,7 +640,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
else
{
name = alsaDevice;
driver = GetConfigValue("alsa", "device", "default");
driver = GetConfigValue(NULL, "alsa", "device", "default");
}
TRACE("Opening device \"%s\"\n", driver);
@@ -704,7 +704,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
break;
}
allowmmap = GetConfigValueBool("alsa", "mmap", 1);
allowmmap = GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "mmap", 1);
periods = device->NumUpdates;
periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
bufferLen = periodLen * periods;
@@ -770,8 +770,11 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
}
CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
/* set rate (implicitly constrains period/buffer parameters) */
if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
ERR("Failed to disable ALSA resampler\n");
if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0))
{
if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
ERR("Failed to disable ALSA resampler\n");
}
CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL));
/* set buffer time (implicitly constrains period/buffer parameters) */
if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0)
@@ -965,7 +968,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
else
{
name = alsaDevice;
driver = GetConfigValue("alsa", "capture", "default");
driver = GetConfigValue(NULL, "alsa", "capture", "default");
}
TRACE("Opening device \"%s\"\n", driver);
@@ -1352,25 +1355,15 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN
if(type == ALCbackend_Playback)
{
ALCplaybackAlsa *backend;
backend = ALCplaybackAlsa_New(sizeof(*backend));
NEW_OBJ(backend, ALCplaybackAlsa)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCplaybackAlsa_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCcaptureAlsa *backend;
backend = ALCcaptureAlsa_New(sizeof(*backend));
NEW_OBJ(backend, ALCcaptureAlsa)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCcaptureAlsa_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
+4 -21
View File
@@ -77,7 +77,7 @@ static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self);
static void PlaybackWrapper_stop(PlaybackWrapper *self);
static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self);
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
@@ -121,12 +121,6 @@ static void PlaybackWrapper_stop(PlaybackWrapper *self)
self->Funcs->StopPlayback(device);
}
static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return self->Funcs->GetLatency(device);
}
typedef struct CaptureWrapper {
DERIVE_FROM_TYPE(ALCbackend);
@@ -143,13 +137,12 @@ static ALCboolean CaptureWrapper_start(CaptureWrapper *self);
static void CaptureWrapper_stop(CaptureWrapper *self);
static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples);
static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self);
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
@@ -195,12 +188,6 @@ static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
return self->Funcs->AvailableSamples(device);
}
static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return self->Funcs->GetLatency(device);
}
ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type)
{
@@ -208,11 +195,9 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs,
{
PlaybackWrapper *backend;
backend = PlaybackWrapper_New(sizeof(*backend));
NEW_OBJ(backend, PlaybackWrapper)(device, funcs);
if(!backend) return NULL;
PlaybackWrapper_Construct(backend, device, funcs);
return STATIC_CAST(ALCbackend, backend);
}
@@ -220,11 +205,9 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs,
{
CaptureWrapper *backend;
backend = CaptureWrapper_New(sizeof(*backend));
NEW_OBJ(backend, CaptureWrapper)(device, funcs);
if(!backend) return NULL;
CaptureWrapper_Construct(backend, device, funcs);
return STATIC_CAST(ALCbackend, backend);
}
+5
View File
@@ -123,9 +123,14 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \
ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
ALCbackendFactory *ALCossBackendFactory_getFactory(void);
ALCbackendFactory *ALCjackBackendFactory_getFactory(void);
ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void);
ALCbackendFactory *ALCportBackendFactory_getFactory(void);
ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
ALCbackendFactory *ALCloopbackFactory_getFactory(void);
ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type);
+10 -5
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -383,6 +383,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
ca_data *data;
OSStatus err;
if(!deviceName)
deviceName = ca_device;
else if(strcmp(deviceName, ca_device) != 0)
return ALC_INVALID_VALUE;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
@@ -514,9 +519,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
case DevFmtQuad:
case DevFmtX51:
case DevFmtX51Side:
case DevFmtX51Rear:
case DevFmtX61:
case DevFmtX71:
case DevFmtBFormat3D:
ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
goto error;
}
@@ -679,8 +685,7 @@ static const BackendFuncs ca_funcs = {
ca_start_capture,
ca_stop_capture,
ca_capture_samples,
ca_available_samples,
ALCdevice_GetLatencyDefault
ca_available_samples
};
ALCboolean alc_ca_init(BackendFuncs *func_list)
+45 -40
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -43,6 +43,9 @@
#ifndef DSSPEAKER_5POINT1
# define DSSPEAKER_5POINT1 0x00000006
#endif
#ifndef DSSPEAKER_5POINT1_BACK
# define DSSPEAKER_5POINT1_BACK 0x00000006
#endif
#ifndef DSSPEAKER_7POINT1
# define DSSPEAKER_7POINT1 0x00000007
#endif
@@ -57,6 +60,8 @@
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
#define DEVNAME_TAIL " on OpenAL Soft"
#ifdef HAVE_DYNLOAD
static void *ds_handle;
@@ -118,15 +123,14 @@ static void clear_devlist(vector_DevMap *list)
{
#define DEINIT_STR(i) AL_STRING_DEINIT((i)->name)
VECTOR_FOR_EACH(DevMap, *list, DEINIT_STR);
#undef DEINIT_STR
VECTOR_RESIZE(*list, 0);
#undef DEINIT_STR
}
static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data)
{
vector_DevMap *devices = data;
OLECHAR *guidstr = NULL;
DevMap *iter, *end;
DevMap entry;
HRESULT hr;
int count;
@@ -137,24 +141,26 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA
AL_STRING_INIT(entry.name);
count = 0;
do {
while(1)
{
const DevMap *iter;
al_string_copy_wcstr(&entry.name, desc);
if(count != 0)
if(count == 0)
al_string_append_cstr(&entry.name, DEVNAME_TAIL);
else
{
char str[64];
snprintf(str, sizeof(str), " #%d", count+1);
snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1);
al_string_append_cstr(&entry.name, str);
}
count++;
iter = VECTOR_ITER_BEGIN(*devices);
end = VECTOR_ITER_END(*devices);
for(;iter != end;++iter)
{
if(al_string_cmp(entry.name, iter->name) == 0)
break;
}
} while(iter != end);
#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY);
if(iter == VECTOR_ITER_END(*devices)) break;
#undef MATCH_ENTRY
count++;
}
entry.guid = *guid;
hr = StringFromCLSID(guid, &guidstr);
@@ -441,28 +447,35 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
hr = IDirectSound_GetSpeakerConfig(self->DS, &speakers);
if(SUCCEEDED(hr))
{
speakers = DSSPEAKER_CONFIG(speakers);
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
{
speakers = DSSPEAKER_CONFIG(speakers);
if(speakers == DSSPEAKER_MONO)
device->FmtChans = DevFmtMono;
else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
device->FmtChans = DevFmtStereo;
else if(speakers == DSSPEAKER_QUAD)
device->FmtChans = DevFmtQuad;
else if(speakers == DSSPEAKER_5POINT1 || speakers == DSSPEAKER_5POINT1_SURROUND)
else if(speakers == DSSPEAKER_5POINT1_SURROUND)
device->FmtChans = DevFmtX51;
else if(speakers == DSSPEAKER_5POINT1_BACK)
device->FmtChans = DevFmtX51Rear;
else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND)
device->FmtChans = DevFmtX71;
else
ERR("Unknown system speaker config: 0x%lx\n", speakers);
}
device->IsHeadphones = (device->FmtChans == DevFmtStereo &&
speakers == DSSPEAKER_HEADPHONE);
switch(device->FmtChans)
{
case DevFmtMono:
OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
break;
case DevFmtBFormat3D:
device->FmtChans = DevFmtStereo;
/*fall-through*/
case DevFmtStereo:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT;
@@ -478,16 +491,16 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtX51Side:
case DevFmtX51Rear:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
break;
case DevFmtX61:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
@@ -745,16 +758,16 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtX51Side:
case DevFmtX51Rear:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT;
break;
case DevFmtX61:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
@@ -775,6 +788,8 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
case DevFmtBFormat3D:
break;
}
InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
@@ -1027,26 +1042,16 @@ static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory
if(type == ALCbackend_Playback)
{
ALCdsoundPlayback *backend;
backend = ALCdsoundPlayback_New(sizeof(*backend));
NEW_OBJ(backend, ALCdsoundPlayback)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCdsoundPlayback_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCdsoundCapture *backend;
backend = ALCdsoundCapture_New(sizeof(*backend));
NEW_OBJ(backend, ALCdsoundCapture)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCdsoundCapture_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
+3 -8
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -124,13 +124,8 @@ static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(s
if(type == ALCbackend_Loopback)
{
ALCloopback *backend;
backend = ALCloopback_New(sizeof(*backend));
NEW_OBJ(backend, ALCloopback)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCloopback_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
+735 -72
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -51,14 +51,18 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
#define MONO SPEAKER_FRONT_CENTER
#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X5DOT1SIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER)
#define DEVNAME_TAIL " on OpenAL Soft"
typedef struct {
@@ -69,16 +73,14 @@ TYPEDEF_VECTOR(DevMap, vector_DevMap)
static void clear_devlist(vector_DevMap *list)
{
DevMap *iter, *end;
iter = VECTOR_ITER_BEGIN(*list);
end = VECTOR_ITER_END(*list);
for(;iter != end;iter++)
{
AL_STRING_DEINIT(iter->name);
free(iter->devid);
}
#define CLEAR_DEVMAP(i) do { \
AL_STRING_DEINIT((i)->name); \
free((i)->devid); \
(i)->devid = NULL; \
} while(0)
VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP);
VECTOR_RESIZE(*list, 0);
#undef CLEAR_DEVMAP
}
static vector_DevMap PlaybackDevices;
@@ -134,39 +136,105 @@ static void get_device_name(IMMDevice *device, al_string *name)
hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname);
if(FAILED(hr))
WARN("GetValue failed: 0x%08lx\n", hr);
else
WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr);
else if(pvname.vt == VT_LPWSTR)
al_string_copy_wcstr(name, pvname.pwszVal);
else
WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt);
PropVariantClear(&pvname);
IPropertyStore_Release(ps);
}
static void add_device(IMMDevice *device, vector_DevMap *list)
static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor)
{
IPropertyStore *ps;
PROPVARIANT pvform;
HRESULT hr;
hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
if(FAILED(hr))
{
WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
return;
}
PropVariantInit(&pvform);
hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_FormFactor, &pvform);
if(FAILED(hr))
WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr);
else if(pvform.vt == VT_UI4)
*formfactor = pvform.ulVal;
else if(pvform.vt == VT_EMPTY)
*formfactor = UnknownFormFactor;
else
WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt);
PropVariantClear(&pvform);
IPropertyStore_Release(ps);
}
static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list)
{
int count = 0;
al_string tmpname;
DevMap entry;
AL_STRING_INIT(tmpname);
AL_STRING_INIT(entry.name);
entry.devid = strdupW(devid);
get_device_name(device, &tmpname);
while(1)
{
const DevMap *iter;
al_string_copy(&entry.name, tmpname);
if(count == 0)
al_string_append_cstr(&entry.name, DEVNAME_TAIL);
else
{
char str[64];
snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1);
al_string_append_cstr(&entry.name, str);
}
#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY);
if(iter == VECTOR_ITER_END(*list)) break;
#undef MATCH_ENTRY
count++;
}
TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
VECTOR_PUSH_BACK(*list, entry);
AL_STRING_DEINIT(tmpname);
}
static LPWSTR get_device_id(IMMDevice *device)
{
LPWSTR devid;
HRESULT hr;
hr = IMMDevice_GetId(device, &devid);
if(SUCCEEDED(hr))
if(FAILED(hr))
{
DevMap entry;
AL_STRING_INIT(entry.name);
entry.devid = strdupW(devid);
get_device_name(device, &entry.name);
CoTaskMemFree(devid);
TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
VECTOR_PUSH_BACK(*list, entry);
ERR("Failed to get device id: %lx\n", hr);
return NULL;
}
return devid;
}
static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list)
{
IMMDeviceCollection *coll;
IMMDevice *defdev = NULL;
LPWSTR defdevid = NULL;
HRESULT hr;
UINT count;
UINT i;
@@ -183,7 +251,7 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve
if(SUCCEEDED(hr) && count > 0)
{
clear_devlist(list);
if(!VECTOR_RESERVE(*list, count+1))
if(!VECTOR_RESERVE(*list, count))
{
IMMDeviceCollection_Release(coll);
return E_OUTOFMEMORY;
@@ -193,22 +261,32 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve
eMultimedia, &defdev);
}
if(SUCCEEDED(hr) && defdev != NULL)
add_device(defdev, list);
{
defdevid = get_device_id(defdev);
if(defdevid)
add_device(defdev, defdevid, list);
}
for(i = 0;i < count;++i)
{
IMMDevice *device;
LPWSTR devid;
if(FAILED(IMMDeviceCollection_Item(coll, i, &device)))
continue;
if(device != defdev)
add_device(device, list);
hr = IMMDeviceCollection_Item(coll, i, &device);
if(FAILED(hr)) continue;
devid = get_device_id(device);
if(devid)
{
if(wcscmp(devid, defdevid) != 0)
add_device(device, devid, list);
CoTaskMemFree(devid);
}
IMMDevice_Release(device);
}
if(defdev) IMMDevice_Release(defdev);
if(defdevid) CoTaskMemFree(defdevid);
IMMDeviceCollection_Release(coll);
return S_OK;
@@ -294,7 +372,7 @@ static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr)
TRACE("Starting message loop\n");
while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last))
{
TRACE("Got message %u\n", msg.message);
TRACE("Got message %u (lparam=%p, wparam=%p)\n", msg.message, (void*)msg.lParam, (void*)msg.wParam);
switch(msg.message)
{
case WM_USER_OpenDevice:
@@ -483,9 +561,9 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
if(FAILED(hr))
{
ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
ALCdevice_Lock(device);
V0(device->Backend,lock)();
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
V0(device->Backend,unlock)();
return 1;
}
@@ -500,9 +578,9 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
if(FAILED(hr))
{
ERR("Failed to get padding: 0x%08lx\n", hr);
ALCdevice_Lock(device);
V0(device->Backend,lock)();
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
V0(device->Backend,unlock)();
break;
}
self->Padding = written;
@@ -521,18 +599,18 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer);
if(SUCCEEDED(hr))
{
ALCdevice_Lock(device);
V0(device->Backend,lock)();
aluMixData(device, buffer, len);
self->Padding = written + len;
ALCdevice_Unlock(device);
V0(device->Backend,unlock)();
hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0);
}
if(FAILED(hr))
{
ERR("Failed to buffer data: 0x%08lx\n", hr);
ALCdevice_Lock(device);
V0(device->Backend,lock)();
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
V0(device->Backend,unlock)();
break;
}
}
@@ -599,7 +677,7 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi
{
if(deviceName)
{
const DevMap *iter, *end;
const DevMap *iter;
if(VECTOR_SIZE(PlaybackDevices) == 0)
{
@@ -609,19 +687,18 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi
}
hr = E_FAIL;
iter = VECTOR_ITER_BEGIN(PlaybackDevices);
end = VECTOR_ITER_END(PlaybackDevices);
for(;iter != end;iter++)
{
if(al_string_cmp_cstr(iter->name, deviceName) == 0)
{
self->devid = strdupW(iter->devid);
hr = S_OK;
break;
}
}
if(FAILED(hr))
#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
if(iter == VECTOR_ITER_END(PlaybackDevices))
WARN("Failed to find device name matching \"%s\"\n", deviceName);
else
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
self->devid = strdupW(iter->devid);
al_string_copy(&device->DeviceName, iter->name);
hr = S_OK;
}
#undef MATCH_NAME
}
}
@@ -677,7 +754,11 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self)
if(SUCCEEDED(hr))
{
self->client = ptr;
get_device_name(self->mmdev, &device->DeviceName);
if(al_string_empty(device->DeviceName))
{
get_device_name(self->mmdev, &device->DeviceName);
al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL);
}
}
if(FAILED(hr))
@@ -734,6 +815,7 @@ static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self)
static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
EndpointFormFactor formfactor = UnknownFormFactor;
WAVEFORMATEXTENSIBLE OutputType;
WAVEFORMATEX *wfx = NULL;
REFERENCE_TIME min_per, buf_time;
@@ -783,11 +865,11 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
device->FmtChans = DevFmtQuad;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
device->FmtChans = DevFmtX51;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
device->FmtChans = DevFmtX51Side;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR)
device->FmtChans = DevFmtX51Rear;
else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
device->FmtChans = DevFmtX61;
else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE))
device->FmtChans = DevFmtX71;
else
ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
@@ -799,6 +881,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
OutputType.Format.nChannels = 1;
OutputType.dwChannelMask = MONO;
break;
case DevFmtBFormat3D:
device->FmtChans = DevFmtStereo;
/*fall-through*/
case DevFmtStereo:
OutputType.Format.nChannels = 2;
OutputType.dwChannelMask = STEREO;
@@ -811,9 +896,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
OutputType.Format.nChannels = 6;
OutputType.dwChannelMask = X5DOT1;
break;
case DevFmtX51Side:
case DevFmtX51Rear:
OutputType.Format.nChannels = 6;
OutputType.dwChannelMask = X5DOT1SIDE;
OutputType.dwChannelMask = X5DOT1REAR;
break;
case DevFmtX61:
OutputType.Format.nChannels = 7;
@@ -894,11 +979,11 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
device->FmtChans = DevFmtQuad;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
device->FmtChans = DevFmtX51;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
device->FmtChans = DevFmtX51Side;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR)
device->FmtChans = DevFmtX51Rear;
else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
device->FmtChans = DevFmtX61;
else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE))
device->FmtChans = DevFmtX71;
else
{
@@ -936,6 +1021,8 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
}
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
}
get_device_formfactor(self->mmdev, &formfactor);
device->IsHeadphones = (device->FmtChans == DevFmtStereo && formfactor == Headphones);
SetDefaultWFXChannelOrder(device);
@@ -1055,6 +1142,575 @@ static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self)
}
typedef struct ALCmmdevCapture {
DERIVE_FROM_TYPE(ALCbackend);
DERIVE_FROM_TYPE(ALCmmdevProxy);
WCHAR *devid;
IMMDevice *mmdev;
IAudioClient *client;
IAudioCaptureClient *capture;
HANDLE NotifyEvent;
HANDLE MsgEvent;
ll_ringbuffer_t *Ring;
volatile int killNow;
althrd_t thread;
} ALCmmdevCapture;
static int ALCmmdevCapture_recordProc(void *arg);
static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device);
static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self);
static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *name);
static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self);
static void ALCmmdevCapture_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, ALint64, getLatency)
static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCmmdevCapture)
DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevCapture);
DEFINE_ALCBACKEND_VTABLE(ALCmmdevCapture);
static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device)
{
SET_VTABLE2(ALCmmdevCapture, ALCbackend, self);
SET_VTABLE2(ALCmmdevCapture, ALCmmdevProxy, self);
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self));
self->devid = NULL;
self->mmdev = NULL;
self->client = NULL;
self->capture = NULL;
self->NotifyEvent = NULL;
self->MsgEvent = NULL;
self->Ring = NULL;
self->killNow = 0;
}
static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self)
{
ll_ringbuffer_free(self->Ring);
self->Ring = NULL;
if(self->NotifyEvent != NULL)
CloseHandle(self->NotifyEvent);
self->NotifyEvent = NULL;
if(self->MsgEvent != NULL)
CloseHandle(self->MsgEvent);
self->MsgEvent = NULL;
free(self->devid);
self->devid = NULL;
ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self));
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg)
{
ALCmmdevCapture *self = arg;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
HRESULT hr;
hr = CoInitialize(NULL);
if(FAILED(hr))
{
ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
V0(device->Backend,lock)();
aluHandleDisconnect(device);
V0(device->Backend,unlock)();
return 1;
}
althrd_setname(althrd_current(), RECORD_THREAD_NAME);
while(!self->killNow)
{
UINT32 avail;
DWORD res;
hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail);
if(FAILED(hr))
ERR("Failed to get next packet size: 0x%08lx\n", hr);
else while(avail > 0 && SUCCEEDED(hr))
{
UINT32 numsamples;
DWORD flags;
BYTE *data;
hr = IAudioCaptureClient_GetBuffer(self->capture,
&data, &numsamples, &flags, NULL, NULL
);
if(FAILED(hr))
{
ERR("Failed to get capture buffer: 0x%08lx\n", hr);
break;
}
ll_ringbuffer_write(self->Ring, (char*)data, numsamples);
hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples);
if(FAILED(hr))
{
ERR("Failed to release capture buffer: 0x%08lx\n", hr);
break;
}
hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail);
if(FAILED(hr))
ERR("Failed to get next packet size: 0x%08lx\n", hr);
}
if(FAILED(hr))
{
V0(device->Backend,lock)();
aluHandleDisconnect(device);
V0(device->Backend,unlock)();
break;
}
res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE);
if(res != WAIT_OBJECT_0)
ERR("WaitForSingleObjectEx error: 0x%lx\n", res);
}
CoUninitialize();
return 0;
}
static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *deviceName)
{
HRESULT hr = S_OK;
self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
self->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(self->NotifyEvent == NULL || self->MsgEvent == NULL)
{
ERR("Failed to create message events: %lu\n", GetLastError());
hr = E_FAIL;
}
if(SUCCEEDED(hr))
{
if(deviceName)
{
const DevMap *iter;
if(VECTOR_SIZE(CaptureDevices) == 0)
{
ThreadRequest req = { self->MsgEvent, 0 };
if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE))
(void)WaitForResponse(&req);
}
hr = E_FAIL;
#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
if(iter == VECTOR_ITER_END(CaptureDevices))
WARN("Failed to find device name matching \"%s\"\n", deviceName);
else
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
self->devid = strdupW(iter->devid);
al_string_copy(&device->DeviceName, iter->name);
hr = S_OK;
}
#undef MATCH_NAME
}
}
if(SUCCEEDED(hr))
{
ThreadRequest req = { self->MsgEvent, 0 };
hr = E_FAIL;
if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
hr = WaitForResponse(&req);
else
ERR("Failed to post thread message: %lu\n", GetLastError());
}
if(FAILED(hr))
{
if(self->NotifyEvent != NULL)
CloseHandle(self->NotifyEvent);
self->NotifyEvent = NULL;
if(self->MsgEvent != NULL)
CloseHandle(self->MsgEvent);
self->MsgEvent = NULL;
free(self->devid);
self->devid = NULL;
ERR("Device init failed: 0x%08lx\n", hr);
return ALC_INVALID_VALUE;
}
else
{
ThreadRequest req = { self->MsgEvent, 0 };
hr = E_FAIL;
if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
hr = WaitForResponse(&req);
else
ERR("Failed to post thread message: %lu\n", GetLastError());
if(FAILED(hr))
{
ALCmmdevCapture_close(self);
if(hr == E_OUTOFMEMORY)
return ALC_OUT_OF_MEMORY;
return ALC_INVALID_VALUE;
}
}
return ALC_NO_ERROR;
}
static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
void *ptr;
HRESULT hr;
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
if(SUCCEEDED(hr))
{
IMMDeviceEnumerator *Enumerator = ptr;
if(!self->devid)
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eCapture, eMultimedia, &self->mmdev);
else
hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev);
IMMDeviceEnumerator_Release(Enumerator);
Enumerator = NULL;
}
if(SUCCEEDED(hr))
hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
if(SUCCEEDED(hr))
{
self->client = ptr;
if(al_string_empty(device->DeviceName))
{
get_device_name(self->mmdev, &device->DeviceName);
al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL);
}
}
if(FAILED(hr))
{
if(self->mmdev)
IMMDevice_Release(self->mmdev);
self->mmdev = NULL;
}
return hr;
}
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);
self->client = NULL;
if(self->mmdev)
IMMDevice_Release(self->mmdev);
self->mmdev = NULL;
}
static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
WAVEFORMATEXTENSIBLE OutputType;
WAVEFORMATEX *wfx = NULL;
REFERENCE_TIME buf_time;
UINT32 buffer_len;
void *ptr = NULL;
HRESULT hr;
if(self->client)
IAudioClient_Release(self->client);
self->client = NULL;
hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
if(FAILED(hr))
{
ERR("Failed to reactivate audio client: 0x%08lx\n", hr);
return hr;
}
self->client = ptr;
buf_time = ((REFERENCE_TIME)device->UpdateSize*device->NumUpdates*10000000 +
device->Frequency-1) / device->Frequency;
OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
switch(device->FmtChans)
{
case DevFmtMono:
OutputType.Format.nChannels = 1;
OutputType.dwChannelMask = MONO;
break;
case DevFmtStereo:
OutputType.Format.nChannels = 2;
OutputType.dwChannelMask = STEREO;
break;
case DevFmtQuad:
OutputType.Format.nChannels = 4;
OutputType.dwChannelMask = QUAD;
break;
case DevFmtX51:
OutputType.Format.nChannels = 6;
OutputType.dwChannelMask = X5DOT1;
break;
case DevFmtX51Rear:
OutputType.Format.nChannels = 6;
OutputType.dwChannelMask = X5DOT1REAR;
break;
case DevFmtX61:
OutputType.Format.nChannels = 7;
OutputType.dwChannelMask = X6DOT1;
break;
case DevFmtX71:
OutputType.Format.nChannels = 8;
OutputType.dwChannelMask = X7DOT1;
break;
case DevFmtBFormat3D:
return E_FAIL;
}
switch(device->FmtType)
{
case DevFmtUByte:
OutputType.Format.wBitsPerSample = 8;
OutputType.Samples.wValidBitsPerSample = 8;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
break;
case DevFmtShort:
OutputType.Format.wBitsPerSample = 16;
OutputType.Samples.wValidBitsPerSample = 16;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
break;
case DevFmtInt:
OutputType.Format.wBitsPerSample = 32;
OutputType.Samples.wValidBitsPerSample = 32;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
break;
case DevFmtFloat:
OutputType.Format.wBitsPerSample = 32;
OutputType.Samples.wValidBitsPerSample = 32;
OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
break;
case DevFmtByte:
case DevFmtUShort:
case DevFmtUInt:
WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
return E_FAIL;
}
OutputType.Format.nSamplesPerSec = device->Frequency;
OutputType.Format.nBlockAlign = OutputType.Format.nChannels *
OutputType.Format.wBitsPerSample / 8;
OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
OutputType.Format.nBlockAlign;
OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format);
hr = IAudioClient_IsFormatSupported(self->client,
AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx
);
if(FAILED(hr))
{
ERR("Failed to check format support: 0x%08lx\n", hr);
return hr;
}
/* FIXME: We should do conversion/resampling if we didn't get a matching format. */
if(wfx->nSamplesPerSec != OutputType.Format.nSamplesPerSec ||
wfx->wBitsPerSample != OutputType.Format.wBitsPerSample ||
wfx->nChannels != OutputType.Format.nChannels ||
wfx->nBlockAlign != OutputType.Format.nBlockAlign)
{
ERR("Did not get matching format, wanted: %s %s %uhz, got: %d channel(s) %d-bit %luhz\n",
DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency,
wfx->nChannels, wfx->wBitsPerSample, wfx->nSamplesPerSec);
CoTaskMemFree(wfx);
return E_FAIL;
}
if(!MakeExtensible(&OutputType, wfx))
{
CoTaskMemFree(wfx);
return E_FAIL;
}
CoTaskMemFree(wfx);
wfx = NULL;
hr = IAudioClient_Initialize(self->client,
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
buf_time, 0, &OutputType.Format, NULL
);
if(FAILED(hr))
{
ERR("Failed to initialize audio client: 0x%08lx\n", hr);
return hr;
}
hr = IAudioClient_GetBufferSize(self->client, &buffer_len);
if(FAILED(hr))
{
ERR("Failed to get buffer size: 0x%08lx\n", hr);
return hr;
}
buffer_len = maxu(device->UpdateSize*device->NumUpdates + 1, buffer_len);
ll_ringbuffer_free(self->Ring);
self->Ring = ll_ringbuffer_create(buffer_len, OutputType.Format.nBlockAlign);
if(!self->Ring)
{
ERR("Failed to allocate capture ring buffer\n");
return E_OUTOFMEMORY;
}
hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent);
if(FAILED(hr))
{
ERR("Failed to set event handle: 0x%08lx\n", hr);
return hr;
}
return hr;
}
static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self)
{
ThreadRequest req = { self->MsgEvent, 0 };
HRESULT hr = E_FAIL;
if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
hr = WaitForResponse(&req);
return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
}
static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self)
{
HRESULT hr;
void *ptr;
ResetEvent(self->NotifyEvent);
hr = IAudioClient_Start(self->client);
if(FAILED(hr))
{
ERR("Failed to start audio client: 0x%08lx\n", hr);
return hr;
}
hr = IAudioClient_GetService(self->client, &IID_IAudioCaptureClient, &ptr);
if(SUCCEEDED(hr))
{
self->capture = ptr;
self->killNow = 0;
if(althrd_create(&self->thread, ALCmmdevCapture_recordProc, self) != althrd_success)
{
ERR("Failed to start thread\n");
IAudioCaptureClient_Release(self->capture);
self->capture = NULL;
hr = E_FAIL;
}
}
if(FAILED(hr))
{
IAudioClient_Stop(self->client);
IAudioClient_Reset(self->client);
}
return hr;
}
static void ALCmmdevCapture_stop(ALCmmdevCapture *self)
{
ThreadRequest req = { self->MsgEvent, 0 };
if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
(void)WaitForResponse(&req);
}
static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self)
{
int res;
if(!self->capture)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
IAudioCaptureClient_Release(self->capture);
self->capture = NULL;
IAudioClient_Stop(self->client);
IAudioClient_Reset(self->client);
}
ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self)
{
return (ALuint)ll_ringbuffer_read_space(self->Ring);
}
ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples)
{
if(ALCmmdevCapture_availableSamples(self) < samples)
return ALC_INVALID_VALUE;
ll_ringbuffer_read(self->Ring, buffer, samples);
return ALC_NO_ERROR;
}
static inline void AppendAllDevicesList2(const DevMap *entry)
{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
static inline void AppendCaptureDeviceList2(const DevMap *entry)
@@ -1125,7 +1781,12 @@ static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory* UNUSED(self))
static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
/* 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;
}
@@ -1162,13 +1823,15 @@ static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory*
if(type == ALCbackend_Playback)
{
ALCmmdevPlayback *backend;
backend = ALCmmdevPlayback_New(sizeof(*backend));
NEW_OBJ(backend, ALCmmdevPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCmmdevCapture *backend;
NEW_OBJ(backend, ALCmmdevCapture)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCmmdevPlayback_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
+4 -9
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -106,7 +106,7 @@ static int ALCnullBackend_mixerProc(void *ptr)
}
if(avail-done < device->UpdateSize)
al_nssleep(0, restTime);
al_nssleep(restTime);
else while(avail-done >= device->UpdateSize)
{
aluMixData(device, NULL, device->UpdateSize);
@@ -214,13 +214,8 @@ static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UN
if(type == ALCbackend_Playback)
{
ALCnullBackend *backend;
backend = ALCnullBackend_New(sizeof(*backend));
NEW_OBJ(backend, ALCnullBackend)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCnullBackend_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
+16 -7
View File
@@ -25,7 +25,7 @@
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
@@ -67,7 +67,10 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans)
SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
SL_SPEAKER_BACK_CENTER|
@@ -76,9 +79,7 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans)
SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT|
SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
case DevFmtX51Side: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
case DevFmtBFormat3D: break;
}
return 0;
}
@@ -378,6 +379,15 @@ static void opensl_stop_playback(ALCdevice *Device)
result = VCALL0(bufferQueue,Clear)();
PRINTERR(result, "bufferQueue->Clear");
}
if(SL_RESULT_SUCCESS == result)
{
SLAndroidSimpleBufferQueueState state;
do {
althrd_yield();
result = VCALL(bufferQueue,GetState)(&state);
} while(SL_RESULT_SUCCESS == result && state.count > 0);
PRINTERR(result, "bufferQueue->GetState");
}
free(data->buffer);
data->buffer = NULL;
@@ -396,8 +406,7 @@ static const BackendFuncs opensl_funcs = {
NULL,
NULL,
NULL,
NULL,
ALCdevice_GetLatencyDefault
NULL
};
+9 -19
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -131,7 +131,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr)
break;
}
al_nssleep(0, 1000000);
al_nssleep(1000000);
continue;
}
@@ -345,7 +345,7 @@ static int ALCcaptureOSS_recordProc(void *ptr)
int amt;
SetRTPriority();
althrd_setname(althrd_current(), "alsoft-record");
althrd_setname(althrd_current(), RECORD_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -362,7 +362,7 @@ static int ALCcaptureOSS_recordProc(void *ptr)
}
if(amt == 0)
{
al_nssleep(0, 1000000);
al_nssleep(1000000);
continue;
}
if(self->doCapture)
@@ -562,8 +562,8 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void)
ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self))
{
ConfigValueStr("oss", "device", &oss_driver);
ConfigValueStr("oss", "capture", &oss_capture);
ConfigValueStr(NULL, "oss", "device", &oss_driver);
ConfigValueStr(NULL, "oss", "capture", &oss_capture);
return ALC_TRUE;
}
@@ -606,25 +606,15 @@ ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self
if(type == ALCbackend_Playback)
{
ALCplaybackOSS *backend;
backend = ALCplaybackOSS_New(sizeof(*backend));
NEW_OBJ(backend, ALCplaybackOSS)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCplaybackOSS_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCcaptureOSS *backend;
backend = ALCcaptureOSS_New(sizeof(*backend));
NEW_OBJ(backend, ALCcaptureOSS)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCcaptureOSS_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
+259 -155
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -28,6 +28,8 @@
#include "alu.h"
#include "compat.h"
#include "backends/base.h"
#include <portaudio.h>
@@ -122,149 +124,171 @@ static ALCboolean pa_load(void)
}
typedef struct {
typedef struct ALCportPlayback {
DERIVE_FROM_TYPE(ALCbackend);
PaStream *stream;
PaStreamParameters params;
ALuint update_size;
} ALCportPlayback;
RingBuffer *ring;
} pa_data;
static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData);
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);
static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback)
DEFINE_ALCBACKEND_VTABLE(ALCportPlayback);
static int pa_callback(const void *UNUSED(inputBuffer), void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
{
ALCdevice *device = (ALCdevice*)userData;
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCportPlayback, ALCbackend, self);
aluMixData(device, outputBuffer, framesPerBuffer);
return 0;
self->stream = NULL;
}
static int pa_capture_cb(const void *inputBuffer, void *UNUSED(outputBuffer),
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
static void ALCportPlayback_Destruct(ALCportPlayback *self)
{
ALCdevice *device = (ALCdevice*)userData;
pa_data *data = (pa_data*)device->ExtraData;
if(self->stream)
Pa_CloseStream(self->stream);
self->stream = NULL;
WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
ALCportPlayback *self = userData;
aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer);
return 0;
}
static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name)
{
pa_data *data;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
PaError err;
if(!deviceName)
deviceName = pa_device;
else if(strcmp(deviceName, pa_device) != 0)
if(!name)
name = pa_device;
else if(strcmp(name, pa_device) != 0)
return ALC_INVALID_VALUE;
data = (pa_data*)calloc(1, sizeof(pa_data));
data->update_size = device->UpdateSize;
self->update_size = device->UpdateSize;
data->params.device = -1;
if(!ConfigValueInt("port", "device", &data->params.device) ||
data->params.device < 0)
data->params.device = Pa_GetDefaultOutputDevice();
data->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
self->params.device = -1;
if(!ConfigValueInt(NULL, "port", "device", &self->params.device) ||
self->params.device < 0)
self->params.device = Pa_GetDefaultOutputDevice();
self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
(float)device->Frequency;
data->params.hostApiSpecificStreamInfo = NULL;
self->params.hostApiSpecificStreamInfo = NULL;
data->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
switch(device->FmtType)
{
case DevFmtByte:
data->params.sampleFormat = paInt8;
self->params.sampleFormat = paInt8;
break;
case DevFmtUByte:
data->params.sampleFormat = paUInt8;
self->params.sampleFormat = paUInt8;
break;
case DevFmtUShort:
/* fall-through */
case DevFmtShort:
data->params.sampleFormat = paInt16;
self->params.sampleFormat = paInt16;
break;
case DevFmtUInt:
/* fall-through */
case DevFmtInt:
data->params.sampleFormat = paInt32;
self->params.sampleFormat = paInt32;
break;
case DevFmtFloat:
data->params.sampleFormat = paFloat32;
self->params.sampleFormat = paFloat32;
break;
}
retry_open:
err = Pa_OpenStream(&data->stream, NULL, &data->params, device->Frequency,
device->UpdateSize, paNoFlag, pa_callback, device);
err = Pa_OpenStream(&self->stream, NULL, &self->params,
device->Frequency, device->UpdateSize, paNoFlag,
ALCportPlayback_WriteCallback, self
);
if(err != paNoError)
{
if(data->params.sampleFormat == paFloat32)
if(self->params.sampleFormat == paFloat32)
{
data->params.sampleFormat = paInt16;
self->params.sampleFormat = paInt16;
goto retry_open;
}
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
free(data);
return ALC_INVALID_VALUE;
}
device->ExtraData = data;
al_string_copy_cstr(&device->DeviceName, deviceName);
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void pa_close_playback(ALCdevice *device)
static void ALCportPlayback_close(ALCportPlayback *self)
{
pa_data *data = (pa_data*)device->ExtraData;
PaError err;
err = Pa_CloseStream(data->stream);
PaError err = Pa_CloseStream(self->stream);
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
free(data);
device->ExtraData = NULL;
self->stream = NULL;
}
static ALCboolean pa_reset_playback(ALCdevice *device)
static ALCboolean ALCportPlayback_reset(ALCportPlayback *self)
{
pa_data *data = (pa_data*)device->ExtraData;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const PaStreamInfo *streamInfo;
streamInfo = Pa_GetStreamInfo(data->stream);
streamInfo = Pa_GetStreamInfo(self->stream);
device->Frequency = streamInfo->sampleRate;
device->UpdateSize = data->update_size;
device->UpdateSize = self->update_size;
if(data->params.sampleFormat == paInt8)
if(self->params.sampleFormat == paInt8)
device->FmtType = DevFmtByte;
else if(data->params.sampleFormat == paUInt8)
else if(self->params.sampleFormat == paUInt8)
device->FmtType = DevFmtUByte;
else if(data->params.sampleFormat == paInt16)
else if(self->params.sampleFormat == paInt16)
device->FmtType = DevFmtShort;
else if(data->params.sampleFormat == paInt32)
else if(self->params.sampleFormat == paInt32)
device->FmtType = DevFmtInt;
else if(data->params.sampleFormat == paFloat32)
else if(self->params.sampleFormat == paFloat32)
device->FmtType = DevFmtFloat;
else
{
ERR("Unexpected sample format: 0x%lx\n", data->params.sampleFormat);
ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat);
return ALC_FALSE;
}
if(data->params.channelCount == 2)
if(self->params.channelCount == 2)
device->FmtChans = DevFmtStereo;
else if(data->params.channelCount == 1)
else if(self->params.channelCount == 1)
device->FmtChans = DevFmtMono;
else
{
ERR("Unexpected channel count: %u\n", data->params.channelCount);
ERR("Unexpected channel count: %u\n", self->params.channelCount);
return ALC_FALSE;
}
SetDefaultChannelOrder(device);
@@ -272,12 +296,11 @@ static ALCboolean pa_reset_playback(ALCdevice *device)
return ALC_TRUE;
}
static ALCboolean pa_start_playback(ALCdevice *device)
static ALCboolean ALCportPlayback_start(ALCportPlayback *self)
{
pa_data *data = (pa_data*)device->ExtraData;
PaError err;
err = Pa_StartStream(data->stream);
err = Pa_StartStream(self->stream);
if(err != paNoError)
{
ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err));
@@ -287,161 +310,209 @@ static ALCboolean pa_start_playback(ALCdevice *device)
return ALC_TRUE;
}
static void pa_stop_playback(ALCdevice *device)
static void ALCportPlayback_stop(ALCportPlayback *self)
{
pa_data *data = (pa_data*)device->ExtraData;
PaError err;
err = Pa_StopStream(data->stream);
PaError err = Pa_StopStream(self->stream);
if(err != paNoError)
ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
}
static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
typedef struct ALCportCapture {
DERIVE_FROM_TYPE(ALCbackend);
PaStream *stream;
PaStreamParameters params;
ll_ringbuffer_t *ring;
} ALCportCapture;
static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
const PaStreamCallbackFlags statusFlags, void *userData);
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);
static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCportCapture_availableSamples(ALCportCapture *self);
static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCportCapture)
DEFINE_ALCBACKEND_VTABLE(ALCportCapture);
static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device)
{
ALuint frame_size;
pa_data *data;
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCportCapture, ALCbackend, self);
self->stream = NULL;
}
static void ALCportCapture_Destruct(ALCportCapture *self)
{
if(self->stream)
Pa_CloseStream(self->stream);
self->stream = NULL;
if(self->ring)
ll_ringbuffer_free(self->ring);
self->ring = NULL;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer),
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
ALCportCapture *self = userData;
size_t writable = ll_ringbuffer_write_space(self->ring);
if(framesPerBuffer > writable)
framesPerBuffer = writable;
ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer);
return 0;
}
static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALuint samples, frame_size;
PaError err;
if(!deviceName)
deviceName = pa_device;
else if(strcmp(deviceName, pa_device) != 0)
if(!name)
name = pa_device;
else if(strcmp(name, pa_device) != 0)
return ALC_INVALID_VALUE;
data = (pa_data*)calloc(1, sizeof(pa_data));
if(data == NULL)
return ALC_OUT_OF_MEMORY;
samples = device->UpdateSize * device->NumUpdates;
samples = maxu(samples, 100 * device->Frequency / 1000);
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates);
if(data->ring == NULL)
goto error;
data->params.device = -1;
if(!ConfigValueInt("port", "capture", &data->params.device) ||
data->params.device < 0)
data->params.device = Pa_GetDefaultInputDevice();
data->params.suggestedLatency = 0.0f;
data->params.hostApiSpecificStreamInfo = NULL;
self->ring = ll_ringbuffer_create(samples, frame_size);
if(self->ring == NULL) return ALC_INVALID_VALUE;
self->params.device = -1;
if(!ConfigValueInt(NULL, "port", "capture", &self->params.device) ||
self->params.device < 0)
self->params.device = Pa_GetDefaultInputDevice();
self->params.suggestedLatency = 0.0f;
self->params.hostApiSpecificStreamInfo = NULL;
switch(device->FmtType)
{
case DevFmtByte:
data->params.sampleFormat = paInt8;
self->params.sampleFormat = paInt8;
break;
case DevFmtUByte:
data->params.sampleFormat = paUInt8;
self->params.sampleFormat = paUInt8;
break;
case DevFmtShort:
data->params.sampleFormat = paInt16;
self->params.sampleFormat = paInt16;
break;
case DevFmtInt:
data->params.sampleFormat = paInt32;
self->params.sampleFormat = paInt32;
break;
case DevFmtFloat:
data->params.sampleFormat = paFloat32;
self->params.sampleFormat = paFloat32;
break;
case DevFmtUInt:
case DevFmtUShort:
ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
goto error;
return ALC_INVALID_VALUE;
}
data->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
self->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency,
paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device);
err = Pa_OpenStream(&self->stream, &self->params, NULL,
device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
ALCportCapture_ReadCallback, self
);
if(err != paNoError)
{
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
goto error;
return ALC_INVALID_VALUE;
}
al_string_copy_cstr(&device->DeviceName, deviceName);
al_string_copy_cstr(&device->DeviceName, name);
device->ExtraData = data;
return ALC_NO_ERROR;
error:
DestroyRingBuffer(data->ring);
free(data);
return ALC_INVALID_VALUE;
}
static void pa_close_capture(ALCdevice *device)
static void ALCportCapture_close(ALCportCapture *self)
{
pa_data *data = (pa_data*)device->ExtraData;
PaError err;
err = Pa_CloseStream(data->stream);
PaError err = Pa_CloseStream(self->stream);
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
self->stream = NULL;
DestroyRingBuffer(data->ring);
data->ring = NULL;
free(data);
device->ExtraData = NULL;
ll_ringbuffer_free(self->ring);
self->ring = NULL;
}
static void pa_start_capture(ALCdevice *device)
{
pa_data *data = device->ExtraData;
PaError err;
err = Pa_StartStream(data->stream);
static ALCboolean ALCportCapture_start(ALCportCapture *self)
{
PaError err = Pa_StartStream(self->stream);
if(err != paNoError)
{
ERR("Error starting stream: %s\n", Pa_GetErrorText(err));
return ALC_FALSE;
}
return ALC_TRUE;
}
static void pa_stop_capture(ALCdevice *device)
static void ALCportCapture_stop(ALCportCapture *self)
{
pa_data *data = (pa_data*)device->ExtraData;
PaError err;
err = Pa_StopStream(data->stream);
PaError err = Pa_StopStream(self->stream);
if(err != paNoError)
ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
}
static ALCenum pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
static ALCuint ALCportCapture_availableSamples(ALCportCapture *self)
{
pa_data *data = device->ExtraData;
ReadRingBuffer(data->ring, buffer, samples);
return ll_ringbuffer_read_space(self->ring);
}
static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples)
{
ll_ringbuffer_read(self->ring, buffer, samples);
return ALC_NO_ERROR;
}
static ALCuint pa_available_samples(ALCdevice *device)
{
pa_data *data = device->ExtraData;
return RingBufferSize(data->ring);
}
typedef struct ALCportBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCportBackendFactory;
#define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } }
static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self);
static void ALCportBackendFactory_deinit(ALCportBackendFactory *self);
static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type);
static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory);
static const BackendFuncs pa_funcs = {
pa_open_playback,
pa_close_playback,
pa_reset_playback,
pa_start_playback,
pa_stop_playback,
pa_open_capture,
pa_close_capture,
pa_start_capture,
pa_stop_capture,
pa_capture_samples,
pa_available_samples,
ALCdevice_GetLatencyDefault
};
ALCboolean alc_pa_init(BackendFuncs *func_list)
static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self))
{
if(!pa_load())
return ALC_FALSE;
*func_list = pa_funcs;
return ALC_TRUE;
}
void alc_pa_deinit(void)
static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self))
{
#ifdef HAVE_DYNLOAD
if(pa_handle)
@@ -455,7 +526,14 @@ void alc_pa_deinit(void)
#endif
}
void alc_pa_probe(enum DevProbe type)
static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback || type == ALCbackend_Capture)
return ALC_TRUE;
return ALC_FALSE;
}
static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
@@ -467,3 +545,29 @@ void alc_pa_probe(enum DevProbe type)
break;
}
}
static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCportPlayback *backend;
NEW_OBJ(backend, ALCportPlayback)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCportCapture *backend;
NEW_OBJ(backend, ALCportCapture)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
ALCbackendFactory *ALCportBackendFactory_getFactory(void)
{
static ALCportBackendFactory factory = ALCPORTBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
+166 -141
View File
@@ -14,8 +14,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -34,13 +34,6 @@
#if PA_API_VERSION == 12
#ifndef PA_CHECK_VERSION
#define PA_CHECK_VERSION(major,minor,micro) \
((PA_MAJOR > (major)) || \
(PA_MAJOR == (major) && PA_MINOR > (minor)) || \
(PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
#endif
#ifdef HAVE_DYNLOAD
static void *pa_handle;
#define MAKE_FUNC(x) static __typeof(x) * p##x
@@ -108,13 +101,9 @@ MAKE_FUNC(pa_operation_unref);
MAKE_FUNC(pa_proplist_new);
MAKE_FUNC(pa_proplist_free);
MAKE_FUNC(pa_proplist_set);
#if PA_CHECK_VERSION(0,9,15)
MAKE_FUNC(pa_channel_map_superset);
MAKE_FUNC(pa_stream_set_buffer_attr_callback);
#endif
#if PA_CHECK_VERSION(0,9,16)
MAKE_FUNC(pa_stream_begin_write);
#endif
#undef MAKE_FUNC
#define pa_context_unref ppa_context_unref
@@ -181,13 +170,9 @@ MAKE_FUNC(pa_stream_begin_write);
#define pa_proplist_new ppa_proplist_new
#define pa_proplist_free ppa_proplist_free
#define pa_proplist_set ppa_proplist_set
#if PA_CHECK_VERSION(0,9,15)
#define pa_channel_map_superset ppa_channel_map_superset
#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback
#endif
#if PA_CHECK_VERSION(0,9,16)
#define pa_stream_begin_write ppa_stream_begin_write
#endif
#endif
@@ -278,18 +263,10 @@ static ALCboolean pulse_load(void)
LOAD_FUNC(pa_proplist_new);
LOAD_FUNC(pa_proplist_free);
LOAD_FUNC(pa_proplist_set);
LOAD_FUNC(pa_channel_map_superset);
LOAD_FUNC(pa_stream_set_buffer_attr_callback);
LOAD_FUNC(pa_stream_begin_write);
#undef LOAD_FUNC
#define LOAD_OPTIONAL_FUNC(x) do { \
p##x = GetSymbol(pa_handle, #x); \
} while(0)
#if PA_CHECK_VERSION(0,9,15)
LOAD_OPTIONAL_FUNC(pa_channel_map_superset);
LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback);
#endif
#if PA_CHECK_VERSION(0,9,16)
LOAD_OPTIONAL_FUNC(pa_stream_begin_write);
#endif
#undef LOAD_OPTIONAL_FUNC
if(ret == ALC_FALSE)
{
@@ -428,8 +405,7 @@ error:
return ALC_FALSE;
}
static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
pa_stream *stream)
static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream)
{
pa_threaded_mainloop_lock(loop);
@@ -438,10 +414,7 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
pa_stream_set_state_callback(stream, NULL, NULL);
pa_stream_set_moved_callback(stream, NULL, NULL);
pa_stream_set_write_callback(stream, NULL, NULL);
#if PA_CHECK_VERSION(0,9,15)
if(pa_stream_set_buffer_attr_callback)
pa_stream_set_buffer_attr_callback(stream, NULL, NULL);
#endif
pa_stream_set_buffer_attr_callback(stream, NULL, NULL);
pa_stream_disconnect(stream);
pa_stream_unref(stream);
}
@@ -544,6 +517,7 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
pa_threaded_mainloop *loop = pdata;
const DevMap *iter;
DevMap entry;
int count;
if(eol)
{
@@ -553,18 +527,34 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
#define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0)
VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME);
if(iter != VECTOR_ITER_END(PlaybackDevices)) return;
#undef MATCH_INFO_NAME
if(iter != VECTOR_ITER_END(PlaybackDevices))
return;
TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
al_string_copy_cstr(&entry.name, info->description);
al_string_copy_cstr(&entry.device_name, info->name);
count = 0;
while(1)
{
al_string_copy_cstr(&entry.name, info->description);
if(count != 0)
{
char str[64];
snprintf(str, sizeof(str), " #%d", count+1);
al_string_append_cstr(&entry.name, str);
}
#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY);
if(iter == VECTOR_ITER_END(PlaybackDevices)) break;
#undef MATCH_ENTRY
count++;
}
TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name));
VECTOR_PUSH_BACK(PlaybackDevices, entry);
}
@@ -660,27 +650,44 @@ static void ALCpulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UN
static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
{
static const struct {
enum DevFmtChannels chans;
pa_channel_map map;
} chanmaps[] = {
{ DevFmtX71, { 8, {
PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
} } },
{ DevFmtX61, { 7, {
PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
PA_CHANNEL_POSITION_REAR_CENTER,
PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
} } },
{ DevFmtX51, { 6, {
PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
} } },
{ DevFmtX51Rear, { 6, {
PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT
} } },
{ DevFmtQuad, { 4, {
PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT
} } },
{ DevFmtStereo, { 2, {
PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT
} } },
{ DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } }
};
ALCpulsePlayback *self = pdata;
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
char chanmap_str[256] = "";
const struct {
const char *str;
enum DevFmtChannels chans;
} chanmaps[] = {
{ "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
DevFmtX71 },
{ "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
DevFmtX61 },
{ "front-left,front-right,front-center,lfe,rear-left,rear-right",
DevFmtX51 },
{ "front-left,front-right,front-center,lfe,side-left,side-right",
DevFmtX51Side },
{ "front-left,front-right,rear-left,rear-right", DevFmtQuad },
{ "front-left,front-right", DevFmtStereo },
{ "mono", DevFmtMono },
{ NULL, 0 }
};
int i;
size_t i;
if(eol)
{
@@ -688,26 +695,27 @@ static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const
return;
}
for(i = 0;chanmaps[i].str;i++)
for(i = 0;i < COUNTOF(chanmaps);i++)
{
pa_channel_map map;
if(!pa_channel_map_parse(&map, chanmaps[i].str))
continue;
if(pa_channel_map_equal(&info->channel_map, &map)
#if PA_CHECK_VERSION(0,9,15)
|| (pa_channel_map_superset &&
pa_channel_map_superset(&info->channel_map, &map))
#endif
)
if(pa_channel_map_superset(&info->channel_map, &chanmaps[i].map))
{
device->FmtChans = chanmaps[i].chans;
return;
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
device->FmtChans = chanmaps[i].chans;
break;
}
}
if(i == COUNTOF(chanmaps))
{
char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX] = "";
pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
WARN("Failed to find format for channel map:\n %s\n", chanmap_str);
}
pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
ERR("Failed to find format for channel map:\n %s\n", chanmap_str);
if(info->active_port)
TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description);
device->IsHeadphones = (info->active_port &&
strcmp(info->active_port->name, "analog-output-headphones") == 0 &&
device->FmtChans == DevFmtStereo);
}
static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
@@ -818,10 +826,7 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
void *buf;
pa_free_cb_t free_func = NULL;
#if PA_CHECK_VERSION(0,9,16)
if(!pa_stream_begin_write ||
pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
#endif
if(pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
{
buf = pa_xmalloc(newlen);
free_func = pa_xfree;
@@ -841,10 +846,10 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name)
{
const_al_string dev_name = AL_STRING_INIT_STATIC();
const char *pulse_name = NULL;
pa_stream_flags_t flags;
pa_sample_spec spec;
pa_operation *o;
if(name)
{
@@ -859,6 +864,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
if(iter == VECTOR_ITER_END(PlaybackDevices))
return ALC_INVALID_VALUE;
pulse_name = al_string_get_cstr(iter->device_name);
dev_name = iter->name;
}
if(!pulse_open(&self->loop, &self->context, ALCpulsePlayback_contextStateCallback, self))
@@ -868,7 +874,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
PA_STREAM_FIX_CHANNELS;
if(!GetConfigValueBool("pulse", "allow-moves", 0))
if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
spec.format = PA_SAMPLE_S16NE;
@@ -889,10 +895,19 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
o = pa_context_get_sink_info_by_name(self->context,
al_string_get_cstr(self->device_name),
ALCpulsePlayback_sinkNameCallback, self);
wait_for_operation(o, self->loop);
if(al_string_empty(dev_name))
{
pa_operation *o = pa_context_get_sink_info_by_name(
self->context, al_string_get_cstr(self->device_name),
ALCpulsePlayback_sinkNameCallback, self
);
wait_for_operation(o, self->loop);
}
else
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
al_string_copy(&device->DeviceName, dev_name);
}
pa_threaded_mainloop_unlock(self->loop);
@@ -915,37 +930,33 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
pa_stream_flags_t flags = 0;
const char *mapname = NULL;
pa_channel_map chanmap;
pa_operation *o;
ALuint len;
pa_threaded_mainloop_lock(self->loop);
if(self->stream)
{
pa_stream_set_state_callback(self->stream, NULL, NULL);
pa_stream_set_moved_callback(self->stream, NULL, NULL);
#if PA_CHECK_VERSION(0,9,15)
if(pa_stream_set_buffer_attr_callback)
pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL);
#endif
pa_stream_set_write_callback(self->stream, NULL, NULL);
pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL);
pa_stream_disconnect(self->stream);
pa_stream_unref(self->stream);
self->stream = NULL;
}
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
{
pa_operation *o;
o = pa_context_get_sink_info_by_name(self->context,
al_string_get_cstr(self->device_name),
ALCpulsePlayback_sinkInfoCallback, self);
wait_for_operation(o, self->loop);
}
if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
flags |= PA_STREAM_FIX_RATE;
o = pa_context_get_sink_info_by_name(self->context, al_string_get_cstr(self->device_name),
ALCpulsePlayback_sinkInfoCallback, self);
wait_for_operation(o, self->loop);
if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) ||
!(device->Flags&DEVICE_FREQUENCY_REQUEST))
flags |= PA_STREAM_FIX_RATE;
flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
flags |= PA_STREAM_ADJUST_LATENCY;
flags |= PA_STREAM_START_CORKED;
if(!GetConfigValueBool("pulse", "allow-moves", 0))
if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
switch(device->FmtType)
@@ -987,6 +998,9 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
case DevFmtMono:
mapname = "mono";
break;
case DevFmtBFormat3D:
device->FmtChans = DevFmtStereo;
/*fall-through*/
case DevFmtStereo:
mapname = "front-left,front-right";
break;
@@ -994,11 +1008,11 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
mapname = "front-left,front-right,rear-left,rear-right";
break;
case DevFmtX51:
mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right";
break;
case DevFmtX51Side:
mapname = "front-left,front-right,front-center,lfe,side-left,side-right";
break;
case DevFmtX51Rear:
mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right";
break;
case DevFmtX61:
mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right";
break;
@@ -1035,8 +1049,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
self->spec = *(pa_stream_get_sample_spec(self->stream));
if(device->Frequency != self->spec.rate)
{
pa_operation *o;
/* Server updated our playback rate, so modify the buffer attribs
* accordingly. */
device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency *
@@ -1053,15 +1065,10 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
device->Frequency = self->spec.rate;
}
#if PA_CHECK_VERSION(0,9,15)
if(pa_stream_set_buffer_attr_callback)
pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
#endif
pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
ALCpulsePlayback_bufferAttrCallback(self->stream, self);
len = self->attr.minreq / pa_frame_size(&self->spec);
if((CPUCapFlags&CPU_CAP_SSE))
len = (len+3)&~3;
device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5);
device->NumUpdates = clampu(device->NumUpdates, 2, 16);
device->UpdateSize = len;
@@ -1083,10 +1090,18 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
pa_operation *o;
int res;
if(!self->stream)
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
* the signal.
*/
pa_threaded_mainloop_lock(self->loop);
pa_threaded_mainloop_unlock(self->loop);
pa_threaded_mainloop_signal(self->loop, 0);
althrd_join(self->thread, &res);
pa_threaded_mainloop_lock(self->loop);
@@ -1199,6 +1214,7 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
pa_threaded_mainloop *loop = pdata;
const DevMap *iter;
DevMap entry;
int count;
if(eol)
{
@@ -1208,18 +1224,34 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
#define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0)
VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME);
if(iter != VECTOR_ITER_END(CaptureDevices)) return;
#undef MATCH_INFO_NAME
if(iter != VECTOR_ITER_END(CaptureDevices))
return;
TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
al_string_copy_cstr(&entry.name, info->description);
al_string_copy_cstr(&entry.device_name, info->name);
count = 0;
while(1)
{
al_string_copy_cstr(&entry.name, info->description);
if(count != 0)
{
char str[64];
snprintf(str, sizeof(str), " #%d", count+1);
al_string_append_cstr(&entry.name, str);
}
#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY);
if(iter == VECTOR_ITER_END(CaptureDevices)) break;
#undef MATCH_ENTRY
count++;
}
TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name));
VECTOR_PUSH_BACK(CaptureDevices, entry);
}
@@ -1372,7 +1404,6 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
const char *pulse_name = NULL;
pa_stream_flags_t flags = 0;
pa_channel_map chanmap;
pa_operation *o;
ALuint samples;
if(name)
@@ -1388,6 +1419,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
if(iter == VECTOR_ITER_END(CaptureDevices))
return ALC_INVALID_VALUE;
pulse_name = al_string_get_cstr(iter->device_name);
al_string_copy(&device->DeviceName, iter->name);
}
if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self))
@@ -1445,7 +1477,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
pa_frame_size(&self->spec);
flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
if(!GetConfigValueBool("pulse", "allow-moves", 0))
if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
@@ -1461,10 +1493,14 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self);
al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
o = pa_context_get_source_info_by_name(self->context,
al_string_get_cstr(self->device_name),
ALCpulseCapture_sourceNameCallback, self);
wait_for_operation(o, self->loop);
if(al_string_empty(device->DeviceName))
{
pa_operation *o = pa_context_get_source_info_by_name(
self->context, al_string_get_cstr(self->device_name),
ALCpulseCapture_sourceNameCallback, self
);
wait_for_operation(o, self->loop);
}
pa_threaded_mainloop_unlock(self->loop);
return ALC_NO_ERROR;
@@ -1607,11 +1643,6 @@ static void ALCpulseCapture_unlock(ALCpulseCapture *self)
}
static inline void AppendAllDevicesList2(const DevMap *entry)
{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
static inline void AppendCaptureDeviceList2(const DevMap *entry)
{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
typedef struct ALCpulseBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCpulseBackendFactory;
@@ -1638,7 +1669,7 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel
pa_threaded_mainloop *loop;
pulse_ctx_flags = 0;
if(!GetConfigValueBool("pulse", "spawn-server", 1))
if(!GetConfigValueBool(NULL, "pulse", "spawn-server", 1))
pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
if((loop=pa_threaded_mainloop_new()) &&
@@ -1701,12 +1732,16 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e
{
case ALL_DEVICE_PROBE:
ALCpulsePlayback_probeDevices();
VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
#define APPEND_ALL_DEVICES_LIST(e) AppendAllDevicesList(al_string_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, AppendCaptureDeviceList2);
#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(al_string_get_cstr((e)->name))
VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_CAPTURE_DEVICE_LIST);
#undef APPEND_CAPTURE_DEVICE_LIST
break;
}
}
@@ -1716,25 +1751,15 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
if(type == ALCbackend_Playback)
{
ALCpulsePlayback *backend;
backend = ALCpulsePlayback_New(sizeof(*backend));
NEW_OBJ(backend, ALCpulsePlayback)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCpulsePlayback_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCpulseCapture *backend;
backend = ALCpulseCapture_New(sizeof(*backend));
NEW_OBJ(backend, ALCpulseCapture)(device);
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCpulseCapture_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
+108 -352
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -53,12 +53,12 @@ typedef struct {
int card;
int dev;
} DevMap;
TYPEDEF_VECTOR(DevMap, vector_DevMap)
static vector_DevMap DeviceNameMap;
static vector_DevMap CaptureNameMap;
static const ALCchar qsaDevice[] = "QSA Default";
static DevMap* allDevNameMap;
static ALuint numDevNames;
static DevMap* allCaptureDevNameMap;
static ALuint numCaptureDevNames;
static const struct {
int32_t format;
@@ -104,69 +104,57 @@ static const struct {
{0},
};
static DevMap *deviceList(int type, ALuint *count)
static void deviceList(int type, vector_DevMap *devmap)
{
snd_ctl_t* handle;
snd_pcm_info_t pcminfo;
int max_cards, card, err, dev, num_devices, idx;
DevMap* dev_list;
int max_cards, card, err, dev;
DevMap entry;
char name[1024];
struct snd_ctl_hw_info info;
void* temp;
idx=0;
num_devices=0;
max_cards=snd_cards();
max_cards = snd_cards();
if(max_cards < 0)
return;
if (max_cards<=0)
VECTOR_RESERVE(*devmap, max_cards+1);
VECTOR_RESIZE(*devmap, 0);
entry.name = strdup(qsaDevice);
entry.card = 0;
entry.dev = 0;
VECTOR_PUSH_BACK(*devmap, entry);
for(card = 0;card < max_cards;card++)
{
return 0;
}
dev_list=malloc(sizeof(DevMap)*1);
dev_list[0].name=strdup(qsaDevice);
num_devices=1;
for (card=0; card<max_cards; card++)
{
if ((err=snd_ctl_open(&handle, card))<0)
{
if((err=snd_ctl_open(&handle, card)) < 0)
continue;
}
if ((err=snd_ctl_hw_info(handle, &info))<0)
if((err=snd_ctl_hw_info(handle, &info)) < 0)
{
snd_ctl_close(handle);
continue;
}
for (dev=0; dev<(int)info.pcmdevs; dev++)
for(dev = 0;dev < (int)info.pcmdevs;dev++)
{
if ((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
{
if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
continue;
}
if ((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
(type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
(type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
{
temp=realloc(dev_list, sizeof(DevMap)*(num_devices+1));
if (temp)
{
dev_list=temp;
snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
dev_list[num_devices].name=strdup(name);
dev_list[num_devices].card=card;
dev_list[num_devices].dev=dev;
num_devices++;
}
snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
entry.name = strdup(name);
entry.card = card;
entry.dev = dev;
VECTOR_PUSH_BACK(*devmap, entry);
TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev);
}
}
snd_ctl_close (handle);
snd_ctl_close(handle);
}
*count=num_devices;
return dev_list;
}
@@ -266,71 +254,48 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr)
static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
{
qsa_data* data;
char driver[64];
int status;
qsa_data *data;
int card, dev;
int status;
strncpy(driver, GetConfigValue("qsa", "device", qsaDevice), sizeof(driver)-1);
driver[sizeof(driver)-1]=0;
data=(qsa_data*)calloc(1, sizeof(qsa_data));
if (data==NULL)
{
data = (qsa_data*)calloc(1, sizeof(qsa_data));
if(data == NULL)
return ALC_OUT_OF_MEMORY;
}
if (!deviceName)
{
deviceName=driver;
}
if(!deviceName)
deviceName = qsaDevice;
if (strcmp(deviceName, qsaDevice)==0)
{
if (!deviceName)
{
deviceName=qsaDevice;
}
status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
}
if(strcmp(deviceName, qsaDevice) == 0)
status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
else
{
size_t idx;
const DevMap *iter;
if (!allDevNameMap)
{
allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames);
}
if(VECTOR_SIZE(DeviceNameMap) == 0)
deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
for (idx=0; idx<numDevNames; idx++)
{
if (allDevNameMap[idx].name && strcmp(deviceName, allDevNameMap[idx].name)==0)
{
if (idx>0)
{
break;
}
}
}
if (idx==numDevNames)
#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME);
#undef MATCH_DEVNAME
if(iter == VECTOR_ITER_END(DeviceNameMap))
{
free(data);
return ALC_INVALID_DEVICE;
}
status=snd_pcm_open(&data->pcmHandle, allDevNameMap[idx].card, allDevNameMap[idx].dev, SND_PCM_OPEN_PLAYBACK);
status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK);
}
if (status<0)
if(status < 0)
{
free(data);
return ALC_INVALID_DEVICE;
}
data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
if (data->audio_fd<0)
data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
if(data->audio_fd < 0)
{
snd_pcm_close(data->pcmHandle);
free(data);
return ALC_INVALID_DEVICE;
}
@@ -633,72 +598,51 @@ static void qsa_stop_playback(ALCdevice* device)
static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
{
qsa_data* data;
int format=-1;
char driver[64];
qsa_data *data;
int card, dev;
int format=-1;
int status;
strncpy(driver, GetConfigValue("qsa", "capture", qsaDevice), sizeof(driver)-1);
driver[sizeof(driver)-1]=0;
data=(qsa_data*)calloc(1, sizeof(qsa_data));
if (data==NULL)
{
return ALC_OUT_OF_MEMORY;
}
if (!deviceName)
{
deviceName=driver;
}
if(!deviceName)
deviceName = qsaDevice;
if (strcmp(deviceName, qsaDevice)==0)
{
if (!deviceName)
{
deviceName=qsaDevice;
}
status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
}
if(strcmp(deviceName, qsaDevice) == 0)
status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
else
{
size_t idx;
const DevMap *iter;
if (!allCaptureDevNameMap)
{
allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numDevNames);
}
if(VECTOR_SIZE(CaptureNameMap) == 0)
deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
for (idx=0; idx<numDevNames; idx++)
{
if (allCaptureDevNameMap[idx].name && strcmp(deviceName, allCaptureDevNameMap[idx].name)==0)
{
if (idx>0)
{
break;
}
}
}
if (idx==numDevNames)
#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME);
#undef MATCH_DEVNAME
if(iter == VECTOR_ITER_END(CaptureNameMap))
{
free(data);
return ALC_INVALID_DEVICE;
}
status=snd_pcm_open(&data->pcmHandle, allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev, SND_PCM_OPEN_CAPTURE);
status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE);
}
if (status<0)
if(status < 0)
{
free(data);
return ALC_INVALID_DEVICE;
}
data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
if (data->audio_fd<0)
data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
if(data->audio_fd < 0)
{
snd_pcm_close(data->pcmHandle);
free(data);
return ALC_INVALID_DEVICE;
}
@@ -753,170 +697,13 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
data->cparams.format.format=format;
if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0)
{
int original_rate=data->cparams.format.rate;
int original_voices=data->cparams.format.voices;
int original_format=data->cparams.format.format;
int it;
int jt;
snd_pcm_close(data->pcmHandle);
free(data);
device->ExtraData=NULL;
for (it=0; it<1; it++)
{
/* Check for second pass */
if (it==1)
{
original_rate=ratelist[0].rate;
original_voices=channellist[0].channels;
original_format=formatlist[0].format;
}
do {
/* At first downgrade sample format */
jt=0;
do {
if (formatlist[jt].format==data->cparams.format.format)
{
data->cparams.format.format=formatlist[jt+1].format;
break;
}
if (formatlist[jt].format==0)
{
data->cparams.format.format=0;
break;
}
jt++;
} while(1);
if (data->cparams.format.format==0)
{
data->cparams.format.format=original_format;
/* At secod downgrade sample rate */
jt=0;
do {
if (ratelist[jt].rate==data->cparams.format.rate)
{
data->cparams.format.rate=ratelist[jt+1].rate;
break;
}
if (ratelist[jt].rate==0)
{
data->cparams.format.rate=0;
break;
}
jt++;
} while(1);
if (data->cparams.format.rate==0)
{
data->cparams.format.rate=original_rate;
data->cparams.format.format=original_format;
/* At third downgrade channels number */
jt=0;
do {
if(channellist[jt].channels==data->cparams.format.voices)
{
data->cparams.format.voices=channellist[jt+1].channels;
break;
}
if (channellist[jt].channels==0)
{
data->cparams.format.voices=0;
break;
}
jt++;
} while(1);
}
if (data->cparams.format.voices==0)
{
break;
}
}
data->cparams.buf.block.frag_size=device->UpdateSize*
data->cparams.format.voices*
snd_pcm_format_width(data->cparams.format.format)/8;
data->cparams.buf.block.frags_max=device->NumUpdates;
data->cparams.buf.block.frags_min=device->NumUpdates;
if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
{
continue;
}
else
{
break;
}
} while(1);
if (data->cparams.format.voices!=0)
{
break;
}
}
if (data->cparams.format.voices==0)
{
return ALC_INVALID_VALUE;
}
}
/* now fill back to the our AL device */
device->Frequency=data->cparams.format.rate;
switch (data->cparams.format.voices)
{
case 1:
device->FmtChans=DevFmtMono;
break;
case 2:
device->FmtChans=DevFmtStereo;
break;
case 4:
device->FmtChans=DevFmtQuad;
break;
case 6:
device->FmtChans=DevFmtX51;
break;
case 7:
device->FmtChans=DevFmtX61;
break;
case 8:
device->FmtChans=DevFmtX71;
break;
default:
device->FmtChans=DevFmtMono;
break;
}
switch (data->cparams.format.format)
{
case SND_PCM_SFMT_S8:
device->FmtType=DevFmtByte;
break;
case SND_PCM_SFMT_U8:
device->FmtType=DevFmtUByte;
break;
case SND_PCM_SFMT_S16_LE:
device->FmtType=DevFmtShort;
break;
case SND_PCM_SFMT_U16_LE:
device->FmtType=DevFmtUShort;
break;
case SND_PCM_SFMT_S32_LE:
device->FmtType=DevFmtInt;
break;
case SND_PCM_SFMT_U32_LE:
device->FmtType=DevFmtUInt;
break;
case SND_PCM_SFMT_FLOAT_LE:
device->FmtType=DevFmtFloat;
break;
default:
device->FmtType=DevFmtShort;
break;
return ALC_INVALID_VALUE;
}
return ALC_NO_ERROR;
@@ -927,9 +714,8 @@ static void qsa_close_capture(ALCdevice* device)
qsa_data* data=(qsa_data*)device->ExtraData;
if (data->pcmHandle!=NULL)
{
snd_pcm_close(data->pcmHandle);
}
free(data);
device->ExtraData=NULL;
}
@@ -954,10 +740,6 @@ static void qsa_start_capture(ALCdevice* device)
}
snd_pcm_capture_go(data->pcmHandle);
device->UpdateSize=data->csetup.buf.block.frag_size/
(ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType));
device->NumUpdates=data->csetup.buf.block.frags;
}
static void qsa_stop_capture(ALCdevice* device)
@@ -1073,16 +855,7 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
return ALC_NO_ERROR;
}
static ALint64 qsa_get_latency(ALCdevice* device)
{
ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
return (ALint64)(device->UpdateSize*device->NumUpdates/frame_size)*
1000000000/device->Frequency;
}
BackendFuncs qsa_funcs=
{
static const BackendFuncs qsa_funcs= {
qsa_open_playback,
qsa_close_playback,
qsa_reset_playback,
@@ -1093,69 +866,52 @@ BackendFuncs qsa_funcs=
qsa_start_capture,
qsa_stop_capture,
qsa_capture_samples,
qsa_available_samples,
qsa_get_latency,
qsa_available_samples
};
ALCboolean alc_qsa_init(BackendFuncs* func_list)
{
*func_list=qsa_funcs;
*func_list = qsa_funcs;
return ALC_TRUE;
}
void alc_qsa_deinit(void)
{
ALuint i;
#define FREE_NAME(iter) free((iter)->name)
VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
VECTOR_DEINIT(DeviceNameMap);
for (i=0; i<numDevNames; ++i)
{
free(allDevNameMap[i].name);
}
free(allDevNameMap);
allDevNameMap=NULL;
numDevNames=0;
for (i=0; i<numCaptureDevNames; ++i)
{
free(allCaptureDevNameMap[i].name);
}
free(allCaptureDevNameMap);
allCaptureDevNameMap=NULL;
numCaptureDevNames=0;
VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
VECTOR_DEINIT(CaptureNameMap);
#undef FREE_NAME
}
void alc_qsa_probe(enum DevProbe type)
{
ALuint i;
switch (type)
{
case ALL_DEVICE_PROBE:
for (i=0; i<numDevNames; ++i)
{
free(allDevNameMap[i].name);
}
free(allDevNameMap);
#define FREE_NAME(iter) free((iter)->name)
VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
#undef FREE_NAME
VECTOR_RESIZE(DeviceNameMap, 0);
deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
#define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name)
VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_DEVICE);
#undef APPEND_DEVICE
break;
allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames);
for (i=0; i<numDevNames; ++i)
{
AppendAllDevicesList(allDevNameMap[i].name);
}
break;
case CAPTURE_DEVICE_PROBE:
for (i=0; i<numCaptureDevNames; ++i)
{
free(allCaptureDevNameMap[i].name);
}
free(allCaptureDevNameMap);
#define FREE_NAME(iter) free((iter)->name)
VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
#undef FREE_NAME
VECTOR_RESIZE(CaptureNameMap, 0);
allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numCaptureDevNames);
for (i=0; i<numCaptureDevNames; ++i)
{
AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
}
break;
deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
#define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name)
VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_DEVICE);
#undef APPEND_DEVICE
break;
}
}
+3 -4
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -266,8 +266,7 @@ static const BackendFuncs sndio_funcs = {
NULL,
NULL,
NULL,
NULL,
ALCdevice_GetLatencyDefault
NULL
};
ALCboolean alc_sndio_init(BackendFuncs *func_list)
+131 -81
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -36,14 +36,14 @@
#include "threads.h"
#include "compat.h"
#include "backends/base.h"
#include <sys/audioio.h>
static const ALCchar solaris_device[] = "Solaris Default";
typedef struct ALCsolarisBackend {
DERIVE_FROM_TYPE(ALCbackend);
static const char *solaris_driver = "/dev/audio";
typedef struct {
int fd;
ALubyte *mix_data;
@@ -51,13 +51,58 @@ typedef struct {
volatile int killNow;
althrd_t thread;
} solaris_data;
} ALCsolarisBackend;
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);
static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend)
DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend);
static int SolarisProc(void *ptr)
static const ALCchar solaris_device[] = "Solaris Default";
static const char *solaris_driver = "/dev/audio";
static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device)
{
ALCdevice *Device = (ALCdevice*)ptr;
solaris_data *data = (solaris_data*)Device->ExtraData;
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCsolarisBackend, ALCbackend, self);
self->fd = -1;
}
static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self)
{
if(self->fd != -1)
close(self->fd);
self->fd = -1;
free(self->mix_data);
self->mix_data = NULL;
self->data_size = 0;
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static int ALCsolarisBackend_mixerProc(void *ptr)
{
ALCsolarisBackend *self = ptr;
ALCdevice *Device = STATIC_CAST(ALCbackend,self)->mDevice;
ALint frameSize;
int wrote;
@@ -66,27 +111,27 @@ static int SolarisProc(void *ptr)
frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
while(!data->killNow && Device->Connected)
while(!self->killNow && Device->Connected)
{
ALint len = data->data_size;
ALubyte *WritePtr = data->mix_data;
ALint len = self->data_size;
ALubyte *WritePtr = self->mix_data;
aluMixData(Device, WritePtr, len/frameSize);
while(len > 0 && !data->killNow)
while(len > 0 && !self->killNow)
{
wrote = write(data->fd, WritePtr, len);
wrote = write(self->fd, WritePtr, len);
if(wrote < 0)
{
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
{
ERR("write failed: %s\n", strerror(errno));
ALCdevice_Lock(Device);
ALCsolarisBackend_lock(self);
aluHandleDisconnect(Device);
ALCdevice_Unlock(Device);
ALCsolarisBackend_unlock(self);
break;
}
al_nssleep(0, 1000000);
al_nssleep(1000000);
continue;
}
@@ -99,43 +144,37 @@ static int SolarisProc(void *ptr)
}
static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name)
{
solaris_data *data;
ALCdevice *device;
if(!deviceName)
deviceName = solaris_device;
else if(strcmp(deviceName, solaris_device) != 0)
if(!name)
name = solaris_device;
else if(strcmp(name, solaris_device) != 0)
return ALC_INVALID_VALUE;
data = (solaris_data*)calloc(1, sizeof(solaris_data));
data->killNow = 0;
data->fd = open(solaris_driver, O_WRONLY);
if(data->fd == -1)
self->fd = open(solaris_driver, O_WRONLY);
if(self->fd == -1)
{
free(data);
ERR("Could not open %s: %s\n", solaris_driver, strerror(errno));
return ALC_INVALID_VALUE;
}
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
device = STATIC_CAST(ALCbackend,self)->mDevice;
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void solaris_close_playback(ALCdevice *device)
static void ALCsolarisBackend_close(ALCsolarisBackend *self)
{
solaris_data *data = (solaris_data*)device->ExtraData;
close(data->fd);
free(data);
device->ExtraData = NULL;
close(self->fd);
self->fd = -1;
}
static ALCboolean solaris_reset_playback(ALCdevice *device)
static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
{
solaris_data *data = (solaris_data*)device->ExtraData;
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
audio_info_t info;
ALuint frameSize;
int numChannels;
@@ -174,7 +213,7 @@ static ALCboolean solaris_reset_playback(ALCdevice *device)
frameSize = numChannels * BytesFromDevFmt(device->FmtType);
info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize;
if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0)
if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0)
{
ERR("ioctl failed: %s\n", strerror(errno));
return ALC_FALSE;
@@ -201,74 +240,72 @@ static ALCboolean solaris_reset_playback(ALCdevice *device)
SetDefaultChannelOrder(device);
free(self->mix_data);
self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
self->mix_data = calloc(1, self->data_size);
return ALC_TRUE;
}
static ALCboolean solaris_start_playback(ALCdevice *device)
static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self)
{
solaris_data *data = (solaris_data*)device->ExtraData;
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
data->killNow = 0;
if(althrd_create(&data->thread, SolarisProc, device) != althrd_success)
{
free(data->mix_data);
data->mix_data = NULL;
self->killNow = 0;
if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success)
return ALC_FALSE;
}
return ALC_TRUE;
}
static void solaris_stop_playback(ALCdevice *device)
static void ALCsolarisBackend_stop(ALCsolarisBackend *self)
{
solaris_data *data = (solaris_data*)device->ExtraData;
int res;
if(data->killNow)
if(self->killNow)
return;
data->killNow = 1;
althrd_join(data->thread, &res);
self->killNow = 1;
althrd_join(self->thread, &res);
if(ioctl(data->fd, AUDIO_DRAIN) < 0)
if(ioctl(self->fd, AUDIO_DRAIN) < 0)
ERR("Error draining device: %s\n", strerror(errno));
free(data->mix_data);
data->mix_data = NULL;
}
static const BackendFuncs solaris_funcs = {
solaris_open_playback,
solaris_close_playback,
solaris_reset_playback,
solaris_start_playback,
solaris_stop_playback,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ALCdevice_GetLatencyDefault
};
typedef struct ALCsolarisBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCsolarisBackendFactory;
#define ALCSOLARISBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory) } }
ALCboolean alc_solaris_init(BackendFuncs *func_list)
ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self);
static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit)
static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type);
static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory);
ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void)
{
ConfigValueStr("solaris", "device", &solaris_driver);
static ALCsolarisBackendFactory factory = ALCSOLARISBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
*func_list = solaris_funcs;
static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory* UNUSED(self))
{
ConfigValueStr(NULL, "solaris", "device", &solaris_driver);
return ALC_TRUE;
}
void alc_solaris_deinit(void)
static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
return ALC_TRUE;
return ALC_FALSE;
}
void alc_solaris_probe(enum DevProbe type)
static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
@@ -286,3 +323,16 @@ void alc_solaris_probe(enum DevProbe type)
break;
}
}
ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCsolarisBackend *backend;
NEW_OBJ(backend, ALCsolarisBackend)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
+196 -131
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -24,26 +24,13 @@
#include <stdio.h>
#include <memory.h>
#include <errno.h>
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
typedef struct {
FILE *f;
long DataStart;
ALvoid *buffer;
ALuint size;
volatile int killNow;
althrd_t thread;
} wave_data;
#include "backends/base.h"
static const ALCchar waveDevice[] = "Wave File Writer";
@@ -57,18 +44,15 @@ static const ALubyte SUBTYPE_FLOAT[] = {
0x00, 0x38, 0x9b, 0x71
};
static const ALuint channel_masks[] = {
0, /* invalid */
0x4, /* Mono */
0x1 | 0x2, /* Stereo */
0, /* 3 channel */
0x1 | 0x2 | 0x10 | 0x20, /* Quad */
0, /* 5 channel */
0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */
0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */
0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */
static const ALubyte SUBTYPE_BFORMAT_PCM[] = {
0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
0xca, 0x00, 0x00, 0x00
};
static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = {
0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
0xca, 0x00, 0x00, 0x00
};
static void fwrite16le(ALushort val, FILE *f)
{
@@ -85,10 +69,57 @@ static void fwrite32le(ALuint val, FILE *f)
}
static int WaveProc(void *ptr)
typedef struct ALCwaveBackend {
DERIVE_FROM_TYPE(ALCbackend);
FILE *mFile;
long mDataStart;
ALvoid *mBuffer;
ALuint mSize;
volatile int killNow;
althrd_t thread;
} ALCwaveBackend;
static int ALCwaveBackend_mixerProc(void *ptr);
static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device);
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);
static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend)
DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend);
static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device)
{
ALCdevice *device = (ALCdevice*)ptr;
wave_data *data = (wave_data*)device->ExtraData;
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCwaveBackend, ALCbackend, self);
self->mFile = NULL;
self->mDataStart = -1;
self->mBuffer = NULL;
self->mSize = 0;
self->killNow = 1;
}
static int ALCwaveBackend_mixerProc(void *ptr)
{
ALCwaveBackend *self = (ALCwaveBackend*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct timespec now, start;
ALint64 avail, done;
ALuint frameSize;
@@ -106,7 +137,7 @@ static int WaveProc(void *ptr)
ERR("Failed to get starting time\n");
return 1;
}
while(!data->killNow && device->Connected)
while(!self->killNow && device->Connected)
{
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
@@ -125,41 +156,41 @@ static int WaveProc(void *ptr)
}
if(avail-done < device->UpdateSize)
al_nssleep(0, restTime);
al_nssleep(restTime);
else while(avail-done >= device->UpdateSize)
{
aluMixData(device, data->buffer, device->UpdateSize);
aluMixData(device, self->mBuffer, device->UpdateSize);
done += device->UpdateSize;
if(!IS_LITTLE_ENDIAN)
{
ALuint bytesize = BytesFromDevFmt(device->FmtType);
ALubyte *bytes = data->buffer;
ALubyte *bytes = self->mBuffer;
ALuint i;
if(bytesize == 1)
{
for(i = 0;i < data->size;i++)
fputc(bytes[i], data->f);
for(i = 0;i < self->mSize;i++)
fputc(bytes[i], self->mFile);
}
else if(bytesize == 2)
{
for(i = 0;i < data->size;i++)
fputc(bytes[i^1], data->f);
for(i = 0;i < self->mSize;i++)
fputc(bytes[i^1], self->mFile);
}
else if(bytesize == 4)
{
for(i = 0;i < data->size;i++)
fputc(bytes[i^3], data->f);
for(i = 0;i < self->mSize;i++)
fputc(bytes[i^3], self->mFile);
}
}
else
{
fs = fwrite(data->buffer, frameSize, device->UpdateSize,
data->f);
fs = fwrite(self->mBuffer, frameSize, device->UpdateSize,
self->mFile);
(void)fs;
}
if(ferror(data->f))
if(ferror(self->mFile))
{
ERR("Error writing to file\n");
ALCdevice_Lock(device);
@@ -173,52 +204,52 @@ static int WaveProc(void *ptr)
return 0;
}
static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name)
{
wave_data *data;
ALCdevice *device;
const char *fname;
fname = GetConfigValue("wave", "file", "");
if(!fname[0])
fname = GetConfigValue(NULL, "wave", "file", "");
if(!fname[0]) return ALC_INVALID_VALUE;
if(!name)
name = waveDevice;
else if(strcmp(name, waveDevice) != 0)
return ALC_INVALID_VALUE;
if(!deviceName)
deviceName = waveDevice;
else if(strcmp(deviceName, waveDevice) != 0)
return ALC_INVALID_VALUE;
data = (wave_data*)calloc(1, sizeof(wave_data));
data->f = al_fopen(fname, "wb");
if(!data->f)
self->mFile = al_fopen(fname, "wb");
if(!self->mFile)
{
free(data);
ERR("Could not open file '%s': %s\n", fname, strerror(errno));
return ALC_INVALID_VALUE;
}
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
device = STATIC_CAST(ALCbackend, self)->mDevice;
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void wave_close_playback(ALCdevice *device)
static void ALCwaveBackend_close(ALCwaveBackend *self)
{
wave_data *data = (wave_data*)device->ExtraData;
fclose(data->f);
free(data);
device->ExtraData = NULL;
if(self->mFile)
fclose(self->mFile);
self->mFile = NULL;
}
static ALCboolean wave_reset_playback(ALCdevice *device)
static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
{
wave_data *data = (wave_data*)device->ExtraData;
ALuint channels=0, bits=0;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALuint channels=0, bits=0, chanmask=0;
int isbformat = 0;
size_t val;
fseek(data->f, 0, SEEK_SET);
clearerr(data->f);
fseek(self->mFile, 0, SEEK_SET);
clearerr(self->mFile);
if(GetConfigValueBool(NULL, "wave", "bformat", 0))
device->FmtChans = DevFmtBFormat3D;
switch(device->FmtType)
{
@@ -237,135 +268,156 @@ static ALCboolean wave_reset_playback(ALCdevice *device)
case DevFmtFloat:
break;
}
switch(device->FmtChans)
{
case DevFmtMono: chanmask = 0x04; break;
case DevFmtStereo: chanmask = 0x01 | 0x02; break;
case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break;
case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
case DevFmtBFormat3D:
isbformat = 1;
chanmask = 0;
break;
}
bits = BytesFromDevFmt(device->FmtType) * 8;
channels = ChannelsFromDevFmt(device->FmtChans);
fprintf(data->f, "RIFF");
fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close
fprintf(self->mFile, "RIFF");
fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close
fprintf(data->f, "WAVE");
fprintf(self->mFile, "WAVE");
fprintf(data->f, "fmt ");
fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE
fprintf(self->mFile, "fmt ");
fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
// 16-bit val, format type id (extensible: 0xFFFE)
fwrite16le(0xFFFE, data->f);
fwrite16le(0xFFFE, self->mFile);
// 16-bit val, channel count
fwrite16le(channels, data->f);
fwrite16le(channels, self->mFile);
// 32-bit val, frequency
fwrite32le(device->Frequency, data->f);
fwrite32le(device->Frequency, self->mFile);
// 32-bit val, bytes per second
fwrite32le(device->Frequency * channels * bits / 8, data->f);
fwrite32le(device->Frequency * channels * bits / 8, self->mFile);
// 16-bit val, frame size
fwrite16le(channels * bits / 8, data->f);
fwrite16le(channels * bits / 8, self->mFile);
// 16-bit val, bits per sample
fwrite16le(bits, data->f);
fwrite16le(bits, self->mFile);
// 16-bit val, extra byte count
fwrite16le(22, data->f);
fwrite16le(22, self->mFile);
// 16-bit val, valid bits per sample
fwrite16le(bits, data->f);
fwrite16le(bits, self->mFile);
// 32-bit val, channel mask
fwrite32le(channel_masks[channels], data->f);
fwrite32le(chanmask, self->mFile);
// 16 byte GUID, sub-type format
val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f);
val = fwrite(((bits==32) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
(isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM)), 1, 16, self->mFile);
(void)val;
fprintf(data->f, "data");
fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close
fprintf(self->mFile, "data");
fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close
if(ferror(data->f))
if(ferror(self->mFile))
{
ERR("Error writing header: %s\n", strerror(errno));
return ALC_FALSE;
}
data->DataStart = ftell(data->f);
self->mDataStart = ftell(self->mFile);
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
static ALCboolean wave_start_playback(ALCdevice *device)
static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self)
{
wave_data *data = (wave_data*)device->ExtraData;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->buffer = malloc(data->size);
if(!data->buffer)
self->mSize = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
self->mBuffer = malloc(self->mSize);
if(!self->mBuffer)
{
ERR("Buffer malloc failed\n");
return ALC_FALSE;
}
data->killNow = 0;
if(althrd_create(&data->thread, WaveProc, device) != althrd_success)
self->killNow = 0;
if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success)
{
free(data->buffer);
data->buffer = NULL;
free(self->mBuffer);
self->mBuffer = NULL;
self->mSize = 0;
return ALC_FALSE;
}
return ALC_TRUE;
}
static void wave_stop_playback(ALCdevice *device)
static void ALCwaveBackend_stop(ALCwaveBackend *self)
{
wave_data *data = (wave_data*)device->ExtraData;
ALuint dataLen;
long size;
int res;
if(data->killNow)
if(self->killNow)
return;
data->killNow = 1;
althrd_join(data->thread, &res);
self->killNow = 1;
althrd_join(self->thread, &res);
free(data->buffer);
data->buffer = NULL;
free(self->mBuffer);
self->mBuffer = NULL;
size = ftell(data->f);
size = ftell(self->mFile);
if(size > 0)
{
dataLen = size - data->DataStart;
if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0)
fwrite32le(dataLen, data->f); // 'data' header len
if(fseek(data->f, 4, SEEK_SET) == 0)
fwrite32le(size-8, data->f); // 'WAVE' header len
dataLen = size - self->mDataStart;
if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0)
fwrite32le(dataLen, self->mFile); // 'data' header len
if(fseek(self->mFile, 4, SEEK_SET) == 0)
fwrite32le(size-8, self->mFile); // 'WAVE' header len
}
}
static const BackendFuncs wave_funcs = {
wave_open_playback,
wave_close_playback,
wave_reset_playback,
wave_start_playback,
wave_stop_playback,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ALCdevice_GetLatencyDefault
};
typedef struct ALCwaveBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCwaveBackendFactory;
#define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } }
ALCboolean alc_wave_init(BackendFuncs *func_list)
ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self);
static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit)
static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type);
static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory);
ALCbackendFactory *ALCwaveBackendFactory_getFactory(void)
{
static ALCwaveBackendFactory factory = ALCWAVEBACKENDFACTORY_INITIALIZER;
return STATIC_CAST(ALCbackendFactory, &factory);
}
static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self))
{
*func_list = wave_funcs;
return ALC_TRUE;
}
void alc_wave_deinit(void)
static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
return !!ConfigValueExists(NULL, "wave", "file");
return ALC_FALSE;
}
void alc_wave_probe(enum DevProbe type)
static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type)
{
if(!ConfigValueExists("wave", "file"))
return;
switch(type)
{
case ALL_DEVICE_PROBE:
@@ -375,3 +427,16 @@ void alc_wave_probe(enum DevProbe type)
break;
}
}
static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
ALCwaveBackend *backend;
NEW_OBJ(backend, ALCwaveBackend)(device);
if(!backend) return NULL;
return STATIC_CAST(ALCbackend, backend);
}
return NULL;
}
File diff suppressed because it is too large Load Diff
+6 -17
View File
@@ -29,9 +29,6 @@
#include "bs2b.h"
#include "alu.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* Set up all data. */
static void init(struct bs2b *bs2b)
@@ -40,8 +37,6 @@ static void init(struct bs2b *bs2b)
float G_lo, G_hi;
float x, g;
bs2b->srate = clampi(bs2b->srate, 2000, 192000);
switch(bs2b->level)
{
case BS2B_LOW_CLEVEL: /* Low crossfeed level */
@@ -105,31 +100,25 @@ static void init(struct bs2b *bs2b)
bs2b->a1_hi = -x * g;
} /* init */
/* Exported functions.
* See descriptions in "bs2b.h"
*/
void bs2b_set_level(struct bs2b *bs2b, int level)
void bs2b_set_params(struct bs2b *bs2b, int level, int srate)
{
if(level == bs2b->level)
return;
if(srate <= 0) srate = 1;
bs2b->level = level;
bs2b->srate = srate;
init(bs2b);
} /* bs2b_set_level */
} /* bs2b_set_params */
int bs2b_get_level(struct bs2b *bs2b)
{
return bs2b->level;
} /* bs2b_get_level */
void bs2b_set_srate(struct bs2b *bs2b, int srate)
{
if (srate == bs2b->srate)
return;
bs2b->srate = srate;
init(bs2b);
} /* bs2b_set_srate */
int bs2b_get_srate(struct bs2b *bs2b)
{
return bs2b->srate;
+12 -14
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -31,15 +31,15 @@
/* Auto-wah is simply a low-pass filter with a cutoff frequency that shifts up
* or down depending on the input signal, and a resonant peak at the cutoff.
*
* Currently, we assume a cutoff frequency range of 500hz (no amplitude) to
* 3khz (peak gain). Peak gain is assumed to be in normalized scale.
* Currently, we assume a cutoff frequency range of 20hz (no amplitude) to
* 20khz (peak gain). Peak gain is assumed to be in normalized scale.
*/
typedef struct ALautowahState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
ALfloat Gain[MaxChannels];
ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALfloat AttackRate;
@@ -66,7 +66,6 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *d
static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, const ALeffectslot *slot)
{
ALfloat attackTime, releaseTime;
ALfloat gain;
attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency;
releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency;
@@ -76,19 +75,18 @@ static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, co
state->PeakGain = slot->EffectProps.Autowah.PeakGain;
state->Resonance = slot->EffectProps.Autowah.Resonance;
gain = sqrtf(1.0f / device->NumChan) * slot->Gain;
SetGains(device, gain, state->Gain);
ComputeAmbientGains(device, slot->Gain, state->Gain);
}
static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint it, kt;
ALuint base;
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[64];
ALuint td = minu(SamplesToDo-base, 64);
ALfloat temps[256];
ALuint td = minu(256, SamplesToDo-base);
ALfloat gain = state->GainCtrl;
for(it = 0;it < td;it++)
@@ -114,7 +112,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
* ALfilterType_LowPass. However, instead of passing a bandwidth,
* we use the resonance property for Q. This also inlines the call.
*/
w0 = F_2PI * cutoff / state->Frequency;
w0 = F_TAU * cutoff / state->Frequency;
/* FIXME: Resonance controls the resonant peak, or Q. How? Not sure
* that Q = resonance*0.1. */
@@ -137,10 +135,10 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
}
state->GainCtrl = gain;
for(kt = 0;kt < MaxChannels;kt++)
for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[kt];
if(!(gain > GAIN_SILENCE_THRESHOLD))
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
+14 -12
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -46,7 +46,7 @@ typedef struct ALchorusState {
ALint lfo_disp;
/* Gains for left and right sides */
ALfloat Gain[2][MaxChannels];
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
/* effect parameters */
enum ChorusWaveForm waveform;
@@ -93,6 +93,8 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev
static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot)
{
static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f };
static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f };
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat rate;
ALint phase;
@@ -111,8 +113,8 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency);
/* Gains for left and right sides */
ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]);
ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]);
ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]);
ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]);
phase = Slot->EffectProps.Chorus.Phase;
rate = Slot->EffectProps.Chorus.Rate;
@@ -132,7 +134,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
state->lfo_scale = 4.0f / state->lfo_range;
break;
case CWF_Sinusoid:
state->lfo_scale = F_2PI / state->lfo_range;
state->lfo_scale = F_TAU / state->lfo_range;
break;
}
@@ -201,15 +203,15 @@ DECL_TEMPLATE(Sinusoid)
#undef DECL_TEMPLATE
static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint it, kt;
ALuint base;
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[64][2];
ALuint td = minu(SamplesToDo-base, 64);
ALfloat temps[128][2];
ALuint td = minu(128, SamplesToDo-base);
switch(state->waveform)
{
@@ -221,17 +223,17 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co
break;
}
for(kt = 0;kt < MaxChannels;kt++)
for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[0][kt];
if(gain > GAIN_SILENCE_THRESHOLD)
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(it = 0;it < td;it++)
SamplesOut[kt][it+base] += temps[it][0] * gain;
}
gain = state->Gain[1][kt];
if(gain > GAIN_SILENCE_THRESHOLD)
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(it = 0;it < td;it++)
SamplesOut[kt][it+base] += temps[it][1] * gain;
+11 -14
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -31,7 +31,7 @@ typedef struct ALcompressorState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
ALfloat Gain[MaxChannels];
ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALboolean Enabled;
@@ -55,25 +55,22 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev
return AL_TRUE;
}
static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *Device, const ALeffectslot *Slot)
static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *device, const ALeffectslot *slot)
{
ALfloat gain;
state->Enabled = slot->EffectProps.Compressor.OnOff;
state->Enabled = Slot->EffectProps.Compressor.OnOff;
gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
SetGains(Device, gain, state->Gain);
ComputeAmbientGains(device, slot->Gain, state->Gain);
}
static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint it, kt;
ALuint base;
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[64];
ALuint td = minu(SamplesToDo-base, 64);
ALfloat temps[256];
ALuint td = minu(256, SamplesToDo-base);
if(state->Enabled)
{
@@ -119,10 +116,10 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples
}
for(kt = 0;kt < MaxChannels;kt++)
for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[kt];
if(!(gain > GAIN_SILENCE_THRESHOLD))
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
+28 -14
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -32,7 +32,7 @@
typedef struct ALdedicatedState {
DERIVE_FROM_TYPE(ALeffectState);
ALfloat gains[MaxChannels];
ALfloat gains[MAX_OUTPUT_CHANNELS];
} ALdedicatedState;
@@ -48,27 +48,41 @@ static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state),
static ALvoid ALdedicatedState_update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot)
{
ALfloat Gain;
ALsizei s;
ALuint i;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
state->gains[i] = 0.0f;
Gain = Slot->Gain * Slot->EffectProps.Dedicated.Gain;
if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains);
else if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
{
for(s = 0;s < MaxChannels;s++)
state->gains[s] = 0.0f;
state->gains[LFE] = Gain;
int idx;
if((idx=GetChannelIdxByName(device, LFE)) != -1)
state->gains[idx] = Gain;
}
else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
{
int idx;
/* Dialog goes to the front-center speaker if it exists, otherwise it
* plays from the front-center location. */
if((idx=GetChannelIdxByName(device, FrontCenter)) != -1)
state->gains[idx] = Gain;
else
{
static const ALfloat front_dir[3] = { 0.0f, 0.0f, -1.0f };
ComputeDirectionalGains(device, front_dir, Gain, state->gains);
}
}
}
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
const ALfloat *gains = state->gains;
ALuint i, c;
for(c = 0;c < MaxChannels;c++)
for(c = 0;c < NumChannels;c++)
{
if(!(gains[c] > GAIN_SILENCE_THRESHOLD))
if(!(fabsf(gains[c]) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < SamplesToDo;i++)
@@ -94,7 +108,7 @@ ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(fa
if(!state) return NULL;
SET_VTABLE2(ALdedicatedState, ALeffectState, state);
for(s = 0;s < MaxChannels;s++)
for(s = 0;s < MAX_OUTPUT_CHANNELS;s++)
state->gains[s] = 0.0f;
return STATIC_CAST(ALeffectState, state);
+18 -20
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -34,7 +34,7 @@ typedef struct ALdistortionState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
ALfloat Gain[MaxChannels];
ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALfilterState lowpass;
@@ -58,7 +58,6 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi
ALfloat bandwidth;
ALfloat cutoff;
ALfloat edge;
ALfloat gain;
/* Store distorted signal attenuation settings */
state->attenuation = Slot->EffectProps.Distortion.Gain;
@@ -73,23 +72,23 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi
/* Bandwidth value is constant in octaves */
bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
cutoff / (frequency*4.0f), bandwidth);
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
);
/* Bandpass filter */
cutoff = Slot->EffectProps.Distortion.EQCenter;
/* Convert bandwidth in Hz to octaves */
bandwidth = Slot->EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f);
ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
cutoff / (frequency*4.0f), bandwidth);
cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
);
gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
SetGains(Device, gain, state->Gain);
ComputeAmbientGains(Device, Slot->Gain, state->Gain);
}
static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
const ALfloat fc = state->edge_coeff;
float oversample_buffer[64][4];
ALuint base;
ALuint it;
ALuint ot;
@@ -97,8 +96,8 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[64];
ALuint td = minu(SamplesToDo-base, 64);
float oversample_buffer[64][4];
ALuint td = minu(64, SamplesToDo-base);
/* Perform 4x oversampling to avoid aliasing. */
/* Oversampling greatly improves distortion */
@@ -150,20 +149,19 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples
smp = ALfilterState_processSingle(&state->bandpass, smp);
oversample_buffer[it][ot] = smp;
}
/* Fourth step, final, do attenuation and perform decimation, */
/* store only one sample out of 4. */
temps[it] = oversample_buffer[it][0] * state->attenuation;
}
for(kt = 0;kt < MaxChannels;kt++)
for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[kt];
if(!(gain > GAIN_SILENCE_THRESHOLD))
/* Fourth step, final, do attenuation and perform decimation,
* store only one sample out of 4.
*/
ALfloat gain = state->Gain[kt] * state->attenuation;
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
SamplesOut[kt][base+it] += gain * temps[it];
SamplesOut[kt][base+it] += gain * oversample_buffer[it][0];
}
base += td;
+18 -16
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -43,7 +43,7 @@ typedef struct ALechoState {
} Tap[2];
ALuint Offset;
/* The panning gains for the two taps */
ALfloat Gain[2][MaxChannels];
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
ALfloat FeedGain;
@@ -83,9 +83,9 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const ALeffectslot *Slot)
{
ALfloat pandir[3] = { 0.0f, 0.0f, 0.0f };
ALuint frequency = Device->Frequency;
ALfloat lrpan, gain;
ALfloat dirGain;
ALfloat gain, lrpan;
state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1;
state->Tap[1].delay = fastf2u(Slot->EffectProps.Echo.LRDelay * frequency);
@@ -95,21 +95,23 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL
state->FeedGain = Slot->EffectProps.Echo.Feedback;
gain = minf(1.0f - Slot->EffectProps.Echo.Damping, 0.01f);
ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
1.0f - Slot->EffectProps.Echo.Damping,
LOWPASSFREQREF/frequency, 0.0f);
gain, LOWPASSFREQREF/frequency,
calc_rcpQ_from_slope(gain, 0.75f));
gain = Slot->Gain;
dirGain = fabsf(lrpan);
/* First tap panning */
ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]);
pandir[0] = -lrpan;
ComputeDirectionalGains(Device, pandir, gain, state->Gain[0]);
/* Second tap panning */
ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]);
pandir[0] = +lrpan;
ComputeDirectionalGains(Device, pandir, gain, state->Gain[1]);
}
static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
const ALuint mask = state->BufferLength-1;
const ALuint tap1 = state->Tap[0].delay;
@@ -121,8 +123,8 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[64][2];
ALuint td = minu(SamplesToDo-base, 64);
ALfloat temps[128][2];
ALuint td = minu(128, SamplesToDo-base);
for(i = 0;i < td;i++)
{
@@ -138,17 +140,17 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const
offset++;
}
for(k = 0;k < MaxChannels;k++)
for(k = 0;k < NumChannels;k++)
{
ALfloat gain = state->Gain[0][k];
if(gain > GAIN_SILENCE_THRESHOLD)
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(gain > GAIN_SILENCE_THRESHOLD)
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < td;i++)
SamplesOut[k][i+base] += temps[i][1] * gain;
+30 -23
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -75,7 +75,7 @@ typedef struct ALequalizerState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
ALfloat Gain[MaxChannels];
ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALfilterState filter[4];
@@ -93,33 +93,40 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state),
static ALvoid ALequalizerState_update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot)
{
ALfloat frequency = (ALfloat)device->Frequency;
ALfloat gain = sqrtf(1.0f / device->NumChan) * slot->Gain;
ALfloat gain, freq_mult;
SetGains(device, gain, state->Gain);
ComputeAmbientGains(device, slot->Gain, state->Gain);
/* Calculate coefficients for the each type of filter */
/* Calculate coefficients for the each type of filter. Note that the shelf
* filters' gain is for the reference frequency, which is the centerpoint
* of the transition band.
*/
gain = sqrtf(slot->EffectProps.Equalizer.LowGain);
freq_mult = slot->EffectProps.Equalizer.LowCutoff/frequency;
ALfilterState_setParams(&state->filter[0], ALfilterType_LowShelf,
sqrtf(slot->EffectProps.Equalizer.LowGain),
slot->EffectProps.Equalizer.LowCutoff/frequency,
0.0f);
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
);
gain = slot->EffectProps.Equalizer.Mid1Gain;
freq_mult = slot->EffectProps.Equalizer.Mid1Center/frequency;
ALfilterState_setParams(&state->filter[1], ALfilterType_Peaking,
sqrtf(slot->EffectProps.Equalizer.Mid1Gain),
slot->EffectProps.Equalizer.Mid1Center/frequency,
slot->EffectProps.Equalizer.Mid1Width);
gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid1Width)
);
gain = slot->EffectProps.Equalizer.Mid2Gain;
freq_mult = slot->EffectProps.Equalizer.Mid2Center/frequency;
ALfilterState_setParams(&state->filter[2], ALfilterType_Peaking,
sqrtf(slot->EffectProps.Equalizer.Mid2Gain),
slot->EffectProps.Equalizer.Mid2Center/frequency,
slot->EffectProps.Equalizer.Mid2Width);
gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid2Width)
);
gain = sqrtf(slot->EffectProps.Equalizer.HighGain);
freq_mult = slot->EffectProps.Equalizer.HighCutoff/frequency;
ALfilterState_setParams(&state->filter[3], ALfilterType_HighShelf,
sqrtf(slot->EffectProps.Equalizer.HighGain),
slot->EffectProps.Equalizer.HighCutoff/frequency,
0.0f);
gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
);
}
static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint base;
ALuint it;
@@ -128,8 +135,8 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[64];
ALuint td = minu(SamplesToDo-base, 64);
ALfloat temps[256];
ALuint td = minu(256, SamplesToDo-base);
for(it = 0;it < td;it++)
{
@@ -141,10 +148,10 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo
temps[it] = smp;
}
for(kt = 0;kt < MaxChannels;kt++)
for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[kt];
if(!(gain > GAIN_SILENCE_THRESHOLD))
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
+14 -12
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -46,7 +46,7 @@ typedef struct ALflangerState {
ALint lfo_disp;
/* Gains for left and right sides */
ALfloat Gain[2][MaxChannels];
ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
/* effect parameters */
enum FlangerWaveForm waveform;
@@ -93,6 +93,8 @@ static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *D
static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, const ALeffectslot *Slot)
{
static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f };
static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f };
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat rate;
ALint phase;
@@ -111,8 +113,8 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
/* Gains for left and right sides */
ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]);
ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]);
ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]);
ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]);
phase = Slot->EffectProps.Flanger.Phase;
rate = Slot->EffectProps.Flanger.Rate;
@@ -132,7 +134,7 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
state->lfo_scale = 4.0f / state->lfo_range;
break;
case FWF_Sinusoid:
state->lfo_scale = F_2PI / state->lfo_range;
state->lfo_scale = F_TAU / state->lfo_range;
break;
}
@@ -201,15 +203,15 @@ DECL_TEMPLATE(Sinusoid)
#undef DECL_TEMPLATE
static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint it, kt;
ALuint base;
for(base = 0;base < SamplesToDo;)
{
ALfloat temps[64][2];
ALuint td = minu(SamplesToDo-base, 64);
ALfloat temps[128][2];
ALuint td = minu(128, SamplesToDo-base);
switch(state->waveform)
{
@@ -221,17 +223,17 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo,
break;
}
for(kt = 0;kt < MaxChannels;kt++)
for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[0][kt];
if(gain > GAIN_SILENCE_THRESHOLD)
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(it = 0;it < td;it++)
SamplesOut[kt][it+base] += temps[it][0] * gain;
}
gain = state->Gain[1][kt];
if(gain > GAIN_SILENCE_THRESHOLD)
if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(it = 0;it < td;it++)
SamplesOut[kt][it+base] += temps[it][1] * gain;
+16 -17
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -42,7 +42,7 @@ typedef struct ALmodulatorState {
ALuint index;
ALuint step;
ALfloat Gain[MaxChannels];
ALfloat Gain[MAX_OUTPUT_CHANNELS];
ALfilterState Filter;
} ALmodulatorState;
@@ -53,7 +53,7 @@ typedef struct ALmodulatorState {
static inline ALfloat Sin(ALuint index)
{
return sinf(index*(F_2PI/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
return sinf(index*(F_TAU/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
}
static inline ALfloat Saw(ALuint index)
@@ -69,7 +69,7 @@ static inline ALfloat Square(ALuint index)
#define DECL_TEMPLATE(func) \
static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \
const ALfloat *restrict SamplesIn, \
ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \
ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) \
{ \
const ALuint step = state->step; \
ALuint index = state->index; \
@@ -77,8 +77,8 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \
\
for(base = 0;base < SamplesToDo;) \
{ \
ALfloat temps[64]; \
ALuint td = minu(SamplesToDo-base, 64); \
ALfloat temps[256]; \
ALuint td = minu(256, SamplesToDo-base); \
ALuint i, k; \
\
for(i = 0;i < td;i++) \
@@ -92,10 +92,10 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \
temps[i] = samp * func(index); \
} \
\
for(k = 0;k < MaxChannels;k++) \
for(k = 0;k < NumChannels;k++) \
{ \
ALfloat gain = state->Gain[k]; \
if(!(gain > GAIN_SILENCE_THRESHOLD)) \
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) \
continue; \
\
for(i = 0;i < td;i++) \
@@ -125,7 +125,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state),
static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot)
{
ALfloat gain, cw, a;
ALfloat cw, a;
if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
state->Waveform = SINUSOID;
@@ -139,7 +139,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device
if(state->step == 0) state->step = 1;
/* Custom filter coeffs, which match the old version instead of a low-shelf. */
cw = cosf(F_2PI * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency);
cw = cosf(F_TAU * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency);
a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
state->Filter.b[0] = a;
@@ -149,24 +149,23 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device
state->Filter.a[1] = -a;
state->Filter.a[2] = 0.0f;
gain = sqrtf(1.0f/Device->NumChan) * Slot->Gain;
SetGains(Device, gain, state->Gain);
ComputeAmbientGains(Device, Slot->Gain, state->Gain);
}
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
switch(state->Waveform)
{
case SINUSOID:
ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut);
ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
break;
case SAWTOOTH:
ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut);
ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
break;
case SQUARE:
ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut);
ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
break;
}
}
+1 -4
View File
@@ -41,11 +41,8 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), ALCdevice* UNUSED(d
* input to the output buffer. The result should be added to the output buffer,
* not replace it.
*/
static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloat (*restrict samplesOut)[BUFFERSIZE])
static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels))
{
/* NOTE: Couldn't use the UNUSED macro on samplesOut due to the way GCC's
* __attribute__ declaration interacts with the parenthesis. */
(void)samplesOut;
}
/* This allocates memory to store the object, before it gets constructed.
File diff suppressed because it is too large Load Diff
+669 -107
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -35,6 +35,9 @@
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifndef AL_NO_UID_DEFS
#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
@@ -55,10 +58,13 @@ DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6);
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17);
#ifdef HAVE_MMDEVAPI
#include <devpropdef.h>
#include <propkeydef.h>
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
#endif
#endif
#endif /* AL_NO_UID_DEFS */
@@ -82,7 +88,9 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
#include <ieeefp.h>
#endif
#ifdef _WIN32_IE
#ifndef _WIN32
#include <unistd.h>
#elif defined(_WIN32_IE)
#include <shlobj.h>
#endif
@@ -144,8 +152,12 @@ void FillCPUCaps(ALuint capfilter)
if((cpuinf[0].regs[3]&(1<<26)))
{
caps |= CPU_CAP_SSE2;
if((cpuinf[0].regs[2]&(1<<19)))
caps |= CPU_CAP_SSE4_1;
if((cpuinf[0].regs[2]&(1<<0)))
{
caps |= CPU_CAP_SSE3;
if((cpuinf[0].regs[2]&(1<<19)))
caps |= CPU_CAP_SSE4_1;
}
}
}
}
@@ -188,8 +200,12 @@ void FillCPUCaps(ALuint capfilter)
if((cpuinf[0].regs[3]&(1<<26)))
{
caps |= CPU_CAP_SSE2;
if((cpuinf[0].regs[2]&(1<<19)))
caps |= CPU_CAP_SSE4_1;
if((cpuinf[0].regs[2]&(1<<0)))
{
caps |= CPU_CAP_SSE3;
if((cpuinf[0].regs[2]&(1<<19)))
caps |= CPU_CAP_SSE4_1;
}
}
}
}
@@ -198,13 +214,16 @@ void FillCPUCaps(ALuint capfilter)
/* Assume support for whatever's supported if we can't check for it */
#if defined(HAVE_SSE4_1)
#warning "Assuming SSE 4.1 run-time support!"
capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1;
caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
#elif defined(HAVE_SSE3)
#warning "Assuming SSE 3 run-time support!"
caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
#elif defined(HAVE_SSE2)
#warning "Assuming SSE 2 run-time support!"
capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
caps |= CPU_CAP_SSE | CPU_CAP_SSE2;
#elif defined(HAVE_SSE)
#warning "Assuming SSE run-time support!"
capfilter |= CPU_CAP_SSE;
caps |= CPU_CAP_SSE;
#endif
#endif
#ifdef HAVE_NEON
@@ -212,9 +231,10 @@ void FillCPUCaps(ALuint capfilter)
caps |= CPU_CAP_NEON;
#endif
TRACE("Extensions:%s%s%s%s%s\n",
TRACE("Extensions:%s%s%s%s%s%s\n",
((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""),
((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""),
((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""),
((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""),
((!capfilter) ? " -none-" : "")
@@ -240,7 +260,7 @@ void *al_malloc(size_t alignment, size_t size)
if(ret != NULL)
{
*(ret++) = 0x00;
while(((ALintptrEXT)ret&(alignment-1)) != 0)
while(((ptrdiff_t)ret&(alignment-1)) != 0)
*(ret++) = 0x55;
}
return ret;
@@ -278,6 +298,8 @@ void SetMixerFPUMode(FPUCtl *ctl)
#ifdef HAVE_FENV_H
fegetenv(STATIC_CAST(fenv_t, ctl));
#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
@@ -421,6 +443,390 @@ FILE *al_fopen(const char *fname, const char *mode)
return file;
}
void al_print(const char *type, const char *func, const char *fmt, ...)
{
char str[1024];
WCHAR *wstr;
va_list ap;
va_start(ap, fmt);
vsnprintf(str, sizeof(str), fmt, ap);
va_end(ap);
str[sizeof(str)-1] = 0;
wstr = FromUTF8(str);
if(!wstr)
fprintf(LogFile, "AL lib: %s %s: <UTF-8 error> %s", type, func, str);
else
{
fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr);
free(wstr);
wstr = NULL;
}
fflush(LogFile);
}
static inline int is_slash(int c)
{ return (c == '\\' || c == '/'); }
FILE *OpenDataFile(const char *fname, const char *subdir)
{
static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
WCHAR *wname=NULL, *wsubdir=NULL;
FILE *f;
size_t i;
wname = FromUTF8(fname);
if(!wname)
{
ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
return NULL;
}
/* If the path is absolute, open it directly. */
if(wname[0] != '\0' && wname[1] == ':' && is_slash(wname[2]))
{
f = _wfopen(wname, L"rb");
if(f) TRACE("Opened %s\n", fname);
else WARN("Could not open %s\n", fname);
free(wname);
return f;
}
/* Try the current directory first before the data directories. */
if((f=_wfopen(wname, L"rb")) != NULL)
{
TRACE("Opened %s\n", fname);
free(wname);
return f;
}
wsubdir = FromUTF8(subdir);
if(!wsubdir)
{
ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir);
free(wname);
return NULL;
}
for(i = 0;i < COUNTOF(ids);i++)
{
WCHAR buffer[PATH_MAX];
size_t len;
if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE)
continue;
len = lstrlenW(buffer);
if(len > 0 && is_slash(buffer[len-1]))
buffer[--len] = '\0';
_snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname);
len = lstrlenW(buffer);
while(len > 0)
{
--len;
if(buffer[len] == '/')
buffer[len] = '\\';
}
if((f=_wfopen(buffer, L"rb")) != NULL)
{
al_string filepath = AL_STRING_INIT_STATIC();
al_string_copy_wcstr(&filepath, buffer);
TRACE("Opened %s\n", al_string_get_cstr(filepath));
al_string_deinit(&filepath);
break;
}
}
free(wname);
free(wsubdir);
if(f == NULL)
WARN("Could not open %s\\%s\n", subdir, fname);
return f;
}
static const WCHAR *strchrW(const WCHAR *str, WCHAR ch)
{
for(;*str != 0;++str)
{
if(*str == ch)
return str;
}
return NULL;
}
static const WCHAR *strrchrW(const WCHAR *str, WCHAR ch)
{
const WCHAR *ret = NULL;
for(;*str != 0;++str)
{
if(*str == ch)
ret = str;
}
return ret;
}
/* Compares the filename in the find data with the match string. The match
* string may contain the "%r" marker to signifiy a sample rate (really any
* positive integer), or "%%" to signify a single '%'.
*/
static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata)
{
const WCHAR *name = fdata->cFileName;
int ret = 1;
do {
const WCHAR *p = strchrW(match, '%');
if(!p)
ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
match, -1, name, -1) == CSTR_EQUAL;
else
{
int len = p-match;
ret = lstrlenW(name) >= len;
if(ret)
ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
match, len, name, len) == CSTR_EQUAL;
if(ret)
{
match += len;
name += len;
++p;
if(*p == 'r')
{
unsigned long l = 0;
while(*name >= '0' && *name <= '9')
{
l = l*10 + (*name-'0');
++name;
}
ret = l > 0;
++p;
}
}
}
match = p;
} while(ret && match && *match);
return ret;
}
static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_al_string *results)
{
WIN32_FIND_DATAW fdata;
const WCHAR *sep, *p;
HANDLE hdl;
if(!match[0])
return;
/* Find the last directory separator and the next '%' marker in the match
* string. */
sep = strrchrW(match, '\\');
p = strchrW(match, '%');
/* If there's no separator, test the files in the specified path against
* the match string, and add the results. */
if(!sep)
{
al_string pathstr = AL_STRING_INIT_STATIC();
WCHAR *wpath;
TRACE("Searching %s for %ls\n", path, match);
al_string_append_cstr(&pathstr, path);
al_string_append_cstr(&pathstr, "\\*.*");
wpath = FromUTF8(al_string_get_cstr(pathstr));
hdl = FindFirstFileW(wpath, &fdata);
if(hdl != INVALID_HANDLE_VALUE)
{
do {
if(MatchFilter(match, &fdata))
{
al_string str = AL_STRING_INIT_STATIC();
al_string_copy_cstr(&str, path);
al_string_append_char(&str, '\\');
al_string_append_wcstr(&str, fdata.cFileName);
TRACE("Got result %s\n", al_string_get_cstr(str));
VECTOR_PUSH_BACK(*results, str);
}
} while(FindNextFileW(hdl, &fdata));
FindClose(hdl);
}
free(wpath);
al_string_deinit(&pathstr);
return;
}
/* If there's no '%' marker, or it's after the final separator, append the
* remaining directories to the path and recurse into it with the remaining
* filename portion. */
if(!p || p-sep >= 0)
{
al_string npath = AL_STRING_INIT_STATIC();
al_string_append_cstr(&npath, path);
al_string_append_char(&npath, '\\');
al_string_append_wrange(&npath, match, sep);
TRACE("Recursing into %s with %ls\n", al_string_get_cstr(npath), sep+1);
RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results);
al_string_deinit(&npath);
return;
}
/* Look for the last separator before the '%' marker, and the first
* separator after it. */
sep = strchrW(match, '\\');
if(sep-p >= 0) sep = NULL;
for(;;)
{
const WCHAR *next = strchrW(sep?sep+1:match, '\\');
if(next-p < 0)
{
al_string npath = AL_STRING_INIT_STATIC();
WCHAR *nwpath, *nwmatch;
/* Append up to the last directory before the one with a '%'. */
al_string_copy_cstr(&npath, path);
if(sep)
{
al_string_append_char(&npath, '\\');
al_string_append_wrange(&npath, match, sep);
}
al_string_append_cstr(&npath, "\\*.*");
nwpath = FromUTF8(al_string_get_cstr(npath));
/* Take the directory name containing a '%' as a new string to
* match against. */
if(!sep)
{
nwmatch = calloc(2, next-match+1);
memcpy(nwmatch, match, (next-match)*2);
}
else
{
nwmatch = calloc(2, next-(sep+1)+1);
memcpy(nwmatch, sep+1, (next-(sep+1))*2);
}
/* For each matching directory name, recurse into it with the
* remaining string. */
TRACE("Searching %s for %ls\n", al_string_get_cstr(npath), nwmatch);
hdl = FindFirstFileW(nwpath, &fdata);
if(hdl != INVALID_HANDLE_VALUE)
{
do {
if(MatchFilter(nwmatch, &fdata))
{
al_string ndir = AL_STRING_INIT_STATIC();
al_string_copy(&ndir, npath);
al_string_append_char(&ndir, '\\');
al_string_append_wcstr(&ndir, fdata.cFileName);
TRACE("Recursing %s with %ls\n", al_string_get_cstr(ndir), next+1);
RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results);
al_string_deinit(&ndir);
}
} while(FindNextFileW(hdl, &fdata));
FindClose(hdl);
}
free(nwmatch);
free(nwpath);
al_string_deinit(&npath);
break;
}
sep = next;
}
}
vector_al_string SearchDataFiles(const char *match, const char *subdir)
{
static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
static RefCount search_lock;
vector_al_string results = VECTOR_INIT_STATIC();
WCHAR *wmatch;
size_t i;
while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
althrd_yield();
wmatch = FromUTF8(match);
if(!wmatch)
{
ERR("Failed to convert UTF-8 filename: \"%s\"\n", match);
return results;
}
for(i = 0;wmatch[i];++i)
{
if(wmatch[i] == '/')
wmatch[i] = '\\';
}
/* If the path is absolute, use it directly. */
if(isalpha(wmatch[0]) && wmatch[1] == ':' && is_slash(wmatch[2]))
{
char drv[3] = { (char)wmatch[0], ':', 0 };
RecurseDirectorySearch(drv, wmatch+3, &results);
}
else if(wmatch[0] == '\\' && wmatch[1] == '\\' && wmatch[2] == '?' && wmatch[3] == '\\')
RecurseDirectorySearch("\\\\?", wmatch+4, &results);
else
{
al_string path = AL_STRING_INIT_STATIC();
WCHAR *cwdbuf;
/* Search the CWD. */
if(!(cwdbuf=_wgetcwd(NULL, 0)))
al_string_copy_cstr(&path, ".");
else
{
al_string_copy_wcstr(&path, cwdbuf);
if(is_slash(VECTOR_BACK(path)))
{
VECTOR_POP_BACK(path);
*VECTOR_ITER_END(path) = 0;
}
free(cwdbuf);
}
RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results);
/* Search the local and global data dirs. */
for(i = 0;i < COUNTOF(ids);i++)
{
WCHAR buffer[PATH_MAX];
if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE)
{
al_string_copy_wcstr(&path, buffer);
if(!is_slash(VECTOR_BACK(path)))
al_string_append_char(&path, '\\');
al_string_append_cstr(&path, subdir);
#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
VECTOR_FOR_EACH(char, path, FIX_SLASH);
#undef FIX_SLASH
RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results);
}
}
al_string_deinit(&path);
}
free(wmatch);
ATOMIC_STORE(&search_lock, 0);
return results;
}
#else
#ifdef HAVE_DLFCN_H
@@ -453,9 +859,7 @@ void *GetSymbol(void *handle, const char *name)
return sym;
}
#endif
#endif
#endif /* HAVE_DLFCN_H */
void al_print(const char *type, const char *func, const char *fmt, ...)
{
@@ -469,76 +873,7 @@ void al_print(const char *type, const char *func, const char *fmt, ...)
fflush(LogFile);
}
#ifdef _WIN32
static inline int is_slash(int c)
{ return (c == '\\' || c == '/'); }
FILE *OpenDataFile(const char *fname, const char *subdir)
{
static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
WCHAR *wname=NULL, *wsubdir=NULL;
FILE *f;
int i;
/* If the path is absolute, open it directly. */
if(fname[0] != '\0' && fname[1] == ':' && is_slash(fname[2]))
{
if((f=al_fopen(fname, "rb")) != NULL)
{
TRACE("Opened %s\n", fname);
return f;
}
WARN("Could not open %s\n", fname);
return NULL;
}
/* If it's relative, try the current directory first before the data directories. */
if((f=al_fopen(fname, "rb")) != NULL)
{
TRACE("Opened %s\n", fname);
return f;
}
WARN("Could not open %s\n", fname);
wname = FromUTF8(fname);
wsubdir = FromUTF8(subdir);
if(!wname)
ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
else if(!wsubdir)
ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir);
else for(i = 0;i < 2;i++)
{
WCHAR buffer[PATH_MAX];
size_t len;
if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE)
continue;
len = lstrlenW(buffer);
if(len > 0 && is_slash(buffer[len-1]))
buffer[--len] = '\0';
_snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname);
len = lstrlenW(buffer);
while(len > 0)
{
--len;
if(buffer[len] == '/')
buffer[len] = '\\';
}
if((f=_wfopen(buffer, L"rb")) != NULL)
{
TRACE("Opened %ls\n", buffer);
return f;
}
WARN("Could not open %ls\n", buffer);
}
free(wname);
free(wsubdir);
return NULL;
}
#else
FILE *OpenDataFile(const char *fname, const char *subdir)
{
char buffer[PATH_MAX] = "";
@@ -561,7 +896,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
TRACE("Opened %s\n", fname);
return f;
}
WARN("Could not open %s\n", fname);
if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
snprintf(buffer, sizeof(buffer), "%s/%s/%s", str, subdir, fname);
@@ -574,7 +908,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
TRACE("Opened %s\n", buffer);
return f;
}
WARN("Could not open %s\n", buffer);
}
if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
@@ -605,11 +938,221 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
TRACE("Opened %s\n", buffer);
return f;
}
WARN("Could not open %s\n", buffer);
}
WARN("Could not open %s/%s\n", subdir, fname);
return NULL;
}
static const char *MatchString;
static int MatchFilter(const struct dirent *dir)
{
const char *match = MatchString;
const char *name = dir->d_name;
int ret = 1;
do {
const char *p = strchr(match, '%');
if(!p)
ret = strcmp(match, name) == 0;
else
{
size_t len = p-match;
ret = strncmp(match, name, len) == 0;
if(ret)
{
match += len;
name += len;
++p;
if(*p == 'r')
{
char *end;
ret = strtoul(name, &end, 10) > 0;
if(ret) name = end;
++p;
}
}
}
match = p;
} while(ret && match && *match);
return ret;
}
static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results)
{
struct dirent **namelist;
char *sep, *p;
int n, i;
if(!match[0])
return;
sep = strrchr(match, '/');
p = strchr(match, '%');
if(!sep)
{
MatchString = match;
TRACE("Searching %s for %s\n", path?path:"/", match);
n = scandir(path?path:"/", &namelist, MatchFilter, alphasort);
if(n >= 0)
{
for(i = 0;i < n;++i)
{
al_string str = AL_STRING_INIT_STATIC();
if(path) al_string_copy_cstr(&str, path);
al_string_append_char(&str, '/');
al_string_append_cstr(&str, namelist[i]->d_name);
TRACE("Got result %s\n", al_string_get_cstr(str));
VECTOR_PUSH_BACK(*results, str);
free(namelist[i]);
}
free(namelist);
}
return;
}
if(!p || p-sep >= 0)
{
al_string npath = AL_STRING_INIT_STATIC();
if(path) al_string_append_cstr(&npath, path);
al_string_append_char(&npath, '/');
al_string_append_range(&npath, match, sep);
TRACE("Recursing into %s with %s\n", al_string_get_cstr(npath), sep+1);
RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results);
al_string_deinit(&npath);
return;
}
sep = strchr(match, '/');
if(sep-p >= 0) sep = NULL;
for(;;)
{
char *next = strchr(sep?sep+1:match, '/');
if(next-p < 0)
{
al_string npath = AL_STRING_INIT_STATIC();
al_string nmatch = AL_STRING_INIT_STATIC();
if(!sep)
{
al_string_append_cstr(&npath, path?path:"/.");
MatchString = match;
}
else
{
if(path) al_string_append_cstr(&npath, path);
al_string_append_char(&npath, '/');
al_string_append_range(&npath, match, sep);
al_string_append_range(&nmatch, sep+1, next);
MatchString = al_string_get_cstr(nmatch);
}
TRACE("Searching %s for %s\n", al_string_get_cstr(npath), MatchString);
n = scandir(al_string_get_cstr(npath), &namelist, MatchFilter, alphasort);
if(n >= 0)
{
al_string ndir = AL_STRING_INIT_STATIC();
for(i = 0;i < n;++i)
{
al_string_copy(&ndir, npath);
al_string_append_char(&ndir, '/');
al_string_append_cstr(&ndir, namelist[i]->d_name);
free(namelist[i]);
TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1);
RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results);
}
al_string_deinit(&ndir);
free(namelist);
}
al_string_deinit(&nmatch);
al_string_deinit(&npath);
break;
}
sep = next;
}
}
vector_al_string SearchDataFiles(const char *match, const char *subdir)
{
static RefCount search_lock;
vector_al_string results = VECTOR_INIT_STATIC();
while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
althrd_yield();
if(match[0] == '/')
RecurseDirectorySearch(NULL, match+1, &results);
else
{
al_string path = AL_STRING_INIT_STATIC();
const char *str, *next;
char cwdbuf[PATH_MAX];
// Search CWD
if(!getcwd(cwdbuf, sizeof(cwdbuf)))
strcpy(cwdbuf, ".");
RecurseDirectorySearch(cwdbuf, match, &results);
// Search local data dir
if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
{
al_string_append_cstr(&path, str);
al_string_append_char(&path, '/');
al_string_append_cstr(&path, subdir);
}
else if((str=getenv("HOME")) != NULL && str[0] != '\0')
{
al_string_append_cstr(&path, str);
al_string_append_cstr(&path, "/.local/share/");
al_string_append_cstr(&path, subdir);
}
if(!al_string_empty(path))
RecurseDirectorySearch(al_string_get_cstr(path), match, &results);
// Search global data dirs
if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
str = "/usr/local/share/:/usr/share/";
next = str;
while((str=next) != NULL && str[0] != '\0')
{
next = strchr(str, ':');
if(!next)
al_string_copy_cstr(&path, str);
else
{
al_string_clear(&path);
al_string_append_range(&path, str, next);
++next;
}
if(!al_string_empty(path))
{
al_string_append_char(&path, '/');
al_string_append_cstr(&path, subdir);
RecurseDirectorySearch(al_string_get_cstr(path), match, &results);
}
}
al_string_deinit(&path);
}
ATOMIC_STORE(&search_lock, 0);
return results;
}
#endif
@@ -638,25 +1181,20 @@ void SetRTPriority(void)
}
ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count, ALboolean exact)
ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact)
{
vector_ *vecptr = (vector_*)ptr;
if(obj_count < 0)
return AL_FALSE;
if((*vecptr ? (*vecptr)->Capacity : 0) < obj_count)
{
ALsizei old_size = (*vecptr ? (*vecptr)->Size : 0);
size_t old_size = (*vecptr ? (*vecptr)->Size : 0);
void *temp;
/* Use the next power-of-2 size if we don't need to allocate the exact
* amount. This is preferred when regularly increasing the vector since
* it means fewer reallocations. Though it means it also wastes some
* memory. */
if(exact == AL_FALSE)
{
if(exact == AL_FALSE && obj_count < INT_MAX)
obj_count = NextPowerOf2((ALuint)obj_count);
if(obj_count < 0) return AL_FALSE;
}
/* Need to be explicit with the caller type's base size, because it
* could have extra padding before the start of the array (that is,
@@ -671,11 +1209,9 @@ ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei o
return AL_TRUE;
}
ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count)
ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count)
{
vector_ *vecptr = (vector_*)ptr;
if(obj_count < 0)
return AL_FALSE;
if(*vecptr || obj_count > 0)
{
if(!vector_reserve((char*)vecptr, base_size, obj_size, obj_count, AL_TRUE))
@@ -696,12 +1232,12 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size;
assert(numins > 0);
if(INT_MAX-VECTOR_SIZE(*vecptr) <= numins ||
if((size_t)numins + VECTOR_SIZE(*vecptr) < (size_t)numins ||
!vector_reserve((char*)vecptr, base_size, obj_size, VECTOR_SIZE(*vecptr)+numins, AL_TRUE))
return AL_FALSE;
/* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */
if(ins_elem < (*vecptr)->Size)
if((size_t)ins_elem < (*vecptr)->Size)
{
memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size),
(char*)(*vecptr) + base_size + ((ins_elem )*obj_size),
@@ -709,14 +1245,14 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
}
memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size),
datstart, numins*obj_size);
(*vecptr)->Size += (ALsizei)numins;
(*vecptr)->Size += numins;
}
return AL_TRUE;
}
extern inline void al_string_deinit(al_string *str);
extern inline ALsizei al_string_length(const_al_string str);
extern inline size_t al_string_length(const_al_string str);
extern inline ALboolean al_string_empty(const_al_string str);
extern inline const al_string_char_type *al_string_get_cstr(const_al_string str);
@@ -730,10 +1266,10 @@ void al_string_clear(al_string *str)
*VECTOR_ITER_END(*str) = 0;
}
static inline int al_string_compare(const al_string_char_type *str1, ALsizei str1len,
const al_string_char_type *str2, ALsizei str2len)
static inline int al_string_compare(const al_string_char_type *str1, size_t str1len,
const al_string_char_type *str2, size_t str2len)
{
ALsizei complen = mini(str1len, str2len);
size_t complen = (str1len < str2len) ? str1len : str2len;
int ret = memcmp(str1, str2, complen);
if(ret == 0)
{
@@ -750,12 +1286,12 @@ int al_string_cmp(const_al_string str1, const_al_string str2)
int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2)
{
return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
str2, (ALsizei)strlen(str2));
str2, strlen(str2));
}
void al_string_copy(al_string *str, const_al_string from)
{
ALsizei len = VECTOR_SIZE(from);
size_t len = al_string_length(from);
VECTOR_RESERVE(*str, len+1);
VECTOR_RESIZE(*str, 0);
VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len);
@@ -811,4 +1347,30 @@ void al_string_copy_wcstr(al_string *str, const wchar_t *from)
*VECTOR_ITER_END(*str) = 0;
}
}
void al_string_append_wcstr(al_string *str, const wchar_t *from)
{
int len;
if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
{
size_t strlen = al_string_length(*str);
VECTOR_RESERVE(*str, strlen+len);
VECTOR_RESIZE(*str, strlen+len-1);
WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str) + strlen, len, NULL, NULL);
*VECTOR_ITER_END(*str) = 0;
}
}
void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to)
{
int len;
if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0)
{
size_t strlen = al_string_length(*str);
VECTOR_RESERVE(*str, strlen+len+1);
VECTOR_RESIZE(*str, strlen+len);
WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str) + strlen, len+1, NULL, NULL);
*VECTOR_ITER_END(*str) = 0;
}
}
#endif
+257 -177
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -30,6 +30,8 @@
#include "alu.h"
#include "hrtf.h"
#include "compat.h"
/* Current data set limits defined by the makehrtf utility. */
#define MIN_IR_SIZE (8)
@@ -52,6 +54,7 @@ struct Hrtf {
const ALshort *coeffs;
const ALubyte *delays;
al_string filename;
struct Hrtf *next;
};
@@ -82,45 +85,12 @@ static void CalcEvIndices(ALuint evcount, ALfloat ev, ALuint *evidx, ALfloat *ev
*/
static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *azmu)
{
az = (F_2PI + az) * azcount / (F_2PI);
az = (F_TAU + az) * azcount / F_TAU;
azidx[0] = fastf2u(az) % azcount;
azidx[1] = (azidx[0] + 1) % azcount;
*azmu = az - floorf(az);
}
/* Calculates the normalized HRTF transition factor (delta) from the changes
* in gain and listener to source angle between updates. The result is a
* normalized delta factor that can be used to calculate moving HRIR stepping
* values.
*/
ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3])
{
ALfloat gainChange, angleChange, change;
// Calculate the normalized dB gain change.
newGain = maxf(newGain, 0.0001f);
oldGain = maxf(oldGain, 0.0001f);
gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
// Calculate the angle change only when there is enough gain to notice it.
angleChange = 0.0f;
if(gainChange > 0.0001f || newGain > 0.0001f)
{
// No angle change when the directions are equal or degenerate (when
// both have zero length).
if(newdir[0] != olddir[0] || newdir[1] != olddir[1] || newdir[2] != olddir[2])
{
ALfloat dotp = olddir[0]*newdir[0] + olddir[1]*newdir[1] + olddir[2]*newdir[2];
angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI;
}
}
// Use the largest of the two changes for the delta factor, and apply a
// significance shaping function to it.
change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
return minf(change, 1.0f);
}
/* Calculates static HRIR coefficients and delays for the given polar
* elevation and azimuth in radians. Linear interpolation is used to
* increase the apparent resolution of the HRIR data set. The coefficients
@@ -183,24 +153,22 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
{
ALfloat c;
gain *= 1.0f/32767.0f;
i = 0;
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain;
coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain;
coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
for(i = 1;i < Hrtf->irSize;i++)
{
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
coeffs[i][0] = lerp(0.0f, c, dirfact) * gain;
coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
coeffs[i][1] = lerp(0.0f, c, dirfact) * gain;
coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
}
}
else
@@ -225,7 +193,7 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
ALuint evidx[2], lidx[4], ridx[4];
ALfloat mu[3], blend[4];
ALfloat left, right;
ALfloat step;
ALfloat steps;
ALuint i;
/* Claculate elevation indices and interpolation factor. */
@@ -248,8 +216,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
}
// Calculate the stepping parameters.
delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f);
step = 1.0f / delta;
steps = maxf(floorf(delta*Hrtf->sampleRate + 0.5f), 1.0f);
delta = 1.0f / steps;
/* Calculate 4 blending weights for 2D bilinear interpolation. */
blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]);
@@ -271,8 +239,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
dirfact + 0.5f) << HRTFDELAY_BITS;
delayStep[0] = fastf2i(step * (delays[0] - left));
delayStep[1] = fastf2i(step * (delays[1] - right));
delayStep[0] = fastf2i(delta * (delays[0] - left));
delayStep[1] = fastf2i(delta * (delays[1] - right));
/* Calculate the sample offsets for the HRIR indices. */
lidx[0] *= Hrtf->irSize;
@@ -294,21 +262,19 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
{
ALfloat c;
gain *= 1.0f/32767.0f;
i = 0;
left = coeffs[i][0] - (coeffStep[i][0] * counter);
right = coeffs[i][1] - (coeffStep[i][1] * counter);
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain;
coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain;
coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
coeffStep[i][0] = step * (coeffs[i][0] - left);
coeffStep[i][1] = step * (coeffs[i][1] - right);
coeffStep[i][0] = delta * (coeffs[i][0] - left);
coeffStep[i][1] = delta * (coeffs[i][1] - right);
for(i = 1;i < Hrtf->irSize;i++)
{
@@ -317,13 +283,13 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
coeffs[i][0] = lerp(0.0f, c, dirfact) * gain;
coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
coeffs[i][1] = lerp(0.0f, c, dirfact) * gain;
coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
coeffStep[i][0] = step * (coeffs[i][0] - left);
coeffStep[i][1] = step * (coeffs[i][1] - right);
coeffStep[i][0] = delta * (coeffs[i][0] - left);
coeffStep[i][1] = delta * (coeffs[i][1] - right);
}
}
else
@@ -336,8 +302,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
coeffs[i][0] = 0.0f;
coeffs[i][1] = 0.0f;
coeffStep[i][0] = step * -left;
coeffStep[i][1] = step * -right;
coeffStep[i][0] = delta * -left;
coeffStep[i][1] = delta * -right;
}
}
@@ -345,13 +311,118 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
* complete its transition. The mixer will only apply stepping for this
* many samples.
*/
return fastf2u(delta);
return fastf2u(steps);
}
static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
/* Calculates HRTF coefficients for B-Format channels (only up to first-order).
* Note that these will decode a B-Format output mix, which uses FuMa ordering
* and scaling, not N3D!
*/
void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list)
{
const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
ALuint elev_idx, azi_idx;
ALfloat scale;
ALuint i, c;
assert(num_chans <= 4);
for(c = 0;c < num_chans;c++)
{
ALfloat (*coeffs)[2] = coeffs_list[c];
ALuint *delay = delay_list[c];
for(i = 0;i < Hrtf->irSize;i++)
{
coeffs[i][0] = 0.0f;
coeffs[i][1] = 0.0f;
}
delay[0] = 0;
delay[1] = 0;
}
/* NOTE: HRTF coefficients are generated by combining all the HRIRs in the
* dataset, with each entry scaled according to how much it contributes to
* the given B-Format channel based on its direction (including negative
* contributions!).
*/
scale = 0.0f;
for(elev_idx = 0;elev_idx < Hrtf->evCount;elev_idx++)
{
ALfloat elev = (ALfloat)elev_idx/(ALfloat)(Hrtf->evCount-1)*F_PI - F_PI_2;
ALuint evoffset = Hrtf->evOffset[elev_idx];
ALuint azcount = Hrtf->azCount[elev_idx];
scale += (ALfloat)azcount;
for(azi_idx = 0;azi_idx < azcount;azi_idx++)
{
ALuint lidx, ridx;
ALfloat ambi_coeffs[4];
ALfloat az, gain;
ALfloat x, y, z;
lidx = evoffset + azi_idx;
ridx = evoffset + ((azcount-azi_idx) % azcount);
az = (ALfloat)azi_idx / (ALfloat)azcount * F_TAU;
if(az > F_PI) az -= F_TAU;
x = cosf(-az) * cosf(elev);
y = sinf(-az) * cosf(elev);
z = sinf(elev);
ambi_coeffs[0] = 1.414213562f;
ambi_coeffs[1] = x;
ambi_coeffs[2] = y;
ambi_coeffs[3] = z;
for(c = 0;c < num_chans;c++)
{
ALfloat (*coeffs)[2] = coeffs_list[c];
ALuint *delay = delay_list[c];
/* NOTE: Always include the total delay average since the
* channels need to have matching delays. */
delay[0] += Hrtf->delays[lidx];
delay[1] += Hrtf->delays[ridx];
gain = ambi_coeffs[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < Hrtf->irSize;i++)
{
coeffs[i][0] += Hrtf->coeffs[lidx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain;
coeffs[i][1] += Hrtf->coeffs[ridx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain;
}
}
}
}
scale = 1.0f/scale;
for(c = 0;c < num_chans;c++)
{
ALfloat (*coeffs)[2] = coeffs_list[c];
ALuint *delay = delay_list[c];
for(i = 0;i < Hrtf->irSize;i++)
{
coeffs[i][0] *= scale;
coeffs[i][1] *= scale;
}
delay[0] = minu((ALuint)((ALfloat)delay[0] * scale), HRTF_HISTORY_LENGTH-1);
delay[0] <<= HRTFDELAY_BITS;
delay[1] = minu((ALuint)((ALfloat)delay[1] * scale), HRTF_HISTORY_LENGTH-1);
delay[1] <<= HRTFDELAY_BITS;
}
}
static struct Hrtf *LoadHrtf00(FILE *f)
{
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
struct Hrtf *Hrtf = NULL;
ALboolean failed = AL_FALSE;
ALuint rate = 0, irCount = 0;
@@ -376,12 +447,6 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
evCount = fgetc(f);
if(rate != deviceRate)
{
ERR("HRIR rate does not match device rate: rate=%d (%d)\n",
rate, deviceRate);
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",
@@ -504,6 +569,7 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
Hrtf->evOffset = evOffset;
Hrtf->coeffs = coeffs;
Hrtf->delays = delays;
AL_STRING_INIT(Hrtf->filename);
Hrtf->next = NULL;
return Hrtf;
}
@@ -516,9 +582,9 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
}
static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
static struct Hrtf *LoadHrtf01(FILE *f)
{
const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
struct Hrtf *Hrtf = NULL;
ALboolean failed = AL_FALSE;
ALuint rate = 0, irCount = 0;
@@ -538,12 +604,6 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
evCount = fgetc(f);
if(rate != deviceRate)
{
ERR("HRIR rate does not match device rate: rate=%d (%d)\n",
rate, deviceRate);
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",
@@ -649,6 +709,7 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
Hrtf->evOffset = evOffset;
Hrtf->coeffs = coeffs;
Hrtf->delays = delays;
AL_STRING_INIT(Hrtf->filename);
Hrtf->next = NULL;
return Hrtf;
}
@@ -661,144 +722,167 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
}
static struct Hrtf *LoadHrtf(ALuint deviceRate)
static void AddFileEntry(vector_HrtfEntry *list, al_string *filename)
{
const char *fnamelist = "default-%r.mhr";
HrtfEntry entry = { AL_STRING_INIT_STATIC(), *filename, NULL };
HrtfEntry *iter;
const char *name;
int i;
ConfigValueStr(NULL, "hrtf_tables", &fnamelist);
while(*fnamelist != '\0')
name = strrchr(al_string_get_cstr(entry.filename), '/');
if(!name) name = strrchr(al_string_get_cstr(entry.filename), '\\');
if(!name) name = al_string_get_cstr(entry.filename);
else ++name;
entry.hrtf = LoadedHrtfs;
while(entry.hrtf)
{
struct Hrtf *Hrtf = NULL;
char fname[PATH_MAX];
const char *next;
if(al_string_cmp(entry.filename, entry.hrtf->filename) == 0)
break;
entry.hrtf = entry.hrtf->next;
}
if(!entry.hrtf)
{
struct Hrtf *hrtf = NULL;
ALchar magic[8];
ALuint i;
FILE *f;
i = 0;
while(isspace(*fnamelist) || *fnamelist == ',')
fnamelist++;
next = fnamelist;
while(*(fnamelist=next) != '\0' && *fnamelist != ',')
{
next = strpbrk(fnamelist, "%,");
while(fnamelist != next && *fnamelist && i < sizeof(fname))
fname[i++] = *(fnamelist++);
if(!next || *next == ',')
break;
/* *next == '%' */
next++;
if(*next == 'r')
{
int wrote = snprintf(&fname[i], sizeof(fname)-i, "%u", deviceRate);
i += minu(wrote, sizeof(fname)-i);
next++;
}
else if(*next == '%')
{
if(i < sizeof(fname))
fname[i++] = '%';
next++;
}
else
ERR("Invalid marker '%%%c'\n", *next);
}
i = minu(i, sizeof(fname)-1);
fname[i] = '\0';
while(i > 0 && isspace(fname[i-1]))
i--;
fname[i] = '\0';
if(fname[0] == '\0')
continue;
TRACE("Loading %s...\n", fname);
f = OpenDataFile(fname, "openal/hrtf");
TRACE("Loading %s...\n", al_string_get_cstr(entry.filename));
f = al_fopen(al_string_get_cstr(entry.filename), "rb");
if(f == NULL)
{
ERR("Could not open %s\n", fname);
continue;
ERR("Could not open %s\n", al_string_get_cstr(entry.filename));
goto error;
}
if(fread(magic, 1, sizeof(magic), f) != sizeof(magic))
ERR("Failed to read header from %s\n", fname);
ERR("Failed to read header from %s\n", al_string_get_cstr(entry.filename));
else
{
if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0)
{
TRACE("Detected data set format v0\n");
Hrtf = LoadHrtf00(f, deviceRate);
hrtf = LoadHrtf00(f);
}
else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0)
{
TRACE("Detected data set format v1\n");
Hrtf = LoadHrtf01(f, deviceRate);
hrtf = LoadHrtf01(f);
}
else
ERR("Invalid header in %s: \"%.8s\"\n", fname, magic);
ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(entry.filename), magic);
}
fclose(f);
f = NULL;
if(Hrtf)
if(!hrtf)
{
Hrtf->next = LoadedHrtfs;
LoadedHrtfs = Hrtf;
TRACE("Loaded HRTF support for format: %s %uhz\n",
DevFmtChannelsString(DevFmtStereo), Hrtf->sampleRate);
return Hrtf;
ERR("Failed to load %s\n", al_string_get_cstr(entry.filename));
goto error;
}
ERR("Failed to load %s\n", fname);
al_string_copy(&hrtf->filename, entry.filename);
hrtf->next = LoadedHrtfs;
LoadedHrtfs = hrtf;
TRACE("Loaded HRTF support for format: %s %uhz\n",
DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
entry.hrtf = hrtf;
}
return NULL;
}
/* TODO: Get a human-readable name from the HRTF data (possibly coming in a
* format update). */
const struct Hrtf *GetHrtf(enum DevFmtChannels chans, ALCuint srate)
{
if(chans == DevFmtStereo)
{
struct Hrtf *Hrtf = LoadedHrtfs;
while(Hrtf != NULL)
i = 0;
do {
al_string_copy_cstr(&entry.name, name);
if(i != 0)
{
if(srate == Hrtf->sampleRate)
return Hrtf;
Hrtf = Hrtf->next;
char str[64];
snprintf(str, sizeof(str), " #%d", i+1);
al_string_append_cstr(&entry.name, str);
}
++i;
Hrtf = LoadHrtf(srate);
if(Hrtf != NULL)
return Hrtf;
}
ERR("Incompatible format: %s %uhz\n", DevFmtChannelsString(chans), srate);
return NULL;
#define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0)
VECTOR_FIND_IF(iter, HrtfEntry, *list, MATCH_NAME);
#undef MATCH_NAME
} while(iter != VECTOR_ITER_END(*list));
TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name),
al_string_get_cstr(entry.filename));
VECTOR_PUSH_BACK(*list, entry);
return;
error:
al_string_deinit(&entry.filename);
}
ALCboolean FindHrtfFormat(enum DevFmtChannels *chans, ALCuint *srate)
vector_HrtfEntry EnumerateHrtf(const_al_string devname)
{
const struct Hrtf *hrtf = LoadedHrtfs;
while(hrtf != NULL)
vector_HrtfEntry list = VECTOR_INIT_STATIC();
const char *fnamelist = "default-%r.mhr";
ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf_tables", &fnamelist);
while(fnamelist && *fnamelist)
{
if(*srate == hrtf->sampleRate)
break;
hrtf = hrtf->next;
while(isspace(*fnamelist) || *fnamelist == ',')
fnamelist++;
if(*fnamelist != '\0')
{
const char *next, *end;
next = strchr(fnamelist, ',');
if(!next)
end = fnamelist + strlen(fnamelist);
else
end = next++;
while(end != fnamelist && isspace(*(end-1)))
--end;
if(end != fnamelist)
{
al_string fname = AL_STRING_INIT_STATIC();
vector_al_string flist;
al_string_append_range(&fname, fnamelist, end);
flist = SearchDataFiles(al_string_get_cstr(fname), "openal/hrtf");
VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list);
VECTOR_DEINIT(flist);
al_string_deinit(&fname);
}
fnamelist = next;
}
}
if(hrtf == NULL)
{
hrtf = LoadHrtf(*srate);
if(hrtf == NULL) return ALC_FALSE;
}
*chans = DevFmtStereo;
*srate = hrtf->sampleRate;
return ALC_TRUE;
return list;
}
void FreeHrtfList(vector_HrtfEntry *list)
{
#define CLEAR_ENTRY(i) do { \
al_string_deinit(&(i)->name); \
al_string_deinit(&(i)->filename); \
} while(0)
VECTOR_FOR_EACH(HrtfEntry, *list, CLEAR_ENTRY);
VECTOR_DEINIT(*list);
#undef CLEAR_ENTRY
}
ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf)
{
return Hrtf->sampleRate;
}
ALuint GetHrtfIrSize(const struct Hrtf *Hrtf)
{
return Hrtf->irSize;
}
void FreeHrtfs(void)
{
struct Hrtf *Hrtf = NULL;
@@ -810,11 +894,7 @@ void FreeHrtfs(void)
free((void*)Hrtf->evOffset);
free((void*)Hrtf->coeffs);
free((void*)Hrtf->delays);
al_string_deinit(&Hrtf->filename);
free(Hrtf);
}
}
ALuint GetHrtfIrSize (const struct Hrtf *Hrtf)
{
return Hrtf->irSize;
}
+16 -4
View File
@@ -4,10 +4,20 @@
#include "AL/al.h"
#include "AL/alc.h"
#include "alstring.h"
enum DevFmtChannels;
struct Hrtf;
typedef struct HrtfEntry {
al_string name;
al_string filename;
const struct Hrtf *hrtf;
} HrtfEntry;
TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry)
#define HRIR_BITS (7)
#define HRIR_LENGTH (1<<HRIR_BITS)
#define HRIR_MASK (HRIR_LENGTH-1)
@@ -15,14 +25,16 @@ struct Hrtf;
#define HRTFDELAY_FRACONE (1<<HRTFDELAY_BITS)
#define HRTFDELAY_MASK (HRTFDELAY_FRACONE-1)
const struct Hrtf *GetHrtf(enum DevFmtChannels chans, ALCuint srate);
ALCboolean FindHrtfFormat(enum DevFmtChannels *chans, ALCuint *srate);
void FreeHrtfs(void);
vector_HrtfEntry EnumerateHrtf(const_al_string devname);
void FreeHrtfList(vector_HrtfEntry *list);
ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf);
ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]);
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep);
void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list);
#endif /* ALC_HRTF_H */
+253 -125
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -38,8 +38,32 @@
#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(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
alignas(16) union ResamplerCoeffs ResampleCoeffs;
enum Resampler {
PointResampler,
LinearResampler,
FIR4Resampler,
FIR8Resampler,
BSincResampler,
ResamplerDefault = LinearResampler
};
/* FIR8 requires 3 extra samples before the current position, and 4 after. */
static_assert(MAX_PRE_SAMPLES >= 3, "MAX_PRE_SAMPLES must be at least 3!");
static_assert(MAX_POST_SAMPLES >= 4, "MAX_POST_SAMPLES must be at least 4!");
static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
static MixerFunc MixSamples = Mix_C;
static ResamplerFunc ResampleSamples = Resample_point32_C;
static inline HrtfMixerFunc SelectHrtfMixer(void)
{
@@ -69,11 +93,9 @@ static inline MixerFunc SelectMixer(void)
return Mix_C;
}
static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
static inline ResamplerFunc SelectResampler(enum Resampler resampler)
{
if(increment == FRACTIONONE)
return Resample_copy32_C;
switch(Resampler)
switch(resampler)
{
case PointResampler:
return Resample_point32_C;
@@ -87,17 +109,181 @@ static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint inc
return Resample_lerp32_SSE2;
#endif
return Resample_lerp32_C;
case CubicResampler:
return Resample_cubic32_C;
case ResamplerMax:
/* Shouldn't happen */
break;
case FIR4Resampler:
#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 FIR8Resampler:
#ifdef HAVE_SSE4_1
if((CPUCapFlags&CPU_CAP_SSE4_1))
return Resample_fir8_32_SSE41;
#endif
#ifdef HAVE_SSE3
if((CPUCapFlags&CPU_CAP_SSE3))
return Resample_fir8_32_SSE3;
#endif
return Resample_fir8_32_C;
case BSincResampler:
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return Resample_bsinc32_SSE;
#endif
return Resample_bsinc32_C;
}
return Resample_point32_C;
}
/* The sinc resampler makes use of a Kaiser window to limit the needed sample
* points to 4 and 8, respectively.
*/
#ifndef M_PI
#define M_PI (3.14159265358979323846)
#endif
static inline double Sinc(double x)
{
if(x == 0.0) return 1.0;
return sin(x*M_PI) / (x*M_PI);
}
/* The zero-order modified Bessel function of the first kind, used for the
* Kaiser window.
*
* I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
* = sum_{k=0}^inf ((x / 2)^k / k!)^2
*/
static double BesselI_0(double x)
{
double term, sum, x2, y, last_sum;
int k;
/* Start at k=1 since k=0 is trivial. */
term = 1.0;
sum = 1.0;
x2 = x / 2.0;
k = 1;
/* Let the integration converge until the term of the sum is no longer
* significant.
*/
do {
y = x2 / k;
k ++;
last_sum = sum;
term *= y * y;
sum += term;
} while(sum != last_sum);
return sum;
}
/* Calculate a Kaiser window from the given beta value and a normalized k
* [-1, 1].
*
* w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
* { 0, elsewhere.
*
* Where k can be calculated as:
*
* k = i / l, where -l <= i <= l.
*
* or:
*
* k = 2 i / M - 1, where 0 <= i <= M.
*/
static inline double Kaiser(double b, double k)
{
if(k <= -1.0 || k >= 1.0) return 0.0;
return BesselI_0(b * sqrt(1.0 - (k*k))) / BesselI_0(b);
}
static inline double CalcKaiserBeta(double rejection)
{
if(rejection > 50.0)
return 0.1102 * (rejection - 8.7);
if(rejection >= 21.0)
return (0.5842 * pow(rejection - 21.0, 0.4)) +
(0.07886 * (rejection - 21.0));
return 0.0;
}
static float SincKaiser(double r, double x)
{
/* Limit rippling to -60dB. */
return (float)(Kaiser(CalcKaiserBeta(60.0), x / r) * Sinc(x));
}
void aluInitMixer(void)
{
enum Resampler resampler = ResamplerDefault;
const char *str;
ALuint i;
if(ConfigValueStr(NULL, NULL, "resampler", &str))
{
if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
resampler = PointResampler;
else if(strcasecmp(str, "linear") == 0)
resampler = LinearResampler;
else if(strcasecmp(str, "sinc4") == 0)
resampler = FIR4Resampler;
else if(strcasecmp(str, "sinc8") == 0)
resampler = FIR8Resampler;
else if(strcasecmp(str, "bsinc") == 0)
resampler = BSincResampler;
else if(strcasecmp(str, "cubic") == 0)
{
WARN("Resampler option \"cubic\" is deprecated, using sinc4\n");
resampler = FIR4Resampler;
}
else
{
char *end;
long n = strtol(str, &end, 0);
if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
resampler = n;
else
WARN("Invalid resampler: %s\n", str);
}
}
if(resampler == FIR8Resampler)
for(i = 0;i < FRACTIONONE;i++)
{
ALdouble mu = (ALdouble)i / FRACTIONONE;
ResampleCoeffs.FIR8[i][0] = SincKaiser(4.0, mu - -3.0);
ResampleCoeffs.FIR8[i][1] = SincKaiser(4.0, mu - -2.0);
ResampleCoeffs.FIR8[i][2] = SincKaiser(4.0, mu - -1.0);
ResampleCoeffs.FIR8[i][3] = SincKaiser(4.0, mu - 0.0);
ResampleCoeffs.FIR8[i][4] = SincKaiser(4.0, mu - 1.0);
ResampleCoeffs.FIR8[i][5] = SincKaiser(4.0, mu - 2.0);
ResampleCoeffs.FIR8[i][6] = SincKaiser(4.0, mu - 3.0);
ResampleCoeffs.FIR8[i][7] = SincKaiser(4.0, mu - 4.0);
}
else if(resampler == FIR4Resampler)
for(i = 0;i < FRACTIONONE;i++)
{
ALdouble mu = (ALdouble)i / FRACTIONONE;
ResampleCoeffs.FIR4[i][0] = SincKaiser(2.0, mu - -1.0);
ResampleCoeffs.FIR4[i][1] = SincKaiser(2.0, mu - 0.0);
ResampleCoeffs.FIR4[i][2] = SincKaiser(2.0, mu - 1.0);
ResampleCoeffs.FIR4[i][3] = SincKaiser(2.0, mu - 2.0);
}
MixHrtfSamples = SelectHrtfMixer();
MixSamples = SelectMixer();
ResampleSamples = SelectResampler(resampler);
}
static inline ALfloat Sample_ALbyte(ALbyte val)
{ return val * (1.0f/127.0f); }
@@ -108,7 +294,7 @@ static inline ALfloat Sample_ALfloat(ALfloat val)
{ return val; }
#define DECL_TEMPLATE(T) \
static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
{ \
ALuint i; \
for(i = 0;i < samples;i++) \
@@ -137,7 +323,7 @@ static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum Fm
}
}
static void SilenceSamples(ALfloat *dst, ALuint samples)
static inline void SilenceSamples(ALfloat *dst, ALuint samples)
{
ALuint i;
for(i = 0;i < samples;i++)
@@ -153,20 +339,24 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter
switch(type)
{
case AF_None:
ALfilterState_processPassthru(lpfilter, src, numsamples);
ALfilterState_processPassthru(hpfilter, src, numsamples);
break;
case AF_LowPass:
ALfilterState_process(lpfilter, dst, src, numsamples);
ALfilterState_processPassthru(hpfilter, dst, numsamples);
return dst;
case AF_HighPass:
ALfilterState_processPassthru(lpfilter, src, numsamples);
ALfilterState_process(hpfilter, dst, src, numsamples);
return dst;
case AF_BandPass:
for(i = 0;i < numsamples;)
{
ALfloat temp[64];
ALuint todo = minu(64, numsamples-i);
ALfloat temp[256];
ALuint todo = minu(256, numsamples-i);
ALfilterState_process(lpfilter, temp, src+i, todo);
ALfilterState_process(hpfilter, dst+i, temp, todo);
@@ -178,22 +368,19 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter
}
ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
{
MixerFunc Mix;
HrtfMixerFunc HrtfMix;
ResamplerFunc Resample;
ALsource *Source = src->Source;
ALbufferlistitem *BufferListItem;
ALuint DataPosInt, DataPosFrac;
ALboolean Looping;
ALuint increment;
enum Resampler Resampler;
ALenum State;
ALuint OutPos;
ALuint NumChannels;
ALuint SampleSize;
ALint64 DataSize64;
ALuint IrSize;
ALuint chan, j;
/* Get source info */
@@ -202,19 +389,17 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
DataPosInt = Source->position;
DataPosFrac = Source->position_fraction;
Looping = Source->Looping;
increment = src->Step;
Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler;
NumChannels = Source->NumChannels;
SampleSize = Source->SampleSize;
increment = voice->Step;
Mix = SelectMixer();
HrtfMix = SelectHrtfMixer();
Resample = SelectResampler(Resampler, increment);
IrSize = (Device->Hrtf ? GetHrtfIrSize(Device->Hrtf) : 0);
Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
Resample_copy32_C : ResampleSamples);
OutPos = 0;
do {
const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
const ALuint BufferPadding = ResamplerPadding[Resampler];
ALuint SrcBufferSize, DstBufferSize;
/* Figure out how many buffer samples will be needed */
@@ -222,13 +407,13 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
DataSize64 *= increment;
DataSize64 += DataPosFrac+FRACTIONMASK;
DataSize64 >>= FRACTIONBITS;
DataSize64 += BufferPadding+BufferPrePadding;
DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
/* Figure out how many samples we can actually mix from this. */
DataSize64 = SrcBufferSize;
DataSize64 -= BufferPadding+BufferPrePadding;
DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= DataPosFrac;
@@ -244,7 +429,11 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
{
const ALfloat *ResampledData;
ALfloat *SrcData = Device->SourceData;
ALuint SrcDataSize = 0;
ALuint SrcDataSize;
/* Load the previous samples into the source data first. */
memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
SrcDataSize = MAX_PRE_SAMPLES;
if(Source->SourceType == AL_STATIC)
{
@@ -253,29 +442,20 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
ALuint DataSize;
ALuint pos;
/* Offset buffer data to current channel */
Data += chan*SampleSize;
/* If current pos is beyond the loop range, do not loop */
if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
{
Looping = AL_FALSE;
if(DataPosInt >= BufferPrePadding)
pos = DataPosInt - BufferPrePadding;
else
{
DataSize = BufferPrePadding - DataPosInt;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
SilenceSamples(&SrcData[SrcDataSize], DataSize);
SrcDataSize += DataSize;
pos = 0;
}
/* Copy what's left to play in the source buffer, and clear the
* rest of the temp buffer */
/* Load what's left to play from the source buffer, and
* clear the rest of the temp buffer */
pos = DataPosInt;
DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
@@ -287,33 +467,13 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
ALuint LoopStart = ALBuffer->LoopStart;
ALuint LoopEnd = ALBuffer->LoopEnd;
if(DataPosInt >= LoopStart)
{
pos = DataPosInt-LoopStart;
while(pos < BufferPrePadding)
pos += LoopEnd-LoopStart;
pos -= BufferPrePadding;
pos += LoopStart;
}
else if(DataPosInt >= BufferPrePadding)
pos = DataPosInt - BufferPrePadding;
else
{
DataSize = BufferPrePadding - DataPosInt;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
SilenceSamples(&SrcData[SrcDataSize], DataSize);
SrcDataSize += DataSize;
pos = 0;
}
/* Copy what's left of this loop iteration, then copy repeats
* of the loop section */
/* Load what's left of this loop iteration, then load
* repeats of the loop section */
pos = DataPosInt;
DataSize = LoopEnd - pos;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
@@ -322,7 +482,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
{
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
LoadSamples(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
}
@@ -332,45 +492,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
{
/* Crawl the buffer queue to fill in the temp buffer */
ALbufferlistitem *tmpiter = BufferListItem;
ALuint pos;
if(DataPosInt >= BufferPrePadding)
pos = DataPosInt - BufferPrePadding;
else
{
pos = BufferPrePadding - DataPosInt;
while(pos > 0)
{
ALbufferlistitem *prev;
if((prev=tmpiter->prev) != NULL)
tmpiter = prev;
else if(Looping)
{
while(tmpiter->next)
tmpiter = tmpiter->next;
}
else
{
ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
SilenceSamples(&SrcData[SrcDataSize], DataSize);
SrcDataSize += DataSize;
pos = 0;
break;
}
if(tmpiter->buffer)
{
if((ALuint)tmpiter->buffer->SampleLen > pos)
{
pos = tmpiter->buffer->SampleLen - pos;
break;
}
pos -= tmpiter->buffer->SampleLen;
}
}
}
ALuint pos = DataPosInt;
while(tmpiter && SrcBufferSize > SrcDataSize)
{
@@ -406,13 +528,19 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
}
}
/* Store the last source samples used for next time. */
memcpy(voice->PrevSamples[chan],
&SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
MAX_PRE_SAMPLES*sizeof(ALfloat)
);
/* Now resample, then filter and mix to the appropriate outputs. */
ResampledData = Resample(
&SrcData[BufferPrePadding], DataPosFrac, increment,
ResampledData = Resample(&voice->SincState,
&SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
Device->ResampledData, DstBufferSize
);
{
DirectParams *parms = &src->Direct;
DirectParams *parms = &voice->Direct;
const ALfloat *samples;
samples = DoFilters(
@@ -420,18 +548,18 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
Device->FilteredData, ResampledData, DstBufferSize,
parms->Filters[chan].ActiveType
);
if(!src->IsHrtf)
Mix(samples, MaxChannels, parms->OutBuffer, parms->Mix.Gains[chan],
parms->Counter, OutPos, DstBufferSize);
if(!voice->IsHrtf)
MixSamples(samples, parms->OutChannels, parms->OutBuffer, parms->Gains[chan],
parms->Counter, OutPos, DstBufferSize);
else
HrtfMix(parms->OutBuffer, samples, parms->Counter, src->Offset,
OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan],
&parms->Mix.Hrtf.State[chan], DstBufferSize);
MixHrtfSamples(parms->OutBuffer, samples, parms->Counter, voice->Offset,
OutPos, IrSize, &parms->Hrtf[chan].Params,
&parms->Hrtf[chan].State, DstBufferSize);
}
for(j = 0;j < Device->NumAuxSends;j++)
{
SendParams *parms = &src->Send[j];
SendParams *parms = &voice->Send[j];
const ALfloat *samples;
if(!parms->OutBuffer)
@@ -442,8 +570,8 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
Device->FilteredData, ResampledData, DstBufferSize,
parms->Filters[chan].ActiveType
);
Mix(samples, 1, parms->OutBuffer, &parms->Gain,
parms->Counter, OutPos, DstBufferSize);
MixSamples(samples, 1, parms->OutBuffer, &parms->Gains[chan],
parms->Counter, OutPos, DstBufferSize);
}
}
/* Update positions */
@@ -452,10 +580,10 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
DataPosFrac &= FRACTIONMASK;
OutPos += DstBufferSize;
src->Offset += DstBufferSize;
src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize;
voice->Offset += DstBufferSize;
voice->Direct.Counter = maxu(voice->Direct.Counter, DstBufferSize) - DstBufferSize;
for(j = 0;j < Device->NumAuxSends;j++)
src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize;
voice->Send[j].Counter = maxu(voice->Send[j].Counter, DstBufferSize) - DstBufferSize;
/* Handle looping sources */
while(1)
+69 -14
View File
@@ -12,13 +12,15 @@ static inline ALfloat point32(const ALfloat *vals, ALuint UNUSED(frac))
{ return vals[0]; }
static inline ALfloat lerp32(const ALfloat *vals, ALuint frac)
{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
static inline ALfloat cubic32(const ALfloat *vals, ALuint frac)
{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); }
static inline ALfloat fir4_32(const ALfloat *vals, ALuint frac)
{ return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); }
static inline ALfloat fir8_32(const ALfloat *vals, ALuint frac)
{ return resample_fir8(vals[-3], vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], vals[4], frac); }
const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
ALuint increment, ALfloat *restrict dst, ALuint numsamples)
const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat *src, ALuint UNUSED(frac),
ALuint UNUSED(increment), ALfloat *restrict dst, ALuint numsamples)
{
assert(increment==FRACTIONONE);
#if defined(HAVE_SSE) || defined(HAVE_NEON)
/* Avoid copying the source data if it's aligned like the destination. */
if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
@@ -29,8 +31,9 @@ const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
}
#define DECL_TEMPLATE(Sampler) \
const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \
ALuint increment, ALfloat *restrict dst, ALuint numsamples) \
const ALfloat *Resample_##Sampler##_C(const BsincState* UNUSED(state), \
const ALfloat *src, ALuint frac, ALuint increment, \
ALfloat *restrict dst, ALuint numsamples) \
{ \
ALuint i; \
for(i = 0;i < numsamples;i++) \
@@ -46,10 +49,49 @@ const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \
DECL_TEMPLATE(point32)
DECL_TEMPLATE(lerp32)
DECL_TEMPLATE(cubic32)
DECL_TEMPLATE(fir4_32)
DECL_TEMPLATE(fir8_32)
#undef DECL_TEMPLATE
const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac,
ALuint increment, ALfloat *restrict dst, ALuint dstlen)
{
const ALfloat *fil, *scd, *phd, *spd;
const ALfloat sf = state->sf;
const ALuint m = state->m;
const ALint l = state->l;
ALuint j_f, pi, i;
ALfloat pf, r;
ALint j_s;
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 = state->coeffs[pi].filter;
scd = state->coeffs[pi].scDelta;
phd = state->coeffs[pi].phDelta;
spd = state->coeffs[pi].spDelta;
// Apply the scale and phase interpolated filter.
r = 0.0f;
for(j_f = 0,j_s = l;j_f < m;j_f++,j_s++)
r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) *
src[j_s];
dst[i] = r;
frac += increment;
src += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples)
{
@@ -59,6 +101,18 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const
}
static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
const HrtfParams *hrtfparams,
ALuint IrSize, ALuint Counter)
{
ALuint c;
for(c = 0;c < IrSize;c++)
{
OutCoeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter);
OutCoeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter);
}
}
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
@@ -90,9 +144,9 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
}
}
#define SUFFIX C
#define MixHrtf MixHrtf_C
#include "mixer_inc.c"
#undef SUFFIX
#undef MixHrtf
void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
@@ -106,19 +160,20 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B
ALuint pos = 0;
gain = Gains[c].Current;
step = Gains[c].Step;
if(step != 1.0f && Counter > 0)
if(step != 0.0f && Counter > 0)
{
for(;pos < BufferSize && pos < Counter;pos++)
ALuint minsize = minu(BufferSize, Counter);
for(;pos < minsize;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain *= step;
gain += step;
}
if(pos == Counter)
gain = Gains[c].Target;
Gains[c].Current = gain;
}
if(!(gain > GAIN_SILENCE_THRESHOLD))
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
+22 -7
View File
@@ -12,10 +12,12 @@ struct HrtfParams;
struct HrtfState;
/* C resamplers */
const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
/* C mixers */
@@ -24,7 +26,7 @@ void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
ALuint BufferSize);
void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
/* SSE mixers */
void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
@@ -49,11 +51,24 @@ inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_a
}
}
const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac,
ALuint increment, ALfloat *restrict dst, ALuint dstlen);
const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
/* Neon mixers */
void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
+18 -32
View File
@@ -8,12 +8,9 @@
#include "align.h"
#define REAL_MERGE(a,b) a##b
#define MERGE(a,b) REAL_MERGE(a,b)
#define MixHrtf MERGE(MixHrtf_,SUFFIX)
static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
const HrtfParams *hrtfparams,
ALuint IrSize, ALuint Counter);
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint irSize,
ALfloat (*restrict Coeffs)[2],
@@ -33,24 +30,20 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
ALuint Delay[2];
ALfloat left, right;
ALuint pos;
ALuint c;
for(c = 0;c < IrSize;c++)
{
Coeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter);
Coeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter);
}
SetupCoeffs(Coeffs, hrtfparams, IrSize, Counter);
Delay[0] = hrtfparams->Delay[0] - (hrtfparams->DelayStep[0]*Counter);
Delay[1] = hrtfparams->Delay[1] - (hrtfparams->DelayStep[1]*Counter);
for(pos = 0;pos < BufferSize && pos < Counter;pos++)
pos = 0;
for(;pos < BufferSize && pos < Counter;pos++)
{
hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos];
left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK],
hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK],
(Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK],
hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK],
(Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
Delay[0] += hrtfparams->DelayStep[0];
@@ -61,8 +54,8 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
Offset++;
ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->CoeffStep, left, right);
OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutPos++;
}
@@ -70,24 +63,17 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
Delay[1] >>= HRTFDELAY_BITS;
for(;pos < BufferSize;pos++)
{
hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
left = hrtfstate->History[(Offset-Delay[0])&SRC_HISTORY_MASK];
right = hrtfstate->History[(Offset-Delay[1])&SRC_HISTORY_MASK];
hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos];
left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK];
right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK];
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
Offset++;
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutPos++;
}
}
#undef MixHrtf
#undef MERGE
#undef REAL_MERGE
+32 -11
View File
@@ -9,6 +9,25 @@
#include "hrtf.h"
static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
const HrtfParams *hrtfparams,
ALuint IrSize, ALuint Counter)
{
ALuint c;
float32x4_t counter4;
{
float32x2_t counter2 = vdup_n_f32(-(float)Counter);
counter4 = vcombine_f32(counter2, counter2);
}
for(c = 0;c < IrSize;c += 2)
{
float32x4_t step4 = vld1q_f32((float32_t*)hrtfparams->CoeffStep[c]);
float32x4_t coeffs = vld1q_f32((float32_t*)hrtfparams->Coeffs[c]);
coeffs = vmlaq_f32(coeffs, step4, counter4);
vst1q_f32((float32_t*)OutCoeffs[c], coeffs);
}
}
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
@@ -69,14 +88,13 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
}
}
#define SUFFIX Neon
#define MixHrtf MixHrtf_Neon
#include "mixer_inc.c"
#undef SUFFIX
#undef MixHrtf
void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
ALfloat gain, step;
float32x4_t gain4;
@@ -87,29 +105,32 @@ void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict Out
ALuint pos = 0;
gain = Gains[c].Current;
step = Gains[c].Step;
if(step != 1.0f && Counter > 0)
if(step != 0.0f && Counter > 0)
{
for(;pos < BufferSize && pos < Counter;pos++)
ALuint minsize = minu(BufferSize, Counter);
for(;pos < minsize;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain *= step;
gain += step;
}
if(pos == Counter)
gain = Gains[c].Target;
Gains[c].Current = gain;
/* Mix until pos is aligned with 4 or the mix is done. */
for(;pos < BufferSize && (pos&3) != 0;pos++)
minsize = minu(BufferSize, (pos+3)&~3);
for(;pos < minsize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
if(!(gain > GAIN_SILENCE_THRESHOLD))
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 = vaddq_f32(dry4, vmulq_f32(val4, gain4));
dry4 = vmlaq_f32(dry4, val4, gain4);
vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
}
for(;pos < BufferSize;pos++)
+99 -22
View File
@@ -1,12 +1,5 @@
#include "config.h"
#ifdef IN_IDE_PARSER
/* KDevelop's parser won't recognize these defines that get added by the -msse
* switch used to compile this source. Without them, xmmintrin.h fails to
* declare anything. */
#define __MMX__
#define __SSE__
#endif
#include <xmmintrin.h>
#include "AL/al.h"
@@ -19,6 +12,82 @@
#include "mixer_defs.h"
const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac,
ALuint increment, ALfloat *restrict dst, ALuint dstlen)
{
const __m128 sf4 = _mm_set1_ps(state->sf);
const ALuint m = state->m;
const ALint l = state->l;
const ALfloat *fil, *scd, *phd, *spd;
ALuint pi, j_f, i;
ALfloat pf;
ALint j_s;
__m128 r4;
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 = state->coeffs[pi].filter;
scd = state->coeffs[pi].scDelta;
phd = state->coeffs[pi].phDelta;
spd = state->coeffs[pi].spDelta;
// Apply the scale and phase interpolated filter.
r4 = _mm_setzero_ps();
{
const __m128 pf4 = _mm_set1_ps(pf);
for(j_f = 0,j_s = l;j_f < m;j_f+=4,j_s+=4)
{
const __m128 f4 = _mm_add_ps(
_mm_add_ps(
_mm_load_ps(&fil[j_f]),
_mm_mul_ps(sf4, _mm_load_ps(&scd[j_f]))
),
_mm_mul_ps(
pf4,
_mm_add_ps(
_mm_load_ps(&phd[j_f]),
_mm_mul_ps(sf4, _mm_load_ps(&spd[j_f]))
)
)
);
r4 = _mm_add_ps(r4, _mm_mul_ps(f4, _mm_loadu_ps(&src[j_s])));
}
}
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));
dst[i] = _mm_cvtss_f32(r4);
frac += increment;
src += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
const HrtfParams *hrtfparams,
ALuint IrSize, ALuint Counter)
{
const __m128 counter4 = _mm_set1_ps((float)Counter);
__m128 coeffs, step4;
ALuint i;
for(i = 0;i < IrSize;i += 2)
{
step4 = _mm_load_ps(&hrtfparams->CoeffStep[i][0]);
coeffs = _mm_load_ps(&hrtfparams->Coeffs[i][0]);
coeffs = _mm_sub_ps(coeffs, _mm_mul_ps(step4, counter4));
_mm_store_ps(&OutCoeffs[i][0], coeffs);
}
}
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
@@ -133,16 +202,16 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
}
}
#define SUFFIX SSE
#define MixHrtf MixHrtf_SSE
#include "mixer_inc.c"
#undef SUFFIX
#undef MixHrtf
void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
ALfloat gain, step;
__m128 gain4, step4;
__m128 gain4;
ALuint c;
for(c = 0;c < OutChans;c++)
@@ -150,43 +219,51 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)
ALuint pos = 0;
gain = Gains[c].Current;
step = Gains[c].Step;
if(step != 1.0f && Counter > 0)
if(step != 0.0f && Counter > 0)
{
ALuint minsize = minu(BufferSize, Counter);
/* Mix with applying gain steps in aligned multiples of 4. */
if(BufferSize-pos > 3 && Counter-pos > 3)
if(minsize-pos > 3)
{
__m128 step4;
gain4 = _mm_setr_ps(
gain,
gain * step,
gain * step * step,
gain * step * step * step
gain + step,
gain + step + step,
gain + step + step + step
);
step4 = _mm_set1_ps(step * step * step * step);
step4 = _mm_set1_ps(step + step + step + step);
do {
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
gain4 = _mm_mul_ps(gain4, step4);
gain4 = _mm_add_ps(gain4, step4);
_mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
pos += 4;
} while(BufferSize-pos > 3 && Counter-pos > 3);
} while(minsize-pos > 3);
/* NOTE: gain4 now represents the next four gains after the
* last four mixed samples, so the lowest element represents
* the next gain to apply.
*/
gain = _mm_cvtss_f32(gain4);
}
/* Mix with applying left over gain steps that aren't aligned multiples of 4. */
for(;pos < BufferSize && pos < Counter;pos++)
for(;pos < minsize;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain *= step;
gain += step;
}
if(pos == Counter)
gain = Gains[c].Target;
Gains[c].Current = gain;
/* Mix until pos is aligned with 4 or the mix is done. */
for(;pos < BufferSize && (pos&3) != 0;pos++)
minsize = minu(BufferSize, (pos+3)&~3);
for(;pos < minsize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
if(!(gain > GAIN_SILENCE_THRESHOLD))
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
gain4 = _mm_set1_ps(gain);
for(;BufferSize-pos > 3;pos += 4)
+6 -3
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -27,7 +27,7 @@
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
@@ -63,6 +63,9 @@ const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint incr
_mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
}
/* NOTE: These four elements represent the position *after* the last four
* samples, so the lowest element is the next position to resample.
*/
pos = pos_.i[0];
frac = _mm_cvtsi128_si32(frac4);
+145 -3
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -28,7 +28,7 @@
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
@@ -67,6 +67,9 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc
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);
@@ -80,3 +83,142 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc
}
return dst;
}
const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
alignas(16) union { ALuint i[4]; float f[4]; } pos_;
alignas(16) union { ALuint i[4]; float f[4]; } frac_;
__m128i frac4, pos4;
ALuint pos;
ALuint 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(ResampleCoeffs.FIR4[frac_.i[0]]);
__m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]);
__m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]);
__m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]);
__m128 out;
k0 = _mm_mul_ps(k0, val0);
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;
}
const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
alignas(16) union { ALuint i[4]; float f[4]; } pos_;
alignas(16) union { ALuint i[4]; float f[4]; } frac_;
__m128i frac4, pos4;
ALuint pos;
ALuint i, j;
InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
src -= 3;
for(i = 0;numsamples-i > 3;i += 4)
{
__m128 out[2];
for(j = 0;j < 8;j+=4)
{
const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]+j]);
const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]+j]);
const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]+j]);
const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]+j]);
__m128 k0 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[0]][j]);
__m128 k1 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[1]][j]);
__m128 k2 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[2]][j]);
__m128 k3 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[3]][j]);
k0 = _mm_mul_ps(k0, val0);
k1 = _mm_mul_ps(k1, val1);
k2 = _mm_mul_ps(k2, val2);
k3 = _mm_mul_ps(k3, val3);
k0 = _mm_hadd_ps(k0, k1);
k2 = _mm_hadd_ps(k2, k3);
out[j>>2] = _mm_hadd_ps(k0, k2);
}
out[0] = _mm_add_ps(out[0], out[1]);
_mm_store_ps(&dst[i], out[0]);
frac4 = _mm_add_epi32(frac4, increment4);
pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
frac4 = _mm_and_si128(frac4, fracMask4);
pos_.i[0] = _mm_extract_epi32(pos4, 0);
pos_.i[1] = _mm_extract_epi32(pos4, 1);
pos_.i[2] = _mm_extract_epi32(pos4, 2);
pos_.i[3] = _mm_extract_epi32(pos4, 3);
frac_.i[0] = _mm_extract_epi32(frac4, 0);
frac_.i[1] = _mm_extract_epi32(frac4, 1);
frac_.i[2] = _mm_extract_epi32(frac4, 2);
frac_.i[3] = _mm_extract_epi32(frac4, 3);
}
pos = pos_.i[0];
frac = frac_.i[0];
for(;i < numsamples;i++)
{
dst[i] = resample_fir8(src[pos ], src[pos+1], src[pos+2], src[pos+3],
src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac);
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
+484 -377
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -30,421 +30,528 @@
#include "AL/al.h"
#include "AL/alc.h"
#include "alu.h"
#include "bool.h"
extern inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels]);
static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChannels],
enum Channel Speaker2Chan[MaxChannels], ALint chans)
#define ZERO_ORDER_SCALE 0.0f
#define FIRST_ORDER_SCALE 1.0f
#define SECOND_ORDER_SCALE (1.0f / 1.22474f)
#define THIRD_ORDER_SCALE (1.0f / 1.30657f)
static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = {
0, /* W */
3, /* X */
1, /* Y */
2, /* Z */
6, /* R */
7, /* S */
5, /* T */
8, /* U */
4, /* V */
12, /* K */
13, /* L */
11, /* M */
14, /* N */
10, /* O */
15, /* P */
9, /* Q */
};
/* NOTE: These are scale factors as applied to Ambisonics content. FuMa
* decoder coefficients should be divided by these values to get N3D decoder
* coefficients.
*/
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 ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
{
char *confkey, *next;
char *layout_str;
char *sep, *end;
enum Channel val;
const char *str;
int i;
ALuint i;
if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str))
return;
layout_str = strdup(str);
next = confkey = layout_str;
while(next && *next)
for(i = 0;i < device->NumChannels;i++)
{
confkey = next;
next = strchr(confkey, ',');
if(next)
{
*next = 0;
do {
next++;
} while(isspace(*next) || *next == ',');
}
// The W coefficients are based on a mathematical average of the
// output. The square root of the base average provides for a more
// perceptual average volume, better suited to non-directional gains.
gains[i] = sqrtf(device->AmbiCoeffs[i][0]) * ingain;
}
for(;i < MAX_OUTPUT_CHANNELS;i++)
gains[i] = 0.0f;
}
sep = strchr(confkey, '=');
if(!sep || confkey == sep)
void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
{
ALfloat dir[3] = {
sinf(angle) * cosf(elevation),
sinf(elevation),
-cosf(angle) * cosf(elevation)
};
ComputeDirectionalGains(device, dir, ingain, gains);
}
void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
{
ALfloat coeffs[MAX_AMBI_COEFFS];
ALuint i, j;
/* 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] = 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 */
coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */
coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
/* Third-order */
coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */
coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
for(i = 0;i < device->NumChannels;i++)
{
float gain = 0.0f;
for(j = 0;j < MAX_AMBI_COEFFS;j++)
gain += device->AmbiCoeffs[i][j]*coeffs[j];
gains[i] = gain * ingain;
}
for(;i < MAX_OUTPUT_CHANNELS;i++)
gains[i] = 0.0f;
}
void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
{
ALuint i, j;
for(i = 0;i < device->NumChannels;i++)
{
float gain = 0.0f;
for(j = 0;j < 4;j++)
gain += device->AmbiCoeffs[i][j] * mtx[j];
gains[i] = gain * ingain;
}
for(;i < MAX_OUTPUT_CHANNELS;i++)
gains[i] = 0.0f;
}
DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel)
{
switch(channel)
{
case FrontLeft: return "front-left";
case FrontRight: return "front-right";
case FrontCenter: return "front-center";
case LFE: return "lfe";
case BackLeft: return "back-left";
case BackRight: return "back-right";
case BackCenter: return "back-center";
case SideLeft: return "side-left";
case SideRight: return "side-right";
case BFormatW: return "bformat-w";
case BFormatX: return "bformat-x";
case BFormatY: return "bformat-y";
case BFormatZ: return "bformat-z";
case InvalidChannel: break;
}
return "(unknown)";
}
typedef struct ChannelMap {
enum Channel ChanName;
ChannelConfig Config;
} ChannelMap;
static void SetChannelMap(ALCdevice *device, const ChannelMap *chanmap, size_t count, ALfloat ambiscale, ALboolean isfuma)
{
size_t j, k;
ALuint i;
device->AmbiScale = ambiscale;
for(i = 0;i < MAX_OUTPUT_CHANNELS && device->ChannelName[i] != InvalidChannel;i++)
{
if(device->ChannelName[i] == LFE)
{
ERR("Malformed speaker key: %s\n", confkey);
for(j = 0;j < MAX_AMBI_COEFFS;j++)
device->AmbiCoeffs[i][j] = 0.0f;
continue;
}
end = sep - 1;
while(isspace(*end) && end != confkey)
end--;
*(++end) = 0;
if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
val = FrontLeft;
else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
val = FrontRight;
else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
val = FrontCenter;
else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
val = BackLeft;
else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
val = BackRight;
else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
val = BackCenter;
else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
val = SideLeft;
else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
val = SideRight;
else
for(j = 0;j < count;j++)
{
ERR("Unknown speaker for %s: \"%s\"\n", name, confkey);
continue;
}
*(sep++) = 0;
while(isspace(*sep))
sep++;
for(i = 0;i < chans;i++)
{
if(Speaker2Chan[i] == val)
if(device->ChannelName[i] == chanmap[j].ChanName)
{
long angle = strtol(sep, NULL, 10);
if(angle >= -180 && angle <= 180)
SpeakerAngle[i] = DEG2RAD(angle);
if(isfuma)
{
/* Reformat FuMa -> ACN/N3D */
for(k = 0;k < MAX_AMBI_COEFFS;++k)
{
ALuint acn = FuMa2ACN[k];
device->AmbiCoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn];
}
}
else
ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
{
for(k = 0;k < MAX_AMBI_COEFFS;++k)
device->AmbiCoeffs[i][k] = chanmap[j].Config[k];
}
break;
}
}
if(j == count)
ERR("Failed to match %s channel (%u) in config\n", GetLabelFromChannel(device->ChannelName[i]), i);
}
free(layout_str);
layout_str = NULL;
for(i = 0;i < chans;i++)
{
int min = i;
int i2;
for(i2 = i+1;i2 < chans;i2++)
{
if(SpeakerAngle[i2] < SpeakerAngle[min])
min = i2;
}
if(min != i)
{
ALfloat tmpf;
enum Channel tmpc;
tmpf = SpeakerAngle[i];
SpeakerAngle[i] = SpeakerAngle[min];
SpeakerAngle[min] = tmpf;
tmpc = Speaker2Chan[i];
Speaker2Chan[i] = Speaker2Chan[min];
Speaker2Chan[min] = tmpc;
}
}
device->NumChannels = i;
}
void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels])
static bool LoadChannelSetup(ALCdevice *device)
{
ALfloat tmpgains[MaxChannels] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
enum Channel Speaker2Chan[MaxChannels];
ALfloat SpeakerAngle[MaxChannels];
ALfloat langle, rangle;
ALfloat a;
ALuint i;
static const enum Channel mono_chans[1] = {
FrontCenter
}, stereo_chans[2] = {
FrontLeft, FrontRight
}, quad_chans[4] = {
FrontLeft, FrontRight,
BackLeft, BackRight
}, surround51_chans[5] = {
FrontLeft, FrontRight, FrontCenter,
SideLeft, SideRight
}, surround51rear_chans[5] = {
FrontLeft, FrontRight, FrontCenter,
BackLeft, BackRight
}, surround61_chans[6] = {
FrontLeft, FrontRight,
FrontCenter, BackCenter,
SideLeft, SideRight
}, surround71_chans[7] = {
FrontLeft, FrontRight, FrontCenter,
BackLeft, BackRight,
SideLeft, SideRight
};
ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
const enum Channel *channels = NULL;
const char *layout = NULL;
ALfloat ambiscale = 1.0f;
size_t count = 0;
int isfuma;
int order;
size_t i;
for(i = 0;i < device->NumChan;i++)
Speaker2Chan[i] = device->Speaker2Chan[i];
for(i = 0;i < device->NumChan;i++)
SpeakerAngle[i] = device->SpeakerAngle[i];
/* Some easy special-cases first... */
if(device->NumChan <= 1 || hwidth >= F_PI)
{
/* Full coverage for all speakers. */
for(i = 0;i < MaxChannels;i++)
gains[i] = 0.0f;
for(i = 0;i < device->NumChan;i++)
{
enum Channel chan = Speaker2Chan[i];
gains[chan] = ingain;
}
return;
}
if(hwidth <= 0.0f)
{
/* Infinitely small sound point. */
for(i = 0;i < MaxChannels;i++)
gains[i] = 0.0f;
for(i = 0;i < device->NumChan-1;i++)
{
if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1])
{
/* Sound is between speakers i and i+1 */
a = (angle-SpeakerAngle[i]) /
(SpeakerAngle[i+1]-SpeakerAngle[i]);
gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain;
gains[Speaker2Chan[i+1]] = sqrtf( a) * ingain;
return;
}
}
/* Sound is between last and first speakers */
if(angle < SpeakerAngle[0])
angle += F_2PI;
a = (angle-SpeakerAngle[i]) /
(F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain;
gains[Speaker2Chan[0]] = sqrtf( a) * ingain;
return;
}
if(fabsf(angle)+hwidth > F_PI)
{
/* The coverage area would go outside of -pi...+pi. Instead, rotate the
* speaker angles so it would be as if angle=0, and keep them wrapped
* within -pi...+pi. */
if(angle > 0.0f)
{
ALuint done;
ALuint i = 0;
while(i < device->NumChan && device->SpeakerAngle[i]-angle < -F_PI)
i++;
for(done = 0;i < device->NumChan;done++)
{
SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
Speaker2Chan[done] = device->Speaker2Chan[i];
i++;
}
for(i = 0;done < device->NumChan;i++)
{
SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_2PI;
Speaker2Chan[done] = device->Speaker2Chan[i];
done++;
}
}
else
{
/* NOTE: '< device->NumChan' on the iterators is correct here since
* we need to handle index 0. Because the iterators are unsigned,
* they'll underflow and wrap to become 0xFFFFFFFF, which will
* break as expected. */
ALuint done;
ALuint i = device->NumChan-1;
while(i < device->NumChan && device->SpeakerAngle[i]-angle > F_PI)
i--;
for(done = device->NumChan-1;i < device->NumChan;done--)
{
SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
Speaker2Chan[done] = device->Speaker2Chan[i];
i--;
}
for(i = device->NumChan-1;done < device->NumChan;i--)
{
SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_2PI;
Speaker2Chan[done] = device->Speaker2Chan[i];
done--;
}
}
angle = 0.0f;
}
langle = angle - hwidth;
rangle = angle + hwidth;
/* First speaker */
i = 0;
do {
ALuint last = device->NumChan-1;
enum Channel chan = Speaker2Chan[i];
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
{
tmpgains[chan] = 1.0f;
continue;
}
if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
{
a = (langle-SpeakerAngle[i]) /
(SpeakerAngle[i+1]-SpeakerAngle[i]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
if(SpeakerAngle[i] > rangle)
{
a = (F_2PI + rangle-SpeakerAngle[last]) /
(F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
else if(SpeakerAngle[last] < rangle)
{
a = (rangle-SpeakerAngle[last]) /
(F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
} while(0);
for(i = 1;i < device->NumChan-1;i++)
{
enum Channel chan = Speaker2Chan[i];
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
{
tmpgains[chan] = 1.0f;
continue;
}
if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
{
a = (langle-SpeakerAngle[i]) /
(SpeakerAngle[i+1]-SpeakerAngle[i]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
{
a = (rangle-SpeakerAngle[i-1]) /
(SpeakerAngle[i]-SpeakerAngle[i-1]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
}
/* Last speaker */
i = device->NumChan-1;
do {
enum Channel chan = Speaker2Chan[i];
if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
{
tmpgains[Speaker2Chan[i]] = 1.0f;
continue;
}
if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
{
a = (rangle-SpeakerAngle[i-1]) /
(SpeakerAngle[i]-SpeakerAngle[i-1]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
}
if(SpeakerAngle[i] < langle)
{
a = (langle-SpeakerAngle[i]) /
(F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
else if(SpeakerAngle[0] > langle)
{
a = (F_2PI + langle-SpeakerAngle[i]) /
(F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
}
} while(0);
for(i = 0;i < device->NumChan;i++)
{
enum Channel chan = device->Speaker2Chan[i];
gains[chan] = sqrtf(tmpgains[chan]) * ingain;
}
}
ALvoid aluInitPanning(ALCdevice *Device)
{
const char *layoutname = NULL;
enum Channel *Speaker2Chan;
ALfloat *SpeakerAngle;
Speaker2Chan = Device->Speaker2Chan;
SpeakerAngle = Device->SpeakerAngle;
switch(Device->FmtChans)
switch(device->FmtChans)
{
case DevFmtMono:
Device->NumChan = 1;
Speaker2Chan[0] = FrontCenter;
SpeakerAngle[0] = DEG2RAD(0.0f);
layoutname = NULL;
layout = "mono";
channels = mono_chans;
count = COUNTOF(mono_chans);
break;
case DevFmtStereo:
layout = "stereo";
channels = stereo_chans;
count = COUNTOF(stereo_chans);
break;
case DevFmtQuad:
layout = "quad";
channels = quad_chans;
count = COUNTOF(quad_chans);
break;
case DevFmtX51:
layout = "surround51";
channels = surround51_chans;
count = COUNTOF(surround51_chans);
break;
case DevFmtX51Rear:
layout = "surround51rear";
channels = surround51rear_chans;
count = COUNTOF(surround51rear_chans);
break;
case DevFmtX61:
layout = "surround61";
channels = surround61_chans;
count = COUNTOF(surround61_chans);
break;
case DevFmtX71:
layout = "surround71";
channels = surround71_chans;
count = COUNTOF(surround71_chans);
break;
case DevFmtBFormat3D:
break;
}
if(!layout)
return false;
else
{
char name[32] = {0};
const char *type;
char eol;
snprintf(name, sizeof(name), "%s/type", layout);
if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", name, &type))
return false;
if(sscanf(type, " %31[^: ] : %d%c", name, &order, &eol) != 2)
{
ERR("Invalid type value '%s' (expected name:order) for layout %s\n", type, layout);
return false;
}
if(strcasecmp(name, "fuma") == 0)
isfuma = 1;
else if(strcasecmp(name, "n3d") == 0)
isfuma = 0;
else
{
ERR("Unhandled type name '%s' (expected FuMa or N3D) for layout %s\n", name, layout);
return false;
}
if(order == 3)
ambiscale = THIRD_ORDER_SCALE;
else if(order == 2)
ambiscale = SECOND_ORDER_SCALE;
else if(order == 1)
ambiscale = FIRST_ORDER_SCALE;
else if(order == 0)
ambiscale = ZERO_ORDER_SCALE;
else
{
ERR("Unhandled type order %d (expected 0, 1, 2, or 3) for layout %s\n", order, layout);
return false;
}
}
for(i = 0;i < count;i++)
{
float coeffs[MAX_AMBI_COEFFS] = {0.0f};
const char *channame;
char chanlayout[32];
const char *value;
int props = 0;
char eol = 0;
int j;
chanmap[i].ChanName = channels[i];
channame = GetLabelFromChannel(channels[i]);
snprintf(chanlayout, sizeof(chanlayout), "%s/%s", layout, channame);
if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", chanlayout, &value))
{
ERR("Missing channel %s\n", channame);
return false;
}
if(order == 3)
props = sscanf(value, " %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %c",
&coeffs[0], &coeffs[1], &coeffs[2], &coeffs[3],
&coeffs[4], &coeffs[5], &coeffs[6], &coeffs[7],
&coeffs[8], &coeffs[9], &coeffs[10], &coeffs[11],
&coeffs[12], &coeffs[13], &coeffs[14], &coeffs[15],
&eol
);
else if(order == 2)
props = sscanf(value, " %f %f %f %f %f %f %f %f %f %c",
&coeffs[0], &coeffs[1], &coeffs[2],
&coeffs[3], &coeffs[4], &coeffs[5],
&coeffs[6], &coeffs[7], &coeffs[8],
&eol
);
else if(order == 1)
props = sscanf(value, " %f %f %f %f %c",
&coeffs[0], &coeffs[1],
&coeffs[2], &coeffs[3],
&eol
);
else if(order == 0)
props = sscanf(value, " %f %c", &coeffs[0], &eol);
if(props == 0)
{
ERR("Failed to parse option %s properties\n", chanlayout);
return false;
}
if(props > (order+1)*(order+1))
{
ERR("Excess elements in option %s (expected %d)\n", chanlayout, (order+1)*(order+1));
return false;
}
for(j = 0;j < MAX_AMBI_COEFFS;++j)
chanmap[i].Config[j] = coeffs[j];
}
SetChannelMap(device, chanmap, count, ambiscale, isfuma);
return true;
}
ALvoid aluInitPanning(ALCdevice *device)
{
/* NOTE: These decoder coefficients are using FuMa channel ordering and
* normalization, since that's what was produced by the Ambisonic Decoder
* Toolbox. SetChannelMap will convert them to N3D.
*/
static const ChannelMap MonoCfg[1] = {
{ FrontCenter, { 1.414213562f } },
}, StereoCfg[2] = {
{ FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } },
{ FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } },
}, QuadCfg[4] = {
{ FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } },
{ FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } },
{ BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } },
{ BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } },
}, X51SideCfg[5] = {
{ FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } },
{ FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } },
{ FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
{ SideLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } },
{ SideRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } },
}, X51RearCfg[5] = {
{ FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } },
{ FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } },
{ FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
{ BackLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } },
{ BackRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } },
}, X61Cfg[6] = {
{ FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } },
{ FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } },
{ FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
{ BackCenter, { 0.353556f, -0.461940f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.165723f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.000000f } },
{ SideLeft, { 0.289151f, -0.081301f, 0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, -0.032897f } },
{ SideRight, { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, 0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, 0.032897f } },
}, X71Cfg[7] = {
{ FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } },
{ FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } },
{ FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
{ BackLeft, { 0.224752f, -0.295009f, 0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, -0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065799f } },
{ BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } },
{ SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } },
{ SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } },
}, BFormat3D[4] = {
{ BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
{ BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } },
{ BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } },
{ BFormatZ, { 0.0f, 0.0f, 0.0f, 1.0f } },
};
const ChannelMap *chanmap = NULL;
ALfloat ambiscale = 1.0f;
size_t count = 0;
device->AmbiScale = 1.0f;
memset(device->AmbiCoeffs, 0, sizeof(device->AmbiCoeffs));
device->NumChannels = 0;
if(device->Hrtf)
{
ALfloat (*coeffs_list[4])[2];
ALuint *delay_list[4];
ALuint i;
count = COUNTOF(BFormat3D);
chanmap = BFormat3D;
ambiscale = 1.0f;
for(i = 0;i < count;i++)
device->ChannelName[i] = chanmap[i].ChanName;
for(;i < MAX_OUTPUT_CHANNELS;i++)
device->ChannelName[i] = InvalidChannel;
SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE);
for(i = 0;i < 4;++i)
{
static const enum Channel inputs[4] = { BFormatW, BFormatX, BFormatY, BFormatZ };
int chan = GetChannelIdxByName(device, inputs[i]);
coeffs_list[i] = device->Hrtf_Params[chan].Coeffs;
delay_list[i] = device->Hrtf_Params[chan].Delay;
}
GetBFormatHrtfCoeffs(device->Hrtf, 4, coeffs_list, delay_list);
return;
}
if(LoadChannelSetup(device))
return;
switch(device->FmtChans)
{
case DevFmtMono:
count = COUNTOF(MonoCfg);
chanmap = MonoCfg;
ambiscale = ZERO_ORDER_SCALE;
break;
case DevFmtStereo:
Device->NumChan = 2;
Speaker2Chan[0] = FrontLeft;
Speaker2Chan[1] = FrontRight;
SpeakerAngle[0] = DEG2RAD(-90.0f);
SpeakerAngle[1] = DEG2RAD( 90.0f);
layoutname = "layout_stereo";
count = COUNTOF(StereoCfg);
chanmap = StereoCfg;
ambiscale = FIRST_ORDER_SCALE;
break;
case DevFmtQuad:
Device->NumChan = 4;
Speaker2Chan[0] = BackLeft;
Speaker2Chan[1] = FrontLeft;
Speaker2Chan[2] = FrontRight;
Speaker2Chan[3] = BackRight;
SpeakerAngle[0] = DEG2RAD(-135.0f);
SpeakerAngle[1] = DEG2RAD( -45.0f);
SpeakerAngle[2] = DEG2RAD( 45.0f);
SpeakerAngle[3] = DEG2RAD( 135.0f);
layoutname = "layout_quad";
count = COUNTOF(QuadCfg);
chanmap = QuadCfg;
ambiscale = SECOND_ORDER_SCALE;
break;
case DevFmtX51:
Device->NumChan = 5;
Speaker2Chan[0] = BackLeft;
Speaker2Chan[1] = FrontLeft;
Speaker2Chan[2] = FrontCenter;
Speaker2Chan[3] = FrontRight;
Speaker2Chan[4] = BackRight;
SpeakerAngle[0] = DEG2RAD(-110.0f);
SpeakerAngle[1] = DEG2RAD( -30.0f);
SpeakerAngle[2] = DEG2RAD( 0.0f);
SpeakerAngle[3] = DEG2RAD( 30.0f);
SpeakerAngle[4] = DEG2RAD( 110.0f);
layoutname = "layout_surround51";
count = COUNTOF(X51SideCfg);
chanmap = X51SideCfg;
ambiscale = THIRD_ORDER_SCALE;
break;
case DevFmtX51Side:
Device->NumChan = 5;
Speaker2Chan[0] = SideLeft;
Speaker2Chan[1] = FrontLeft;
Speaker2Chan[2] = FrontCenter;
Speaker2Chan[3] = FrontRight;
Speaker2Chan[4] = SideRight;
SpeakerAngle[0] = DEG2RAD(-90.0f);
SpeakerAngle[1] = DEG2RAD(-30.0f);
SpeakerAngle[2] = DEG2RAD( 0.0f);
SpeakerAngle[3] = DEG2RAD( 30.0f);
SpeakerAngle[4] = DEG2RAD( 90.0f);
layoutname = "layout_side51";
case DevFmtX51Rear:
count = COUNTOF(X51RearCfg);
chanmap = X51RearCfg;
ambiscale = THIRD_ORDER_SCALE;
break;
case DevFmtX61:
Device->NumChan = 6;
Speaker2Chan[0] = SideLeft;
Speaker2Chan[1] = FrontLeft;
Speaker2Chan[2] = FrontCenter;
Speaker2Chan[3] = FrontRight;
Speaker2Chan[4] = SideRight;
Speaker2Chan[5] = BackCenter;
SpeakerAngle[0] = DEG2RAD(-90.0f);
SpeakerAngle[1] = DEG2RAD(-30.0f);
SpeakerAngle[2] = DEG2RAD( 0.0f);
SpeakerAngle[3] = DEG2RAD( 30.0f);
SpeakerAngle[4] = DEG2RAD( 90.0f);
SpeakerAngle[5] = DEG2RAD(180.0f);
layoutname = "layout_surround61";
count = COUNTOF(X61Cfg);
chanmap = X61Cfg;
ambiscale = THIRD_ORDER_SCALE;
break;
case DevFmtX71:
Device->NumChan = 7;
Speaker2Chan[0] = BackLeft;
Speaker2Chan[1] = SideLeft;
Speaker2Chan[2] = FrontLeft;
Speaker2Chan[3] = FrontCenter;
Speaker2Chan[4] = FrontRight;
Speaker2Chan[5] = SideRight;
Speaker2Chan[6] = BackRight;
SpeakerAngle[0] = DEG2RAD(-150.0f);
SpeakerAngle[1] = DEG2RAD( -90.0f);
SpeakerAngle[2] = DEG2RAD( -30.0f);
SpeakerAngle[3] = DEG2RAD( 0.0f);
SpeakerAngle[4] = DEG2RAD( 30.0f);
SpeakerAngle[5] = DEG2RAD( 90.0f);
SpeakerAngle[6] = DEG2RAD( 150.0f);
layoutname = "layout_surround71";
count = COUNTOF(X71Cfg);
chanmap = X71Cfg;
ambiscale = THIRD_ORDER_SCALE;
break;
case DevFmtBFormat3D:
count = COUNTOF(BFormat3D);
chanmap = BFormat3D;
ambiscale = 1.0f;
break;
}
if(layoutname && Device->Type != Loopback)
SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan);
SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE);
}
+26 -8
View File
@@ -7,21 +7,21 @@
/* "Base" vector type, designed to alias with the actual vector types. */
typedef struct vector__s {
ALsizei Capacity;
ALsizei Size;
size_t Capacity;
size_t Size;
} *vector_;
#define TYPEDEF_VECTOR(T, N) typedef struct { \
ALsizei Capacity; \
ALsizei Size; \
size_t Capacity; \
size_t Size; \
T Data[]; \
} _##N; \
typedef _##N* N; \
typedef const _##N* const_##N;
#define VECTOR(T) struct { \
ALsizei Capacity; \
ALsizei Size; \
size_t Capacity; \
size_t Size; \
T Data[]; \
}*
@@ -30,10 +30,10 @@ typedef const _##N* const_##N;
#define VECTOR_DEINIT(_x) do { free((_x)); (_x) = NULL; } while(0)
/* Helper to increase a vector's reserve. Do not call directly. */
ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count, ALboolean exact);
ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact);
#define VECTOR_RESERVE(_x, _c) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c), AL_TRUE))
ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count);
ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count);
#define VECTOR_RESIZE(_x, _c) (vector_resize((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c)))
#define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0)
@@ -73,6 +73,13 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
_f(_iter); \
} while(0)
#define VECTOR_FOR_EACH_PARAMS(_t, _x, _f, ...) do { \
_t *_iter = VECTOR_ITER_BEGIN((_x)); \
_t *_end = VECTOR_ITER_END((_x)); \
for(;_iter != _end;++_iter) \
_f(__VA_ARGS__, _iter); \
} while(0)
#define VECTOR_FIND_IF(_i, _t, _x, _f) do { \
_t *_iter = VECTOR_ITER_BEGIN((_x)); \
_t *_end = VECTOR_ITER_END((_x)); \
@@ -84,4 +91,15 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
(_i) = _iter; \
} while(0)
#define VECTOR_FIND_IF_PARMS(_i, _t, _x, _f, ...) do { \
_t *_iter = VECTOR_ITER_BEGIN((_x)); \
_t *_end = VECTOR_ITER_END((_x)); \
for(;_iter != _end;++_iter) \
{ \
if(_f(__VA_ARGS__, _iter)) \
break; \
} \
(_i) = _iter; \
} while(0)
#endif /* AL_VECTOR_H */
+167 -117
View File
@@ -34,9 +34,11 @@ OPTION(ALSOFT_UTILS "Build and install utility programs" OFF)
OPTION(ALSOFT_NO_CONFIG_UTIL "Disable building the alsoft-config utility" OFF)
OPTION(ALSOFT_EXAMPLES "Build and install example programs" OFF)
OPTION(ALSOFT_TESTS "Build and install test programs" OFF)
OPTION(ALSOFT_CONFIG "Install alsoft.conf sample configuration file" OFF)
OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" ON)
OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" OFF)
OPTION(ALSOFT_INSTALL "Install headers and libraries" ON)
IF(WIN32)
@@ -89,7 +91,7 @@ IF(NOT LIBTYPE)
ENDIF()
SET(LIB_MAJOR_VERSION "1")
SET(LIB_MINOR_VERSION "16")
SET(LIB_MINOR_VERSION "17")
SET(LIB_REVISION "0")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}")
@@ -101,9 +103,14 @@ CHECK_TYPE_SIZE("long" SIZEOF_LONG)
CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99)
IF(HAVE_STD_C99)
SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
CHECK_C_COMPILER_FLAG(-std=c11 HAVE_STD_C11)
IF(HAVE_STD_C11)
SET(CMAKE_C_FLAGS "-std=c11 ${CMAKE_C_FLAGS}")
ELSE()
CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99)
IF(HAVE_STD_C99)
SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
ENDIF()
ENDIF()
# MSVC may need workarounds for C99 restrict and inline
@@ -188,7 +195,7 @@ HAVE_C11_ALIGNAS)
# Check if we have C11 _Atomic
CHECK_C_SOURCE_COMPILES(
"#include <stdatomic.h>
int _Atomic foo;
const int _Atomic foo = ATOMIC_VAR_INIT(~0);
int main()
{
return atomic_load(&foo);
@@ -216,11 +223,6 @@ IF(NOT CMAKE_DEBUG_POSTFIX)
ENDIF()
IF(MSVC)
# ???
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEBUG")
SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -DNDEBUG")
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
ADD_DEFINITIONS("/wd4098")
@@ -232,9 +234,6 @@ IF(MSVC)
ENDIF()
IF(DXSDK_DIR)
MESSAGE(STATUS "Using DirectX SDK directory: ${DXSDK_DIR}")
SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} "${DXSDK_DIR}/Include")
INCLUDE_DIRECTORIES("${DXSDK_DIR}/Include")
LINK_DIRECTORIES("${DXSDK_DIR}/Lib")
ENDIF()
OPTION(FORCE_STATIC_VCRT "Force /MT for static VC runtimes" OFF)
@@ -258,27 +257,24 @@ ELSE()
ADD_DEFINITIONS(-Werror)
ENDIF()
# Force enable PIC if available. The static common library will be linked
# into the dynamic openal library, which requires all its code to be
# position-independent, and CMake doesn't automatically enable PIC for
# static library targets (Windows code is always position-independent).
CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH)
IF(HAVE_FPIC_SWITCH AND NOT WIN32)
ADD_DEFINITIONS(-fPIC)
# Force enable -fPIC for CMake versions before 2.8.9 (later versions have
# the POSITION_INDEPENDENT_CODE target property). The static common library
# will be linked into the dynamic openal library, which requires all its
# code to be position-independent.
IF(CMAKE_VERSION VERSION_LESS "2.8.9" AND NOT WIN32)
CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH)
IF(HAVE_FPIC_SWITCH)
ADD_DEFINITIONS(-fPIC)
ENDIF()
ENDIF()
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O2 -D_DEBUG" CACHE STRING
"Flags used by the compiler during Release with Debug Info builds."
FORCE)
SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" CACHE STRING
"Flags used by the compiler during release minsize builds."
FORCE)
SET(CMAKE_C_FLAGS_RELEASE "-O2 -fomit-frame-pointer -DNDEBUG" CACHE STRING
"Flags used by the compiler during release builds"
FORCE)
SET(CMAKE_C_FLAGS_DEBUG "-g3 -D_DEBUG" CACHE STRING
"Flags used by the compiler during debug builds."
FORCE)
# We want RelWithDebInfo to actually include debug stuff (define _DEBUG
# instead of NDEBUG)
FOREACH(flag_var CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO)
IF(${flag_var} MATCHES "-DNDEBUG")
STRING(REGEX REPLACE "-DNDEBUG" "-D_DEBUG" ${flag_var} "${${flag_var}}")
ENDIF()
ENDFOREACH()
CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
@@ -337,6 +333,10 @@ IF(NOT MSVC)
IF(HAVE_MSSE2_SWITCH)
SET(SSE2_SWITCH "-msse2")
ENDIF()
CHECK_C_COMPILER_FLAG(-msse3 HAVE_MSSE3_SWITCH)
IF(HAVE_MSSE3_SWITCH)
SET(SSE3_SWITCH "-msse3")
ENDIF()
CHECK_C_COMPILER_FLAG(-msse4.1 HAVE_MSSE4_1_SWITCH)
IF(HAVE_MSSE4_1_SWITCH)
SET(SSE4_1_SWITCH "-msse4.1")
@@ -349,7 +349,7 @@ CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(pri
CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H)
CHECK_INCLUDE_FILE(stdalign.h HAVE_STDALIGN_H)
CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H)
CHECK_INCLUDE_FILE(ftw.h HAVE_FTW_H)
CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H)
CHECK_INCLUDE_FILE(io.h HAVE_IO_H)
CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H)
CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H)
@@ -368,7 +368,7 @@ IF(HAVE_CPUID_H)
int main()
{
unsigned int eax, ebx, ecx, edx;
return __get_cpuid(0, eax, ebx, ecx, edx);
return __get_cpuid(0, &eax, &ebx, &ecx, &edx);
}" HAVE_GCC_GET_CPUID)
ENDIF()
@@ -394,6 +394,7 @@ CHECK_SYMBOL_EXISTS(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC)
CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)
CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC)
CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF)
CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF)
IF(NOT HAVE_C99_VLA)
CHECK_SYMBOL_EXISTS(alloca malloc.h HAVE_ALLOCA)
IF(NOT HAVE_ALLOCA)
@@ -405,12 +406,6 @@ IF(HAVE_FLOAT_H)
CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP)
CHECK_SYMBOL_EXISTS(__control87_2 float.h HAVE___CONTROL87_2)
ENDIF()
IF(HAVE_FTW_H)
CHECK_SYMBOL_EXISTS(ftw ftw.h HAVE_FTW)
ENDIF()
IF(HAVE_IO_H)
CHECK_SYMBOL_EXISTS(_wfindfirst io.h HAVE__WFINDFIRST)
ENDIF()
CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF)
CHECK_FUNCTION_EXISTS(stat HAVE_STAT)
@@ -515,12 +510,18 @@ IF(NOT HAVE_WINDOWS_H)
CHECK_SYMBOL_EXISTS(pthread_setschedparam pthread.h HAVE_PTHREAD_SETSCHEDPARAM)
CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
IF(NOT HAVE_PTHREAD_SETNAME_NP)
CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP)
ENDIF()
IF(HAVE_PTHREAD_NP_H)
CHECK_SYMBOL_EXISTS(pthread_setname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SETNAME_NP)
IF(NOT HAVE_PTHREAD_SETNAME_NP)
CHECK_SYMBOL_EXISTS(pthread_set_name_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SET_NAME_NP)
ENDIF()
CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np "pthread.h;pthread_np.h" HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
ELSE()
CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
IF(NOT HAVE_PTHREAD_SETNAME_NP)
CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP)
ENDIF()
CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np pthread.h HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
ENDIF()
CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK)
@@ -561,11 +562,7 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
OpenAL32/alError.c
OpenAL32/alExtension.c
OpenAL32/alFilter.c
OpenAL32/alFontsound.c
OpenAL32/alListener.c
OpenAL32/alMidi.c
OpenAL32/alPreset.c
OpenAL32/alSoundfont.c
OpenAL32/alSource.c
OpenAL32/alState.c
OpenAL32/alThunk.c
@@ -588,6 +585,7 @@ SET(ALC_OBJS Alc/ALc.c
Alc/effects/null.c
Alc/effects/reverb.c
Alc/helpers.c
Alc/bsinc.c
Alc/hrtf.c
Alc/panning.c
Alc/mixer.c
@@ -598,11 +596,10 @@ SET(ALC_OBJS Alc/ALc.c
SET(CPU_EXTS "Default")
SET(HAVE_SSE 0)
SET(HAVE_SSE2 0)
SET(HAVE_SSE3 0)
SET(HAVE_SSE4_1 0)
SET(HAVE_NEON 0)
SET(HAVE_FLUIDSYNTH 0)
SET(HAVE_ALSA 0)
SET(HAVE_OSS 0)
SET(HAVE_SOLARIS 0)
@@ -658,6 +655,26 @@ IF(ALSOFT_REQUIRE_SSE2 AND NOT HAVE_SSE2)
MESSAGE(FATAL_ERROR "Failed to enable required SSE2 CPU extensions")
ENDIF()
OPTION(ALSOFT_REQUIRE_SSE2 "Require SSE3 support" OFF)
CHECK_INCLUDE_FILE(pmmintrin.h HAVE_PMMINTRIN_H "${SSE3_SWITCH}")
IF(HAVE_EMMINTRIN_H)
OPTION(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON)
IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE3)
IF(ALIGN_DECL OR HAVE_C11_ALIGNAS)
SET(HAVE_SSE3 1)
SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_sse3.c)
IF(SSE2_SWITCH)
SET_SOURCE_FILES_PROPERTIES(Alc/mixer_sse3.c PROPERTIES
COMPILE_FLAGS "${SSE3_SWITCH}")
ENDIF()
SET(CPU_EXTS "${CPU_EXTS}, SSE3")
ENDIF()
ENDIF()
ENDIF()
IF(ALSOFT_REQUIRE_SSE3 AND NOT HAVE_SSE3)
MESSAGE(FATAL_ERROR "Failed to enable required SSE3 CPU extensions")
ENDIF()
OPTION(ALSOFT_REQUIRE_SSE4_1 "Require SSE4.1 support" OFF)
CHECK_INCLUDE_FILE(smmintrin.h HAVE_SMMINTRIN_H "${SSE4_1_SWITCH}")
IF(HAVE_SMMINTRIN_H)
@@ -705,32 +722,6 @@ ELSE()
ENDMACRO()
ENDIF()
SET(ALC_OBJS ${ALC_OBJS}
Alc/midi/base.c
Alc/midi/sf2load.c
Alc/midi/dummy.c
Alc/midi/fluidsynth.c
Alc/midi/soft.c
)
# Check for FluidSynth support
OPTION(ALSOFT_REQUIRE_FLUIDSYNTH "Require FluidSynth MIDI" OFF)
FIND_PACKAGE(FluidSynth)
IF(FLUIDSYNTH_FOUND)
OPTION(ALSOFT_MIDI_FLUIDSYNTH "Enable FluidSynth MIDI" ON)
IF(ALSOFT_MIDI_FLUIDSYNTH)
SET(HAVE_FLUIDSYNTH 1)
ADD_BACKEND_LIBS(${FLUIDSYNTH_LIBRARIES})
IF(CMAKE_VERSION VERSION_LESS "2.8.8")
INCLUDE_DIRECTORIES(${FLUIDSYNTH_INCLUDE_DIR})
ENDIF()
ENDIF()
ENDIF()
IF(ALSOFT_REQUIRE_FLUIDSYNTH AND NOT HAVE_FLUIDSYNTH)
MESSAGE(FATAL_ERROR "Failed to enabled required FluidSynth support")
ENDIF()
SET(BACKENDS "")
SET(ALC_OBJS ${ALC_OBJS}
Alc/backends/base.c
@@ -926,6 +917,25 @@ IF(ALSOFT_REQUIRE_PULSEAUDIO AND NOT HAVE_PULSEAUDIO)
MESSAGE(FATAL_ERROR "Failed to enabled required PulseAudio backend")
ENDIF()
# Check JACK backend
OPTION(ALSOFT_REQUIRE_JACK "Require JACK backend" OFF)
FIND_PACKAGE(JACK)
IF(JACK_FOUND)
OPTION(ALSOFT_BACKEND_JACK "Enable JACK backend" ON)
IF(ALSOFT_BACKEND_JACK)
SET(HAVE_JACK 1)
SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},")
SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.c)
ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES})
IF(CMAKE_VERSION VERSION_LESS "2.8.8")
INCLUDE_DIRECTORIES(${JACK_INCLUDE_DIRS})
ENDIF()
ENDIF()
ENDIF()
IF(ALSOFT_REQUIRE_JACK AND NOT HAVE_JACK)
MESSAGE(FATAL_ERROR "Failed to enabled required JACK backend")
ENDIF()
# Check CoreAudio backend
OPTION(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" OFF)
FIND_LIBRARY(COREAUDIO_FRAMEWORK
@@ -1030,17 +1040,21 @@ CONFIGURE_FILE(
# Build a common library with reusable helpers
ADD_LIBRARY(common STATIC ${COMMON_OBJS})
IF(NOT LIBTYPE STREQUAL "STATIC")
SET_PROPERTY(TARGET common PROPERTY POSITION_INDEPENDENT_CODE TRUE)
ENDIF()
# Build main library
ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
IF(LIBTYPE STREQUAL "STATIC")
ADD_LIBRARY(${LIBNAME} STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS})
ELSE()
ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS})
ENDIF()
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES)
IF(WIN32 AND ALSOFT_NO_UID_DEFS)
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS)
ENDIF()
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc")
IF(FLUIDSYNTH_FOUND)
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${FLUIDSYNTH_INCLUDE_DIR})
ENDIF()
IF(HAVE_ALSA)
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS})
ENDIF()
@@ -1065,6 +1079,9 @@ ENDIF()
IF(HAVE_PULSEAUDIO)
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS})
ENDIF()
IF(HAVE_JACK)
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS})
ENDIF()
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION}
SOVERSION ${LIB_MAJOR_VERSION})
IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
@@ -1096,25 +1113,28 @@ ENDIF()
TARGET_LINK_LIBRARIES(${LIBNAME} common ${EXTRA_LIBS})
TARGET_INCLUDE_DIRECTORIES(${LIBNAME} PUBLIC include)
# Add an install target here
IF(NOT MEGA)
INSTALL(TARGETS ${LIBNAME}
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
INSTALL(FILES include/AL/al.h
include/AL/alc.h
include/AL/alext.h
include/AL/efx.h
include/AL/efx-creative.h
include/AL/efx-presets.h
DESTINATION include/AL
)
INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
IF(ALSOFT_INSTALL)
# Add an install target here
IF(NOT MEGA)
INSTALL(TARGETS ${LIBNAME}
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
INSTALL(FILES include/AL/al.h
include/AL/alc.h
include/AL/alext.h
include/AL/efx.h
include/AL/efx-creative.h
include/AL/efx-presets.h
DESTINATION include/AL
)
INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
ENDIF()
ENDIF()
MESSAGE(STATUS "")
MESSAGE(STATUS "Building OpenAL with support for the following backends:")
MESSAGE(STATUS " ${BACKENDS}")
@@ -1122,10 +1142,6 @@ MESSAGE(STATUS "")
MESSAGE(STATUS "Building with support for CPU extensions:")
MESSAGE(STATUS " ${CPU_EXTS}")
MESSAGE(STATUS "")
IF(HAVE_FLUIDSYNTH)
MESSAGE(STATUS "FluidSynth support for ALC_SOFT_midi_interface enabled")
MESSAGE(STATUS "")
ENDIF()
IF(WIN32)
IF(NOT HAVE_DSOUND)
@@ -1163,11 +1179,18 @@ IF(ALSOFT_UTILS)
TARGET_LINK_LIBRARIES(makehrtf m)
ENDIF()
INSTALL(TARGETS openal-info makehrtf
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
ADD_EXECUTABLE(bsincgen utils/bsincgen.c)
IF(HAVE_LIBM)
TARGET_LINK_LIBRARIES(bsincgen m)
ENDIF()
IF(ALSOFT_INSTALL)
INSTALL(TARGETS openal-info makehrtf bsincgen
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
ENDIF()
MESSAGE(STATUS "Building utility programs")
IF(TARGET alsoft-config)
@@ -1176,6 +1199,24 @@ IF(ALSOFT_UTILS)
MESSAGE(STATUS "")
ENDIF()
IF(ALSOFT_TESTS)
ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c)
ADD_EXECUTABLE(altonegen examples/altonegen.c)
TARGET_LINK_LIBRARIES(altonegen test-common ${LIBNAME})
IF(ALSOFT_INSTALL)
INSTALL(TARGETS altonegen
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
ENDIF()
MESSAGE(STATUS "Building test programs")
MESSAGE(STATUS "")
ENDIF()
IF(ALSOFT_EXAMPLES)
IF(SDL2_FOUND AND SDL_SOUND_FOUND)
ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c
@@ -1203,11 +1244,18 @@ IF(ALSOFT_EXAMPLES)
SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
${SDL_SOUND_INCLUDE_DIR})
INSTALL(TARGETS alstream alreverb allatency alloopback
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
ADD_EXECUTABLE(alhrtf examples/alhrtf.c)
TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME})
SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
${SDL_SOUND_INCLUDE_DIR})
IF(ALSOFT_INSTALL)
INSTALL(TARGETS alstream alreverb allatency alloopback
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
ENDIF()
SET(FFVER_OK FALSE)
IF(FFMPEG_FOUND)
@@ -1239,11 +1287,13 @@ IF(ALSOFT_EXAMPLES)
SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
${FFMPEG_INCLUDE_DIRS})
INSTALL(TARGETS alffplay
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
IF(ALSOFT_INSTALL)
INSTALL(TARGETS alffplay
RUNTIME DESTINATION bin
LIBRARY DESTINATION "lib${LIB_SUFFIX}"
ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
)
ENDIF()
MESSAGE(STATUS "Building SDL and FFmpeg example programs")
ELSE()
MESSAGE(STATUS "Building SDL example programs")
+10 -13
View File
@@ -1,17 +1,15 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -101,7 +99,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
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
@@ -413,7 +411,7 @@ decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
@@ -436,9 +434,9 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
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
@@ -465,8 +463,8 @@ convey the exclusion of warranty; and each file should have at least the
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., 675 Mass Ave, Cambridge, MA 02139, USA.
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.
@@ -481,4 +479,3 @@ necessary. Here is a sample; alter the names:
Ty Coon, President of Vice
That's all there is to it!
+58
View File
@@ -1,3 +1,61 @@
openal-soft-1.17.0:
Implemented a JACK playback backend.
Implemented the AL_EXT_BFORMAT and AL_EXT_MULAW_BFORMAT extensions.
Implemented the ALC_SOFT_HRTF extension.
Implemented C, SSE3, and SSE4.1 based 4- and 8-point Sinc resamplers.
Implemented a C and SSE based band-limited Sinc resampler. This does 12- to
24-point Sinc resampling, and performs anti-aliasing.
Implemented B-Format output support for the wave file writer. This creates
FuMa-style first-order Ambisonics wave files (AMB format).
Implemented a stereo-mode config option for treating stereo modes as either
speakers or headphones.
Implemented per-device configuration options.
Fixed handling of PulseAudio and MMDevAPI devices that have identical
descriptions.
Fixed a potential lockup when stopping playback of suspended PulseAudio devices.
Fixed logging of Unicode characters on Windows.
Fixed 5.1 surround sound channels. By default it will now use the side
channels for the surround output. A configuration using rear channels is
still available.
Fixed the QSA backend potentially altering the capture format.
Fixed detecting MMDevAPI's default device.
Fixed returning the default capture device name.
Fixed mixing property calculations when deferring context updates.
Altered the behavior of alcSuspendContext and alcProcessContext to better
match certain Windows drivers.
Altered the panning algorithm, utilizing Ambisonics for better side and
back positioning cues with surround sound output.
Improved support for certain older Windows apps.
Improved the alffplay example to support surround sound streams.
Improved support for building as a sub-project.
Added an HRTF playback example.
Added a tone generator output test.
Added a toolchain to help with cross-compiling to Android.
openal-soft-1.16.0:
Implemented EFX Chorus, Flanger, Distortion, Equalizer, and Compressor
@@ -22,7 +22,7 @@ struct ALeffectStateVtable {
ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
void (*const update)(ALeffectState *state, ALCdevice *device, const struct ALeffectslot *slot);
void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE]);
void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels);
void (*const Delete)(void *ptr);
};
@@ -31,7 +31,7 @@ struct ALeffectStateVtable {
DECLARE_THUNK(T, ALeffectState, void, Destruct) \
DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
DECLARE_THUNK2(T, ALeffectState, void, update, ALCdevice*, const ALeffectslot*) \
DECLARE_THUNK3(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict) \
DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \
static void T##_ALeffectState_Delete(void *ptr) \
{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \
\
+6 -2
View File
@@ -32,6 +32,8 @@ enum UserFmtChannels {
UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */
UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */
UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */
UserFmtBFormat2D = 0x10000000, /* WXY */
UserFmtBFormat3D, /* WXYZ */
};
ALuint BytesFromUserFmt(enum UserFmtType type) DECL_CONST;
@@ -56,6 +58,8 @@ enum FmtChannels {
FmtX51 = UserFmtX51,
FmtX61 = UserFmtX61,
FmtX71 = UserFmtX71,
FmtBFormat2D = UserFmtBFormat2D,
FmtBFormat3D = UserFmtBFormat3D,
};
#define MAX_INPUT_CHANNELS (8)
@@ -85,8 +89,8 @@ typedef struct ALbuffer {
ALsizei LoopStart;
ALsizei LoopEnd;
ALsizei UnpackAlign;
ALsizei PackAlign;
ATOMIC(ALsizei) UnpackAlign;
ATOMIC(ALsizei) PackAlign;
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
RefCount ref;
@@ -132,7 +132,6 @@ typedef union ALeffectProps {
} Echo;
struct {
ALfloat Delay;
ALfloat LowCutoff;
ALfloat LowGain;
ALfloat Mid1Center;
+37 -8
View File
@@ -3,6 +3,8 @@
#include "alMain.h"
#include "math_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -11,23 +13,29 @@ extern "C" {
#define HIGHPASSFREQREF (250.0f)
/* Filters implementation is based on the "Cookbook formulae for audio *
* EQ biquad filter coefficients" by Robert Bristow-Johnson *
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */
/* Filters implementation is based on the "Cookbook formulae for audio
* EQ biquad filter coefficients" by Robert Bristow-Johnson
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
*/
/* Implementation note: For the shelf filters, the specified gain is for the
* reference frequency, which is the centerpoint of the transition band. This
* better matches EFX filter design. To set the gain for the shelf itself, use
* the square root of the desired linear gain (or halve the dB gain).
*/
typedef enum ALfilterType {
/** EFX-style low-pass filter, specifying a gain and reference frequency. */
ALfilterType_HighShelf,
/** EFX-style high-pass filter, specifying a gain and reference frequency. */
ALfilterType_LowShelf,
/** Peaking filter, specifying a gain, reference frequency, and bandwidth. */
/** Peaking filter, specifying a gain and reference frequency. */
ALfilterType_Peaking,
/** Low-pass cut-off filter, specifying a cut-off frequency and bandwidth. */
/** Low-pass cut-off filter, specifying a cut-off frequency. */
ALfilterType_LowPass,
/** High-pass cut-off filter, specifying a cut-off frequency and bandwidth. */
/** High-pass cut-off filter, specifying a cut-off frequency. */
ALfilterType_HighPass,
/** Band-pass filter, specifying a center frequency and bandwidth. */
/** Band-pass filter, specifying a center frequency. */
ALfilterType_BandPass,
} ALfilterType;
@@ -41,8 +49,27 @@ typedef struct ALfilterState {
} ALfilterState;
#define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__))
/* 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));
}
void ALfilterState_clear(ALfilterState *filter);
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth);
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample)
{
@@ -63,6 +90,8 @@ inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples);
void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples);
typedef struct ALfilter {
// Filter type (AL_FILTER_NULL, ...)
@@ -2,22 +2,23 @@
#define _AL_LISTENER_H_
#include "alMain.h"
#include "alu.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ALlistener {
volatile ALfloat Position[3];
volatile ALfloat Velocity[3];
aluVector Position;
aluVector Velocity;
volatile ALfloat Forward[3];
volatile ALfloat Up[3];
volatile ALfloat Gain;
volatile ALfloat MetersPerUnit;
struct {
ALfloat Matrix[4][4];
ALfloat Velocity[3];
aluMatrixd Matrix;
aluVector Velocity;
} Params;
} ALlistener;
+135 -289
View File
@@ -37,209 +37,7 @@
#include "vector.h"
#include "alstring.h"
#ifndef ALC_SOFT_HRTF
#define ALC_SOFT_HRTF 1
#define ALC_HRTF_SOFT 0x1992
#endif
#ifndef ALC_SOFT_midi_interface
#define ALC_SOFT_midi_interface 1
/* Global properties */
#define AL_MIDI_CLOCK_SOFT 0x9999
#define AL_MIDI_STATE_SOFT 0x9986
#define AL_MIDI_GAIN_SOFT 0x9998
#define AL_SOUNDFONTS_SIZE_SOFT 0x9995
#define AL_SOUNDFONTS_SOFT 0x9994
/* Soundfont properties */
#define AL_PRESETS_SIZE_SOFT 0x9993
#define AL_PRESETS_SOFT 0x9992
/* Preset properties */
#define AL_MIDI_PRESET_SOFT 0x9997
#define AL_MIDI_BANK_SOFT 0x9996
#define AL_FONTSOUNDS_SIZE_SOFT 0x9991
#define AL_FONTSOUNDS_SOFT 0x9990
/* Fontsound properties */
/* AL_BUFFER */
#define AL_SAMPLE_START_SOFT 0x2000
#define AL_SAMPLE_END_SOFT 0x2001
#define AL_SAMPLE_LOOP_START_SOFT 0x2002
#define AL_SAMPLE_LOOP_END_SOFT 0x2003
#define AL_SAMPLE_RATE_SOFT 0x2004
#define AL_BASE_KEY_SOFT 0x2005
#define AL_KEY_CORRECTION_SOFT 0x2006
#define AL_SAMPLE_TYPE_SOFT 0x2007
#define AL_FONTSOUND_LINK_SOFT 0x2008
#define AL_MOD_LFO_TO_PITCH_SOFT 0x0005
#define AL_VIBRATO_LFO_TO_PITCH_SOFT 0x0006
#define AL_MOD_ENV_TO_PITCH_SOFT 0x0007
#define AL_FILTER_CUTOFF_SOFT 0x0008
#define AL_FILTER_RESONANCE_SOFT 0x0009
#define AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT 0x000A
#define AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT 0x000B
#define AL_MOD_LFO_TO_VOLUME_SOFT 0x000D
#define AL_CHORUS_SEND_SOFT 0x000F
#define AL_REVERB_SEND_SOFT 0x0010
#define AL_PAN_SOFT 0x0011
#define AL_MOD_LFO_DELAY_SOFT 0x0015
#define AL_MOD_LFO_FREQUENCY_SOFT 0x0016
#define AL_VIBRATO_LFO_DELAY_SOFT 0x0017
#define AL_VIBRATO_LFO_FREQUENCY_SOFT 0x0018
#define AL_MOD_ENV_DELAYTIME_SOFT 0x0019
#define AL_MOD_ENV_ATTACKTIME_SOFT 0x001A
#define AL_MOD_ENV_HOLDTIME_SOFT 0x001B
#define AL_MOD_ENV_DECAYTIME_SOFT 0x001C
#define AL_MOD_ENV_SUSTAINVOLUME_SOFT 0x001D
#define AL_MOD_ENV_RELEASETIME_SOFT 0x002E
#define AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT 0x001F
#define AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT 0x0020
#define AL_VOLUME_ENV_DELAYTIME_SOFT 0x0021
#define AL_VOLUME_ENV_ATTACKTIME_SOFT 0x0022
#define AL_VOLUME_ENV_HOLDTIME_SOFT 0x0023
#define AL_VOLUME_ENV_DECAYTIME_SOFT 0x0024
#define AL_VOLUME_ENV_SUSTAINVOLUME_SOFT 0x0025
#define AL_VOLUME_ENV_RELEASETIME_SOFT 0x0026
#define AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT 0x0027
#define AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT 0x0028
#define AL_KEY_RANGE_SOFT 0x002B
#define AL_VELOCITY_RANGE_SOFT 0x002C
#define AL_ATTENUATION_SOFT 0x0030
#define AL_TUNING_COARSE_SOFT 0x0033
#define AL_TUNING_FINE_SOFT 0x0034
#define AL_LOOP_MODE_SOFT 0x0036
#define AL_TUNING_SCALE_SOFT 0x0038
#define AL_EXCLUSIVE_CLASS_SOFT 0x0039
/* Sample Types */
/* AL_MONO_SOFT */
#define AL_RIGHT_SOFT 0x0002
#define AL_LEFT_SOFT 0x0004
/* Loop Modes */
/* AL_NONE */
#define AL_LOOP_CONTINUOUS_SOFT 0x0001
#define AL_LOOP_UNTIL_RELEASE_SOFT 0x0003
/* Fontsound modulator stage properties */
#define AL_SOURCE0_INPUT_SOFT 0x998F
#define AL_SOURCE0_TYPE_SOFT 0x998E
#define AL_SOURCE0_FORM_SOFT 0x998D
#define AL_SOURCE1_INPUT_SOFT 0x998C
#define AL_SOURCE1_TYPE_SOFT 0x998B
#define AL_SOURCE1_FORM_SOFT 0x998A
#define AL_AMOUNT_SOFT 0x9989
#define AL_TRANSFORM_OP_SOFT 0x9988
#define AL_DESTINATION_SOFT 0x9987
/* Sounce Inputs */
#define AL_ONE_SOFT 0x0080
#define AL_NOTEON_VELOCITY_SOFT 0x0082
#define AL_NOTEON_KEY_SOFT 0x0083
/* AL_KEYPRESSURE_SOFT */
/* AL_CHANNELPRESSURE_SOFT */
/* AL_PITCHBEND_SOFT */
#define AL_PITCHBEND_SENSITIVITY_SOFT 0x0090
/* CC 0...127 */
/* Source Types */
#define AL_UNORM_SOFT 0x0000
#define AL_UNORM_REV_SOFT 0x0100
#define AL_SNORM_SOFT 0x0200
#define AL_SNORM_REV_SOFT 0x0300
/* Source Forms */
#define AL_LINEAR_SOFT 0x0000
#define AL_CONCAVE_SOFT 0x0400
#define AL_CONVEX_SOFT 0x0800
#define AL_SWITCH_SOFT 0x0C00
/* Transform Ops */
/* AL_LINEAR_SOFT */
#define AL_ABSOLUTE_SOFT 0x0002
/* Events */
#define AL_NOTEOFF_SOFT 0x0080
#define AL_NOTEON_SOFT 0x0090
#define AL_KEYPRESSURE_SOFT 0x00A0
#define AL_CONTROLLERCHANGE_SOFT 0x00B0
#define AL_PROGRAMCHANGE_SOFT 0x00C0
#define AL_CHANNELPRESSURE_SOFT 0x00D0
#define AL_PITCHBEND_SOFT 0x00E0
typedef void (AL_APIENTRY*LPALGENSOUNDFONTSSOFT)(ALsizei n, ALuint *ids);
typedef void (AL_APIENTRY*LPALDELETESOUNDFONTSSOFT)(ALsizei n, const ALuint *ids);
typedef ALboolean (AL_APIENTRY*LPALISSOUNDFONTSOFT)(ALuint id);
typedef void (AL_APIENTRY*LPALGETSOUNDFONTIVSOFT)(ALuint id, ALenum param, ALint *values);
typedef void (AL_APIENTRY*LPALSOUNDFONTPRESETSSOFT)(ALuint id, ALsizei count, const ALuint *pids);
typedef void (AL_APIENTRY*LPALGENPRESETSSOFT)(ALsizei n, ALuint *ids);
typedef void (AL_APIENTRY*LPALDELETEPRESETSSOFT)(ALsizei n, const ALuint *ids);
typedef ALboolean (AL_APIENTRY*LPALISPRESETSOFT)(ALuint id);
typedef void (AL_APIENTRY*LPALPRESETISOFT)(ALuint id, ALenum param, ALint value);
typedef void (AL_APIENTRY*LPALPRESETIVSOFT)(ALuint id, ALenum param, const ALint *values);
typedef void (AL_APIENTRY*LPALPRESETFONTSOUNDSSOFT)(ALuint id, ALsizei count, const ALuint *fsids);
typedef void (AL_APIENTRY*LPALGETPRESETIVSOFT)(ALuint id, ALenum param, ALint *values);
typedef void (AL_APIENTRY*LPALGENFONTSOUNDSSOFT)(ALsizei n, ALuint *ids);
typedef void (AL_APIENTRY*LPALDELETEFONTSOUNDSSOFT)(ALsizei n, const ALuint *ids);
typedef ALboolean (AL_APIENTRY*LPALISFONTSOUNDSOFT)(ALuint id);
typedef void (AL_APIENTRY*LPALFONTSOUNDISOFT)(ALuint id, ALenum param, ALint value);
typedef void (AL_APIENTRY*LPALFONTSOUND2ISOFT)(ALuint id, ALenum param, ALint value1, ALint value2);
typedef void (AL_APIENTRY*LPALFONTSOUNDIVSOFT)(ALuint id, ALenum param, const ALint *values);
typedef void (AL_APIENTRY*LPALGETFONTSOUNDIVSOFT)(ALuint id, ALenum param, ALint *values);
typedef void (AL_APIENTRY*LPALFONTSOUNDMOFULATORISOFT)(ALuint id, ALsizei stage, ALenum param, ALint value);
typedef void (AL_APIENTRY*LPALGETFONTSOUNDMODULATORIVSOFT)(ALuint id, ALsizei stage, ALenum param, ALint *values);
typedef void (AL_APIENTRY*LPALMIDISOUNDFONTSOFT)(ALuint id);
typedef void (AL_APIENTRY*LPALMIDISOUNDFONTVSOFT)(ALsizei count, const ALuint *ids);
typedef void (AL_APIENTRY*LPALMIDIEVENTSOFT)(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2);
typedef void (AL_APIENTRY*LPALMIDISYSEXSOFT)(ALuint64SOFT time, const ALbyte *data, ALsizei size);
typedef void (AL_APIENTRY*LPALMIDIPLAYSOFT)(void);
typedef void (AL_APIENTRY*LPALMIDIPAUSESOFT)(void);
typedef void (AL_APIENTRY*LPALMIDISTOPSOFT)(void);
typedef void (AL_APIENTRY*LPALMIDIRESETSOFT)(void);
typedef void (AL_APIENTRY*LPALMIDIGAINSOFT)(ALfloat value);
typedef ALint64SOFT (AL_APIENTRY*LPALGETINTEGER64SOFT)(ALenum pname);
typedef void (AL_APIENTRY*LPALGETINTEGER64VSOFT)(ALenum pname, ALint64SOFT *values);
typedef void (AL_APIENTRY*LPALLOADSOUNDFONTSOFT)(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user);
#ifdef AL_ALEXT_PROTOTYPES
AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids);
AL_API void AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids);
AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id);
AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values);
AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids);
AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids);
AL_API void AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids);
AL_API ALboolean AL_APIENTRY alIsPresetSOFT(ALuint id);
AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value);
AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *values);
AL_API void AL_APIENTRY alGetPresetivSOFT(ALuint id, ALenum param, ALint *values);
AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids);
AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids);
AL_API void AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids);
AL_API ALboolean AL_APIENTRY alIsFontsoundSOFT(ALuint id);
AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value);
AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1, ALint value2);
AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *values);
AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *values);
AL_API void AL_APIENTRY alFontsoundModulatoriSOFT(ALuint id, ALsizei stage, ALenum param, ALint value);
AL_API void AL_APIENTRY alGetFontsoundModulatorivSOFT(ALuint id, ALsizei stage, ALenum param, ALint *values);
AL_API void AL_APIENTRY alMidiSoundfontSOFT(ALuint id);
AL_API void AL_APIENTRY alMidiSoundfontvSOFT(ALsizei count, const ALuint *ids);
AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2);
AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, ALsizei size);
AL_API void AL_APIENTRY alMidiPlaySOFT(void);
AL_API void AL_APIENTRY alMidiPauseSOFT(void);
AL_API void AL_APIENTRY alMidiStopSOFT(void);
AL_API void AL_APIENTRY alMidiResetSOFT(void);
AL_API void AL_APIENTRY alMidiGainSOFT(ALfloat value);
AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname);
AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values);
AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user);
#endif
#endif
#include "hrtf.h"
#ifndef ALC_SOFT_device_clock
#define ALC_SOFT_device_clock 1
@@ -253,19 +51,9 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
#endif
#ifdef IN_IDE_PARSER
/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
* recent versions (at least 4.5.1) do recognize GCC's __restrict. */
#define restrict __restrict
#endif
typedef ALint64SOFT ALint64;
typedef ALuint64SOFT ALuint64;
typedef ptrdiff_t ALintptrEXT;
typedef ptrdiff_t ALsizeiptrEXT;
#ifndef U64
#if defined(_MSC_VER)
#define U64(x) ((ALuint64)(x##ui64))
@@ -385,9 +173,13 @@ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); }
#define DECLARE_DEFAULT_ALLOCATORS(T) \
static void* T##_New(size_t size) { return malloc(size); } \
static void T##_Delete(void *ptr) { free(ptr); }
static void* T##_New(size_t size) { return al_malloc(16, size); } \
static void T##_Delete(void *ptr) { al_free(ptr); }
/* Helper to extract an argument list for VCALL. Not used directly. */
#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
@@ -406,6 +198,18 @@ static void T##_Delete(void *ptr) { free(ptr); }
} while(0)
#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \
} \
} while(0)
#define NEW_OBJ(_res, T) do { \
_res = T##_New(sizeof(T)); \
if(_res) \
{ \
memset(_res, 0, sizeof(T)); \
T##_Construct(_res, EXTRACT_NEW_ARGS
#ifdef __cplusplus
extern "C" {
#endif
@@ -472,25 +276,11 @@ typedef struct {
void (*StopCapture)(ALCdevice*);
ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint);
ALCuint (*AvailableSamples)(ALCdevice*);
ALint64 (*GetLatency)(ALCdevice*);
} BackendFuncs;
ALCboolean alc_solaris_init(BackendFuncs *func_list);
void alc_solaris_deinit(void);
void alc_solaris_probe(enum DevProbe type);
ALCboolean alc_sndio_init(BackendFuncs *func_list);
void alc_sndio_deinit(void);
void alc_sndio_probe(enum DevProbe type);
ALCboolean alcWinMMInit(BackendFuncs *FuncList);
void alcWinMMDeinit(void);
void alcWinMMProbe(enum DevProbe type);
ALCboolean alc_pa_init(BackendFuncs *func_list);
void alc_pa_deinit(void);
void alc_pa_probe(enum DevProbe type);
ALCboolean alc_wave_init(BackendFuncs *func_list);
void alc_wave_deinit(void);
void alc_wave_probe(enum DevProbe type);
ALCboolean alc_ca_init(BackendFuncs *func_list);
void alc_ca_deinit(void);
void alc_ca_probe(enum DevProbe type);
@@ -516,14 +306,6 @@ enum DistanceModel {
DefaultDistanceModel = InverseDistanceClamped
};
enum Resampler {
PointResampler,
LinearResampler,
CubicResampler,
ResamplerMax,
};
enum Channel {
FrontLeft = 0,
FrontRight,
@@ -535,7 +317,12 @@ enum Channel {
SideLeft,
SideRight,
MaxChannels,
BFormatW,
BFormatX,
BFormatY,
BFormatZ,
InvalidChannel
};
@@ -559,11 +346,14 @@ enum DevFmtChannels {
DevFmtX61 = ALC_6POINT1_SOFT,
DevFmtX71 = ALC_7POINT1_SOFT,
/* Similar to 5.1, except using the side channels instead of back */
DevFmtX51Side = 0x80000000,
/* Similar to 5.1, except using rear channels instead of sides */
DevFmtX51Rear = 0x80000000,
DevFmtBFormat3D,
DevFmtChannelsDefault = DevFmtStereo
};
#define MAX_OUTPUT_CHANNELS (8)
ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST;
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST;
@@ -588,6 +378,38 @@ enum DeviceType {
};
enum HrtfMode {
DisabledHrtf,
BasicHrtf,
FullHrtf
};
/* The maximum number of Ambisonics coefficients. For a given order (o), the
* size needed will be (o+1)**2, thus zero-order has 1, first-order has 4,
* second-order has 9, and third-order has 16. */
#define MAX_AMBI_COEFFS 16
typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS];
#define HRTF_HISTORY_BITS (6)
#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
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];
alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
ALuint Delay[2];
ALint DelayStep[2];
} HrtfParams;
/* Size for temporary storage of buffer data, in ALfloats. Larger values need
* more memory, while smaller values may need more iterations. The value needs
* to be a sensible size, however, as it constrains the max stepping value used
@@ -595,7 +417,6 @@ enum DeviceType {
*/
#define BUFFERSIZE (2048u)
struct ALCdevice_struct
{
RefCount ref;
@@ -608,6 +429,7 @@ struct ALCdevice_struct
ALuint NumUpdates;
enum DevFmtChannels FmtChans;
enum DevFmtType FmtType;
ALboolean IsHeadphones;
al_string DeviceName;
@@ -631,36 +453,26 @@ struct ALCdevice_struct
// Map of Filters for this device
UIntMap FilterMap;
// Map of Soundfonts for this device
UIntMap SfontMap;
// Map of Presets for this device
UIntMap PresetMap;
// Map of Fontsounds for this device
UIntMap FontsoundMap;
/* Default soundfont (accessible as ID 0) */
struct ALsoundfont *DefaultSfont;
/* MIDI synth engine */
struct MidiSynth *Synth;
/* HRTF filter tables */
vector_HrtfEntry Hrtf_List;
al_string Hrtf_Name;
const struct Hrtf *Hrtf;
ALCenum Hrtf_Status;
enum HrtfMode Hrtf_Mode;
HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS];
HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS];
ALuint Hrtf_Offset;
// Stereo-to-binaural filter
struct bs2b *Bs2b;
ALCint Bs2bLevel;
// Device flags
ALuint Flags;
ALuint Flags;
ALuint ChannelOffsets[MaxChannels];
enum Channel Speaker2Chan[MaxChannels];
ALfloat SpeakerAngle[MaxChannels];
ALuint NumChan;
enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS];
ALfloat AmbiScale; /* Scale for first-order XYZ inputs using AmbCoeffs. */
ALuint NumChannels;
ALuint64 ClockBase;
ALuint SamplesDone;
@@ -670,8 +482,8 @@ struct ALCdevice_struct
alignas(16) ALfloat ResampledData[BUFFERSIZE];
alignas(16) ALfloat FilteredData[BUFFERSIZE];
// Dry path buffer mix
alignas(16) ALfloat DryBuffer[MaxChannels][BUFFERSIZE];
/* Dry path buffer mix. */
alignas(16) ALfloat (*DryBuffer)[BUFFERSIZE];
/* Running count of the mixer invocations, in 31.1 fixed point. This
* actually increments *twice* when mixing, first at the start and then at
@@ -702,11 +514,6 @@ struct ALCdevice_struct
#define DEVICE_CHANNELS_REQUEST (1<<2)
// Sample type was requested by the config file
#define DEVICE_SAMPLE_TYPE_REQUEST (1<<3)
// HRTF was requested by the app
#define DEVICE_HRTF_REQUEST (1<<4)
// Stereo sources cover 120-degree angles around +/-90
#define DEVICE_WIDE_STEREO (1<<16)
// Specifies if the DSP is paused at user request
#define DEVICE_PAUSED (1<<30)
@@ -714,9 +521,6 @@ struct ALCdevice_struct
// Specifies if the device is currently running
#define DEVICE_RUNNING (1<<31)
/* Invalid channel offset */
#define INVALID_OFFSET (~0u)
/* Nanosecond resolution for the device clock time. */
#define DEVICE_CLOCK_RES U64(1000000000)
@@ -726,6 +530,8 @@ struct ALCdevice_struct
* compatibility with pthread_setname_np limitations. */
#define MIXER_THREAD_NAME "alsoft-mixer"
#define RECORD_THREAD_NAME "alsoft-record"
struct ALCcontext_struct
{
@@ -748,9 +554,9 @@ struct ALCcontext_struct
volatile ALfloat SpeedOfSound;
volatile ALenum DeferUpdates;
struct ALactivesource **ActiveSources;
ALsizei ActiveSourceCount;
ALsizei MaxActiveSources;
struct ALvoice *Voices;
ALsizei VoiceCount;
ALsizei MaxVoices;
VECTOR(struct ALeffectslot*) ActiveAuxSlots;
@@ -771,11 +577,11 @@ void ALCcontext_DecRef(ALCcontext *context);
void AppendAllDevicesList(const ALCchar *name);
void AppendCaptureDeviceList(const ALCchar *name);
ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device);
void ALCdevice_Lock(ALCdevice *device);
void ALCdevice_Unlock(ALCdevice *device);
ALint64 ALCdevice_GetLatency(ALCdevice *device);
void ALCcontext_DeferUpdates(ALCcontext *context);
void ALCcontext_ProcessUpdates(ALCcontext *context);
inline void LockContext(ALCcontext *context)
{ ALCdevice_Lock(context->Device); }
@@ -810,15 +616,35 @@ ALsizei RingBufferSize(RingBuffer *ring);
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len);
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len);
typedef struct ll_ringbuffer ll_ringbuffer_t;
typedef struct ll_ringbuffer_data {
char *buf;
size_t len;
} ll_ringbuffer_data_t;
ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz);
void ll_ringbuffer_free(ll_ringbuffer_t *rb);
void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt);
size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt);
void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt);
size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb);
int ll_ringbuffer_mlock(ll_ringbuffer_t *rb);
void ll_ringbuffer_reset(ll_ringbuffer_t *rb);
size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt);
void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt);
size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb);
void ReadALConfig(void);
void FreeALConfig(void);
int ConfigValueExists(const char *blockName, const char *keyName);
const char *GetConfigValue(const char *blockName, const char *keyName, const char *def);
int GetConfigValueBool(const char *blockName, const char *keyName, int def);
int ConfigValueStr(const char *blockName, const char *keyName, const char **ret);
int ConfigValueInt(const char *blockName, const char *keyName, int *ret);
int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret);
int ConfigValueFloat(const char *blockName, const char *keyName, float *ret);
int ConfigValueExists(const char *devName, const char *blockName, const char *keyName);
const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def);
int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def);
int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret);
int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret);
int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret);
int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret);
int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret);
void SetRTPriority(void);
@@ -828,10 +654,27 @@ void SetDefaultWFXChannelOrder(ALCdevice *device);
const ALCchar *DevFmtTypeString(enum DevFmtType type) DECL_CONST;
const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST;
/**
* GetChannelIdxByName
*
* Returns the device's channel index given a channel name (e.g. FrontCenter),
* or -1 if it doesn't exist.
*/
inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan)
{
ALint i = 0;
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
{
if(device->ChannelName[i] == chan)
return i;
}
return -1;
}
extern FILE *LogFile;
#if defined(__GNUC__) && !defined(IN_IDE_PARSER)
#if defined(__GNUC__) && !defined(_WIN32) && !defined(IN_IDE_PARSER)
#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__)
#else
void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4);
@@ -875,14 +718,17 @@ extern ALuint CPUCapFlags;
enum {
CPU_CAP_SSE = 1<<0,
CPU_CAP_SSE2 = 1<<1,
CPU_CAP_SSE4_1 = 1<<2,
CPU_CAP_NEON = 1<<3,
CPU_CAP_SSE3 = 1<<2,
CPU_CAP_SSE4_1 = 1<<3,
CPU_CAP_NEON = 1<<4,
};
void FillCPUCaps(ALuint capfilter);
FILE *OpenDataFile(const char *fname, const char *subdir);
vector_al_string SearchDataFiles(const char *match, const char *subdir);
/* Small hack to use a pointer-to-array type as a normal argument type.
* Shouldn't be used directly. */
typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
+14 -13
View File
@@ -11,10 +11,8 @@
extern "C" {
#endif
extern enum Resampler DefaultResampler;
extern const ALsizei ResamplerPadding[ResamplerMax];
extern const ALsizei ResamplerPrePadding[ResamplerMax];
struct ALbuffer;
struct ALsource;
typedef struct ALbufferlistitem {
@@ -24,11 +22,11 @@ typedef struct ALbufferlistitem {
} ALbufferlistitem;
typedef struct ALactivesource {
struct ALsource *Source;
typedef struct ALvoice {
struct ALsource *volatile Source;
/** Method to update mixing parameters. */
ALvoid (*Update)(struct ALactivesource *self, const ALCcontext *context);
ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const ALCcontext *context);
/** Current target parameters used for mixing. */
ALint Step;
@@ -37,9 +35,13 @@ typedef struct ALactivesource {
ALuint Offset; /* Number of output samples mixed since starting. */
alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
BsincState SincState;
DirectParams Direct;
SendParams Send[MAX_SENDS];
} ALactivesource;
} ALvoice;
typedef struct ALsource {
@@ -54,9 +56,10 @@ typedef struct ALsource {
volatile ALfloat RefDistance;
volatile ALfloat MaxDistance;
volatile ALfloat RollOffFactor;
volatile ALfloat Position[3];
volatile ALfloat Velocity[3];
volatile ALfloat Orientation[3];
aluVector Position;
aluVector Velocity;
aluVector Direction;
volatile ALfloat Orientation[2][3];
volatile ALboolean HeadRelative;
volatile ALboolean Looping;
volatile enum DistanceModel DistanceModel;
@@ -73,8 +76,6 @@ typedef struct ALsource {
volatile ALfloat Radius;
enum Resampler Resampler;
/**
* Last user-specified offset, and the offset type (bytes, samples, or
* seconds).
+160 -66
View File
@@ -16,31 +16,112 @@
#include "hrtf.h"
#include "align.h"
#include "math_defs.h"
#define F_PI (3.14159265358979323846f)
#define F_PI_2 (1.57079632679489661923f)
#define F_2PI (6.28318530717958647692f)
#define MAX_PITCH (255)
#ifndef FLT_EPSILON
#define FLT_EPSILON (1.19209290e-07f)
#endif
/* Maximum number of buffer samples before the current pos needed for resampling. */
#define MAX_PRE_SAMPLES 12
#define DEG2RAD(x) ((ALfloat)(x) * (F_PI/180.0f))
#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI))
#define SRC_HISTORY_BITS (6)
#define SRC_HISTORY_LENGTH (1<<SRC_HISTORY_BITS)
#define SRC_HISTORY_MASK (SRC_HISTORY_LENGTH-1)
#define MAX_PITCH (10)
/* Maximum number of buffer samples after the current pos needed for resampling. */
#define MAX_POST_SAMPLES 12
#ifdef __cplusplus
extern "C" {
#endif
struct ALsource;
struct ALvoice;
/* 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
#define BSINC_PHASE_COUNT (1<<BSINC_PHASE_BITS)
/* Interpolator state. Kind of a misnomer since the interpolator itself is
* stateless. This just keeps it from having to recompute scale-related
* mappings for every sample.
*/
typedef struct BsincState {
ALfloat sf; /* Scale interpolation factor. */
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 aluVector {
alignas(16) ALfloat v[4];
} aluVector;
inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w)
{
vector->v[0] = x;
vector->v[1] = y;
vector->v[2] = z;
vector->v[3] = w;
}
typedef union aluMatrixf {
alignas(16) ALfloat m[4][4];
} aluMatrixf;
inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3)
{
matrix->m[row][0] = m0;
matrix->m[row][1] = m1;
matrix->m[row][2] = m2;
matrix->m[row][3] = m3;
}
inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33)
{
aluMatrixfSetRow(matrix, 0, m00, m01, m02, m03);
aluMatrixfSetRow(matrix, 1, m10, m11, m12, m13);
aluMatrixfSetRow(matrix, 2, m20, m21, m22, m23);
aluMatrixfSetRow(matrix, 3, m30, m31, m32, m33);
}
typedef union aluMatrixd {
alignas(16) ALdouble m[4][4];
} aluMatrixd;
inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3)
{
matrix->m[row][0] = m0;
matrix->m[row][1] = m1;
matrix->m[row][2] = m2;
matrix->m[row][3] = m3;
}
inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33)
{
aluMatrixdSetRow(matrix, 0, m00, m01, m02, m03);
aluMatrixdSetRow(matrix, 1, m10, m11, m12, m13);
aluMatrixdSetRow(matrix, 2, m20, m21, m22, m23);
aluMatrixdSetRow(matrix, 3, m30, m31, m32, m33);
}
enum ActiveFilters {
AF_None = 0,
AF_LowPass = 1,
@@ -49,19 +130,6 @@ enum ActiveFilters {
};
typedef struct HrtfState {
alignas(16) ALfloat History[SRC_HISTORY_LENGTH];
alignas(16) ALfloat Values[HRIR_LENGTH][2];
} HrtfState;
typedef struct HrtfParams {
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
ALuint Delay[2];
ALint DelayStep[2];
} HrtfParams;
typedef struct MixGains {
ALfloat Current;
ALfloat Step;
@@ -71,11 +139,15 @@ typedef struct MixGains {
typedef struct DirectParams {
ALfloat (*OutBuffer)[BUFFERSIZE];
ALuint OutChannels;
/* If not 'moving', gain/coefficients are set directly without fading. */
ALboolean Moving;
/* Stepping counter for gain/coefficient fading. */
ALuint Counter;
/* Last direction (relative to listener) and gain of a moving source. */
aluVector LastDir;
ALfloat LastGain;
struct {
enum ActiveFilters ActiveType;
@@ -83,17 +155,11 @@ typedef struct DirectParams {
ALfilterState HighPass;
} Filters[MAX_INPUT_CHANNELS];
union {
struct {
HrtfParams Params[MAX_INPUT_CHANNELS];
HrtfState State[MAX_INPUT_CHANNELS];
ALuint IrSize;
ALfloat Gain;
ALfloat Dir[3];
} Hrtf;
MixGains Gains[MAX_INPUT_CHANNELS][MaxChannels];
} Mix;
struct {
HrtfParams Params;
HrtfState State;
} Hrtf[MAX_INPUT_CHANNELS];
MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
} DirectParams;
typedef struct SendParams {
@@ -108,14 +174,15 @@ typedef struct SendParams {
ALfilterState HighPass;
} Filters[MAX_INPUT_CHANNELS];
/* Gain control, which applies to all input channels to a single (mono)
/* Gain control, which applies to each input channel to a single (mono)
* output buffer. */
MixGains Gain;
MixGains Gains[MAX_INPUT_CHANNELS];
} SendParams;
typedef const ALfloat* (*ResamplerFunc)(const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint dstlen);
typedef const ALfloat* (*ResamplerFunc)(const BsincState *state,
const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen
);
typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans,
ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains,
@@ -131,7 +198,7 @@ typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const A
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
#define FRACTIONBITS (14)
#define FRACTIONBITS (12)
#define FRACTIONONE (1<<FRACTIONBITS)
#define FRACTIONMASK (FRACTIONONE-1)
@@ -179,47 +246,75 @@ inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
{ return minu64(max, maxu64(min, val)); }
union ResamplerCoeffs {
ALfloat FIR4[FRACTIONONE][4];
ALfloat FIR8[FRACTIONONE][8];
};
extern alignas(16) union ResamplerCoeffs ResampleCoeffs;
extern alignas(16) const ALfloat bsincTab[18840];
inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
{
return val1 + (val2-val1)*mu;
}
inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu)
inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac)
{
ALfloat mu2 = mu*mu;
ALfloat a0 = -0.5f*val0 + 1.5f*val1 + -1.5f*val2 + 0.5f*val3;
ALfloat a1 = val0 + -2.5f*val1 + 2.0f*val2 + -0.5f*val3;
ALfloat a2 = -0.5f*val0 + 0.5f*val2;
ALfloat a3 = val1;
return a0*mu*mu2 + a1*mu2 + a2*mu + a3;
const ALfloat *k = ResampleCoeffs.FIR4[frac];
return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3;
}
inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac)
{
const ALfloat *k = ResampleCoeffs.FIR8[frac];
return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3 +
k[4]*val4 + k[5]*val5 + k[6]*val6 + k[7]*val7;
}
void aluInitMixer(void);
ALvoid aluInitPanning(ALCdevice *Device);
/**
* ComputeAngleGains
* ComputeDirectionalGains
*
* Sets channel gains based on a given source's angle and its half-width. The
* angle and hwidth parameters are in radians.
* Sets channel gains based on a direction. The direction must be a 3-component
* vector no longer than 1 unit.
*/
void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels]);
void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
/**
* SetGains
* ComputeAngleGains
*
* Helper to set the appropriate channels to the specified gain.
* Sets channel gains based on angle and elevation. The angle and elevation
* parameters are in radians, going right and up respectively.
*/
inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels])
{
ComputeAngleGains(device, 0.0f, F_PI, ingain, gains);
}
void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
/**
* ComputeAmbientGains
*
* Sets channel gains for ambient, omni-directional sounds.
*/
void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
/**
* ComputeBFormatGains
*
* Sets channel gains for a given (first-order) B-Format channel. The matrix is
* a 1x4 'slice' of the rotation matrix for a given channel used to orient the
* coefficients.
*/
void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
ALvoid CalcSourceParams(struct ALactivesource *src, const ALCcontext *ALContext);
ALvoid CalcNonAttnSourceParams(struct ALactivesource *src, const ALCcontext *ALContext);
ALvoid UpdateContextSources(ALCcontext *context);
ALvoid MixSource(struct ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo);
ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext);
ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext);
ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo);
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
/* Caller must lock the device. */
@@ -233,4 +328,3 @@ extern ALfloat ZScale;
#endif
#endif
+4 -7
View File
@@ -69,19 +69,16 @@ struct bs2b {
} last_sample;
};
/* Clear buffers and set new coefficients with new crossfeed level value.
/* Clear buffers and set new coefficients with new crossfeed level and sample
* rate values.
* level - crossfeed level of *LEVEL values.
* srate - sample rate by Hz.
*/
void bs2b_set_level(struct bs2b *bs2b, int level);
void bs2b_set_params(struct bs2b *bs2b, int level, int srate);
/* Return current crossfeed level value */
int bs2b_get_level(struct bs2b *bs2b);
/* Clear buffers and set new coefficients with new sample rate value.
* srate - sample rate by Hz.
*/
void bs2b_set_srate(struct bs2b *bs2b, int srate);
/* Return current sample rate value */
int bs2b_get_srate(struct bs2b *bs2b);
+2 -2
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
+41 -11
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -151,7 +151,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
align = albuf->UnpackAlign;
align = ATOMIC_LOAD(&albuf->UnpackAlign);
if(SanitizeAlignment(srctype, &align) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(srctype)
@@ -189,6 +189,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_FLOAT32; break;
case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_FLOAT32; break;
}
err = LoadData(albuf, freq, newformat, size/framesize*align,
srcchannels, srctype, data, align, AL_TRUE);
@@ -211,6 +213,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
}
err = LoadData(albuf, freq, newformat, size/framesize*align,
srcchannels, srctype, data, align, AL_TRUE);
@@ -233,6 +237,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
}
err = LoadData(albuf, freq, newformat, size/framesize*align,
srcchannels, srctype, data, align, AL_TRUE);
@@ -255,6 +261,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
}
err = LoadData(albuf, freq, newformat, size/framesize*align,
srcchannels, srctype, data, align, AL_TRUE);
@@ -291,7 +299,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
WriteLock(&albuf->lock);
align = albuf->UnpackAlign;
align = ATOMIC_LOAD(&albuf->UnpackAlign);
if(SanitizeAlignment(srctype, &align) == AL_FALSE)
{
WriteUnlock(&albuf->lock);
@@ -368,7 +376,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
align = albuf->UnpackAlign;
align = ATOMIC_LOAD(&albuf->UnpackAlign);
if(SanitizeAlignment(type, &align) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if((samples%align) != 0)
@@ -404,7 +412,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
WriteLock(&albuf->lock);
align = albuf->UnpackAlign;
align = ATOMIC_LOAD(&albuf->UnpackAlign);
if(SanitizeAlignment(type, &align) == AL_FALSE)
{
WriteUnlock(&albuf->lock);
@@ -457,7 +465,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
ReadLock(&albuf->lock);
align = albuf->PackAlign;
align = ATOMIC_LOAD(&albuf->PackAlign);
if(SanitizeAlignment(type, &align) == AL_FALSE)
{
ReadUnlock(&albuf->lock);
@@ -596,13 +604,13 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
if(!(value >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
ExchangeInt(&albuf->UnpackAlign, value);
ATOMIC_STORE(&albuf->UnpackAlign, value);
break;
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
if(!(value >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
ExchangeInt(&albuf->PackAlign, value);
ATOMIC_STORE(&albuf->PackAlign, value);
break;
default:
@@ -834,11 +842,11 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value
break;
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
*value = albuf->UnpackAlign;
*value = ATOMIC_LOAD(&albuf->UnpackAlign);
break;
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
*value = albuf->PackAlign;
*value = ATOMIC_LOAD(&albuf->PackAlign);
break;
default:
@@ -1045,6 +1053,8 @@ ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
case UserFmtX51: return 6;
case UserFmtX61: return 7;
case UserFmtX71: return 8;
case UserFmtBFormat2D: return 3;
case UserFmtBFormat3D: return 4;
}
return 0;
}
@@ -1101,6 +1111,16 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
{ AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
{ AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
{ AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
{ AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte },
{ AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort },
{ AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat },
{ AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw },
{ AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte },
{ AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort },
{ AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat },
{ AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw },
};
ALuint i;
@@ -1138,6 +1158,8 @@ ALuint ChannelsFromFmt(enum FmtChannels chans)
case FmtX51: return 6;
case FmtX61: return 7;
case FmtX71: return 8;
case FmtBFormat2D: return 3;
case FmtBFormat3D: return 4;
}
return 0;
}
@@ -1178,6 +1200,14 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm
{ AL_7POINT1_8_SOFT, FmtX71, FmtByte },
{ AL_7POINT1_16_SOFT, FmtX71, FmtShort },
{ AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
{ AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtByte },
{ AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort },
{ AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat },
{ AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtByte },
{ AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort },
{ AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat },
};
ALuint i;
+16 -2
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -402,13 +402,27 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN;
effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
effect->Props.Reverb.GainLF = 1.0f;
effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
effect->Props.Reverb.DecayLFRatio = 1.0f;
effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
effect->Props.Reverb.ReflectionsPan[0] = 0.0f;
effect->Props.Reverb.ReflectionsPan[1] = 0.0f;
effect->Props.Reverb.ReflectionsPan[2] = 0.0f;
effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
effect->Props.Reverb.LateReverbPan[0] = 0.0f;
effect->Props.Reverb.LateReverbPan[1] = 0.0f;
effect->Props.Reverb.LateReverbPan[2] = 0.0f;
effect->Props.Reverb.EchoTime = 0.25f;
effect->Props.Reverb.EchoDepth = 0.0f;
effect->Props.Reverb.ModulationTime = 0.25f;
effect->Props.Reverb.ModulationDepth = 0.0f;
effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
effect->Props.Reverb.HFReference = 5000.0f;
effect->Props.Reverb.LFReference = 250.0f;
effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
SET_VTABLE1(ALreverb, effect);
+2 -2
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
+2 -2
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
+57 -37
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -32,6 +32,8 @@
extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample);
extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth);
static void InitFilterParams(ALfilter *filter, ALenum type);
@@ -336,72 +338,72 @@ void ALfilterState_clear(ALfilterState *filter)
filter->y[1] = 0.0f;
}
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth)
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ)
{
ALfloat alpha;
ALfloat w0;
ALfloat alpha, sqrtgain_alpha_2;
ALfloat w0, sin_w0, cos_w0;
// Limit gain to -100dB
gain = maxf(gain, 0.00001f);
w0 = F_2PI * freq_mult;
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:
alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f);
filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha);
filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cosf(w0) );
filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha);
filter->a[0] = (gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha;
filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cosf(w0) );
filter->a[2] = (gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha;
sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
filter->a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
filter->a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
break;
case ALfilterType_LowShelf:
alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f);
filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha);
filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cosf(w0) );
filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha);
filter->a[0] = (gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha;
filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cosf(w0) );
filter->a[2] = (gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha;
sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
filter->a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
filter->a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
break;
case ALfilterType_Peaking:
alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
gain = sqrtf(gain);
filter->b[0] = 1.0f + alpha * gain;
filter->b[1] = -2.0f * cosf(w0);
filter->b[1] = -2.0f * cos_w0;
filter->b[2] = 1.0f - alpha * gain;
filter->a[0] = 1.0f + alpha / gain;
filter->a[1] = -2.0f * cosf(w0);
filter->a[1] = -2.0f * cos_w0;
filter->a[2] = 1.0f - alpha / gain;
break;
case ALfilterType_LowPass:
alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
filter->b[0] = (1.0f - cosf(w0)) / 2.0f;
filter->b[1] = 1.0f - cosf(w0);
filter->b[2] = (1.0f - cosf(w0)) / 2.0f;
filter->b[0] = (1.0f - cos_w0) / 2.0f;
filter->b[1] = 1.0f - cos_w0;
filter->b[2] = (1.0f - cos_w0) / 2.0f;
filter->a[0] = 1.0f + alpha;
filter->a[1] = -2.0f * cosf(w0);
filter->a[1] = -2.0f * cos_w0;
filter->a[2] = 1.0f - alpha;
break;
case ALfilterType_HighPass:
alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
filter->b[0] = (1.0f + cosf(w0)) / 2.0f;
filter->b[1] = 1.0f + cosf(w0);
filter->b[2] = (1.0f + cosf(w0)) / 2.0f;
filter->a[0] = 1.0f + alpha;
filter->a[1] = -2.0f * cosf(w0);
filter->a[2] = 1.0f - alpha;
filter->b[0] = (1.0f + cos_w0) / 2.0f;
filter->b[1] = -(1.0f + cos_w0);
filter->b[2] = (1.0f + cos_w0) / 2.0f;
filter->a[0] = 1.0f + alpha;
filter->a[1] = -2.0f * cos_w0;
filter->a[2] = 1.0f - alpha;
break;
case ALfilterType_BandPass:
alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
filter->b[0] = alpha;
filter->b[1] = 0;
filter->b[2] = -alpha;
filter->a[0] = 1.0f + alpha;
filter->a[1] = -2.0f * cosf(w0);
filter->a[1] = -2.0f * cos_w0;
filter->a[2] = 1.0f - alpha;
break;
}
@@ -416,6 +418,24 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g
filter->process = ALfilterState_processC;
}
void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples)
{
if(numsamples >= 2)
{
filter->x[1] = src[numsamples-2];
filter->x[0] = src[numsamples-1];
filter->y[1] = src[numsamples-2];
filter->y[0] = src[numsamples-1];
}
else if(numsamples == 1)
{
filter->x[1] = filter->x[0];
filter->x[0] = src[0];
filter->y[1] = filter->y[0];
filter->y[0] = src[0];
}
}
static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
+16 -20
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -74,9 +74,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
LockContext(context);
context->Listener->Position[0] = value1;
context->Listener->Position[1] = value2;
context->Listener->Position[2] = value3;
aluVectorSet(&context->Listener->Position, value1, value2, value3, 1.0f);
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
UnlockContext(context);
break;
@@ -86,9 +84,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
LockContext(context);
context->Listener->Velocity[0] = value1;
context->Listener->Velocity[1] = value2;
context->Listener->Velocity[2] = value3;
aluVectorSet(&context->Listener->Velocity, value1, value2, value3, 0.0f);
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
UnlockContext(context);
break;
@@ -282,17 +278,17 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
{
case AL_POSITION:
LockContext(context);
*value1 = context->Listener->Position[0];
*value2 = context->Listener->Position[1];
*value3 = context->Listener->Position[2];
*value1 = context->Listener->Position.v[0];
*value2 = context->Listener->Position.v[1];
*value3 = context->Listener->Position.v[2];
UnlockContext(context);
break;
case AL_VELOCITY:
LockContext(context);
*value1 = context->Listener->Velocity[0];
*value2 = context->Listener->Velocity[1];
*value3 = context->Listener->Velocity[2];
*value1 = context->Listener->Velocity.v[0];
*value2 = context->Listener->Velocity.v[1];
*value3 = context->Listener->Velocity.v[2];
UnlockContext(context);
break;
@@ -383,17 +379,17 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
{
case AL_POSITION:
LockContext(context);
*value1 = (ALint)context->Listener->Position[0];
*value2 = (ALint)context->Listener->Position[1];
*value3 = (ALint)context->Listener->Position[2];
*value1 = (ALint)context->Listener->Position.v[0];
*value2 = (ALint)context->Listener->Position.v[1];
*value3 = (ALint)context->Listener->Position.v[2];
UnlockContext(context);
break;
case AL_VELOCITY:
LockContext(context);
*value1 = (ALint)context->Listener->Velocity[0];
*value2 = (ALint)context->Listener->Velocity[1];
*value3 = (ALint)context->Listener->Velocity[2];
*value1 = (ALint)context->Listener->Velocity.v[0];
*value2 = (ALint)context->Listener->Velocity.v[1];
*value3 = (ALint)context->Listener->Velocity.v[2];
UnlockContext(context);
break;
File diff suppressed because it is too large Load Diff
+5 -172
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -28,9 +28,8 @@
#include "alError.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
#include "alMidi.h"
#include "midi/base.h"
#include "backends/base.h"
static const ALchar alVendor[] = "OpenAL Community";
@@ -159,7 +158,6 @@ done:
AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
{
ALCdevice *device;
ALCcontext *context;
ALdouble value = 0.0;
@@ -188,16 +186,6 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
value = (ALdouble)context->DeferUpdates;
break;
case AL_MIDI_GAIN_SOFT:
device = context->Device;
value = (ALdouble)MidiSynth_getGain(device->Synth);
break;
case AL_MIDI_STATE_SOFT:
device = context->Device;
value = (ALdouble)MidiSynth_getState(device->Synth);
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -210,7 +198,6 @@ done:
AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
{
ALCdevice *device;
ALCcontext *context;
ALfloat value = 0.0f;
@@ -239,16 +226,6 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
value = (ALfloat)context->DeferUpdates;
break;
case AL_MIDI_GAIN_SOFT:
device = context->Device;
value = MidiSynth_getGain(device->Synth);
break;
case AL_MIDI_STATE_SOFT:
device = context->Device;
value = (ALfloat)MidiSynth_getState(device->Synth);
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -262,8 +239,6 @@ done:
AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
{
ALCcontext *context;
ALCdevice *device;
MidiSynth *synth;
ALint value = 0;
context = GetContextRef();
@@ -291,17 +266,6 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
value = (ALint)context->DeferUpdates;
break;
case AL_SOUNDFONTS_SIZE_SOFT:
device = context->Device;
synth = device->Synth;
value = synth->NumSoundfonts;
break;
case AL_MIDI_STATE_SOFT:
device = context->Device;
value = MidiSynth_getState(device->Synth);
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -315,8 +279,6 @@ done:
AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
{
ALCcontext *context;
ALCdevice *device;
MidiSynth *synth;
ALint64SOFT value = 0;
context = GetContextRef();
@@ -344,24 +306,6 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
value = (ALint64SOFT)context->DeferUpdates;
break;
case AL_MIDI_CLOCK_SOFT:
device = context->Device;
ALCdevice_Lock(device);
value = MidiSynth_getTime(device->Synth);
ALCdevice_Unlock(device);
break;
case AL_SOUNDFONTS_SIZE_SOFT:
device = context->Device;
synth = device->Synth;
value = (ALint64SOFT)synth->NumSoundfonts;
break;
case AL_MIDI_STATE_SOFT:
device = context->Device;
value = (ALint64SOFT)MidiSynth_getState(device->Synth);
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -418,8 +362,6 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_MIDI_GAIN_SOFT:
case AL_MIDI_STATE_SOFT:
values[0] = alGetDouble(pname);
return;
}
@@ -453,8 +395,6 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_MIDI_GAIN_SOFT:
case AL_MIDI_STATE_SOFT:
values[0] = alGetFloat(pname);
return;
}
@@ -478,9 +418,6 @@ done:
AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
{
ALCcontext *context;
ALCdevice *device;
MidiSynth *synth;
ALsizei i;
if(values)
{
@@ -491,8 +428,6 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_SOUNDFONTS_SIZE_SOFT:
case AL_MIDI_STATE_SOFT:
values[0] = alGetInteger(pname);
return;
}
@@ -503,18 +438,6 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
switch(pname)
{
case AL_SOUNDFONTS_SOFT:
device = context->Device;
synth = device->Synth;
if(synth->NumSoundfonts > 0)
{
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < synth->NumSoundfonts;i++)
values[i] = synth->Soundfonts[i]->id;
}
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -526,9 +449,6 @@ done:
AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
{
ALCcontext *context;
ALCdevice *device;
MidiSynth *synth;
ALsizei i;
if(values)
{
@@ -539,9 +459,6 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
case AL_MIDI_CLOCK_SOFT:
case AL_SOUNDFONTS_SIZE_SOFT:
case AL_MIDI_STATE_SOFT:
values[0] = alGetInteger64SOFT(pname);
return;
}
@@ -552,18 +469,6 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
switch(pname)
{
case AL_SOUNDFONTS_SOFT:
device = context->Device;
synth = device->Synth;
if(synth->NumSoundfonts > 0)
{
if(!(values))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < synth->NumSoundfonts;i++)
values[i] = (ALint64SOFT)synth->Soundfonts[i]->id;
}
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -712,54 +617,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
context = GetContextRef();
if(!context) return;
if(!context->DeferUpdates)
{
ALboolean UpdateSources;
ALactivesource **src, **src_end;
ALeffectslot **slot, **slot_end;
FPUCtl oldMode;
SetMixerFPUMode(&oldMode);
LockContext(context);
context->DeferUpdates = AL_TRUE;
/* Make sure all pending updates are performed */
UpdateSources = ATOMIC_EXCHANGE(ALenum, &context->UpdateSources, AL_FALSE);
src = context->ActiveSources;
src_end = src + context->ActiveSourceCount;
while(src != src_end)
{
ALsource *source = (*src)->Source;
if(source->state != AL_PLAYING && source->state != AL_PAUSED)
{
ALactivesource *temp = *(--src_end);
*src_end = *src;
*src = temp;
--(context->ActiveSourceCount);
continue;
}
if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || UpdateSources)
(*src)->Update(*src, context);
src++;
}
slot = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
slot_end = VECTOR_ITER_END(context->ActiveAuxSlots);
while(slot != slot_end)
{
if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
V((*slot)->EffectState,update)(context->Device, *slot);
slot++;
}
UnlockContext(context);
RestoreFPUMode(&oldMode);
}
ALCcontext_DeferUpdates(context);
ALCcontext_DecRef(context);
}
@@ -771,32 +629,7 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
context = GetContextRef();
if(!context) return;
if(ExchangeInt(&context->DeferUpdates, AL_FALSE))
{
ALsizei pos;
LockContext(context);
LockUIntMapRead(&context->SourceMap);
for(pos = 0;pos < context->SourceMap.size;pos++)
{
ALsource *Source = context->SourceMap.array[pos].value;
ALenum new_state;
if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
Source->Offset >= 0.0)
{
ReadLock(&Source->queue_lock);
ApplyOffset(Source);
ReadUnlock(&Source->queue_lock);
}
new_state = ExchangeInt(&Source->new_state, AL_NONE);
if(new_state)
SetSourceState(Source, context, new_state);
}
UnlockUIntMapRead(&context->SourceMap);
UnlockContext(context);
}
ALCcontext_ProcessUpdates(context);
ALCcontext_DecRef(context);
}
+28 -14
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -26,33 +26,33 @@
#include "alThunk.h"
static ALenum *ThunkArray;
static ALuint ThunkArraySize;
static RWLock ThunkLock;
static ATOMIC(ALenum) *ThunkArray;
static ALuint ThunkArraySize;
static RWLock ThunkLock;
void ThunkInit(void)
{
RWLockInit(&ThunkLock);
ThunkArraySize = 1;
ThunkArray = calloc(1, ThunkArraySize * sizeof(*ThunkArray));
ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray));
}
void ThunkExit(void)
{
free(ThunkArray);
al_free(ThunkArray);
ThunkArray = NULL;
ThunkArraySize = 0;
}
ALenum NewThunkEntry(ALuint *index)
{
ALenum *NewList;
void *NewList;
ALuint i;
ReadLock(&ThunkLock);
for(i = 0;i < ThunkArraySize;i++)
{
if(ExchangeInt(&ThunkArray[i], AL_TRUE) == AL_FALSE)
if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
{
ReadUnlock(&ThunkLock);
*index = i+1;
@@ -62,18 +62,32 @@ ALenum NewThunkEntry(ALuint *index)
ReadUnlock(&ThunkLock);
WriteLock(&ThunkLock);
NewList = realloc(ThunkArray, ThunkArraySize*2 * sizeof(*ThunkArray));
/* Double-check that there's still no free entries, in case another
* invocation just came through and increased the size of the array.
*/
for(;i < ThunkArraySize;i++)
{
if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
{
WriteUnlock(&ThunkLock);
*index = i+1;
return AL_NO_ERROR;
}
}
NewList = al_calloc(16, ThunkArraySize*2 * sizeof(*ThunkArray));
if(!NewList)
{
WriteUnlock(&ThunkLock);
ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2);
return AL_OUT_OF_MEMORY;
}
memset(&NewList[ThunkArraySize], 0, ThunkArraySize*sizeof(*ThunkArray));
ThunkArraySize *= 2;
memcpy(NewList, ThunkArray, ThunkArraySize*sizeof(*ThunkArray));
al_free(ThunkArray);
ThunkArray = NewList;
ThunkArraySize *= 2;
ThunkArray[i] = AL_TRUE;
ATOMIC_STORE(&ThunkArray[i], AL_TRUE);
WriteUnlock(&ThunkLock);
*index = i+1;
@@ -84,6 +98,6 @@ void FreeThunkEntry(ALuint index)
{
ReadLock(&ThunkLock);
if(index > 0 && index <= ThunkArraySize)
ExchangeInt(&ThunkArray[index-1], AL_FALSE);
ATOMIC_STORE(&ThunkArray[index-1], AL_FALSE);
ReadUnlock(&ThunkLock);
}
+6 -4
View File
@@ -45,9 +45,11 @@ Special thanks go to:
Creative Labs for the original source code this is based off of.
Christopher Fitzgerald for the current reverb effect implementation, and
helping with the low-pass filter.
helping with the low-pass and HRTF filters.
Christian Borss for the 3D panning code the current implementation is heavilly
based on.
Christian Borss for the 3D panning code previous versions used as a base.
Ben Davis for the idea behind the current click-removal code.
Ben Davis for the idea behind a previous version of the click-removal code.
Richard Furse for helping with my understanding of Ambisonics that is used by
the various parts of the library.
+12 -5
View File
@@ -1,7 +1,6 @@
# Cross-compiling requires CMake 2.6 or newer. To use it from build/, call it
# like this:
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-pc-mingw32
# Where 'i686-pc-mingw32' is the host prefix for your cross-compiler. If you
# Cross-compiling requires CMake 2.6 or newer. Example:
# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-w64-mingw32
# Where 'i686-w64-mingw32' is the host prefix for your cross-compiler. If you
# already have a toolchain file setup, you may use that instead of this file.
# the name of the target operating system
@@ -10,12 +9,13 @@ SET(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER "${HOST}-gcc")
SET(CMAKE_CXX_COMPILER "${HOST}-g++")
SET(CMAKE_RC_COMPILER "${HOST}-windres")
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH "/usr/${HOST}")
# here is where stuff gets installed to
SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}/usr" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
@@ -28,3 +28,10 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# .pc files (as there seems to be no way to force using ${HOST}-pkg-config)
set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
set(ENV{PKG_CONFIG_PATH} "")
# Qt4 tools
SET(QT_QMAKE_EXECUTABLE ${HOST}-qmake)
SET(QT_MOC_EXECUTABLE ${HOST}-moc)
SET(QT_RCC_EXECUTABLE ${HOST}-rcc)
SET(QT_UIC_EXECUTABLE ${HOST}-uic)
SET(QT_LRELEASE_EXECUTABLE ${HOST}-lrelease)
+121 -123
View File
@@ -8,12 +8,18 @@
# specifying "$HOME/file.ext" would typically result in something like
# "/home/user/file.ext". To specify an actual "$" character, use "$$".
#
# Device-specific values may be specified by including the device name in the
# block name, with "general" replaced by the device name. That is, general
# options for the device "Name of Device" would be in the [Name of Device]
# block, while ALSA options would be in the [alsa/Name of Device] block.
# Options marked as "(global)" are not influenced by the device.
#
# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
# specific override settings in $HOME/.alsoftrc.
# For Windows, these settings should go into $AppData\alsoft.ini
#
# Option and block names are case-insenstive. The supplied values are only
# hints and may not be honored (though generally it'll try to get as close as
# Option and block names are case-senstive. The supplied values are only hints
# and may not be honored (though generally it'll try to get as close as
# possible). Note: options that are left unset may default to app- or system-
# specified values. These are the current available settings:
@@ -22,18 +28,27 @@
##
[general]
## disable-cpu-exts:
## disable-cpu-exts: (global)
# Disables use of specialized methods that use specific CPU intrinsics.
# Certain methods may utilize CPU extensions for improved performance, and
# this option is useful for preventing some or all of those methods from being
# used. The available extensions are: sse, sse2, sse4.1, and neon. Specifying
# 'all' disables use of all such specialized methods.
# used. The available extensions are: sse, sse2, sse3, sse4.1, and neon.
# Specifying 'all' disables use of all such specialized methods.
#disable-cpu-exts =
## drivers: (global)
# Sets the backend driver list order, comma-seperated. Unknown backends and
# duplicated names are ignored. Unlisted backends won't be considered for use
# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before
# other backends, while 'oss' will try OSS only). Backends prepended with -
# won't be considered for use (e.g. '-oss,' will try all available backends
# except OSS). An empty list means to try all backends.
#drivers =
## channels:
# Sets the output channel configuration. If left unspecified, one will try to
# be detected from the system, and defaulting to stereo. The available values
# are: mono, stereo, quad, surround51, surround61, surround71
# are: mono, stereo, quad, surround51, surround51rear, surround61, surround71
#channels =
## sample-type:
@@ -48,14 +63,40 @@
# float32 - 32-bit float
#sample-type = float32
## hrtf:
# Enables HRTF filters. These filters provide for better sound spatialization
# while using headphones. The default filter will only work when output is
# 44100hz stereo. While HRTF is active, the cf_level option is disabled.
# Default is disabled since stereo speaker output quality may suffer.
#hrtf = false
## frequency:
# Sets the output frequency. If left unspecified it will try to detect a
# default from the system, otherwise it will default to 44100.
#frequency =
## hrtf_tables
## period_size:
# Sets the update period size, in frames. This is the number of frames needed
# for each mixing update. Acceptable values range between 64 and 8192.
#period_size = 1024
## periods:
# Sets the number of update periods. Higher values create a larger mix ahead,
# which helps protect against skips when the CPU is under load, but increases
# the delay between a sound getting mixed and being heard. Acceptable values
# range between 2 and 16.
#periods = 4
## stereo-mode:
# Specifies if stereo output is treated as being headphones or speakers. With
# headphones, HRTF or crossfeed filters may be used for better audio quality.
# Valid settings are auto, speakers, and headphones.
#stereo-mode = auto
## hrtf:
# Controls HRTF processing. These filters provide better spatialization of
# sounds while using headphones, but do require a bit more CPU power. The
# default filters will only work with 44100hz or 48000hz stereo output. While
# HRTF is used, the cf_level option is ignored. Setting this to auto (default)
# will allow HRTF to be used when headphones are detected or the app requests
# it, while setting true or false will forcefully enable or disable HRTF
# respectively.
#hrtf = auto
## hrtf_tables:
# Specifies a comma-separated list of files containing HRTF data sets. The
# format of the files are described in hrtf.txt. The filenames may contain
# these markers, which will be replaced as needed:
@@ -84,28 +125,18 @@
# stereo modes.
#cf_level = 0
## wide-stereo:
# Specifies that stereo sources are given a width of about 120 degrees on each
# channel, centering on -90 (left) and +90 (right), as opposed to being points
# placed at -30 (left) and +30 (right). This can be useful for surround-sound
# to give stereo sources a more encompassing sound. Note that the sound's
# overall volume will be slightly reduced to account for the extra output.
#wide-stereo = false
## frequency:
# Sets the output frequency. If left unspecified it will try to detect a
# default from the system, otherwise it will default to 44100.
#frequency =
## resampler:
## resampler: (global)
# Selects the resampler used when mixing sources. Valid values are:
# point - nearest sample, no interpolation
# linear - extrapolates samples using a linear slope between samples
# cubic - extrapolates samples using a Catmull-Rom spline
# sinc4 - extrapolates samples using a 4-point Sinc filter
# sinc8 - extrapolates samples using an 8-point Sinc filter
# bsinc - extrapolates samples using a band-limited Sinc filter (varying
# between 12 and 24 points, with anti-aliasing)
# Specifying other values will result in using the default (linear).
#resampler = linear
## rt-prio:
## rt-prio: (global)
# Sets real-time priority for the mixing thread. Not all drivers may use this
# (eg. PortAudio) as they already control the priority of the mixing thread.
# 0 and negative values will disable it. Note that this may constitute a
@@ -114,39 +145,11 @@
# disabled.
#rt-prio = 0
## period_size:
# Sets the update period size, in frames. This is the number of frames needed
# for each mixing update. Acceptable values range between 64 and 8192.
#period_size = 1024
## periods:
# Sets the number of update periods. Higher values create a larger mix ahead,
# which helps protect against skips when the CPU is under load, but increases
# the delay between a sound getting mixed and being heard. Acceptable values
# range between 2 and 16.
#periods = 4
## sources:
# Sets the maximum number of allocatable sources. Lower values may help for
# systems with apps that try to play more sounds than the CPU can handle.
#sources = 256
## drivers:
# Sets the backend driver list order, comma-seperated. Unknown backends and
# duplicated names are ignored. Unlisted backends won't be considered for use
# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before
# other backends, while 'oss' will try OSS only). Backends prepended with -
# won't be considered for use (e.g. '-oss,' will try all available backends
# except OSS). An empty list means to try all backends.
#drivers =
## excludefx:
# Sets which effects to exclude, preventing apps from using them. This can
# help for apps that try to use effects which are too CPU intensive for the
# system to handle. Available effects are: eaxreverb,reverb,autowah,chorus,
# compressor,distortion,echo,equalizer,flanger,modulator,dedicated
#excludefx =
## slots:
# Sets the maximum number of Auxiliary Effect Slots an app can create. A slot
# can use a non-negligible amount of CPU time if an effect is set on it even
@@ -160,26 +163,14 @@
# possible is 4.
#sends =
## layout:
# Sets the virtual speaker layout. Values are specified in degrees, where 0 is
# straight in front, negative goes left, and positive goes right. Unspecified
# speakers will remain at their default positions (which are dependant on the
# output format). Available speakers are back-left(bl), side-left(sl), front-
# left(fl), front-center(fc), front-right(fr), side-right(sr), back-right(br),
# and back-center(bc).
#layout =
## excludefx: (global)
# Sets which effects to exclude, preventing apps from using them. This can
# help for apps that try to use effects which are too CPU intensive for the
# system to handle. Available effects are: eaxreverb,reverb,chorus,compressor,
# distortion,echo,equalizer,flanger,modulator,dedicated
#excludefx =
## layout_*:
# Channel-specific layouts may be specified to override the layout option. The
# same speakers as the layout option are available, and the default settings
# are shown below.
#layout_stereo = fl=-90, fr=90
#layout_quad = fl=-45, fr=45, bl=-135, br=135
#layout_surround51 = fl=-30, fr=30, fc=0, bl=-110, br=110
#layout_surround61 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bc=180
#layout_surround71 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bl=-150, br=150
## default-reverb:
## default-reverb: (global)
# A reverb preset that applies by default to all sources on send 0
# (applications that set their own slots on send 0 will override this).
# Available presets are: None, Generic, PaddedCell, Room, Bathroom,
@@ -188,54 +179,31 @@
# Quarry, Plain, ParkingLot, SewerPipe, Underwater, Drugged, Dizzy, Psychotic.
#default-reverb =
## trap-alc-error:
## trap-alc-error: (global)
# Generates a SIGTRAP signal when an ALC device error is generated, on systems
# that support it. This helps when debugging, while trying to find the cause
# of a device error. On Windows, a breakpoint exception is generated.
#trap-alc-error = false
## trap-al-error:
## trap-al-error: (global)
# Generates a SIGTRAP signal when an AL context error is generated, on systems
# that support it. This helps when debugging, while trying to find the cause
# of a context error. On Windows, a breakpoint exception is generated.
#trap-al-error = false
##
## MIDI stuff (EXPERIMENTAL)
##
[midi]
## soundfont:
# A default soundfont (sf2 format). Used when an app requests the system
# default. The listed file is relative to system-dependant data directories.
# On Windows this is:
# $AppData\openal\soundfonts
# And on other systems, it's (in order):
# $XDG_DATA_HOME/openal/soundfonts
# $XDG_DATA_DIRS/openal/soundfonts
# An absolute path may also be specified, if the given file is elsewhere.
#soundfont =
## volume:
# Additional attenuation applied to MIDI output, expressed in decibels. This
# is used to help keep the mix from clipping, and so must be 0 or less. The
# value is logarithmic, so -6 will be about half amplitude, and -12 about
# 1/4th. The default is roughly -13.9794 (0.2, or 1/5th).
#volume =
##
## Reverb effect stuff (includes EAX reverb)
##
[reverb]
## boost:
## boost: (global)
# A global amplification for reverb output, expressed in decibels. The value
# is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will be a
# scale of 4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
# value of 0 means no change.
#boost = 0
## emulate-eax:
## emulate-eax: (global)
# Allows the standard reverb effect to be used in place of EAX reverb. EAX
# reverb processing is a bit more CPU intensive than standard, so this option
# allows a simpler effect to be used at the loss of some quality.
@@ -246,52 +214,59 @@
##
[pulse]
## spawn-server:
## spawn-server: (global)
# Attempts to autospawn a PulseAudio server whenever needed (initializing the
# backend, enumerating devices, etc). Setting autospawn to false in Pulse's
# client.conf will still prevent autospawning even if this is set to true.
#spawn-server = true
## allow-moves:
## allow-moves: (global)
# Allows PulseAudio to move active streams to different devices. Note that the
# device specifier (seen by applications) will not be updated when this
# occurs, and neither will the AL device configuration (sample rate, format,
# etc).
#allow-moves = false
## fix-rate:
# Specifies whether to match the playback stream's sample rate to the device's
# sample rate. Enabling this forces OpenAL Soft to mix sources and effects
# directly to the actual output rate, avoiding a second resample pass by the
# PulseAudio server.
#fix-rate = false
##
## ALSA backend stuff
##
[alsa]
## device:
## device: (global)
# Sets the device name for the default playback device.
#device = default
## device-prefix:
## device-prefix: (global)
# Sets the prefix used by the discovered (non-default) playback devices. This
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
# device index for the requested device name.
#device-prefix = plughw:
## device-prefix-*:
## device-prefix-*: (global)
# Card- and device-specific prefixes may be used to override the device-prefix
# option. The option may specify the card id (eg, device-prefix-NVidia), or
# the card id and device index (eg, device-prefix-NVidia-0). The card id is
# case-sensitive.
#device-prefix- =
## capture:
## capture: (global)
# Sets the device name for the default capture device.
#capture = default
## capture-prefix:
## capture-prefix: (global)
# Sets the prefix used by the discovered (non-default) capture devices. This
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
# device number for the requested device name.
#capture-prefix = plughw:
## capture-prefix-*:
## capture-prefix-*: (global)
# Card- and device-specific prefixes may be used to override the
# capture-prefix option. The option may specify the card id (eg,
# capture-prefix-NVidia), or the card id and device index (eg,
@@ -305,16 +280,23 @@
# and anything else will force mmap off.
#mmap = true
## allow-resampler:
# Specifies whether to allow ALSA's built-in resampler. Enabling this will
# allow the playback device to be set to a different sample rate than the
# actual output, causing ALSA to apply its own resampling pass after OpenAL
# Soft resamples and mixes the sources and effects for output.
#allow-resampler = false
##
## OSS backend stuff
##
[oss]
## device:
## device: (global)
# Sets the device name for OSS output.
#device = /dev/dsp
## capture:
## capture: (global)
# Sets the device name for OSS capture.
#capture = /dev/dsp
@@ -323,7 +305,7 @@
##
[solaris]
## device:
## device: (global)
# Sets the device name for Solaris output.
#device = /dev/audio
@@ -332,13 +314,24 @@
##
[qsa]
## device:
# Sets the device name for the default playback device.
#device = default
##
## JACK backend stuff
##
[jack]
## capture:
# Sets the device name for the default capture device.
#capture = default
## spawn-server: (global)
# Attempts to autospawn a JACK server whenever needed (initializing the
# backend, opening devices, etc).
#spawn-server = false
## buffer-size:
# Sets the update buffer size, in samples, that the backend will keep buffered
# to handle the server's real-time processing requests. This value must be a
# power of 2, or else it will be rounded up to the next power of 2. If it is
# less than JACK's buffer update size, it will be clamped. This option may
# be useful in case the server's update size is too small and doesn't give the
# mixer time to keep enough audio available for the processing requests.
#buffer-size = 0
##
## MMDevApi backend stuff
@@ -360,12 +353,12 @@
##
[port]
## device:
## device: (global)
# Sets the device index for output. Negative values will use the default as
# given by PortAudio itself.
#device = -1
## capture:
## capture: (global)
# Sets the device index for capture. Negative values will use the default as
# given by PortAudio itself.
#capture = -1
@@ -375,8 +368,13 @@
##
[wave]
## file:
## file: (global)
# Sets the filename of the wave file to write to. An empty name prevents the
# backend from opening, even when explicitly requested.
# THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION!
#file =
## bformat: (global)
# Creates AMB format files using first-order ambisonics instead of a standard
# single- or multi-channel .wav file.
#bformat = false
@@ -17,12 +17,12 @@ MACRO(CHECK_FILE_OFFSET_BITS)
IF(NOT DEFINED _FILE_OFFSET_BITS)
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files")
TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
IF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
@@ -58,12 +58,12 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE)
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\nvoid cmakeRequireSymbol(int dummy,...){(void)dummy;}\nint main()\n{\n cmakeRequireSymbol(0,&${SYMBOL});\n return 0;\n}\n")
CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
"${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY)
"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY)
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY}")
TRY_COMPILE(${VARIABLE}
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
CMAKE_FLAGS
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS}
@@ -74,18 +74,18 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE)
IF(${VARIABLE})
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - found")
SET(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}")
FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determining if the ${SYMBOL} "
"exist in ${LIBRARY} passed with the following output:\n"
"${OUTPUT}\nFile ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
"${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
ELSE(${VARIABLE})
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - not found.")
SET(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}")
FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if the ${SYMBOL} "
"exist in ${LIBRARY} failed with the following output:\n"
"${OUTPUT}\nFile ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
"${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
ENDIF(${VARIABLE})
ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")
+4 -2
View File
@@ -9,14 +9,16 @@
#
find_path(DSOUND_INCLUDE_DIR
PATHS "${DXSDK_DIR}/include"
NAMES dsound.h
PATHS "${DXSDK_DIR}"
PATH_SUFFIXES include
DOC "The DirectSound include directory"
)
find_library(DSOUND_LIBRARY
PATHS "${DXSDK_DIR}/lib"
NAMES dsound
PATHS "${DXSDK_DIR}"
PATH_SUFFIXES lib lib/x86 lib/x64
DOC "The DirectSound library"
)
+221 -172
View File
@@ -146,197 +146,152 @@ if(SDL2_FOUND OR SDL_FOUND)
# The ;-framework Cocoa seems to be confusing CMake once the OS X
# framework support was added. I was told that breaking up the list
# would fix the problem.
set(TMP_TRY_LIBS)
set(TMP_LIBS "")
if(SDL2_FOUND)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY})
foreach(lib ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY})
set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"")
set(TMP_LIBS "${TMP_LIBS} \"${lib}\"")
endforeach()
set(TMP_INCLUDE_DIRS ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
else()
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"")
set(TMP_LIBS "${TMP_LIBS} \"${lib}\"")
endforeach()
set(TMP_INCLUDE_DIRS ${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
endif()
# message("TMP_TRY_LIBS ${TMP_TRY_LIBS}")
# Keep trying to build a temp project until we find all missing libs.
set(TRY_AGAIN TRUE)
WHILE(TRY_AGAIN)
set(TRY_AGAIN FALSE)
# message("TMP_TRY_LIBS ${TMP_TRY_LIBS}")
# Write the CMakeLists.txt and test project
# Weird, this is still sketchy. If I don't quote the variables
# in the TARGET_LINK_LIBRARIES, I seem to loose everything
# in the SDL2_LIBRARY string after the "-framework".
# But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
"cmake_minimum_required(VERSION 2.8)
project(DetermineSoundLibs C)
include_directories(${TMP_INCLUDE_DIRS})
add_executable(DetermineSoundLibs DetermineSoundLibs.c)
target_link_libraries(DetermineSoundLibs ${TMP_TRY_LIBS})"
)
unset(TMP_INCLUDE_DIRS)
unset(TMP_TRY_LIBS)
# Write the CMakeLists.txt and test project
# Weird, this is still sketchy. If I don't quote the variables
# in the TARGET_LINK_LIBRARIES, I seem to loose everything
# in the SDL2_LIBRARY string after the "-framework".
# But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
"cmake_minimum_required(VERSION 2.8)
project(DetermineSoundLibs C)
include_directories(${TMP_INCLUDE_DIRS})
add_executable(DetermineSoundLibs DetermineSoundLibs.c)
target_link_libraries(DetermineSoundLibs ${TMP_LIBS})"
)
try_compile(
MY_RESULT
${PROJECT_BINARY_DIR}/CMakeTmp
${PROJECT_BINARY_DIR}/CMakeTmp
DetermineSoundLibs
OUTPUT_VARIABLE MY_OUTPUT
)
# message("${MY_RESULT}")
# message(${MY_OUTPUT})
try_compile(
MY_RESULT
${PROJECT_BINARY_DIR}/CMakeTmp
${PROJECT_BINARY_DIR}/CMakeTmp
DetermineSoundLibs
OUTPUT_VARIABLE MY_OUTPUT
)
# message("${MY_RESULT}")
# message(${MY_OUTPUT})
if(NOT MY_RESULT)
# I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
# I think Timidity is also compiled in statically.
# I've never had to explcitly link against Quicktime, so I'll skip that for now.
if(NOT MY_RESULT)
# I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
# I think Timidity is also compiled in statically.
# I've never had to explcitly link against Quicktime, so I'll skip that for now.
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY})
# Find libmath
if("${MY_OUTPUT}" MATCHES "cos@@GLIBC")
find_library(MATH_LIBRARY NAMES m)
if(MATH_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MATH_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MATH_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif(MATH_LIBRARY)
endif("${MY_OUTPUT}" MATCHES "cos@@GLIBC")
# Find MikMod
if("${MY_OUTPUT}" MATCHES "MikMod_")
find_library(MIKMOD_LIBRARY
NAMES libmikmod-coreaudio mikmod
PATHS
ENV MIKMODDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(MIKMOD_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
endif(MIKMOD_LIBRARY)
endif("${MY_OUTPUT}" MATCHES "MikMod_")
# Find MikMod
if("${MY_OUTPUT}" MATCHES "MikMod_")
find_library(MIKMOD_LIBRARY
NAMES libmikmod-coreaudio mikmod
PATHS
ENV MIKMODDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(MIKMOD_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MIKMOD_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif(MIKMOD_LIBRARY)
endif("${MY_OUTPUT}" MATCHES "MikMod_")
# Find ModPlug
if("${MY_OUTPUT}" MATCHES "MODPLUG_")
find_library(MODPLUG_LIBRARY
NAMES modplug
PATHS
ENV MODPLUGDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(MODPLUG_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
endif()
endif()
# Find Ogg and Vorbis
if("${MY_OUTPUT}" MATCHES "ov_")
find_library(VORBIS_LIBRARY
NAMES vorbis Vorbis VORBIS
PATHS
ENV VORBISDIR
ENV OGGDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(VORBIS_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
endif()
find_library(OGG_LIBRARY
NAMES ogg Ogg OGG
PATHS
ENV OGGDIR
ENV VORBISDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(OGG_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
endif()
endif()
# Find SMPEG
if("${MY_OUTPUT}" MATCHES "SMPEG_")
find_library(SMPEG_LIBRARY
NAMES smpeg SMPEG Smpeg SMpeg
PATHS
ENV SMPEGDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(SMPEG_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
endif()
endif()
# Find FLAC
if("${MY_OUTPUT}" MATCHES "FLAC_")
find_library(FLAC_LIBRARY
NAMES flac FLAC
PATHS
ENV FLACDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(FLAC_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
endif()
endif()
# Hmmm...Speex seems to depend on Ogg. This might be a problem if
# the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
# in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
# above for here or if two ogg entries will screw up things.
if("${MY_OUTPUT}" MATCHES "speex_")
find_library(SPEEX_LIBRARY
NAMES speex SPEEX
PATHS
ENV SPEEXDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(SPEEX_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
# Find ModPlug
if("${MY_OUTPUT}" MATCHES "MODPLUG_")
find_library(MODPLUG_LIBRARY
NAMES modplug
PATHS
ENV MODPLUGDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(MODPLUG_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MODPLUG_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif()
endif()
# Find OGG (needed for Speex)
# We might have already found Ogg for Vorbis, so skip it if so.
if(NOT OGG_LIBRARY)
# Find Ogg and Vorbis
if("${MY_OUTPUT}" MATCHES "ov_")
find_library(VORBISFILE_LIBRARY
NAMES vorbisfile VorbisFile VORBISFILE
PATHS
ENV VORBISDIR
ENV OGGDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(VORBISFILE_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBISFILE_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${VORBISFILE_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif()
find_library(VORBIS_LIBRARY
NAMES vorbis Vorbis VORBIS
PATHS
ENV OGGDIR
ENV VORBISDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(VORBIS_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${VORBIS_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif()
find_library(OGG_LIBRARY
NAMES ogg Ogg OGG
PATHS
ENV OGGDIR
ENV VORBISDIR
ENV SPEEXDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
@@ -347,14 +302,108 @@ if(SDL2_FOUND OR SDL_FOUND)
)
if(OGG_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${OGG_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif()
endif()
# Find SMPEG
if("${MY_OUTPUT}" MATCHES "SMPEG_")
find_library(SMPEG_LIBRARY
NAMES smpeg SMPEG Smpeg SMpeg
PATHS
ENV SMPEGDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(SMPEG_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${SMPEG_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif()
endif()
# Find FLAC
if("${MY_OUTPUT}" MATCHES "FLAC_")
find_library(FLAC_LIBRARY
NAMES flac FLAC
PATHS
ENV FLACDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(FLAC_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${FLAC_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif()
endif()
# Hmmm...Speex seems to depend on Ogg. This might be a problem if
# the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
# in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
# above for here or if two ogg entries will screw up things.
if("${MY_OUTPUT}" MATCHES "speex_")
find_library(SPEEX_LIBRARY
NAMES speex SPEEX
PATHS
ENV SPEEXDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(SPEEX_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${SPEEX_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif()
# Find OGG (needed for Speex)
# We might have already found Ogg for Vorbis, so skip it if so.
if(NOT OGG_LIBRARY)
find_library(OGG_LIBRARY
NAMES ogg Ogg OGG
PATHS
ENV OGGDIR
ENV VORBISDIR
ENV SPEEXDIR
ENV SDLSOUNDDIR
ENV SDLDIR
/sw
/opt/local
/opt/csw
/opt
PATH_SUFFIXES lib
)
if(OGG_LIBRARY)
set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${OGG_LIBRARY}\"")
set(TRY_AGAIN TRUE)
endif()
endif()
endif()
endif()
ENDWHILE()
unset(TMP_INCLUDE_DIRS)
unset(TMP_LIBS)
set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries")
else()
set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARY} CACHE INTERNAL "SDL_sound and dependent libraries")
endif()
set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries")
endif()
endif()
+5 -5
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -733,11 +733,11 @@ int altimespec_get(struct timespec *ts, int base)
#endif
void al_nssleep(time_t sec, long nsec)
void al_nssleep(unsigned long nsec)
{
struct timespec ts, rem;
ts.tv_sec = sec;
ts.tv_nsec = nsec;
ts.tv_sec = nsec / 1000000000ul;
ts.tv_nsec = nsec % 1000000000ul;
while(althrd_sleep(&ts, &rem) == -1)
ts = rem;
+10 -12
View File
@@ -9,7 +9,7 @@
/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
* recent versions (at least 4.5.1) do recognize GCC's __restrict. */
#define restrict __restrict
#endif
#endif
/* Define any available alignment declaration */
#define ALIGN(x) ${ALIGN_DECL}
@@ -26,14 +26,12 @@
/* Define if we have SSE CPU extensions */
#cmakedefine HAVE_SSE
#cmakedefine HAVE_SSE2
#cmakedefine HAVE_SSE3
#cmakedefine HAVE_SSE4_1
/* Define if we have ARM Neon CPU extensions */
#cmakedefine HAVE_NEON
/* Define if we have FluidSynth support */
#cmakedefine HAVE_FLUIDSYNTH
/* Define if we have the ALSA backend */
#cmakedefine HAVE_ALSA
@@ -64,6 +62,9 @@
/* Define if we have the PulseAudio backend */
#cmakedefine HAVE_PULSEAUDIO
/* Define if we have the JACK backend */
#cmakedefine HAVE_JACK
/* Define if we have the CoreAudio backend */
#cmakedefine HAVE_COREAUDIO
@@ -79,6 +80,9 @@
/* Define if we have the lrintf function */
#cmakedefine HAVE_LRINTF
/* Define if we have the modff function */
#cmakedefine HAVE_MODFF
/* Define if we have the strtof function */
#cmakedefine HAVE_STRTOF
@@ -136,8 +140,8 @@
/* Define if we have malloc.h */
#cmakedefine HAVE_MALLOC_H
/* Define if we have ftw.h */
#cmakedefine HAVE_FTW_H
/* Define if we have dirent.h */
#cmakedefine HAVE_DIRENT_H
/* Define if we have io.h */
#cmakedefine HAVE_IO_H
@@ -181,12 +185,6 @@
/* Define if we have __control87_2() */
#cmakedefine HAVE___CONTROL87_2
/* Define if we have ftw() */
#cmakedefine HAVE_FTW
/* Define if we have _wfindfirst() */
#cmakedefine HAVE__WFINDFIRST
/* Define if we have pthread_setschedparam() */
#cmakedefine HAVE_PTHREAD_SETSCHEDPARAM
+10
View File
@@ -69,3 +69,13 @@ sound (i.e., sounds that are supposed to be behind you sound like they're in
front, and vice-versa). Setting this to "true" or "1" will negate the localized
Z coordinate to attempt to fix output for apps that have incorrect front/back
panning.
__ALSOFT_SUSPEND_CONTEXT
Due to the OpenAL spec not being very clear about them, behavior of the
alcSuspendContext and alcProcessContext methods has varied, and because of
that, previous versions of OpenAL Soft had them no-op. Creative's hardware
drivers and the Rapture3D driver, however, use these methods to batch changes,
which some applications make use of to protect against partial updates. In an
attempt to standardize on that behavior, OpenAL Soft has changed those methods
accordingly. Setting this to "ignore" restores the previous no-op behavior for
applications that interact poorly with the new behavior.
+64 -10
View File
@@ -548,6 +548,7 @@ static int audio_thread(void *userdata)
MovieState *movState = (MovieState*)userdata;
uint8_t *samples = NULL;
ALsizei buffer_len;
ALenum fmt;
alGenBuffers(AUDIO_BUFFER_QUEUE_SIZE, movState->audio.buffer);
alGenSources(1, &movState->audio.source);
@@ -557,56 +558,107 @@ static int audio_thread(void *userdata)
av_new_packet(&movState->audio.pkt, 0);
/* Find a suitable format for OpenAL. Currently does not handle surround
* sound (everything non-mono becomes stereo). */
/* Find a suitable format for OpenAL. */
movState->audio.format = AL_NONE;
if(movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8 ||
movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
{
movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_U8;
movState->audio.frame_size = 1;
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
alIsExtensionPresent("AL_EXT_MCFORMATS") &&
(fmt=alGetEnumValue("AL_FORMAT_71CHN8")) != AL_NONE && fmt != -1)
{
movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
movState->audio.frame_size *= 8;
movState->audio.format = fmt;
}
if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
alIsExtensionPresent("AL_EXT_MCFORMATS") &&
(fmt=alGetEnumValue("AL_FORMAT_51CHN8")) != AL_NONE && fmt != -1)
{
movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
movState->audio.frame_size *= 6;
movState->audio.format = fmt;
}
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
movState->audio.frame_size *= 1;
movState->audio.format = AL_FORMAT_MONO8;
}
else
if(movState->audio.format == AL_NONE)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
movState->audio.frame_size *= 2;
movState->audio.format = AL_FORMAT_STEREO8;
}
}
else if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT ||
movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) &&
alIsExtensionPresent("AL_EXT_FLOAT32"))
if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT ||
movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) &&
alIsExtensionPresent("AL_EXT_FLOAT32"))
{
movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_FLT;
movState->audio.frame_size = 4;
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
alIsExtensionPresent("AL_EXT_MCFORMATS") &&
(fmt=alGetEnumValue("AL_FORMAT_71CHN32")) != AL_NONE && fmt != -1)
{
movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
movState->audio.frame_size *= 8;
movState->audio.format = fmt;
}
if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
alIsExtensionPresent("AL_EXT_MCFORMATS") &&
(fmt=alGetEnumValue("AL_FORMAT_51CHN32")) != AL_NONE && fmt != -1)
{
movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
movState->audio.frame_size *= 6;
movState->audio.format = fmt;
}
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
movState->audio.frame_size *= 1;
movState->audio.format = AL_FORMAT_MONO_FLOAT32;
}
else
if(movState->audio.format == AL_NONE)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
movState->audio.frame_size *= 2;
movState->audio.format = AL_FORMAT_STEREO_FLOAT32;
}
}
else
if(movState->audio.format == AL_NONE)
{
movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_S16;
movState->audio.frame_size = 2;
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
alIsExtensionPresent("AL_EXT_MCFORMATS") &&
(fmt=alGetEnumValue("AL_FORMAT_71CHN16")) != AL_NONE && fmt != -1)
{
movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
movState->audio.frame_size *= 8;
movState->audio.format = fmt;
}
if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
alIsExtensionPresent("AL_EXT_MCFORMATS") &&
(fmt=alGetEnumValue("AL_FORMAT_51CHN16")) != AL_NONE && fmt != -1)
{
movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
movState->audio.frame_size *= 6;
movState->audio.format = fmt;
}
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
movState->audio.frame_size *= 1;
movState->audio.format = AL_FORMAT_MONO16;
}
else
if(movState->audio.format == AL_NONE)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
movState->audio.frame_size *= 2;
@@ -632,7 +684,9 @@ static int audio_thread(void *userdata)
movState->audio.dst_ch_layout,
movState->audio.dst_sample_fmt,
movState->audio.st->codec->sample_rate,
movState->audio.st->codec->channel_layout,
movState->audio.st->codec->channel_layout ?
movState->audio.st->codec->channel_layout :
av_get_default_channel_layout(movState->audio.st->codec->channels),
movState->audio.st->codec->sample_fmt,
movState->audio.st->codec->sample_rate,
0, NULL
+3 -3
View File
@@ -65,13 +65,13 @@ void SDLCALL RenderSDLSamples(void *userdata, Uint8 *stream, int len)
* buffer ID. */
static ALuint CreateSineWave(void)
{
ALshort data[44100];
ALshort data[44100*4];
ALuint buffer;
ALenum err;
ALuint i;
for(i = 0;i < 44100;i++)
data[i] = (ALshort)(sin(i * 441.0 / 44100.0 * 2.0*M_PI)*32767.0);
for(i = 0;i < 44100*4;i++)
data[i] = (ALshort)(sin(i/44100.0 * 1000.0 * 2.0*M_PI) * 32767.0);
/* Buffer the audio data into a new buffer object. */
buffer = 0;
+1 -1
View File
@@ -14,7 +14,7 @@ sides.
The default data set is based on the KEMAR HRTF data provided by MIT, which can
be found at <http://sound.media.mit.edu/resources/KEMAR.html>. It's only
available when using 44100hz playback.
available when using 44100hz or 48000hz playback.
Custom HRTF Data Sets
+40 -2
View File
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -393,6 +393,44 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device);
#endif
#endif
#ifndef AL_EXT_BFORMAT
#define AL_EXT_BFORMAT 1
#define AL_FORMAT_BFORMAT2D_8 0x20021
#define AL_FORMAT_BFORMAT2D_16 0x20022
#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023
#define AL_FORMAT_BFORMAT3D_8 0x20031
#define AL_FORMAT_BFORMAT3D_16 0x20032
#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033
#endif
#ifndef AL_EXT_MULAW_BFORMAT
#define AL_EXT_MULAW_BFORMAT 1
#define AL_FORMAT_BFORMAT2D_MULAW 0x10031
#define AL_FORMAT_BFORMAT3D_MULAW 0x10032
#endif
#ifndef ALC_SOFT_HRTF
#define ALC_SOFT_HRTF 1
#define ALC_HRTF_SOFT 0x1992
#define ALC_DONT_CARE_SOFT 0x0002
#define ALC_HRTF_STATUS_SOFT 0x1993
#define ALC_HRTF_DISABLED_SOFT 0x0000
#define ALC_HRTF_ENABLED_SOFT 0x0001
#define ALC_HRTF_DENIED_SOFT 0x0002
#define ALC_HRTF_REQUIRED_SOFT 0x0003
#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004
#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005
#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994
#define ALC_HRTF_SPECIFIER_SOFT 0x1995
#define ALC_HRTF_ID_SOFT 0x1996
typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index);
typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs);
#ifdef AL_ALEXT_PROTOTYPES
ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index);
ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs);
#endif
#endif
#ifdef __cplusplus
}
#endif
+1 -1
View File
@@ -345,7 +345,7 @@ typedef struct {
/* Driving Presets */
#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \
{ 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
{ 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \
{ 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
+4 -4
View File
@@ -1,16 +1,16 @@
#ifndef AL_ALIGN_H
#define AL_ALIGN_H
#ifdef HAVE_STDALIGN_H
#if defined(HAVE_STDALIGN_H) && defined(HAVE_C11_ALIGNAS)
#include <stdalign.h>
#endif
#ifndef alignas
#ifdef HAVE_C11_ALIGNAS
#define alignas _Alignas
#elif defined(IN_IDE_PARSER)
#if defined(IN_IDE_PARSER)
/* KDevelop has problems with our align macro, so just use nothing for parsing. */
#define alignas(x)
#elif defined(HAVE_C11_ALIGNAS)
#define alignas _Alignas
#else
/* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For
* maximum compatibility, only provide constant integer values to alignas. */
+99 -78
View File
@@ -8,74 +8,81 @@
extern "C" {
#endif
typedef void *volatile XchgPtr;
/* Atomics using C11 */
#ifdef HAVE_C11_ATOMIC
#include <stdatomic.h>
inline int ExchangeInt(volatile int *ptr, int newval)
{ return atomic_exchange(ptr, newval); }
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{ return atomic_exchange(ptr, newval); }
#define almemory_order memory_order
#define almemory_order_relaxed memory_order_relaxed
#define almemory_order_consume memory_order_consume
#define almemory_order_acquire memory_order_acquire
#define almemory_order_release memory_order_release
#define almemory_order_acq_rel memory_order_acq_rel
#define almemory_order_seq_cst memory_order_seq_cst
#define ATOMIC(T) T _Atomic
#define ATOMIC(T) struct { T _Atomic value; }
#define ATOMIC_INIT(_val, _newval) atomic_init((_val), (_newval))
#define ATOMIC_INIT_STATIC(_newval) ATOMIC_VAR_INIT(_newval)
#define ATOMIC_INIT(_val, _newval) atomic_init(&(_val)->value, (_newval))
#define ATOMIC_INIT_STATIC(_newval) {ATOMIC_VAR_INIT(_newval)}
#define PARAM2(f, a, b, ...) (f((a), (b)))
#define PARAM3(f, a, b, c, ...) (f((a), (b), (c)))
#define PARAM5(f, a, b, c, d, e, ...) (f((a), (b), (c), (d), (e)))
#define ATOMIC_LOAD(_val) atomic_load(&(_val)->value)
#define ATOMIC_STORE(_val, _newval) atomic_store(&(_val)->value, (_newval))
#define ATOMIC_LOAD(...) PARAM2(atomic_load_explicit, __VA_ARGS__, memory_order_seq_cst)
#define ATOMIC_STORE(...) PARAM3(atomic_store_explicit, __VA_ARGS__, memory_order_seq_cst)
#define ATOMIC_ADD(T, _val, _incr) atomic_fetch_add(&(_val)->value, (_incr))
#define ATOMIC_SUB(T, _val, _decr) atomic_fetch_sub(&(_val)->value, (_decr))
#define ATOMIC_ADD(T, ...) PARAM3(atomic_fetch_add_explicit, __VA_ARGS__, memory_order_seq_cst)
#define ATOMIC_SUB(T, ...) PARAM3(atomic_fetch_sub_explicit, __VA_ARGS__, memory_order_seq_cst)
#define ATOMIC_EXCHANGE(T, _val, _newval) atomic_exchange(&(_val)->value, (_newval))
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) \
atomic_compare_exchange_strong(&(_val)->value, (_oldval), (_newval))
#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, _val, _oldval, _newval) \
atomic_compare_exchange_weak(&(_val)->value, (_oldval), (_newval))
#define ATOMIC_EXCHANGE(T, ...) PARAM3(atomic_exchange_explicit, __VA_ARGS__, memory_order_seq_cst)
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, ...) \
PARAM5(atomic_compare_exchange_strong_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst)
#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...) \
PARAM5(atomic_compare_exchange_weak_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst)
/* Atomics using GCC intrinsics */
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
inline int ExchangeInt(volatile int *ptr, int newval)
{ return __sync_lock_test_and_set(ptr, newval); }
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{ return __sync_lock_test_and_set(ptr, newval); }
enum almemory_order {
almemory_order_relaxed,
almemory_order_consume,
almemory_order_acquire,
almemory_order_release,
almemory_order_acq_rel,
almemory_order_seq_cst
};
#define ATOMIC(T) struct { T volatile value; }
#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
#define ATOMIC_LOAD(_val) __extension__({ \
#define ATOMIC_LOAD(_val, ...) __extension__({ \
__typeof((_val)->value) _r = (_val)->value; \
__asm__ __volatile__("" ::: "memory"); \
_r; \
})
#define ATOMIC_STORE(_val, _newval) do { \
__asm__ __volatile__("" ::: "memory"); \
(_val)->value = (_newval); \
#define ATOMIC_STORE(_val, _newval, ...) do { \
__asm__ __volatile__("" ::: "memory"); \
(_val)->value = (_newval); \
} while(0)
#define ATOMIC_ADD(T, _val, _incr) __extension__({ \
#define ATOMIC_ADD(T, _val, _incr, ...) __extension__({ \
static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
__sync_fetch_and_add(&(_val)->value, (_incr)); \
})
#define ATOMIC_SUB(T, _val, _decr) __extension__({ \
#define ATOMIC_SUB(T, _val, _decr, ...) __extension__({ \
static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
__sync_fetch_and_sub(&(_val)->value, (_decr)); \
})
#define ATOMIC_EXCHANGE(T, _val, _newval) __extension__({ \
#define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \
static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
__sync_lock_test_and_set(&(_val)->value, (_newval)); \
})
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) __extension__({ \
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \
static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
T _o = *(_oldval); \
*(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \
@@ -112,41 +119,38 @@ inline void *ExchangePtr(XchgPtr *ptr, void *newval)
)
inline int ExchangeInt(volatile int *dest, int newval)
{ int ret; WRAP_XCHG("l", ret, dest, newval); return ret; }
#ifdef __i386__
inline void *ExchangePtr(XchgPtr *dest, void *newval)
{ void *ret; WRAP_XCHG("l", ret, dest, newval); return ret; }
#else
inline void *ExchangePtr(XchgPtr *dest, void *newval)
{ void *ret; WRAP_XCHG("q", ret, dest, newval); return ret; }
#endif
enum almemory_order {
almemory_order_relaxed,
almemory_order_consume,
almemory_order_acquire,
almemory_order_release,
almemory_order_acq_rel,
almemory_order_seq_cst
};
#define ATOMIC(T) struct { T volatile value; }
#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
#define ATOMIC_LOAD(_val) __extension__({ \
#define ATOMIC_LOAD(_val, ...) __extension__({ \
__typeof((_val)->value) _r = (_val)->value; \
__asm__ __volatile__("" ::: "memory"); \
_r; \
})
#define ATOMIC_STORE(_val, _newval) do { \
__asm__ __volatile__("" ::: "memory"); \
(_val)->value = (_newval); \
#define ATOMIC_STORE(_val, _newval, ...) do { \
__asm__ __volatile__("" ::: "memory"); \
(_val)->value = (_newval); \
} while(0)
#define ATOMIC_ADD(T, _val, _incr) __extension__({ \
#define ATOMIC_ADD(T, _val, _incr, ...) __extension__({ \
static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \
static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
T _r; \
WRAP_ADD(_r, &(_val)->value, (T)(_incr)); \
_r; \
})
#define ATOMIC_SUB(T, _val, _decr) __extension__({ \
#define ATOMIC_SUB(T, _val, _decr, ...) __extension__({ \
static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \
static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
T _r; \
@@ -154,7 +158,7 @@ inline void *ExchangePtr(XchgPtr *dest, void *newval)
_r; \
})
#define ATOMIC_EXCHANGE(T, _val, _newval) __extension__({ \
#define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \
static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \
static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
T _r; \
@@ -162,7 +166,7 @@ inline void *ExchangePtr(XchgPtr *dest, void *newval)
else if(sizeof(T) == 8) WRAP_XCHG("q", _r, &(_val)->value, (T)(_newval)); \
_r; \
})
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) __extension__({ \
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \
static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \
static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
T _old = *(_oldval); \
@@ -222,42 +226,40 @@ inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG
#define WRAP_XCHG(T, _func, _ptr, _newval) ((T(*)(T volatile*,T))_func)((_ptr), (_newval))
#define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) ((bool(*)(T volatile*,T,T*))_func)((_ptr), (_newval), (_oldval))
inline int ExchangeInt(volatile int *ptr, int newval)
{ return WRAP_XCHG(int,AtomicSwap32,ptr,newval); }
#ifdef _WIN64
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{ return WRAP_XCHG(void*,AtomicSwap64,ptr,newval); }
#else
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{ return WRAP_XCHG(void*,AtomicSwap32,ptr,newval); }
#endif
enum almemory_order {
almemory_order_relaxed,
almemory_order_consume,
almemory_order_acquire,
almemory_order_release,
almemory_order_acq_rel,
almemory_order_seq_cst
};
#define ATOMIC(T) struct { T volatile value; }
#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
#define ATOMIC_LOAD(_val) ((_val)->value)
#define ATOMIC_STORE(_val, _newval) do { \
(_val)->value = (_newval); \
#define ATOMIC_LOAD(_val, ...) ((_val)->value)
#define ATOMIC_STORE(_val, _newval, ...) do { \
(_val)->value = (_newval); \
} while(0)
int _al_invalid_atomic_size(); /* not defined */
#define ATOMIC_ADD(T, _val, _incr) \
#define ATOMIC_ADD(T, _val, _incr, ...) \
((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicAdd32, &(_val)->value, (_incr)) : \
(T)_al_invalid_atomic_size())
#define ATOMIC_SUB(T, _val, _decr) \
#define ATOMIC_SUB(T, _val, _decr, ...) \
((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicSub32, &(_val)->value, (_decr)) : \
(T)_al_invalid_atomic_size())
#define ATOMIC_EXCHANGE(T, _val, _newval) \
#define ATOMIC_EXCHANGE(T, _val, _newval, ...) \
((sizeof(T)==4) ? WRAP_XCHG(T, AtomicSwap32, &(_val)->value, (_newval)) : \
(sizeof(T)==8) ? WRAP_XCHG(T, AtomicSwap64, &(_val)->value, (_newval)) : \
(T)_al_invalid_atomic_size())
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) \
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) \
((sizeof(T)==4) ? WRAP_CMPXCHG(T, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \
(sizeof(T)==8) ? WRAP_CMPXCHG(T, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \
(bool)_al_invalid_atomic_size())
@@ -273,26 +275,22 @@ int _al_invalid_atomic_size(); /* not defined */
#define ATOMIC_LOAD_UNSAFE(_val) (0)
#define ATOMIC_STORE_UNSAFE(_val, _newval) ((void)0)
#define ATOMIC_LOAD(_val) (0)
#define ATOMIC_STORE(_val, _newval) ((void)0)
#define ATOMIC_LOAD(_val, ...) (0)
#define ATOMIC_STORE(_val, _newval, ...) ((void)0)
#define ATOMIC_ADD(T, _val, _incr) (0)
#define ATOMIC_SUB(T, _val, _decr) (0)
#define ATOMIC_ADD(T, _val, _incr, ...) (0)
#define ATOMIC_SUB(T, _val, _decr, ...) (0)
#define ATOMIC_EXCHANGE(T, _val, _newval) (0)
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) (0)
#define ATOMIC_EXCHANGE(T, _val, _newval, ...) (0)
#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) (0)
#endif
/* If no weak cmpxchg is provided (not all systems will have one), substitute a
* strong cmpxchg. */
#ifndef ATOMIC_COMPARE_EXCHANGE_WEAK
#define ATOMIC_COMPARE_EXCHANGE_WEAK(a, b, c, d) ATOMIC_COMPARE_EXCHANGE_STRONG(a, b, c, d)
#define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG
#endif
/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non-
* atomic variables. */
#define COMPARE_EXCHANGE(_val, _oldval, _newval) ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false))
typedef unsigned int uint;
typedef ATOMIC(uint) RefCount;
@@ -306,6 +304,29 @@ inline uint IncrementRef(RefCount *ptr)
inline uint DecrementRef(RefCount *ptr)
{ return ATOMIC_SUB(uint, ptr, 1)-1; }
/* NOTE: Not atomic! */
inline int ExchangeInt(volatile int *ptr, int newval)
{
int old = *ptr;
*ptr = newval;
return old;
}
typedef void *volatile XchgPtr;
/* NOTE: Not atomic! */
inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{
void *old = *ptr;
*ptr = newval;
return old;
}
/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non-
* atomic variables. */
#define COMPARE_EXCHANGE(_val, _oldval, _newval) ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false))
#ifdef __cplusplus
}
#endif
+4
View File
@@ -10,7 +10,11 @@
#else
#define CTASTR2(_pre,_post) _pre##_post
#define CTASTR(_pre,_post) CTASTR2(_pre,_post)
#if defined(__COUNTER__)
#define static_assert(_cond, _msg) typedef struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } CTASTR(static_assertion_,__COUNTER__)
#else
#define static_assert(_cond, _msg) struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); }
#endif
#endif
#endif
+1 -1
View File
@@ -234,7 +234,7 @@ void altss_delete(altss_t tss_id);
int altimespec_get(struct timespec *ts, int base);
void al_nssleep(time_t sec, long nsec);
void al_nssleep(unsigned long nsec);
#ifdef __cplusplus
}
@@ -1,3 +1,6 @@
#include "config.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
@@ -10,26 +13,92 @@ static const struct {
char backend_name[16];
char menu_string[32];
} backendMenuList[] = {
#ifdef Q_OS_WIN32
{ "mmdevapi", "Add MMDevAPI" },
{ "dsound", "Add DirectSound" },
{ "winmm", "Add Windows Multimedia" },
#ifdef HAVE_JACK
{ "jack", "Add JACK" },
#endif
#ifdef Q_OS_MAC
#ifdef HAVE_PULSEAUDIO
{ "pulse", "Add PulseAudio" },
#endif
#ifdef HAVE_ALSA
{ "alsa", "Add ALSA" },
#endif
#ifdef HAVE_COREAUDIO
{ "core", "Add CoreAudio" },
#endif
{ "pulse", "Add PulseAudio" },
#ifdef Q_OS_UNIX
{ "alsa", "Add ALSA" },
#ifdef HAVE_OSS
{ "oss", "Add OSS" },
#endif
#ifdef HAVE_SOLARIS
{ "solaris", "Add Solaris" },
#endif
#ifdef HAVE_SNDIO
{ "sndio", "Add SndIO" },
#endif
#ifdef HAVE_QSA
{ "qsa", "Add QSA" },
#endif
#ifdef HAVE_MMDEVAPI
{ "mmdevapi", "Add MMDevAPI" },
#endif
#ifdef HAVE_DSOUND
{ "dsound", "Add DirectSound" },
#endif
#ifdef HAVE_WINMM
{ "winmm", "Add Windows Multimedia" },
#endif
#ifdef HAVE_PORTAUDIO
{ "port", "Add PortAudio" },
#endif
#ifdef HAVE_OPENSL
{ "opensl", "Add OpenSL" },
#endif
{ "null", "Add Null Output" },
#ifdef HAVE_WAVE
{ "wave", "Add Wave Writer" },
#endif
{ "", "" }
};
static const struct {
const char name[64];
const char value[16];
} speakerModeList[] = {
{ "Autodetect", "" },
{ "Mono", "mono" },
{ "Stereo", "stereo" },
{ "Quadrophonic", "quad" },
{ "5.1 Surround (Side)", "surround51" },
{ "5.1 Surround (Rear)", "surround51rear" },
{ "6.1 Surround", "surround61" },
{ "7.1 Surround", "surround71" },
{ "", "" }
}, sampleTypeList[] = {
{ "Autodetect", "" },
{ "8-bit int", "int8" },
{ "8-bit uint", "uint8" },
{ "16-bit int", "int16" },
{ "16-bit uint", "uint16" },
{ "32-bit int", "int32" },
{ "32-bit uint", "uint32" },
{ "32-bit float", "float32" },
{ "", "" }
}, resamplerList[] = {
{ "Default", "" },
{ "Point (low quality, very fast)", "point" },
{ "Linear (basic quality, fast)", "linear" },
{ "4-Point Sinc (good quality)", "sinc4" },
{ "8-Point Sinc (high quality, slow)", "sinc8" },
{ "Band-limited Sinc (very high quality, very slow)", "bsinc" },
{ "", "" }
}, stereoModeList[] = {
{ "Autodetect", "" },
{ "Speakers", "speakers" },
{ "Headphones", "headphones" },
{ "", "" }
};
@@ -104,11 +173,65 @@ MainWindow::MainWindow(QWidget *parent) :
mSourceCountValidator(NULL),
mEffectSlotValidator(NULL),
mSourceSendValidator(NULL),
mSampleRateValidator(NULL),
mReverbBoostValidator(NULL)
mSampleRateValidator(NULL)
{
ui->setupUi(this);
for(int i = 0;speakerModeList[i].name[0];i++)
ui->channelConfigCombo->addItem(speakerModeList[i].name);
ui->channelConfigCombo->adjustSize();
for(int i = 0;sampleTypeList[i].name[0];i++)
ui->sampleFormatCombo->addItem(sampleTypeList[i].name);
ui->sampleFormatCombo->adjustSize();
for(int i = 0;resamplerList[i].name[0];i++)
ui->resamplerComboBox->addItem(resamplerList[i].name);
ui->resamplerComboBox->adjustSize();
for(int i = 0;stereoModeList[i].name[0];i++)
ui->stereoModeCombo->addItem(stereoModeList[i].name);
ui->stereoModeCombo->adjustSize();
ui->hrtfStateComboBox->adjustSize();
#if !defined(HAVE_NEON) && !defined(HAVE_SSE)
ui->cpuExtDisabledLabel->move(ui->cpuExtDisabledLabel->x(), ui->cpuExtDisabledLabel->y() - 60);
#else
ui->cpuExtDisabledLabel->setVisible(false);
#endif
#ifndef HAVE_NEON
#ifndef HAVE_SSE4_1
#ifndef HAVE_SSE3
#ifndef HAVE_SSE2
#ifndef HAVE_SSE
ui->enableSSECheckBox->setVisible(false);
#endif /* !SSE */
ui->enableSSE2CheckBox->setVisible(false);
#endif /* !SSE2 */
ui->enableSSE3CheckBox->setVisible(false);
#endif /* !SSE3 */
ui->enableSSE41CheckBox->setVisible(false);
#endif /* !SSE4.1 */
ui->enableNeonCheckBox->setVisible(false);
#else /* !Neon */
#ifndef HAVE_SSE4_1
#ifndef HAVE_SSE3
#ifndef HAVE_SSE2
#ifndef HAVE_SSE
ui->enableNeonCheckBox->move(ui->enableNeonCheckBox->x(), ui->enableNeonCheckBox->y() - 30);
ui->enableSSECheckBox->setVisible(false);
#endif /* !SSE */
ui->enableSSE2CheckBox->setVisible(false);
#endif /* !SSE2 */
ui->enableSSE3CheckBox->setVisible(false);
#endif /* !SSE3 */
ui->enableSSE41CheckBox->setVisible(false);
#endif /* !SSE4.1 */
#endif
mPeriodSizeValidator = new QIntValidator(64, 8192, this);
ui->periodSizeEdit->setValidator(mPeriodSizeValidator);
mPeriodCountValidator = new QIntValidator(2, 16, this);
@@ -123,9 +246,6 @@ MainWindow::MainWindow(QWidget *parent) :
mSampleRateValidator = new QIntValidator(8000, 192000, this);
ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator);
mReverbBoostValidator = new QDoubleValidator(-12.0, +12.0, 1, this);
ui->reverbBoostEdit->setValidator(mReverbBoostValidator);
connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile()));
connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile()));
@@ -146,9 +266,6 @@ MainWindow::MainWindow(QWidget *parent) :
ui->disabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->disabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDisabledBackendMenu(QPoint)));
connect(ui->reverbBoostSlider, SIGNAL(valueChanged(int)), this, SLOT(updateReverbBoostEdit(int)));
connect(ui->reverbBoostEdit, SIGNAL(textEdited(QString)), this, SLOT(updateReverbBoostSlider(QString)));
loadConfig(getDefaultConfigName());
}
@@ -161,7 +278,6 @@ MainWindow::~MainWindow()
delete mEffectSlotValidator;
delete mSourceSendValidator;
delete mSampleRateValidator;
delete mReverbBoostValidator;
}
void MainWindow::loadConfigFromFile()
@@ -179,12 +295,19 @@ void MainWindow::loadConfig(const QString &fname)
ui->sampleFormatCombo->setCurrentIndex(0);
if(sampletype.isEmpty() == false)
{
for(int i = 1;i < ui->sampleFormatCombo->count();i++)
for(int i = 0;sampleTypeList[i].name[i];i++)
{
QString item = ui->sampleFormatCombo->itemText(i);
if(item.startsWith(sampletype))
if(sampletype == sampleTypeList[i].value)
{
ui->sampleFormatCombo->setCurrentIndex(i);
for(int j = 1;j < ui->sampleFormatCombo->count();j++)
{
QString item = ui->sampleFormatCombo->itemText(j);
if(item == sampleTypeList[i].name)
{
ui->sampleFormatCombo->setCurrentIndex(j);
break;
}
}
break;
}
}
@@ -194,12 +317,19 @@ void MainWindow::loadConfig(const QString &fname)
ui->channelConfigCombo->setCurrentIndex(0);
if(channelconfig.isEmpty() == false)
{
for(int i = 1;i < ui->channelConfigCombo->count();i++)
for(int i = 0;speakerModeList[i].name[i];i++)
{
QString item = ui->channelConfigCombo->itemText(i);
if(item.startsWith(channelconfig))
if(channelconfig == speakerModeList[i].value)
{
ui->channelConfigCombo->setCurrentIndex(i);
for(int j = 1;j < ui->channelConfigCombo->count();j++)
{
QString item = ui->channelConfigCombo->itemText(j);
if(item == speakerModeList[i].name)
{
ui->channelConfigCombo->setCurrentIndex(j);
break;
}
}
break;
}
}
@@ -222,18 +352,49 @@ void MainWindow::loadConfig(const QString &fname)
ui->srcSendLineEdit->insert(settings.value("sends").toString());
QString resampler = settings.value("resampler").toString().trimmed();
if(resampler.isEmpty())
ui->resamplerComboBox->setCurrentIndex(0);
else
ui->resamplerComboBox->setCurrentIndex(0);
if(resampler.isEmpty() == false)
{
for(int i = 1;i < ui->resamplerComboBox->count();i++)
/* The "cubic" resampler is no longer supported. It's been replaced by
* "sinc4". */
if(resampler == "cubic")
resampler = "sinc4";
for(int i = 0;resamplerList[i].name[i];i++)
{
QString item = ui->resamplerComboBox->itemText(i);
int end = item.indexOf(' ');
if(end < 0) end = item.size();
if(resampler.size() == end && resampler.compare(item.leftRef(end), Qt::CaseInsensitive) == 0)
if(resampler == resamplerList[i].value)
{
ui->resamplerComboBox->setCurrentIndex(i);
for(int j = 1;j < ui->resamplerComboBox->count();j++)
{
QString item = ui->resamplerComboBox->itemText(j);
if(item == resamplerList[i].name)
{
ui->resamplerComboBox->setCurrentIndex(j);
break;
}
}
break;
}
}
}
QString stereomode = settings.value("stereo-mode").toString().trimmed();
ui->stereoModeCombo->setCurrentIndex(0);
if(stereomode.isEmpty() == false)
{
for(int i = 0;stereoModeList[i].name[i];i++)
{
if(stereomode == stereoModeList[i].value)
{
for(int j = 1;j < ui->stereoModeCombo->count();j++)
{
QString item = ui->stereoModeCombo->itemText(j);
if(item == stereoModeList[i].name)
{
ui->stereoModeCombo->setCurrentIndex(j);
break;
}
}
break;
}
}
@@ -262,17 +423,18 @@ void MainWindow::loadConfig(const QString &fname)
disabledCpuExts.begin(), std::mem_fun_ref(&QString::trimmed));
ui->enableSSECheckBox->setChecked(!disabledCpuExts.contains("sse", Qt::CaseInsensitive));
ui->enableSSE2CheckBox->setChecked(!disabledCpuExts.contains("sse2", Qt::CaseInsensitive));
ui->enableSSE3CheckBox->setChecked(!disabledCpuExts.contains("sse3", Qt::CaseInsensitive));
ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive));
ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive));
if(settings.value("hrtf").toString() == QString())
ui->hrtfEnableButton->setChecked(true);
ui->hrtfStateComboBox->setCurrentIndex(0);
else
{
if(settings.value("hrtf", true).toBool())
ui->hrtfForceButton->setChecked(true);
ui->hrtfStateComboBox->setCurrentIndex(1);
else
ui->hrtfDisableButton->setChecked(true);
ui->hrtfStateComboBox->setCurrentIndex(2);
}
QStringList hrtf_tables = settings.value("hrtf_tables").toStringList();
@@ -323,8 +485,6 @@ void MainWindow::loadConfig(const QString &fname)
}
ui->emulateEaxCheckBox->setChecked(settings.value("reverb/emulate-eax", false).toBool());
ui->reverbBoostEdit->clear();
ui->reverbBoostEdit->insert(settings.value("reverb/boost").toString());
QStringList excludefx = settings.value("excludefx").toStringList();
if(excludefx.size() == 1)
@@ -371,15 +531,27 @@ void MainWindow::saveConfig(const QString &fname) const
}
QString str = ui->sampleFormatCombo->currentText();
str.truncate(str.indexOf('-'));
settings.setValue("sample-type", str.trimmed());
for(int i = 0;sampleTypeList[i].name[0];i++)
{
if(str == sampleTypeList[i].name)
{
settings.setValue("sample-type", sampleTypeList[i].value);
break;
}
}
str = ui->channelConfigCombo->currentText();
str.truncate(str.indexOf('-'));
settings.setValue("channels", str.trimmed());
for(int i = 0;speakerModeList[i].name[0];i++)
{
if(str == speakerModeList[i].name)
{
settings.setValue("channels", speakerModeList[i].value);
break;
}
}
uint rate = ui->sampleRateCombo->currentText().toUInt();
if(rate == 0)
if(!(rate > 0))
settings.setValue("frequency", QString());
else
settings.setValue("frequency", rate);
@@ -390,12 +562,24 @@ void MainWindow::saveConfig(const QString &fname) const
settings.setValue("sources", ui->srcCountLineEdit->text());
settings.setValue("slots", ui->effectSlotLineEdit->text());
if(ui->resamplerComboBox->currentIndex() == 0)
settings.setValue("resampler", QString());
else
str = ui->resamplerComboBox->currentText();
for(int i = 0;resamplerList[i].name[0];i++)
{
str = ui->resamplerComboBox->currentText();
settings.setValue("resampler", str.split(' ').first().toLower());
if(str == resamplerList[i].name)
{
settings.setValue("resampler", resamplerList[i].value);
break;
}
}
str = ui->stereoModeCombo->currentText();
for(int i = 0;stereoModeList[i].name[0];i++)
{
if(str == stereoModeList[i].name)
{
settings.setValue("stereo-mode", stereoModeList[i].value);
break;
}
}
QStringList strlist;
@@ -403,15 +587,17 @@ void MainWindow::saveConfig(const QString &fname) const
strlist.append("sse");
if(!ui->enableSSE2CheckBox->isChecked())
strlist.append("sse2");
if(!ui->enableSSE3CheckBox->isChecked())
strlist.append("sse3");
if(!ui->enableSSE41CheckBox->isChecked())
strlist.append("sse4.1");
if(!ui->enableNeonCheckBox->isChecked())
strlist.append("neon");
settings.setValue("disable-cpu-exts", strlist.join(QChar(',')));
if(ui->hrtfForceButton->isChecked())
if(ui->hrtfStateComboBox->currentIndex() == 1)
settings.setValue("hrtf", "true");
else if(ui->hrtfDisableButton->isChecked())
else if(ui->hrtfStateComboBox->currentIndex() == 2)
settings.setValue("hrtf", "false");
else
settings.setValue("hrtf", QString());
@@ -449,12 +635,6 @@ void MainWindow::saveConfig(const QString &fname) const
else
settings.setValue("reverb/emulate-eax", QString()/*"false"*/);
// TODO: Remove check when we can properly match global values.
if(ui->reverbBoostSlider->sliderPosition() == 0)
settings.setValue("reverb/boost", QString());
else
settings.setValue("reverb/boost", ui->reverbBoostEdit->text());
strlist.clear();
if(!ui->enableEaxReverbCheck->isChecked())
strlist.append("eaxreverb");
@@ -645,16 +825,3 @@ void MainWindow::showDisabledBackendMenu(QPoint pt)
ui->disabledBackendList->addItem(iter.value());
}
}
void MainWindow::updateReverbBoostEdit(int value)
{
ui->reverbBoostEdit->clear();
if(value != 0)
ui->reverbBoostEdit->insert(QString::number(value/10.0, 'f', 1));
}
void MainWindow::updateReverbBoostSlider(QString value)
{
int pos = int(value.toFloat()*10.0f);
ui->reverbBoostSlider->setSliderPosition(pos);
}
@@ -35,9 +35,6 @@ private slots:
void showEnabledBackendMenu(QPoint pt);
void showDisabledBackendMenu(QPoint pt);
void updateReverbBoostEdit(int size);
void updateReverbBoostSlider(QString value);
private:
Ui::MainWindow *ui;
@@ -47,7 +44,6 @@ private:
QValidator *mEffectSlotValidator;
QValidator *mSourceSendValidator;
QValidator *mSampleRateValidator;
QValidator *mReverbBoostValidator;
void loadConfig(const QString &fname);
void saveConfig(const QString &fname) const;
+154 -279
View File
@@ -57,8 +57,8 @@
<property name="geometry">
<rect>
<x>120</x>
<y>20</y>
<width>188</width>
<y>50</y>
<width>78</width>
<height>22</height>
</rect>
</property>
@@ -69,52 +69,12 @@ float and converted to the output sample type as needed.</string>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>- Autodetect -</string>
</property>
</item>
<item>
<property name="text">
<string>int8 - signed 8-bit int</string>
</property>
</item>
<item>
<property name="text">
<string>uint8 - unsigned 8-bit int</string>
</property>
</item>
<item>
<property name="text">
<string>int16 - signed 16-bit int</string>
</property>
</item>
<item>
<property name="text">
<string>uint16 - unsigned 16-bit int</string>
</property>
</item>
<item>
<property name="text">
<string>int32 - signed 32-bit int</string>
</property>
</item>
<item>
<property name="text">
<string>uint32 - unsigned 32-bit int</string>
</property>
</item>
<item>
<property name="text">
<string>float32 - 32-bit float</string>
</property>
</item>
</widget>
<widget class="QLabel" name="label_5">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<y>50</y>
<width>101</width>
<height>21</height>
</rect>
@@ -130,7 +90,7 @@ float and converted to the output sample type as needed.</string>
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<y>20</y>
<width>101</width>
<height>21</height>
</rect>
@@ -146,8 +106,8 @@ float and converted to the output sample type as needed.</string>
<property name="geometry">
<rect>
<x>120</x>
<y>50</y>
<width>227</width>
<y>20</y>
<width>78</width>
<height>22</height>
</rect>
</property>
@@ -159,48 +119,13 @@ to stereo output.</string>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>- Autodetect -</string>
</property>
</item>
<item>
<property name="text">
<string>mono - 1-channel Mono</string>
</property>
</item>
<item>
<property name="text">
<string>stereo - 2-channel Stereo</string>
</property>
</item>
<item>
<property name="text">
<string>quad - 4-channel Quadraphonic</string>
</property>
</item>
<item>
<property name="text">
<string>surround51 - 5.1 Surround Sound</string>
</property>
</item>
<item>
<property name="text">
<string>surround61 - 6.1 Surround Sound</string>
</property>
</item>
<item>
<property name="text">
<string>surround71 - 7.1 Surround Sound</string>
</property>
</item>
</widget>
<widget class="QComboBox" name="sampleRateCombo">
<property name="geometry">
<rect>
<x>120</x>
<y>80</y>
<width>111</width>
<x>370</x>
<y>20</y>
<width>96</width>
<height>22</height>
</rect>
</property>
@@ -218,37 +143,12 @@ to stereo output.</string>
</property>
<item>
<property name="text">
<string>- Autodetect -</string>
<string>Autodetect</string>
</property>
</item>
<item>
<property name="text">
<string>96000</string>
</property>
</item>
<item>
<property name="text">
<string>48000</string>
</property>
</item>
<item>
<property name="text">
<string>44100</string>
</property>
</item>
<item>
<property name="text">
<string>32000</string>
</property>
</item>
<item>
<property name="text">
<string>22050</string>
</property>
</item>
<item>
<property name="text">
<string>16000</string>
<string>8000</string>
</property>
</item>
<item>
@@ -258,16 +158,36 @@ to stereo output.</string>
</item>
<item>
<property name="text">
<string>8000</string>
<string>16000</string>
</property>
</item>
<item>
<property name="text">
<string>22050</string>
</property>
</item>
<item>
<property name="text">
<string>32000</string>
</property>
</item>
<item>
<property name="text">
<string>44100</string>
</property>
</item>
<item>
<property name="text">
<string>48000</string>
</property>
</item>
</widget>
<widget class="QLabel" name="label_7">
<property name="geometry">
<rect>
<x>10</x>
<y>80</y>
<width>101</width>
<x>280</x>
<y>20</y>
<width>81</width>
<height>21</height>
</rect>
</property>
@@ -282,73 +202,20 @@ to stereo output.</string>
<property name="geometry">
<rect>
<x>10</x>
<y>200</y>
<y>180</y>
<width>511</width>
<height>161</height>
<height>191</height>
</rect>
</property>
<property name="title">
<string>HRTF (Stereo only)</string>
</property>
<widget class="QRadioButton" name="hrtfEnableButton">
<property name="geometry">
<rect>
<x>20</x>
<y>30</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="toolTip">
<string>Allows applications to request HRTF mixing.</string>
</property>
<property name="text">
<string>Enable</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QRadioButton" name="hrtfDisableButton">
<property name="geometry">
<rect>
<x>20</x>
<y>50</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="toolTip">
<string>Does not allow HRTF mixing, even when requested.</string>
</property>
<property name="text">
<string>Disable</string>
</property>
</widget>
<widget class="QRadioButton" name="hrtfForceButton">
<property name="geometry">
<rect>
<x>20</x>
<y>70</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="toolTip">
<string>Attempts to force HRTF mixing, even if applications request not
to do it. This may override the channel configuration and
sample rate.</string>
</property>
<property name="text">
<string>Force</string>
</property>
</widget>
<widget class="QListWidget" name="hrtfFileList">
<property name="geometry">
<rect>
<x>110</x>
<x>20</x>
<y>30</y>
<width>301</width>
<width>391</width>
<height>121</height>
</rect>
</property>
@@ -378,7 +245,7 @@ contain these markers, which will be replaced as needed:
<widget class="QPushButton" name="hrtfAddButton">
<property name="geometry">
<rect>
<x>419</x>
<x>420</x>
<y>30</y>
<width>81</width>
<height>25</height>
@@ -399,7 +266,7 @@ contain these markers, which will be replaced as needed:
<widget class="QPushButton" name="hrtfRemoveButton">
<property name="geometry">
<rect>
<x>419</x>
<x>420</x>
<y>60</y>
<width>81</width>
<height>25</height>
@@ -414,12 +281,56 @@ contain these markers, which will be replaced as needed:
</iconset>
</property>
</widget>
<widget class="QComboBox" name="hrtfStateComboBox">
<property name="geometry">
<rect>
<x>110</x>
<y>160</y>
<width>161</width>
<height>22</height>
</rect>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
<item>
<property name="text">
<string>Application preference</string>
</property>
</item>
<item>
<property name="text">
<string>Force on</string>
</property>
</item>
<item>
<property name="text">
<string>Force off</string>
</property>
</item>
</widget>
<widget class="QLabel" name="label_15">
<property name="geometry">
<rect>
<x>30</x>
<y>160</y>
<width>71</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>HRTF Mode:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_3">
<property name="geometry">
<rect>
<x>10</x>
<y>110</y>
<y>90</y>
<width>511</width>
<height>91</height>
</rect>
@@ -590,6 +501,37 @@ frames needed for each mixing update.</string>
</widget>
</widget>
</widget>
<widget class="QLabel" name="label_14">
<property name="geometry">
<rect>
<x>280</x>
<y>50</y>
<width>81</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Stereo Mode:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QComboBox" name="stereoModeCombo">
<property name="geometry">
<rect>
<x>370</x>
<y>50</y>
<width>78</width>
<height>22</height>
</rect>
</property>
<property name="toolTip">
<string>How to treat stereo output. As headphones, HRTF or crossfeed
filters may be used to improve binaural quality, which may not
otherwise be suitable for speakers.</string>
</property>
</widget>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
@@ -737,7 +679,7 @@ value currently possible is 4.</string>
<rect>
<x>110</x>
<y>120</y>
<width>185</width>
<width>78</width>
<height>22</height>
</rect>
</property>
@@ -747,34 +689,14 @@ value currently possible is 4.</string>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>- Default -</string>
</property>
</item>
<item>
<property name="text">
<string>Point (low quality, fast)</string>
</property>
</item>
<item>
<property name="text">
<string>Linear (basic quality, fast)</string>
</property>
</item>
<item>
<property name="text">
<string>Cubic Spline (good quality)</string>
</property>
</item>
</widget>
<widget class="QGroupBox" name="groupBox_2">
<widget class="QGroupBox" name="cpuExtGroupBox">
<property name="geometry">
<rect>
<x>10</x>
<y>150</y>
<width>511</width>
<height>91</height>
<height>121</height>
</rect>
</property>
<property name="toolTip">
@@ -788,7 +710,7 @@ be useful for preventing those extensions from being used.</string>
<widget class="QCheckBox" name="enableSSECheckBox">
<property name="geometry">
<rect>
<x>180</x>
<x>100</x>
<y>20</y>
<width>71</width>
<height>31</height>
@@ -805,7 +727,7 @@ be useful for preventing those extensions from being used.</string>
<property name="geometry">
<rect>
<x>180</x>
<y>50</y>
<y>20</y>
<width>71</width>
<height>31</height>
</rect>
@@ -820,7 +742,7 @@ be useful for preventing those extensions from being used.</string>
<widget class="QCheckBox" name="enableNeonCheckBox">
<property name="geometry">
<rect>
<x>260</x>
<x>100</x>
<y>50</y>
<width>71</width>
<height>31</height>
@@ -836,7 +758,7 @@ be useful for preventing those extensions from being used.</string>
<widget class="QCheckBox" name="enableSSE41CheckBox">
<property name="geometry">
<rect>
<x>260</x>
<x>340</x>
<y>20</y>
<width>71</width>
<height>31</height>
@@ -849,6 +771,35 @@ be useful for preventing those extensions from being used.</string>
<bool>true</bool>
</property>
</widget>
<widget class="QCheckBox" name="enableSSE3CheckBox">
<property name="geometry">
<rect>
<x>260</x>
<y>20</y>
<width>71</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>SSE3</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="cpuExtDisabledLabel">
<property name="geometry">
<rect>
<x>101</x>
<y>80</y>
<width>311</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;No support enabled for CPU Extensions&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</widget>
</widget>
<widget class="QWidget" name="tab">
@@ -956,87 +907,11 @@ some quality.</string>
<string>Emulate EAX Reverb:</string>
</property>
</widget>
<widget class="QGroupBox" name="groupBox_4">
<property name="geometry">
<rect>
<x>10</x>
<y>100</y>
<width>511</width>
<height>61</height>
</rect>
</property>
<property name="toolTip">
<string>Global amplification for reverb output, expressed in decibels.
+6 will be a scale of (approximately) 2x, +12 will be a scale of
4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
value of 0 means no change.</string>
</property>
<property name="title">
<string>Reverb Boost</string>
</property>
<widget class="QSlider" name="reverbBoostSlider">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>391</width>
<height>23</height>
</rect>
</property>
<property name="toolTip">
<string/>
</property>
<property name="minimum">
<number>-120</number>
</property>
<property name="maximum">
<number>120</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>10</number>
</property>
</widget>
<widget class="QLineEdit" name="reverbBoostEdit">
<property name="geometry">
<rect>
<x>410</x>
<y>30</y>
<width>51</width>
<height>22</height>
</rect>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="placeholderText">
<string>0.0</string>
</property>
</widget>
<widget class="QLabel" name="label_12">
<property name="geometry">
<rect>
<x>460</x>
<y>30</y>
<width>31</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>dB</string>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_5">
<property name="geometry">
<rect>
<x>10</x>
<y>170</y>
<y>100</y>
<width>511</width>
<height>191</height>
</rect>
+1 -93
View File
@@ -227,8 +227,7 @@ enum HeadModelT {
// Desired output format from the command line.
enum OutputFormatT {
OF_NONE = 0,
OF_MHR , // OpenAL Soft MHR data set file.
OF_TABLE // OpenAL Soft built-in table file (used when compiling).
OF_MHR // OpenAL Soft MHR data set file.
};
// Unsigned integer type.
@@ -2089,84 +2088,6 @@ static int StoreMhr (const HrirDataT * hData, const char * filename) {
return (1);
}
// Store the OpenAL Soft built-in table.
static int StoreTable (const HrirDataT * hData, const char * filename) {
FILE * fp = NULL;
uint step, end, n, j, i;
int hpHist, v;
char text [128 + 1];
if ((fp = fopen (filename, "wb")) == NULL) {
fprintf (stderr, "Error: Could not open table file '%s'.\n", filename);
return (0);
}
snprintf (text, 128, "/* Elevation metrics */\n"
"static const ALubyte defaultAzCount[%u] = { ", hData -> mEvCount);
if (! WriteAscii (text, fp, filename))
return (0);
for (i = 0; i < hData -> mEvCount; i ++) {
snprintf (text, 128, "%u, ", hData -> mAzCount [i]);
if (! WriteAscii (text, fp, filename))
return (0);
}
snprintf (text, 128, "};\n"
"static const ALushort defaultEvOffset[%u] = { ", hData -> mEvCount);
if (! WriteAscii (text, fp, filename))
return (0);
for (i = 0; i < hData -> mEvCount; i ++) {
snprintf (text, 128, "%u, ", hData -> mEvOffset [i]);
if (! WriteAscii (text, fp, filename))
return (0);
}
step = hData -> mIrSize;
end = hData -> mIrCount * step;
n = hData -> mIrPoints;
snprintf (text, 128, "};\n\n"
"/* HRIR Coefficients */\n"
"static const ALshort defaultCoeffs[%u] =\n{\n", hData -> mIrCount * n);
if (! WriteAscii (text, fp, filename))
return (0);
srand (0x31DF840C);
for (j = 0; j < end; j += step) {
if (! WriteAscii (" ", fp, filename))
return (0);
hpHist = 0;
for (i = 0; i < n; i ++) {
v = HpTpdfDither (32767.0 * hData -> mHrirs [j + i], & hpHist);
snprintf (text, 128, " %+d,", v);
if (! WriteAscii (text, fp, filename))
return (0);
}
if (! WriteAscii ("\n", fp, filename))
return (0);
}
snprintf (text, 128, "};\n\n"
"/* HRIR Delays */\n"
"static const ALubyte defaultDelays[%u] =\n{\n"
" ", hData -> mIrCount);
if (! WriteAscii (text, fp, filename))
return (0);
for (j = 0; j < hData -> mIrCount; j ++) {
v = (int) fmin (round (hData -> mIrRate * hData -> mHrtds [j]), MAX_HRTD);
snprintf (text, 128, " %d,", v);
if (! WriteAscii (text, fp, filename))
return (0);
}
if (! WriteAscii ("\n};\n\n"
"/* Default HRTF Definition */\n", fp, filename))
return (0);
snprintf (text, 128, "static const struct Hrtf DefaultHrtf = {\n"
" %u, %u, %u, defaultAzCount, defaultEvOffset,\n",
hData -> mIrRate, hData -> mIrPoints, hData -> mEvCount);
if (! WriteAscii (text, fp, filename))
return (0);
if (! WriteAscii (" defaultCoeffs, defaultDelays, NULL\n"
"};\n", fp, filename))
return (0);
fclose (fp);
return (1);
}
// Process the data set definition to read and validate the data set metrics.
static int ProcessMetrics (TokenReaderT * tr, const uint fftSize, const uint truncSize, HrirDataT * hData) {
char ident [MAX_IDENT_LEN + 1];
@@ -2583,11 +2504,6 @@ static int ProcessDefinition (const char * inName, const uint outRate, const uin
if (! StoreMhr (& hData, expName))
return (0);
break;
case OF_TABLE :
fprintf (stderr, "Creating OpenAL Soft table file...\n");
if (! StoreTable (& hData, expName))
return (0);
break;
default :
break;
}
@@ -2619,8 +2535,6 @@ int main (const int argc, const char * argv []) {
fprintf (stdout, "Commands:\n");
fprintf (stdout, " -m, --make-mhr Makes an OpenAL Soft compatible HRTF data set.\n");
fprintf (stdout, " Defaults output to: ./oalsoft_hrtf_%%r.mhr\n");
fprintf (stdout, " -t, --make-tab Makes the built-in table used when compiling OpenAL Soft.\n");
fprintf (stdout, " Defaults output to: ./hrtf_tables.inc\n");
fprintf (stdout, " -h, --help Displays this help information.\n\n");
fprintf (stdout, "Options:\n");
fprintf (stdout, " -r=<rate> Change the data set sample rate to the specified value and\n");
@@ -2647,12 +2561,6 @@ int main (const int argc, const char * argv []) {
else
outName = "./oalsoft_hrtf_%r.mhr";
outFormat = OF_MHR;
} else if ((strcmp (argv [1], "--make-tab") == 0) || (strcmp (argv [1], "-t") == 0)) {
if (argc > 3)
outName = argv [3];
else
outName = "./hrtf_tables.inc";
outFormat = OF_TABLE;
} else {
fprintf (stderr, "Error: Invalid command '%s'.\n", argv [1]);
return (-1);
+30
View File
@@ -147,6 +147,35 @@ static void printALCInfo(ALCdevice *device)
}
}
static void printHRTFInfo(ALCdevice *device)
{
LPALCGETSTRINGISOFT alcGetStringiSOFT;
ALCint num_hrtfs;
if(alcIsExtensionPresent(device, "ALC_SOFT_HRTF") == ALC_FALSE)
{
printf("HRTF extension not available\n");
return;
}
alcGetStringiSOFT = alcGetProcAddress(device, "alcGetStringiSOFT");
alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtfs);
if(!num_hrtfs)
printf("No HRTFs found\n");
else
{
ALCint i;
printf("Available HRTFs:\n");
for(i = 0;i < num_hrtfs;++i)
{
const ALCchar *name = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
printf(" %s\n", name);
}
}
checkALCErrors(device);
}
static void printALInfo(void)
{
printf("OpenAL vendor string: %s\n", alGetString(AL_VENDOR));
@@ -287,6 +316,7 @@ int main(int argc, char *argv[])
return 1;
}
printALCInfo(device);
printHRTFInfo(device);
context = alcCreateContext(device, NULL);
if(!context || alcMakeContextCurrent(context) == ALC_FALSE)