updated OpenAL-Soft to version 1.16.0

This commit is contained in:
fysx
2014-09-08 21:17:12 +02:00
parent 4f11bd0e7b
commit 70eef137ae
164 changed files with 14660 additions and 10016 deletions
+4 -3
View File
@@ -6,7 +6,8 @@ include $(CLEAR_VARS)
LOCAL_MODULE := liblove
LOCAL_CFLAGS := -fexceptions -g -Dlinux -Dunix \
-DHAVE_GCC_DESTRUCTOR=1 -DOPT_GENERIC -DREAL_IS_FLOAT \
-DGL_GLEXT_PROTOTYPES -DLOVE_TURBO_JPEG -DLOVE_NO_DEVIL
-DGL_GLEXT_PROTOTYPES -DLOVE_TURBO_JPEG -DLOVE_NO_DEVIL \
-DAL_ALEXT_PROTOTYPES
LOCAL_CPPFLAGS := ${LOCAL_CFLAGS}
@@ -21,8 +22,8 @@ LOCAL_C_INCLUDES := \
${LOCAL_PATH}/../libjpeg-turbo-1.3.1/ \
${LOCAL_PATH}/../lcms2-2.5/include \
${LOCAL_PATH}/../tiff-3.9.5/libtiff \
${LOCAL_PATH}/../openal-soft-android/include \
${LOCAL_PATH}/../openal-soft-android/OpenAL32/Include \
${LOCAL_PATH}/../openal-soft-1.16.0/include \
${LOCAL_PATH}/../openal-soft-1.16.0/OpenAL32/Include \
${LOCAL_PATH}/../freetype2-android/include \
${LOCAL_PATH}/../freetype2-android/src \
${LOCAL_PATH}/../physfs-2.1.0/src \
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -32,13 +32,14 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "alMain.h"
#ifdef _WIN32_IE
#include <shlobj.h>
#endif
#include "alMain.h"
#include "compat.h"
typedef struct ConfigEntry {
char *key;
char *value;
@@ -48,10 +49,8 @@ typedef struct ConfigBlock {
ConfigEntry *entries;
unsigned int entryCount;
} ConfigBlock;
static ConfigBlock cfgBlock;
static char buffer[1024];
static char *lstrip(char *line)
{
@@ -69,23 +68,132 @@ static char *rstrip(char *line)
return line;
}
static int readline(FILE *f, char **output, size_t *maxlen)
{
size_t len = 0;
int c;
while((c=fgetc(f)) != EOF && (c == '\r' || c == '\n'))
;
if(c == EOF)
return 0;
do {
if(len+1 >= *maxlen)
{
void *temp = NULL;
size_t newmax;
newmax = (*maxlen ? (*maxlen)<<1 : 32);
if(newmax > *maxlen)
temp = realloc(*output, newmax);
if(!temp)
{
ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, *maxlen);
return 0;
}
*output = temp;
*maxlen = newmax;
}
(*output)[len++] = c;
(*output)[len] = '\0';
} while((c=fgetc(f)) != EOF && c != '\r' && c != '\n');
return 1;
}
static char *expdup(const char *str)
{
char *output = NULL;
size_t maxlen = 0;
size_t len = 0;
while(*str != '\0')
{
const char *addstr;
size_t addstrlen;
size_t i;
if(str[0] != '$')
{
const char *next = strchr(str, '$');
addstr = str;
addstrlen = next ? (size_t)(next-str) : strlen(str);
str += addstrlen;
}
else
{
str++;
if(*str == '$')
{
const char *next = strchr(str+1, '$');
addstr = str;
addstrlen = next ? (size_t)(next-str) : strlen(str);
str += addstrlen;
}
else
{
char envname[1024];
size_t k = 0;
while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1)
envname[k++] = *(str++);
envname[k++] = '\0';
if((addstr=getenv(envname)) == NULL)
continue;
addstrlen = strlen(addstr);
}
}
if(addstrlen == 0)
continue;
if(addstrlen >= maxlen-len)
{
void *temp = NULL;
size_t newmax;
newmax = len+addstrlen+1;
if(newmax > maxlen)
temp = realloc(output, newmax);
if(!temp)
{
ERR("Failed to realloc "SZFMT" bytes from "SZFMT"!\n", newmax, maxlen);
return output;
}
output = temp;
maxlen = newmax;
}
for(i = 0;i < addstrlen;i++)
output[len++] = addstr[i];
output[len] = '\0';
}
return output ? output : calloc(1, 1);
}
static void LoadConfigFromFile(FILE *f)
{
char curSection[128] = "";
char *buffer = NULL;
size_t maxlen = 0;
ConfigEntry *ent;
while(fgets(buffer, sizeof(buffer), f))
while(readline(f, &buffer, &maxlen))
{
char *line, *comment;
char key[256] = "";
char value[256] = "";
comment = strchr(buffer, '#');
if(comment)
{
*(comment++) = 0;
comment = rstrip(lstrip(comment));
}
if(comment) *(comment++) = 0;
line = rstrip(lstrip(buffer));
if(!line[0])
@@ -123,26 +231,26 @@ static void LoadConfigFromFile(FILE *f)
* manually. */
if(strcmp(value, "\"\"") == 0 || strcmp(value, "''") == 0)
value[0] = 0;
}
else if(sscanf(line, "%255[^=] %255[=]", key, value) == 2)
{
/* Special case for 'key =' */
value[0] = 0;
}
else
{
ERR("config parse error: malformed option line: \"%s\"\n\n", line);
continue;
}
rstrip(key);
}
else if(sscanf(line, "%255[^=] %255[=]", key, value) == 2)
{
/* Special case for 'key =' */
value[0] = 0;
}
else
{
ERR("config parse error: malformed option line: \"%s\"\n\n", line);
continue;
}
rstrip(key);
if(curSection[0] != 0)
{
size_t len = strlen(curSection);
memmove(&key[len+1], key, sizeof(key)-1-len);
key[len] = '/';
memcpy(key, curSection, len);
}
if(curSection[0] != 0)
{
size_t len = strlen(curSection);
memmove(&key[len+1], key, sizeof(key)-1-len);
key[len] = '/';
memcpy(key, curSection, len);
}
/* Check if we already have this option set */
ent = cfgBlock.entries;
@@ -171,36 +279,57 @@ static void LoadConfigFromFile(FILE *f)
}
free(ent->value);
ent->value = strdup(value);
ent->value = expdup(value);
TRACE("found '%s' = '%s'\n", ent->key, ent->value);
}
free(buffer);
}
#ifdef _WIN32
void ReadALConfig(void)
{
const char *str;
WCHAR buffer[PATH_MAX];
const WCHAR *str;
FILE *f;
#ifdef _WIN32
if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
{
size_t p = strlen(buffer);
snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini");
size_t p = lstrlenW(buffer);
_snwprintf(buffer+p, PATH_MAX-p, L"\\alsoft.ini");
TRACE("Loading config %s...\n", buffer);
f = fopen(buffer, "rt");
TRACE("Loading config %ls...\n", buffer);
f = _wfopen(buffer, L"rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str)
{
TRACE("Loading config %ls...\n", str);
f = _wfopen(str, L"rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
}
#else
void ReadALConfig(void)
{
char buffer[PATH_MAX];
const char *str;
FILE *f;
str = "/etc/openal/alsoft.conf";
TRACE("Loading config %s...\n", str);
f = fopen(str, "r");
f = al_fopen(str, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -231,7 +360,7 @@ void ReadALConfig(void)
buffer[sizeof(buffer)-1] = 0;
TRACE("Loading config %s...\n", next);
f = fopen(next, "r");
f = al_fopen(next, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -247,7 +376,7 @@ void ReadALConfig(void)
snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str);
TRACE("Loading config %s...\n", buffer);
f = fopen(buffer, "r");
f = al_fopen(buffer, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -266,19 +395,18 @@ void ReadALConfig(void)
if(buffer[0] != 0)
{
TRACE("Loading config %s...\n", buffer);
f = fopen(buffer, "r");
f = al_fopen(buffer, "r");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
}
#endif
if((str=getenv("ALSOFT_CONF")) != NULL && *str)
{
TRACE("Loading config %s...\n", str);
f = fopen(str, "r");
f = al_fopen(str, "r");
if(f)
{
LoadConfigFromFile(f);
@@ -286,6 +414,7 @@ void ReadALConfig(void)
}
}
}
#endif
void FreeALConfig(void)
{
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include "alMain.h"
#include "threads.h"
#include "compat.h"
@@ -35,7 +36,7 @@ struct RingBuffer {
ALint read_pos;
ALint write_pos;
CRITICAL_SECTION cs;
almtx_t mtx;
};
@@ -51,7 +52,7 @@ RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length)
ring->read_pos = 0;
ring->write_pos = 0;
InitializeCriticalSection(&ring->cs);
almtx_init(&ring->mtx, almtx_plain);
}
return ring;
}
@@ -60,7 +61,7 @@ void DestroyRingBuffer(RingBuffer *ring)
{
if(ring)
{
DeleteCriticalSection(&ring->cs);
almtx_destroy(&ring->mtx);
free(ring);
}
}
@@ -69,9 +70,9 @@ ALsizei RingBufferSize(RingBuffer *ring)
{
ALsizei s;
EnterCriticalSection(&ring->cs);
almtx_lock(&ring->mtx);
s = (ring->write_pos-ring->read_pos+ring->length) % ring->length;
LeaveCriticalSection(&ring->cs);
almtx_unlock(&ring->mtx);
return s;
}
@@ -80,7 +81,7 @@ void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
{
int remain;
EnterCriticalSection(&ring->cs);
almtx_lock(&ring->mtx);
remain = (ring->read_pos-ring->write_pos-1+ring->length) % ring->length;
if(remain < len) len = remain;
@@ -103,14 +104,14 @@ void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
ring->write_pos %= ring->length;
}
LeaveCriticalSection(&ring->cs);
almtx_unlock(&ring->mtx);
}
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
{
int remain;
EnterCriticalSection(&ring->cs);
almtx_lock(&ring->mtx);
remain = ring->length - ring->read_pos;
if(remain < len)
@@ -124,5 +125,5 @@ void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
ring->read_pos += len;
ring->read_pos %= ring->length;
LeaveCriticalSection(&ring->cs);
almtx_unlock(&ring->mtx);
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef ALSTRING_H
#define ALSTRING_H
#include <string.h>
#include "vector.h"
typedef char al_string_char_type;
TYPEDEF_VECTOR(al_string_char_type, al_string)
inline void al_string_deinit(al_string *str)
{ VECTOR_DEINIT(*str); }
#define AL_STRING_INIT(_x) do { (_x) = (al_string)NULL; } while(0)
#define AL_STRING_INIT_STATIC() ((al_string)NULL)
#define AL_STRING_DEINIT(_x) al_string_deinit(&(_x))
inline ALsizei al_string_length(const_al_string str)
{ return VECTOR_SIZE(str); }
inline ALboolean al_string_empty(const_al_string str)
{ return al_string_length(str) == 0; }
inline const al_string_char_type *al_string_get_cstr(const_al_string str)
{ return str ? &VECTOR_FRONT(str) : ""; }
void al_string_clear(al_string *str);
int al_string_cmp(const_al_string str1, const_al_string str2);
int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2);
void al_string_copy(al_string *str, const_al_string from);
void al_string_copy_cstr(al_string *str, const al_string_char_type *from);
void al_string_append_char(al_string *str, const al_string_char_type c);
void al_string_append_cstr(al_string *str, const al_string_char_type *from);
void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to);
#ifdef _WIN32
#include <wchar.h>
/* Windows-only methods to deal with WideChar strings. */
void al_string_copy_wcstr(al_string *str, const wchar_t *from);
#endif
#endif /* ALSTRING_H */
@@ -227,14 +227,27 @@ static ALCboolean alsa_load(void)
typedef struct {
ALCchar *name;
char *device;
al_string name;
al_string device_name;
} DevMap;
TYPEDEF_VECTOR(DevMap, vector_DevMap)
static DevMap *allDevNameMap;
static ALuint numDevNames;
static DevMap *allCaptureDevNameMap;
static ALuint numCaptureDevNames;
static vector_DevMap PlaybackDevices;
static vector_DevMap CaptureDevices;
static void clear_devlist(vector_DevMap *devlist)
{
DevMap *iter, *end;
iter = VECTOR_ITER_BEGIN(*devlist);
end = VECTOR_ITER_END(*devlist);
for(;iter != end;iter++)
{
AL_STRING_DEINIT(iter->name);
AL_STRING_DEINIT(iter->device_name);
}
VECTOR_RESIZE(*devlist, 0);
}
static const char *prefix_name(snd_pcm_stream_t stream)
@@ -243,23 +256,26 @@ static const char *prefix_name(snd_pcm_stream_t stream)
return (stream==SND_PCM_STREAM_PLAYBACK) ? "device-prefix" : "capture-prefix";
}
static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
{
const char *main_prefix = "plughw:";
snd_ctl_t *handle;
int card, err, dev, idx;
snd_ctl_card_info_t *info;
snd_pcm_info_t *pcminfo;
DevMap *DevList;
int card, err, dev;
DevMap entry;
clear_devlist(DeviceList);
snd_ctl_card_info_malloc(&info);
snd_pcm_info_malloc(&pcminfo);
DevList = malloc(sizeof(DevMap) * 1);
DevList[0].name = strdup(alsaDevice);
DevList[0].device = strdup(GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
"device" : "capture", "default"));
idx = 1;
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) ?
"device" : "capture", "default"));
VECTOR_PUSH_BACK(*DeviceList, entry);
card = -1;
if((err=snd_card_next(&card)) < 0)
@@ -293,8 +309,9 @@ static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
dev = -1;
while(1)
{
const char *device_prefix = card_prefix;
const char *devname;
void *temp;
char device[128];
if(snd_ctl_pcm_next_device(handle, &dev) < 0)
ERR("snd_ctl_pcm_next_device failed\n");
@@ -310,28 +327,22 @@ static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
continue;
}
temp = realloc(DevList, sizeof(DevMap) * (idx+1));
if(temp)
{
const char *device_prefix = card_prefix;
char device[128];
devname = snd_pcm_info_get_name(pcminfo);
DevList = temp;
devname = snd_pcm_info_get_name(pcminfo);
snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
ConfigValueStr("alsa", name, &device_prefix);
snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
ConfigValueStr("alsa", name, &device_prefix);
snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
cardname, devname, cardid, dev);
snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
device_prefix, cardid, dev);
snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
cardname, devname, cardid, dev);
snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
device_prefix, cardid, dev);
TRACE("Got device \"%s\", \"%s\"\n", name, device);
DevList[idx].name = strdup(name);
DevList[idx].device = strdup(device);
idx++;
}
TRACE("Got device \"%s\", \"%s\"\n", name, device);
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
al_string_copy_cstr(&entry.name, name);
al_string_copy_cstr(&entry.device_name, device);
VECTOR_PUSH_BACK(*DeviceList, entry);
}
snd_ctl_close(handle);
next_card:
@@ -343,9 +354,6 @@ static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
snd_pcm_info_free(pcminfo);
snd_ctl_card_info_free(info);
*count = idx;
return DevList;
}
@@ -390,12 +398,11 @@ typedef struct ALCplaybackAlsa {
ALsizei size;
volatile int killNow;
althread_t thread;
althrd_t thread;
} ALCplaybackAlsa;
DECLARE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr);
static ALuint ALCplaybackAlsa_mixerNoMMapProc(ALvoid *ptr);
static int ALCplaybackAlsa_mixerProc(void *ptr);
static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr);
static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, Destruct)
@@ -406,8 +413,12 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
static DECLARE_FORWARD2(ALCplaybackAlsa, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, ALCuint, availableSamples)
static ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self);
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCplaybackAlsa)
DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
@@ -417,7 +428,7 @@ static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
}
static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr)
static int ALCplaybackAlsa_mixerProc(void *ptr)
{
ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -429,7 +440,7 @@ static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr)
int err;
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
update_size = device->UpdateSize;
num_updates = device->NumUpdates;
@@ -509,7 +520,7 @@ static ALuint ALCplaybackAlsa_mixerProc(ALvoid *ptr)
return 0;
}
static ALuint ALCplaybackAlsa_mixerNoMMapProc(ALvoid *ptr)
static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr)
{
ALCplaybackAlsa *self = (ALCplaybackAlsa*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -519,7 +530,7 @@ static ALuint ALCplaybackAlsa_mixerNoMMapProc(ALvoid *ptr)
int err;
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
update_size = device->UpdateSize;
num_updates = device->NumUpdates;
@@ -614,21 +625,17 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
if(name)
{
size_t idx;
const DevMap *iter;
if(!allDevNameMap)
allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
if(VECTOR_SIZE(PlaybackDevices) == 0)
probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
for(idx = 0;idx < numDevNames;idx++)
{
if(strcmp(name, allDevNameMap[idx].name) == 0)
{
driver = allDevNameMap[idx].device;
break;
}
}
if(idx == numDevNames)
#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, name) == 0)
VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
#undef MATCH_NAME
if(iter == VECTOR_ITER_END(PlaybackDevices))
return ALC_INVALID_VALUE;
driver = al_string_get_cstr(iter->device_name);
}
else
{
@@ -636,6 +643,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
driver = GetConfigValue("alsa", "device", "default");
}
TRACE("Opening device \"%s\"\n", driver);
err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if(err < 0)
{
@@ -646,7 +654,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
/* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
snd_config_update_free_global();
device->DeviceName = strdup(name);
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
@@ -663,15 +671,14 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
unsigned int periodLen, bufferLen;
snd_pcm_sw_params_t *sp = NULL;
snd_pcm_hw_params_t *hp = NULL;
snd_pcm_format_t format = -1;
snd_pcm_access_t access;
snd_pcm_format_t format;
unsigned int periods;
unsigned int rate;
const char *funcerr;
int allowmmap;
int err;
format = -1;
switch(device->FmtType)
{
case DevFmtByte:
@@ -809,7 +816,7 @@ error:
static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALuint (*thread_func)(ALvoid*) = NULL;
int (*thread_func)(void*) = NULL;
snd_pcm_hw_params_t *hp = NULL;
snd_pcm_access_t access;
const char *funcerr;
@@ -845,7 +852,8 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
}
thread_func = ALCplaybackAlsa_mixerProc;
}
if(!StartThread(&self->thread, thread_func, self))
self->killNow = 0;
if(althrd_create(&self->thread, thread_func, self) != althrd_success)
{
ERR("Could not create playback thread\n");
free(self->buffer);
@@ -863,13 +871,14 @@ error:
static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self)
{
if(self->thread)
{
self->killNow = 1;
StopThread(self->thread);
self->thread = NULL;
}
self->killNow = 0;
int res;
if(self->killNow)
return;
self->killNow = 1;
althrd_join(self->thread, &res);
free(self->buffer);
self->buffer = NULL;
}
@@ -889,14 +898,6 @@ static ALint64 ALCplaybackAlsa_getLatency(ALCplaybackAlsa *self)
}
static void ALCplaybackAlsa_Delete(ALCplaybackAlsa *self)
{
free(self);
}
DEFINE_ALCBACKEND_VTABLE(ALCplaybackAlsa);
typedef struct ALCcaptureAlsa {
DERIVE_FROM_TYPE(ALCbackend);
@@ -910,7 +911,6 @@ typedef struct ALCcaptureAlsa {
snd_pcm_sframes_t last_avail;
} ALCcaptureAlsa;
DECLARE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, Destruct)
@@ -921,8 +921,12 @@ static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self);
static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self);
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCcaptureAlsa)
DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device)
@@ -940,27 +944,23 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
snd_pcm_uframes_t bufferSizeInFrames;
snd_pcm_uframes_t periodSizeInFrames;
ALboolean needring = AL_FALSE;
snd_pcm_format_t format;
snd_pcm_format_t format = -1;
const char *funcerr;
int err;
if(name)
{
size_t idx;
const DevMap *iter;
if(!allCaptureDevNameMap)
allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
if(VECTOR_SIZE(CaptureDevices) == 0)
probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
for(idx = 0;idx < numCaptureDevNames;idx++)
{
if(strcmp(name, allCaptureDevNameMap[idx].name) == 0)
{
driver = allCaptureDevNameMap[idx].device;
break;
}
}
if(idx == numCaptureDevNames)
#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, name) == 0)
VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
#undef MATCH_NAME
if(iter == VECTOR_ITER_END(CaptureDevices))
return ALC_INVALID_VALUE;
driver = al_string_get_cstr(iter->device_name);
}
else
{
@@ -968,6 +968,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
driver = GetConfigValue("alsa", "capture", "default");
}
TRACE("Opening device \"%s\"\n", driver);
err = snd_pcm_open(&self->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
if(err < 0)
{
@@ -978,7 +979,6 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
/* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
snd_config_update_free_global();
format = -1;
switch(device->FmtType)
{
case DevFmtByte:
@@ -1056,7 +1056,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
}
}
device->DeviceName = strdup(name);
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
@@ -1114,11 +1114,12 @@ static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self)
void *ptr;
size = snd_pcm_frames_to_bytes(self->pcmHandle, avail);
ptr = realloc(self->buffer, size);
ptr = malloc(size);
if(ptr)
{
ALCcaptureAlsa_captureSamples(self, ptr, avail);
free(self->buffer);
self->buffer = ptr;
ALCcaptureAlsa_captureSamples(self, self->buffer, avail);
self->size = size;
}
}
@@ -1150,7 +1151,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
if((snd_pcm_uframes_t)amt > samples) amt = samples;
amt = snd_pcm_frames_to_bytes(self->pcmHandle, amt);
memmove(buffer, self->buffer, amt);
memcpy(buffer, self->buffer, amt);
if(self->size > amt)
{
@@ -1287,14 +1288,11 @@ static ALint64 ALCcaptureAlsa_getLatency(ALCcaptureAlsa *self)
return maxi64((ALint64)delay*1000000000/device->Frequency, 0);
}
static void ALCcaptureAlsa_Delete(ALCcaptureAlsa *self)
{
free(self);
}
DEFINE_ALCBACKEND_VTABLE(ALCcaptureAlsa);
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 ALCalsaBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
@@ -1303,6 +1301,9 @@ typedef struct ALCalsaBackendFactory {
static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self))
{
VECTOR_INIT(PlaybackDevices);
VECTOR_INIT(CaptureDevices);
if(!alsa_load())
return ALC_FALSE;
return ALC_TRUE;
@@ -1310,25 +1311,11 @@ static ALCboolean ALCalsaBackendFactory_init(ALCalsaBackendFactory* UNUSED(self)
static void ALCalsaBackendFactory_deinit(ALCalsaBackendFactory* UNUSED(self))
{
ALuint i;
clear_devlist(&PlaybackDevices);
VECTOR_DEINIT(PlaybackDevices);
for(i = 0;i < numDevNames;++i)
{
free(allDevNameMap[i].name);
free(allDevNameMap[i].device);
}
free(allDevNameMap);
allDevNameMap = NULL;
numDevNames = 0;
for(i = 0;i < numCaptureDevNames;++i)
{
free(allCaptureDevNameMap[i].name);
free(allCaptureDevNameMap[i].device);
}
free(allCaptureDevNameMap);
allCaptureDevNameMap = NULL;
numCaptureDevNames = 0;
clear_devlist(&CaptureDevices);
VECTOR_DEINIT(CaptureDevices);
#ifdef HAVE_DYNLOAD
if(alsa_handle)
@@ -1346,36 +1333,16 @@ static ALCboolean ALCalsaBackendFactory_querySupport(ALCalsaBackendFactory* UNUS
static void ALCalsaBackendFactory_probe(ALCalsaBackendFactory* UNUSED(self), enum DevProbe type)
{
ALuint i;
switch(type)
{
case ALL_DEVICE_PROBE:
for(i = 0;i < numDevNames;++i)
{
free(allDevNameMap[i].name);
free(allDevNameMap[i].device);
}
free(allDevNameMap);
allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
for(i = 0;i < numDevNames;++i)
AppendAllDevicesList(allDevNameMap[i].name);
probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
for(i = 0;i < numCaptureDevNames;++i)
{
free(allCaptureDevNameMap[i].name);
free(allCaptureDevNameMap[i].device);
}
free(allCaptureDevNameMap);
allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
for(i = 0;i < numCaptureDevNames;++i)
AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
}
}
@@ -1386,8 +1353,9 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN
{
ALCplaybackAlsa *backend;
backend = calloc(1, sizeof(*backend));
backend = ALCplaybackAlsa_New(sizeof(*backend));
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCplaybackAlsa_Construct(backend, device);
@@ -1397,8 +1365,9 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN
{
ALCcaptureAlsa *backend;
backend = calloc(1, sizeof(*backend));
backend = ALCcaptureAlsa_New(sizeof(*backend));
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCcaptureAlsa_Construct(backend, device);
@@ -11,13 +11,15 @@
/* Base ALCbackend method implementations. */
void ALCbackend_Construct(ALCbackend *self, ALCdevice *device)
{
int ret;
self->mDevice = device;
InitializeCriticalSection(&self->mMutex);
ret = almtx_init(&self->mMutex, almtx_recursive);
assert(ret == althrd_success);
}
void ALCbackend_Destruct(ALCbackend *self)
{
DeleteCriticalSection(&self->mMutex);
almtx_destroy(&self->mMutex);
}
ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self))
@@ -42,12 +44,14 @@ ALint64 ALCbackend_getLatency(ALCbackend* UNUSED(self))
void ALCbackend_lock(ALCbackend *self)
{
EnterCriticalSection(&self->mMutex);
int ret = almtx_lock(&self->mMutex);
assert(ret == althrd_success);
}
void ALCbackend_unlock(ALCbackend *self)
{
LeaveCriticalSection(&self->mMutex);
int ret = almtx_unlock(&self->mMutex);
assert(ret == althrd_success);
}
@@ -60,9 +64,11 @@ void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self))
/* Wrappers to use an old-style backend with the new interface. */
typedef struct PlaybackWrapper {
DERIVE_FROM_TYPE(ALCbackend);
const BackendFuncs *Funcs;
} PlaybackWrapper;
static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device);
static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs);
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, Destruct)
static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name);
static void PlaybackWrapper_close(PlaybackWrapper *self);
@@ -74,62 +80,61 @@ static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self);
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
static void PlaybackWrapper_Delete(PlaybackWrapper *self);
DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper);
static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device)
static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(PlaybackWrapper, ALCbackend, self);
self->Funcs = funcs;
}
static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return device->Funcs->OpenPlayback(device, name);
return self->Funcs->OpenPlayback(device, name);
}
static void PlaybackWrapper_close(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->Funcs->ClosePlayback(device);
self->Funcs->ClosePlayback(device);
}
static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return device->Funcs->ResetPlayback(device);
return self->Funcs->ResetPlayback(device);
}
static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return device->Funcs->StartPlayback(device);
return self->Funcs->StartPlayback(device);
}
static void PlaybackWrapper_stop(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->Funcs->StopPlayback(device);
self->Funcs->StopPlayback(device);
}
static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return device->Funcs->GetLatency(device);
}
static void PlaybackWrapper_Delete(PlaybackWrapper *self)
{
free(self);
return self->Funcs->GetLatency(device);
}
typedef struct CaptureWrapper {
DERIVE_FROM_TYPE(ALCbackend);
const BackendFuncs *Funcs;
} CaptureWrapper;
static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device);
static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs);
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, Destruct)
static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name);
static void CaptureWrapper_close(CaptureWrapper *self);
@@ -141,75 +146,72 @@ static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self);
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
static void CaptureWrapper_Delete(CaptureWrapper *self);
DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device)
static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(CaptureWrapper, ALCbackend, self);
self->Funcs = funcs;
}
static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return device->Funcs->OpenCapture(device, name);
return self->Funcs->OpenCapture(device, name);
}
static void CaptureWrapper_close(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->Funcs->CloseCapture(device);
self->Funcs->CloseCapture(device);
}
static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->Funcs->StartCapture(device);
self->Funcs->StartCapture(device);
return ALC_TRUE;
}
static void CaptureWrapper_stop(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->Funcs->StopCapture(device);
self->Funcs->StopCapture(device);
}
static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return device->Funcs->CaptureSamples(device, buffer, samples);
return self->Funcs->CaptureSamples(device, buffer, samples);
}
static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return device->Funcs->AvailableSamples(device);
return self->Funcs->AvailableSamples(device);
}
static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
return device->Funcs->GetLatency(device);
}
static void CaptureWrapper_Delete(CaptureWrapper *self)
{
free(self);
return self->Funcs->GetLatency(device);
}
ALCbackend *create_backend_wrapper(ALCdevice *device, ALCbackend_Type type)
ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type)
{
if(type == ALCbackend_Playback)
{
PlaybackWrapper *backend;
backend = malloc(sizeof(*backend));
backend = PlaybackWrapper_New(sizeof(*backend));
if(!backend) return NULL;
PlaybackWrapper_Construct(backend, device);
PlaybackWrapper_Construct(backend, device, funcs);
return STATIC_CAST(ALCbackend, backend);
}
@@ -218,10 +220,10 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, ALCbackend_Type type)
{
CaptureWrapper *backend;
backend = malloc(sizeof(*backend));
backend = CaptureWrapper_New(sizeof(*backend));
if(!backend) return NULL;
CaptureWrapper_Construct(backend, device);
CaptureWrapper_Construct(backend, device, funcs);
return STATIC_CAST(ALCbackend, backend);
}
@@ -2,7 +2,7 @@
#define AL_BACKENDS_BASE_H
#include "alMain.h"
#include "compat.h"
#include "threads.h"
struct ALCbackendVtable;
@@ -12,7 +12,7 @@ typedef struct ALCbackend {
ALCdevice *mDevice;
CRITICAL_SECTION mMutex;
almtx_t mMutex;
} ALCbackend;
void ALCbackend_Construct(ALCbackend *self, ALCdevice *device);
@@ -42,12 +42,9 @@ struct ALCbackendVtable {
void (*const lock)(ALCbackend*);
void (*const unlock)(ALCbackend*);
void (*const Delete)(ALCbackend*);
void (*const Delete)(void*);
};
#define DECLARE_ALCBACKEND_VTABLE(T) \
static const struct ALCbackendVtable T##_ALCbackend_vtable
#define DEFINE_ALCBACKEND_VTABLE(T) \
DECLARE_THUNK(T, ALCbackend, void, Destruct) \
DECLARE_THUNK1(T, ALCbackend, ALCenum, open, const ALCchar*) \
@@ -60,9 +57,10 @@ DECLARE_THUNK(T, ALCbackend, ALCuint, availableSamples) \
DECLARE_THUNK(T, ALCbackend, ALint64, getLatency) \
DECLARE_THUNK(T, ALCbackend, void, lock) \
DECLARE_THUNK(T, ALCbackend, void, unlock) \
DECLARE_THUNK(T, ALCbackend, void, Delete) \
static void T##_ALCbackend_Delete(void *ptr) \
{ T##_Delete(STATIC_UPCAST(T, ALCbackend, (ALCbackend*)ptr)); } \
\
DECLARE_ALCBACKEND_VTABLE(T) = { \
static const struct ALCbackendVtable T##_ALCbackend_vtable = { \
T##_ALCbackend_Destruct, \
\
T##_ALCbackend_open, \
@@ -125,9 +123,11 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \
ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
ALCbackendFactory *ALCossBackendFactory_getFactory(void);
ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
ALCbackendFactory *ALCloopbackFactory_getFactory(void);
ALCbackend *create_backend_wrapper(ALCdevice *device, ALCbackend_Type type);
ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type);
#endif /* AL_BACKENDS_BASE_H */
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloca.h>
#include "alMain.h"
#include "alu.h"
@@ -180,7 +181,7 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName)
return ALC_INVALID_VALUE;
}
device->DeviceName = strdup(deviceName);
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
}
@@ -577,6 +578,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
if(data->ring == NULL)
goto error;
al_string_copy_cstr(&device->DeviceName, deviceName);
return ALC_NO_ERROR;
error:
@@ -44,7 +44,7 @@ static DECLARE_FORWARD(ALCloopback, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCloopback, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCloopback, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCloopback, ALCbackend, void, unlock)
static void ALCloopback_Delete(ALCloopback *self);
DECLARE_DEFAULT_ALLOCATORS(ALCloopback)
DEFINE_ALCBACKEND_VTABLE(ALCloopback);
@@ -59,7 +59,7 @@ static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->DeviceName = strdup(name);
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
@@ -83,12 +83,6 @@ static void ALCloopback_stop(ALCloopback* UNUSED(self))
}
static void ALCloopback_Delete(ALCloopback *self)
{
free(self);
}
typedef struct ALCloopbackFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCloopbackFactory;
@@ -127,14 +121,18 @@ static void ALCloopbackFactory_probe(ALCloopbackFactory* UNUSED(self), enum DevP
static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
ALCloopback *backend;
if(type == ALCbackend_Loopback)
{
ALCloopback *backend;
assert(type == ALCbackend_Loopback);
backend = ALCloopback_New(sizeof(*backend));
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
backend = calloc(1, sizeof(*backend));
if(!backend) return NULL;
ALCloopback_Construct(backend, device);
ALCloopback_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
return STATIC_CAST(ALCbackend, backend);
return NULL;
}
@@ -37,11 +37,10 @@ typedef struct ALCnullBackend {
DERIVE_FROM_TYPE(ALCbackend);
volatile int killNow;
althread_t thread;
althrd_t thread;
} ALCnullBackend;
DECLARE_ALCBACKEND_VTABLE(ALCnullBackend);
static ALuint ALCnullBackend_mixerProc(ALvoid *ptr);
static int ALCnullBackend_mixerProc(void *ptr);
static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device);
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, Destruct)
@@ -55,6 +54,10 @@ static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(ALCnullBackend)
DEFINE_ALCBACKEND_VTABLE(ALCnullBackend);
static const ALCchar nullDevice[] = "No Output";
@@ -66,42 +69,49 @@ static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device)
}
static ALuint ALCnullBackend_mixerProc(ALvoid *ptr)
static int ALCnullBackend_mixerProc(void *ptr)
{
ALCnullBackend *self = (ALCnullBackend*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALuint now, start;
struct timespec now, start;
ALuint64 avail, done;
const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 /
device->Frequency / 2);
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
done = 0;
start = timeGetTime();
if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
{
ERR("Failed to get starting time\n");
return 1;
}
while(!self->killNow && device->Connected)
{
now = timeGetTime();
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
ERR("Failed to get current time\n");
return 1;
}
avail = (ALuint64)(now-start) * device->Frequency / 1000;
avail = (now.tv_sec - start.tv_sec) * device->Frequency;
avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000;
if(avail < done)
{
/* Timer wrapped (50 days???). Add the remainder of the cycle to
* the available count and reset the number of samples done */
avail += (U64(1)<<32)*device->Frequency/1000 - done;
done = 0;
}
if(avail-done < device->UpdateSize)
{
ALuint restTime = (ALuint)((device->UpdateSize - (avail-done)) * 1000 /
device->Frequency);
Sleep(restTime);
continue;
/* Oops, time skipped backwards. Reset the number of samples done
* with one update available since we (likely) just came back from
* sleeping. */
done = avail - device->UpdateSize;
}
do {
if(avail-done < device->UpdateSize)
al_nssleep(0, restTime);
else while(avail-done >= device->UpdateSize)
{
aluMixData(device, NULL, device->UpdateSize);
done += device->UpdateSize;
} while(avail-done >= device->UpdateSize);
}
}
return 0;
@@ -118,7 +128,7 @@ static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name)
return ALC_INVALID_VALUE;
device = STATIC_CAST(ALCbackend, self)->mDevice;
device->DeviceName = strdup(name);
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
@@ -135,32 +145,24 @@ static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
static ALCboolean ALCnullBackend_start(ALCnullBackend *self)
{
if(!StartThread(&self->thread, ALCnullBackend_mixerProc, self))
self->killNow = 0;
if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
static void ALCnullBackend_stop(ALCnullBackend *self)
{
if(!self->thread)
int res;
if(self->killNow)
return;
self->killNow = 1;
StopThread(self->thread);
self->thread = NULL;
self->killNow = 0;
althrd_join(self->thread, &res);
}
static void ALCnullBackend_Delete(ALCnullBackend *self)
{
free(self);
}
DEFINE_ALCBACKEND_VTABLE(ALCnullBackend);
typedef struct ALCnullBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCnullBackendFactory;
@@ -209,14 +211,18 @@ static void ALCnullBackendFactory_probe(ALCnullBackendFactory* UNUSED(self), enu
static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
{
ALCnullBackend *backend;
if(type == ALCbackend_Playback)
{
ALCnullBackend *backend;
assert(type == ALCbackend_Playback);
backend = ALCnullBackend_New(sizeof(*backend));
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
backend = calloc(1, sizeof(*backend));
if(!backend) return NULL;
ALCnullBackend_Construct(backend, device);
ALCnullBackend_Construct(backend, device);
return STATIC_CAST(ALCbackend, backend);
}
return STATIC_CAST(ALCbackend, backend);
return NULL;
}
@@ -28,62 +28,9 @@
#include <SLES/OpenSLES.h>
#if 1
#include <SLES/OpenSLES_Android.h>
#else
extern SLAPIENTRY const SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
struct SLAndroidSimpleBufferQueueItf_;
typedef const struct SLAndroidSimpleBufferQueueItf_ * const * SLAndroidSimpleBufferQueueItf;
typedef void (*slAndroidSimpleBufferQueueCallback)(SLAndroidSimpleBufferQueueItf caller, void *pContext);
typedef struct SLAndroidSimpleBufferQueueState_ {
SLuint32 count;
SLuint32 index;
} SLAndroidSimpleBufferQueueState;
struct SLAndroidSimpleBufferQueueItf_ {
SLresult (*Enqueue) (
SLAndroidSimpleBufferQueueItf self,
const void *pBuffer,
SLuint32 size
);
SLresult (*Clear) (
SLAndroidSimpleBufferQueueItf self
);
SLresult (*GetState) (
SLAndroidSimpleBufferQueueItf self,
SLAndroidSimpleBufferQueueState *pState
);
SLresult (*RegisterCallback) (
SLAndroidSimpleBufferQueueItf self,
slAndroidSimpleBufferQueueCallback callback,
void* pContext
);
};
#define SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE ((SLuint32) 0x800007BD)
typedef struct SLDataLocator_AndroidSimpleBufferQueue {
SLuint32 locatorType;
SLuint32 numBuffers;
} SLDataLocator_AndroidSimpleBufferQueue;
#endif
/* Helper macros */
#define SLObjectItf_Realize(a,b) ((*(a))->Realize((a),(b)))
#define SLObjectItf_GetInterface(a,b,c) ((*(a))->GetInterface((a),(b),(c)))
#define SLObjectItf_Destroy(a) ((*(a))->Destroy((a)))
#define SLEngineItf_CreateOutputMix(a,b,c,d,e) ((*(a))->CreateOutputMix((a),(b),(c),(d),(e)))
#define SLEngineItf_CreateAudioPlayer(a,b,c,d,e,f,g) ((*(a))->CreateAudioPlayer((a),(b),(c),(d),(e),(f),(g)))
#define SLPlayItf_SetPlayState(a,b) ((*(a))->SetPlayState((a),(b)))
/* Should start using these generic callers instead of the name-specific ones above. */
#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
@@ -186,7 +133,7 @@ static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
buf = (ALbyte*)data->buffer + data->curBuffer*data->bufferSize;
aluMixData(Device, buf, data->bufferSize/data->frameSize);
result = (*bq)->Enqueue(bq, buf, data->bufferSize);
result = VCALL(bq,Enqueue)(buf, data->bufferSize);
PRINTERR(result, "bq->Enqueue");
data->curBuffer = (data->curBuffer+1) % Device->NumUpdates;
@@ -212,33 +159,33 @@ static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName
PRINTERR(result, "slCreateEngine");
if(SL_RESULT_SUCCESS == result)
{
result = SLObjectItf_Realize(data->engineObject, SL_BOOLEAN_FALSE);
result = VCALL(data->engineObject,Realize)(SL_BOOLEAN_FALSE);
PRINTERR(result, "engine->Realize");
}
if(SL_RESULT_SUCCESS == result)
{
result = SLObjectItf_GetInterface(data->engineObject, SL_IID_ENGINE, &data->engine);
result = VCALL(data->engineObject,GetInterface)(SL_IID_ENGINE, &data->engine);
PRINTERR(result, "engine->GetInterface");
}
if(SL_RESULT_SUCCESS == result)
{
result = SLEngineItf_CreateOutputMix(data->engine, &data->outputMix, 0, NULL, NULL);
result = VCALL(data->engine,CreateOutputMix)(&data->outputMix, 0, NULL, NULL);
PRINTERR(result, "engine->CreateOutputMix");
}
if(SL_RESULT_SUCCESS == result)
{
result = SLObjectItf_Realize(data->outputMix, SL_BOOLEAN_FALSE);
result = VCALL(data->outputMix,Realize)(SL_BOOLEAN_FALSE);
PRINTERR(result, "outputMix->Realize");
}
if(SL_RESULT_SUCCESS != result)
{
if(data->outputMix != NULL)
SLObjectItf_Destroy(data->outputMix);
VCALL0(data->outputMix,Destroy)();
data->outputMix = NULL;
if(data->engineObject != NULL)
SLObjectItf_Destroy(data->engineObject);
VCALL0(data->engineObject,Destroy)();
data->engineObject = NULL;
data->engine = NULL;
@@ -246,7 +193,7 @@ static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName
return ALC_INVALID_VALUE;
}
Device->DeviceName = strdup(deviceName);
al_string_copy_cstr(&Device->DeviceName, deviceName);
Device->ExtraData = data;
return ALC_NO_ERROR;
@@ -258,13 +205,13 @@ static void opensl_close_playback(ALCdevice *Device)
osl_data *data = Device->ExtraData;
if(data->bufferQueueObject != NULL)
SLObjectItf_Destroy(data->bufferQueueObject);
VCALL0(data->bufferQueueObject,Destroy)();
data->bufferQueueObject = NULL;
SLObjectItf_Destroy(data->outputMix);
VCALL0(data->outputMix,Destroy)();
data->outputMix = NULL;
SLObjectItf_Destroy(data->engineObject);
VCALL0(data->engineObject,Destroy)();
data->engineObject = NULL;
data->engine = NULL;
@@ -321,21 +268,21 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device)
if(data->bufferQueueObject != NULL)
SLObjectItf_Destroy(data->bufferQueueObject);
VCALL0(data->bufferQueueObject,Destroy)();
data->bufferQueueObject = NULL;
result = SLEngineItf_CreateAudioPlayer(data->engine, &data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req);
result = VCALL(data->engine,CreateAudioPlayer)(&data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req);
PRINTERR(result, "engine->CreateAudioPlayer");
if(SL_RESULT_SUCCESS == result)
{
result = SLObjectItf_Realize(data->bufferQueueObject, SL_BOOLEAN_FALSE);
result = VCALL(data->bufferQueueObject,Realize)(SL_BOOLEAN_FALSE);
PRINTERR(result, "bufferQueue->Realize");
}
if(SL_RESULT_SUCCESS != result)
{
if(data->bufferQueueObject != NULL)
SLObjectItf_Destroy(data->bufferQueueObject);
VCALL0(data->bufferQueueObject,Destroy)();
data->bufferQueueObject = NULL;
return ALC_FALSE;
@@ -352,11 +299,11 @@ static ALCboolean opensl_start_playback(ALCdevice *Device)
SLresult result;
ALuint i;
result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_BUFFERQUEUE, &bufferQueue);
result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue);
PRINTERR(result, "bufferQueue->GetInterface");
if(SL_RESULT_SUCCESS == result)
{
result = (*bufferQueue)->RegisterCallback(bufferQueue, opensl_callback, Device);
result = VCALL(bufferQueue,RegisterCallback)(opensl_callback, Device);
PRINTERR(result, "bufferQueue->RegisterCallback");
}
if(SL_RESULT_SUCCESS == result)
@@ -376,26 +323,26 @@ static ALCboolean opensl_start_playback(ALCdevice *Device)
if(SL_RESULT_SUCCESS == result)
{
ALvoid *buf = (ALbyte*)data->buffer + i*data->bufferSize;
result = (*bufferQueue)->Enqueue(bufferQueue, buf, data->bufferSize);
result = VCALL(bufferQueue,Enqueue)(buf, data->bufferSize);
PRINTERR(result, "bufferQueue->Enqueue");
}
}
data->curBuffer = 0;
if(SL_RESULT_SUCCESS == result)
{
result = SLObjectItf_GetInterface(data->bufferQueueObject, SL_IID_PLAY, &player);
result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player);
PRINTERR(result, "bufferQueue->GetInterface");
}
if(SL_RESULT_SUCCESS == result)
{
result = SLPlayItf_SetPlayState(player, SL_PLAYSTATE_PLAYING);
result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
PRINTERR(result, "player->SetPlayState");
}
if(SL_RESULT_SUCCESS != result)
{
if(data->bufferQueueObject != NULL)
SLObjectItf_Destroy(data->bufferQueueObject);
VCALL0(data->bufferQueueObject,Destroy)();
data->bufferQueueObject = NULL;
free(data->buffer);
@@ -78,10 +78,10 @@ typedef struct ALCplaybackOSS {
int data_size;
volatile int killNow;
althread_t thread;
althrd_t thread;
} ALCplaybackOSS;
static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr);
static int ALCplaybackOSS_mixerProc(void *ptr);
static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct)
@@ -95,11 +95,11 @@ static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALCuint, availableSamples)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, unlock)
static void ALCplaybackOSS_Delete(ALCplaybackOSS *self);
DECLARE_DEFAULT_ALLOCATORS(ALCplaybackOSS)
DEFINE_ALCBACKEND_VTABLE(ALCplaybackOSS);
static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr)
static int ALCplaybackOSS_mixerProc(void *ptr)
{
ALCplaybackOSS *self = (ALCplaybackOSS*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -107,7 +107,7 @@ static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr)
ssize_t wrote;
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -131,7 +131,7 @@ static ALuint ALCplaybackOSS_mixerProc(ALvoid *ptr)
break;
}
Sleep(1);
al_nssleep(0, 1000000);
continue;
}
@@ -168,7 +168,7 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
return ALC_INVALID_VALUE;
}
device->DeviceName = strdup(name);
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
@@ -275,7 +275,8 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
self->mix_data = calloc(1, self->data_size);
if(!StartThread(&self->thread, ALCplaybackOSS_mixerProc, self))
self->killNow = 0;
if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success)
{
free(self->mix_data);
self->mix_data = NULL;
@@ -287,14 +288,14 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
{
if(!self->thread)
int res;
if(self->killNow)
return;
self->killNow = 1;
StopThread(self->thread);
self->thread = NULL;
althrd_join(self->thread, &res);
self->killNow = 0;
if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
ERR("Error resetting device: %s\n", strerror(errno));
@@ -302,11 +303,6 @@ static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
self->mix_data = NULL;
}
static void ALCplaybackOSS_Delete(ALCplaybackOSS *self)
{
free(self);
}
typedef struct ALCcaptureOSS {
DERIVE_FROM_TYPE(ALCbackend);
@@ -320,10 +316,10 @@ typedef struct ALCcaptureOSS {
int doCapture;
volatile int killNow;
althread_t thread;
althrd_t thread;
} ALCcaptureOSS;
static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr);
static int ALCcaptureOSS_recordProc(void *ptr);
static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct)
@@ -337,11 +333,11 @@ static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self);
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, lock)
static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, unlock)
static void ALCcaptureOSS_Delete(ALCcaptureOSS *self);
DECLARE_DEFAULT_ALLOCATORS(ALCcaptureOSS)
DEFINE_ALCBACKEND_VTABLE(ALCcaptureOSS);
static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr)
static int ALCcaptureOSS_recordProc(void *ptr)
{
ALCcaptureOSS *self = (ALCcaptureOSS*)ptr;
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -349,7 +345,7 @@ static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr)
int amt;
SetRTPriority();
SetThreadName("alsoft-record");
althrd_setname(althrd_current(), "alsoft-record");
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -366,7 +362,7 @@ static ALuint ALCcaptureOSS_recordProc(ALvoid *ptr)
}
if(amt == 0)
{
Sleep(1);
al_nssleep(0, 1000000);
continue;
}
if(self->doCapture)
@@ -488,7 +484,8 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
self->data_size = info.fragsize;
self->read_data = calloc(1, self->data_size);
if(!StartThread(&self->thread, ALCcaptureOSS_recordProc, self))
self->killNow = 0;
if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success)
{
device->ExtraData = NULL;
close(self->fd);
@@ -496,16 +493,17 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
return ALC_OUT_OF_MEMORY;
}
device->DeviceName = strdup(name);
al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
}
static void ALCcaptureOSS_close(ALCcaptureOSS *self)
{
int res;
self->killNow = 1;
StopThread(self->thread);
self->killNow = 0;
althrd_join(self->thread, &res);
close(self->fd);
self->fd = -1;
@@ -539,12 +537,6 @@ static ALCuint ALCcaptureOSS_availableSamples(ALCcaptureOSS *self)
return RingBufferSize(self->ring);
}
void ALCcaptureOSS_Delete(ALCcaptureOSS *self)
{
free(self);
}
typedef struct ALCossBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
@@ -615,8 +607,9 @@ ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self
{
ALCplaybackOSS *backend;
backend = calloc(1, sizeof(*backend));
backend = ALCplaybackOSS_New(sizeof(*backend));
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCplaybackOSS_Construct(backend, device);
@@ -626,8 +619,9 @@ ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self
{
ALCcaptureOSS *backend;
backend = calloc(1, sizeof(*backend));
backend = ALCcaptureOSS_New(sizeof(*backend));
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCcaptureOSS_Construct(backend, device);
@@ -45,6 +45,7 @@ MAKE_FUNC(Pa_StopStream);
MAKE_FUNC(Pa_OpenStream);
MAKE_FUNC(Pa_CloseStream);
MAKE_FUNC(Pa_GetDefaultOutputDevice);
MAKE_FUNC(Pa_GetDefaultInputDevice);
MAKE_FUNC(Pa_GetStreamInfo);
#undef MAKE_FUNC
@@ -56,6 +57,7 @@ MAKE_FUNC(Pa_GetStreamInfo);
#define Pa_OpenStream pPa_OpenStream
#define Pa_CloseStream pPa_CloseStream
#define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice
#define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice
#define Pa_GetStreamInfo pPa_GetStreamInfo
#endif
@@ -97,6 +99,7 @@ static ALCboolean pa_load(void)
LOAD_FUNC(Pa_OpenStream);
LOAD_FUNC(Pa_CloseStream);
LOAD_FUNC(Pa_GetDefaultOutputDevice);
LOAD_FUNC(Pa_GetDefaultInputDevice);
LOAD_FUNC(Pa_GetStreamInfo);
#undef LOAD_FUNC
@@ -212,7 +215,7 @@ retry_open:
}
device->ExtraData = data;
device->DeviceName = strdup(deviceName);
al_string_copy_cstr(&device->DeviceName, deviceName);
return ALC_NO_ERROR;
}
@@ -318,7 +321,7 @@ static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
data->params.device = -1;
if(!ConfigValueInt("port", "capture", &data->params.device) ||
data->params.device < 0)
data->params.device = Pa_GetDefaultOutputDevice();
data->params.device = Pa_GetDefaultInputDevice();
data->params.suggestedLatency = 0.0f;
data->params.hostApiSpecificStreamInfo = NULL;
@@ -354,7 +357,7 @@ static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
goto error;
}
device->DeviceName = strdup(deviceName);
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
@@ -306,9 +306,6 @@ static ALCboolean pulse_load(void)
static pa_context_flags_t pulse_ctx_flags;
static pa_proplist *prop_filter;
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
/* PulseAudio Event Callbacks */
static void context_state_callback(pa_context *context, void *pdata)
@@ -438,7 +435,9 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
if(stream)
{
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);
@@ -458,20 +457,27 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
typedef struct {
char *name;
char *device_name;
al_string name;
al_string device_name;
} DevMap;
TYPEDEF_VECTOR(DevMap, vector_DevMap)
static DevMap *allDevNameMap;
static ALuint numDevNames;
static DevMap *allCaptureDevNameMap;
static ALuint numCaptureDevNames;
static vector_DevMap PlaybackDevices;
static vector_DevMap CaptureDevices;
static void clear_devlist(vector_DevMap *list)
{
#define DEINIT_STRS(i) (AL_STRING_DEINIT((i)->name),AL_STRING_DEINIT((i)->device_name))
VECTOR_FOR_EACH(DevMap, *list, DEINIT_STRS);
#undef DEINIT_STRS
VECTOR_RESIZE(*list, 0);
}
typedef struct ALCpulsePlayback {
DERIVE_FROM_TYPE(ALCbackend);
char *device_name;
al_string device_name;
pa_buffer_attr attr;
pa_sample_spec spec;
@@ -482,9 +488,8 @@ typedef struct ALCpulsePlayback {
pa_context *context;
volatile ALboolean killNow;
althread_t thread;
althrd_t thread;
} ALCpulsePlayback;
DECLARE_ALCBACKEND_VTABLE(ALCpulsePlayback);
static void ALCpulsePlayback_deviceCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
static void ALCpulsePlayback_probeDevices(void);
@@ -492,6 +497,7 @@ static void ALCpulsePlayback_probeDevices(void);
static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata);
static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata);
static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata);
static void ALCpulsePlayback_streamWriteCallback(pa_stream *p, size_t nbytes, void *userdata);
static void ALCpulsePlayback_sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
static void ALCpulsePlayback_sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata);
@@ -499,10 +505,10 @@ static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, pa_thr
pa_context *context, pa_stream_flags_t flags,
pa_buffer_attr *attr, pa_sample_spec *spec,
pa_channel_map *chanmap);
static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr);
static int ALCpulsePlayback_mixerProc(void *ptr);
static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device);
static DECLARE_FORWARD(ALCpulsePlayback, ALCbackend, void, Destruct)
static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self);
static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name);
static void ALCpulsePlayback_close(ALCpulsePlayback *self);
static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self);
@@ -510,22 +516,34 @@ static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self);
static void ALCpulsePlayback_stop(ALCpulsePlayback *self);
static DECLARE_FORWARD2(ALCpulsePlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
static DECLARE_FORWARD(ALCpulsePlayback, ALCbackend, ALCuint, availableSamples)
static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self);
static void ALCpulsePlayback_lock(ALCpulsePlayback *self);
static void ALCpulsePlayback_unlock(ALCpulsePlayback *self);
DECLARE_DEFAULT_ALLOCATORS(ALCpulsePlayback)
DEFINE_ALCBACKEND_VTABLE(ALCpulsePlayback);
static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCpulsePlayback, ALCbackend, self);
AL_STRING_INIT(self->device_name);
}
static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self)
{
AL_STRING_DEINIT(self->device_name);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
{
pa_threaded_mainloop *loop = pdata;
void *temp;
ALuint i;
const DevMap *iter;
DevMap entry;
if(eol)
{
@@ -533,29 +551,29 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
return;
}
for(i = 0;i < numDevNames;i++)
{
if(strcmp(info->name, allDevNameMap[i].device_name) == 0)
return;
}
#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);
#undef MATCH_INFO_NAME
if(iter != VECTOR_ITER_END(PlaybackDevices))
return;
TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
temp = realloc(allDevNameMap, (numDevNames+1) * sizeof(*allDevNameMap));
if(temp)
{
allDevNameMap = temp;
allDevNameMap[numDevNames].name = strdup(info->description);
allDevNameMap[numDevNames].device_name = strdup(info->name);
numDevNames++;
}
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);
VECTOR_PUSH_BACK(PlaybackDevices, entry);
}
static void ALCpulsePlayback_probeDevices(void)
{
pa_threaded_mainloop *loop;
allDevNameMap = malloc(sizeof(DevMap) * 1);
clear_devlist(&PlaybackDevices);
if((loop=pa_threaded_mainloop_new()) &&
pa_threaded_mainloop_start(loop) >= 0)
{
@@ -634,6 +652,12 @@ static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata)
pa_threaded_mainloop_signal(self->loop, 0);
}
static void ALCpulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata)
{
ALCpulsePlayback *self = pdata;
pa_threaded_mainloop_signal(self->loop, 0);
}
static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
{
ALCpulsePlayback *self = pdata;
@@ -697,8 +721,7 @@ static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const
return;
}
free(device->DeviceName);
device->DeviceName = strdup(info->description);
al_string_copy_cstr(&device->DeviceName, info->description);
}
@@ -706,10 +729,9 @@ static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata)
{
ALCpulsePlayback *self = pdata;
free(self->device_name);
self->device_name = strdup(pa_stream_get_device_name(stream));
al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(stream));
TRACE("Stream moved to %s\n", self->device_name);
TRACE("Stream moved to %s\n", al_string_get_cstr(self->device_name));
}
@@ -754,7 +776,7 @@ static pa_stream *ALCpulsePlayback_connectStream(const char *device_name,
}
static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr)
static int ALCpulsePlayback_mixerProc(void *ptr)
{
ALCpulsePlayback *self = ptr;
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
@@ -764,7 +786,7 @@ static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr)
ssize_t len;
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
pa_threaded_mainloop_lock(self->loop);
frame_size = pa_frame_size(&self->spec);
@@ -785,9 +807,7 @@ static ALuint ALCpulsePlayback_mixerProc(ALvoid *ptr)
o = pa_stream_cork(self->stream, 0, NULL, NULL);
if(o) pa_operation_unref(o);
}
pa_threaded_mainloop_unlock(self->loop);
Sleep(1);
pa_threaded_mainloop_lock(self->loop);
pa_threaded_mainloop_wait(self->loop);
continue;
}
len -= len%update_size;
@@ -828,21 +848,17 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
if(name)
{
ALuint i;
const DevMap *iter;
if(!allDevNameMap)
if(VECTOR_SIZE(PlaybackDevices) == 0)
ALCpulsePlayback_probeDevices();
for(i = 0;i < numDevNames;i++)
{
if(strcmp(name, allDevNameMap[i].name) == 0)
{
pulse_name = allDevNameMap[i].device_name;
break;
}
}
if(i == numDevNames)
#define MATCH_NAME(iter) (al_string_cmp_cstr((iter)->name, name) == 0)
VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
#undef MATCH_NAME
if(iter == VECTOR_ITER_END(PlaybackDevices))
return ALC_INVALID_VALUE;
pulse_name = al_string_get_cstr(iter->device_name);
}
if(!pulse_open(&self->loop, &self->context, ALCpulsePlayback_contextStateCallback, self))
@@ -859,6 +875,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
spec.rate = 44100;
spec.channels = 2;
TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
self->stream = ALCpulsePlayback_connectStream(pulse_name, self->loop, self->context,
flags, NULL, &spec, NULL);
if(!self->stream)
@@ -871,8 +888,9 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
}
pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
self->device_name = strdup(pa_stream_get_device_name(self->stream));
o = pa_context_get_sink_info_by_name(self->context, self->device_name,
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);
@@ -888,16 +906,15 @@ static void ALCpulsePlayback_close(ALCpulsePlayback *self)
self->context = NULL;
self->stream = NULL;
free(self->device_name);
self->device_name = NULL;
al_string_clear(&self->device_name);
}
static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
pa_stream_flags_t flags = 0;
const char *mapname = NULL;
pa_channel_map chanmap;
const char *mapname;
ALuint len;
pa_threaded_mainloop_lock(self->loop);
@@ -917,7 +934,8 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
{
pa_operation *o;
o = pa_context_get_sink_info_by_name(self->context, self->device_name,
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);
}
@@ -964,7 +982,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
return ALC_FALSE;
}
mapname = "(invalid)";
switch(device->FmtChans)
{
case DevFmtMono:
@@ -1003,9 +1020,9 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2);
self->attr.maxlength = -1;
self->stream = ALCpulsePlayback_connectStream(self->device_name, self->loop,
self->context, flags, &self->attr,
&self->spec, &chanmap);
self->stream = ALCpulsePlayback_connectStream(al_string_get_cstr(self->device_name),
self->loop, self->context, flags,
&self->attr, &self->spec, &chanmap);
if(!self->stream)
{
pa_threaded_mainloop_unlock(self->loop);
@@ -1013,6 +1030,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
}
pa_stream_set_state_callback(self->stream, ALCpulsePlayback_streamStateCallback, self);
pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
pa_stream_set_write_callback(self->stream, ALCpulsePlayback_streamWriteCallback, self);
self->spec = *(pa_stream_get_sample_spec(self->stream));
if(device->Frequency != self->spec.rate)
@@ -1054,7 +1072,8 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self)
{
if(!StartThread(&self->thread, ALCpulsePlayback_mixerProc, self))
self->killNow = AL_FALSE;
if(althrd_create(&self->thread, ALCpulsePlayback_mixerProc, self) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
}
@@ -1062,17 +1081,13 @@ static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self)
static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
{
pa_operation *o;
int res;
if(!self->stream)
return;
self->killNow = AL_TRUE;
if(self->thread)
{
StopThread(self->thread);
self->thread = NULL;
}
self->killNow = AL_FALSE;
althrd_join(self->thread, &res);
pa_threaded_mainloop_lock(self->loop);
@@ -1083,6 +1098,27 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
}
static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self)
{
pa_usec_t latency = 0;
int neg, err;
if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0)
{
/* FIXME: if err = -PA_ERR_NODATA, it means we were called too soon
* after starting the stream and no timing info has been received from
* the server yet. Should we wait, possibly stalling the app, or give a
* dummy value? Either way, it shouldn't be 0. */
if(err != -PA_ERR_NODATA)
ERR("Failed to get stream latency: 0x%x\n", err);
return 0;
}
if(neg) latency = 0;
return (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000;
}
static void ALCpulsePlayback_lock(ALCpulsePlayback *self)
{
pa_threaded_mainloop_lock(self->loop);
@@ -1094,34 +1130,10 @@ static void ALCpulsePlayback_unlock(ALCpulsePlayback *self)
}
static ALint64 ALCpulsePlayback_getLatency(ALCpulsePlayback *self)
{
pa_usec_t latency = 0;
int neg;
if(pa_stream_get_latency(self->stream, &latency, &neg) != 0)
{
ERR("Failed to get stream latency!\n");
return 0;
}
if(neg) latency = 0;
return (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000;
}
static void ALCpulsePlayback_Delete(ALCpulsePlayback *self)
{
free(self);
}
DEFINE_ALCBACKEND_VTABLE(ALCpulsePlayback);
typedef struct ALCpulseCapture {
DERIVE_FROM_TYPE(ALCbackend);
char *device_name;
al_string device_name;
const void *cap_store;
size_t cap_len;
@@ -1137,7 +1149,6 @@ typedef struct ALCpulseCapture {
pa_stream *stream;
pa_context *context;
} ALCpulseCapture;
DECLARE_ALCBACKEND_VTABLE(ALCpulseCapture);
static void ALCpulseCapture_deviceCallback(pa_context *context, const pa_source_info *info, int eol, void *pdata);
static void ALCpulseCapture_probeDevices(void);
@@ -1152,7 +1163,7 @@ static pa_stream *ALCpulseCapture_connectStream(const char *device_name,
pa_sample_spec *spec, pa_channel_map *chanmap);
static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device);
static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, void, Destruct)
static void ALCpulseCapture_Destruct(ALCpulseCapture *self);
static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name);
static void ALCpulseCapture_close(ALCpulseCapture *self);
static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, ALCboolean, reset)
@@ -1160,22 +1171,34 @@ static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self);
static void ALCpulseCapture_stop(ALCpulseCapture *self);
static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples);
static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self);
static ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self);
static void ALCpulseCapture_lock(ALCpulseCapture *self);
static void ALCpulseCapture_unlock(ALCpulseCapture *self);
DECLARE_DEFAULT_ALLOCATORS(ALCpulseCapture)
DEFINE_ALCBACKEND_VTABLE(ALCpulseCapture);
static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
SET_VTABLE2(ALCpulseCapture, ALCbackend, self);
AL_STRING_INIT(self->device_name);
}
static void ALCpulseCapture_Destruct(ALCpulseCapture *self)
{
AL_STRING_DEINIT(self->device_name);
ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata)
{
pa_threaded_mainloop *loop = pdata;
void *temp;
ALuint i;
const DevMap *iter;
DevMap entry;
if(eol)
{
@@ -1183,29 +1206,29 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
return;
}
for(i = 0;i < numCaptureDevNames;i++)
{
if(strcmp(info->name, allCaptureDevNameMap[i].device_name) == 0)
return;
}
#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);
#undef MATCH_INFO_NAME
if(iter != VECTOR_ITER_END(CaptureDevices))
return;
TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
if(temp)
{
allCaptureDevNameMap = temp;
allCaptureDevNameMap[numCaptureDevNames].name = strdup(info->description);
allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
numCaptureDevNames++;
}
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);
VECTOR_PUSH_BACK(CaptureDevices, entry);
}
static void ALCpulseCapture_probeDevices(void)
{
pa_threaded_mainloop *loop;
allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
clear_devlist(&CaptureDevices);
if((loop=pa_threaded_mainloop_new()) &&
pa_threaded_mainloop_start(loop) >= 0)
{
@@ -1288,8 +1311,7 @@ static void ALCpulseCapture_sourceNameCallback(pa_context *UNUSED(context), cons
return;
}
free(device->DeviceName);
device->DeviceName = strdup(info->description);
al_string_copy_cstr(&device->DeviceName, info->description);
}
@@ -1297,10 +1319,9 @@ static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata)
{
ALCpulseCapture *self = pdata;
free(self->device_name);
self->device_name = strdup(pa_stream_get_device_name(stream));
al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(stream));
TRACE("Stream moved to %s\n", self->device_name);
TRACE("Stream moved to %s\n", al_string_get_cstr(self->device_name));
}
@@ -1356,21 +1377,17 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
if(name)
{
ALuint i;
const DevMap *iter;
if(!allCaptureDevNameMap)
if(VECTOR_SIZE(CaptureDevices) == 0)
ALCpulseCapture_probeDevices();
for(i = 0;i < numCaptureDevNames;i++)
{
if(strcmp(name, allCaptureDevNameMap[i].name) == 0)
{
pulse_name = allCaptureDevNameMap[i].device_name;
break;
}
}
if(i == numCaptureDevNames)
#define MATCH_NAME(iter) (al_string_cmp_cstr((iter)->name, name) == 0)
VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
#undef MATCH_NAME
if(iter == VECTOR_ITER_END(CaptureDevices))
return ALC_INVALID_VALUE;
pulse_name = al_string_get_cstr(iter->device_name);
}
if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self))
@@ -1431,6 +1448,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
if(!GetConfigValueBool("pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
self->stream = ALCpulseCapture_connectStream(pulse_name, self->loop, self->context,
flags, &self->attr, &self->spec,
&chanmap);
@@ -1442,8 +1460,9 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
pa_stream_set_moved_callback(self->stream, ALCpulseCapture_streamMovedCallback, self);
pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self);
self->device_name = strdup(pa_stream_get_device_name(self->stream));
o = pa_context_get_source_info_by_name(self->context, self->device_name,
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);
@@ -1466,8 +1485,7 @@ static void ALCpulseCapture_close(ALCpulseCapture *self)
self->context = NULL;
self->stream = NULL;
free(self->device_name);
self->device_name = NULL;
al_string_clear(&self->device_name);
}
static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self)
@@ -1562,17 +1580,6 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self)
}
static void ALCpulseCapture_lock(ALCpulseCapture *self)
{
pa_threaded_mainloop_lock(self->loop);
}
static void ALCpulseCapture_unlock(ALCpulseCapture *self)
{
pa_threaded_mainloop_unlock(self->loop);
}
static ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self)
{
pa_usec_t latency = 0;
@@ -1589,23 +1596,43 @@ static ALint64 ALCpulseCapture_getLatency(ALCpulseCapture *self)
}
static void ALCpulseCapture_Delete(ALCpulseCapture *self)
static void ALCpulseCapture_lock(ALCpulseCapture *self)
{
free(self);
pa_threaded_mainloop_lock(self->loop);
}
DEFINE_ALCBACKEND_VTABLE(ALCpulseCapture);
static void ALCpulseCapture_unlock(ALCpulseCapture *self)
{
pa_threaded_mainloop_unlock(self->loop);
}
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;
#define ALCPULSEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCpulseBackendFactory, ALCbackendFactory) } }
static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory *self);
static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory *self);
static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory *self, ALCbackend_Type type);
static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory *self, enum DevProbe type);
static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory);
static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(self))
{
ALCboolean ret = ALC_FALSE;
VECTOR_INIT(PlaybackDevices);
VECTOR_INIT(CaptureDevices);
if(pulse_load())
{
pa_threaded_mainloop *loop;
@@ -1648,25 +1675,11 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel
static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self))
{
ALuint i;
clear_devlist(&PlaybackDevices);
VECTOR_DEINIT(PlaybackDevices);
for(i = 0;i < numDevNames;++i)
{
free(allDevNameMap[i].name);
free(allDevNameMap[i].device_name);
}
free(allDevNameMap);
allDevNameMap = NULL;
numDevNames = 0;
for(i = 0;i < numCaptureDevNames;++i)
{
free(allCaptureDevNameMap[i].name);
free(allCaptureDevNameMap[i].device_name);
}
free(allCaptureDevNameMap);
allCaptureDevNameMap = NULL;
numCaptureDevNames = 0;
clear_devlist(&CaptureDevices);
VECTOR_DEINIT(CaptureDevices);
if(prop_filter)
pa_proplist_free(prop_filter);
@@ -1684,40 +1697,16 @@ static ALCboolean ALCpulseBackendFactory_querySupport(ALCpulseBackendFactory* UN
static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), enum DevProbe type)
{
ALuint i;
switch(type)
{
case ALL_DEVICE_PROBE:
for(i = 0;i < numDevNames;++i)
{
free(allDevNameMap[i].name);
free(allDevNameMap[i].device_name);
}
free(allDevNameMap);
allDevNameMap = NULL;
numDevNames = 0;
ALCpulsePlayback_probeDevices();
for(i = 0;i < numDevNames;i++)
AppendAllDevicesList(allDevNameMap[i].name);
VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
for(i = 0;i < numCaptureDevNames;++i)
{
free(allCaptureDevNameMap[i].name);
free(allCaptureDevNameMap[i].device_name);
}
free(allCaptureDevNameMap);
allCaptureDevNameMap = NULL;
numCaptureDevNames = 0;
ALCpulseCapture_probeDevices();
for(i = 0;i < numCaptureDevNames;i++)
AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
}
}
@@ -1728,8 +1717,9 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
{
ALCpulsePlayback *backend;
backend = calloc(1, sizeof(*backend));
backend = ALCpulsePlayback_New(sizeof(*backend));
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCpulsePlayback_Construct(backend, device);
@@ -1739,8 +1729,9 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
{
ALCpulseCapture *backend;
backend = calloc(1, sizeof(*backend));
backend = ALCpulseCapture_New(sizeof(*backend));
if(!backend) return NULL;
memset(backend, 0, sizeof(*backend));
ALCpulseCapture_Construct(backend, device);
@@ -1750,8 +1741,6 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
return NULL;
}
DEFINE_ALCBACKENDFACTORY_VTABLE(ALCpulseBackendFactory);
#else /* PA_API_VERSION == 12 */
@@ -34,8 +34,7 @@
#include "threads.h"
typedef struct
{
typedef struct {
snd_pcm_t* pcmHandle;
int audio_fd;
@@ -46,27 +45,24 @@ typedef struct
ALsizei size;
volatile int killNow;
althread_t thread;
althrd_t thread;
} qsa_data;
typedef struct
{
typedef struct {
ALCchar* name;
int card;
int dev;
} DevMap;
static const ALCchar qsaDevice[]="QSA Default";
static const ALCchar qsaDevice[] = "QSA Default";
static DevMap* allDevNameMap;
static ALuint numDevNames;
static DevMap* allCaptureDevNameMap;
static ALuint numCaptureDevNames;
static const struct
{
static const struct {
int32_t format;
} formatlist[]=
{
} formatlist[] = {
{SND_PCM_SFMT_FLOAT_LE},
{SND_PCM_SFMT_S32_LE},
{SND_PCM_SFMT_U32_LE},
@@ -77,11 +73,9 @@ static const struct
{0},
};
static const struct
{
static const struct {
int32_t rate;
} ratelist[]=
{
} ratelist[] = {
{192000},
{176400},
{96000},
@@ -98,11 +92,9 @@ static const struct
{0},
};
static const struct
{
static const struct {
int32_t channels;
} channellist[]=
{
} channellist[] = {
{8},
{7},
{6},
@@ -112,7 +104,7 @@ static const struct
{0},
};
static DevMap* deviceList(int type, ALuint* count)
static DevMap *deviceList(int type, ALuint *count)
{
snd_ctl_t* handle;
snd_pcm_info_t pcminfo;
@@ -178,7 +170,7 @@ static DevMap* deviceList(int type, ALuint* count)
}
FORCE_ALIGN static ALuint qsa_proc_playback(ALvoid* ptr)
FORCE_ALIGN static int qsa_proc_playback(void* ptr)
{
ALCdevice* device=(ALCdevice*)ptr;
qsa_data* data=(qsa_data*)device->ExtraData;
@@ -191,7 +183,7 @@ FORCE_ALIGN static ALuint qsa_proc_playback(ALvoid* ptr)
struct timeval timeout;
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
/* Increase default 10 priority to 11 to avoid jerky sound */
SchedGet(0, 0, &param);
@@ -343,8 +335,8 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
return ALC_INVALID_DEVICE;
}
device->DeviceName=strdup(deviceName);
device->ExtraData=data;
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
}
@@ -616,7 +608,8 @@ static ALCboolean qsa_start_playback(ALCdevice* device)
{
qsa_data *data = (qsa_data*)device->ExtraData;
if(!StartThread(&data->thread, qsa_proc_playback, device))
data->killNow = 0;
if(althrd_create(&data->thread, qsa_proc_playback, device) != althrd_success)
return ALC_FALSE;
return ALC_TRUE;
@@ -624,15 +617,14 @@ static ALCboolean qsa_start_playback(ALCdevice* device)
static void qsa_stop_playback(ALCdevice* device)
{
qsa_data* data=(qsa_data*)device->ExtraData;
qsa_data *data = (qsa_data*)device->ExtraData;
int res;
if (data->thread)
{
data->killNow=1;
StopThread(data->thread);
data->thread=NULL;
}
data->killNow=0;
if(data->killNow)
return;
data->killNow = 1;
althrd_join(data->thread, &res);
}
/***********/
@@ -711,8 +703,8 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
return ALC_INVALID_DEVICE;
}
device->DeviceName=strdup(deviceName);
device->ExtraData=data;
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
switch (device->FmtType)
{
@@ -47,11 +47,11 @@ typedef struct {
ALsizei data_size;
volatile int killNow;
althread_t thread;
althrd_t thread;
} sndio_data;
static ALuint sndio_proc(ALvoid *ptr)
static int sndio_proc(void *ptr)
{
ALCdevice *device = ptr;
sndio_data *data = device->ExtraData;
@@ -59,7 +59,7 @@ static ALuint sndio_proc(ALvoid *ptr)
size_t wrote;
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -111,7 +111,7 @@ static ALCenum sndio_open_playback(ALCdevice *device, const ALCchar *deviceName)
return ALC_INVALID_VALUE;
}
device->DeviceName = strdup(deviceName);
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
@@ -224,7 +224,8 @@ static ALCboolean sndio_start_playback(ALCdevice *device)
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
if(!StartThread(&data->thread, sndio_proc, device))
data->killNow = 0;
if(althrd_create(&data->thread, sndio_proc, device) != althrd_success)
{
sio_stop(data->sndHandle);
free(data->mix_data);
@@ -238,15 +239,14 @@ static ALCboolean sndio_start_playback(ALCdevice *device)
static void sndio_stop_playback(ALCdevice *device)
{
sndio_data *data = device->ExtraData;
int res;
if(!data->thread)
if(data->killNow)
return;
data->killNow = 1;
StopThread(data->thread);
data->thread = NULL;
althrd_join(data->thread, &res);
data->killNow = 0;
if(!sio_stop(data->sndHandle))
ERR("Error stopping device\n");
@@ -50,11 +50,11 @@ typedef struct {
int data_size;
volatile int killNow;
althread_t thread;
althrd_t thread;
} solaris_data;
static ALuint SolarisProc(ALvoid *ptr)
static int SolarisProc(void *ptr)
{
ALCdevice *Device = (ALCdevice*)ptr;
solaris_data *data = (solaris_data*)Device->ExtraData;
@@ -62,7 +62,7 @@ static ALuint SolarisProc(ALvoid *ptr)
int wrote;
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
@@ -86,7 +86,7 @@ static ALuint SolarisProc(ALvoid *ptr)
break;
}
Sleep(1);
al_nssleep(0, 1000000);
continue;
}
@@ -119,7 +119,7 @@ static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceNam
return ALC_INVALID_VALUE;
}
device->DeviceName = strdup(deviceName);
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
}
@@ -211,7 +211,8 @@ static ALCboolean solaris_start_playback(ALCdevice *device)
data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
data->mix_data = calloc(1, data->data_size);
if(!StartThread(&data->thread, SolarisProc, device))
data->killNow = 0;
if(althrd_create(&data->thread, SolarisProc, device) != althrd_success)
{
free(data->mix_data);
data->mix_data = NULL;
@@ -224,15 +225,14 @@ static ALCboolean solaris_start_playback(ALCdevice *device)
static void solaris_stop_playback(ALCdevice *device)
{
solaris_data *data = (solaris_data*)device->ExtraData;
int res;
if(!data->thread)
if(data->killNow)
return;
data->killNow = 1;
StopThread(data->thread);
data->thread = NULL;
althrd_join(data->thread, &res);
data->killNow = 0;
if(ioctl(data->fd, AUDIO_DRAIN) < 0)
ERR("Error draining device: %s\n", strerror(errno));
@@ -42,7 +42,7 @@ typedef struct {
ALuint size;
volatile int killNow;
althread_t thread;
althrd_t thread;
} wave_data;
@@ -85,49 +85,55 @@ static void fwrite32le(ALuint val, FILE *f)
}
static ALuint WaveProc(ALvoid *ptr)
static int WaveProc(void *ptr)
{
ALCdevice *Device = (ALCdevice*)ptr;
wave_data *data = (wave_data*)Device->ExtraData;
ALCdevice *device = (ALCdevice*)ptr;
wave_data *data = (wave_data*)device->ExtraData;
struct timespec now, start;
ALint64 avail, done;
ALuint frameSize;
ALuint now, start;
ALuint64 avail, done;
size_t fs;
const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 /
Device->Frequency / 2;
const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 /
device->Frequency / 2);
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
done = 0;
start = timeGetTime();
while(!data->killNow && Device->Connected)
if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
{
now = timeGetTime();
ERR("Failed to get starting time\n");
return 1;
}
while(!data->killNow && device->Connected)
{
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
ERR("Failed to get current time\n");
return 1;
}
avail = (ALuint64)(now-start) * Device->Frequency / 1000;
avail = (now.tv_sec - start.tv_sec) * device->Frequency;
avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000;
if(avail < done)
{
/* Timer wrapped (50 days???). Add the remainder of the cycle to
* the available count and reset the number of samples done */
avail += ((ALuint64)1<<32)*Device->Frequency/1000 - done;
done = 0;
}
if(avail-done < Device->UpdateSize)
{
Sleep(restTime);
continue;
/* Oops, time skipped backwards. Reset the number of samples done
* with one update available since we (likely) just came back from
* sleeping. */
done = avail - device->UpdateSize;
}
while(avail-done >= Device->UpdateSize)
if(avail-done < device->UpdateSize)
al_nssleep(0, restTime);
else while(avail-done >= device->UpdateSize)
{
aluMixData(Device, data->buffer, Device->UpdateSize);
done += Device->UpdateSize;
aluMixData(device, data->buffer, device->UpdateSize);
done += device->UpdateSize;
if(!IS_LITTLE_ENDIAN)
{
ALuint bytesize = BytesFromDevFmt(Device->FmtType);
ALuint bytesize = BytesFromDevFmt(device->FmtType);
ALubyte *bytes = data->buffer;
ALuint i;
@@ -149,16 +155,16 @@ static ALuint WaveProc(ALvoid *ptr)
}
else
{
fs = fwrite(data->buffer, frameSize, Device->UpdateSize,
fs = fwrite(data->buffer, frameSize, device->UpdateSize,
data->f);
(void)fs;
}
if(ferror(data->f))
{
ERR("Error writing to file\n");
ALCdevice_Lock(Device);
aluHandleDisconnect(Device);
ALCdevice_Unlock(Device);
ALCdevice_Lock(device);
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
break;
}
}
@@ -183,7 +189,7 @@ static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
data = (wave_data*)calloc(1, sizeof(wave_data));
data->f = fopen(fname, "wb");
data->f = al_fopen(fname, "wb");
if(!data->f)
{
free(data);
@@ -191,7 +197,7 @@ static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
return ALC_INVALID_VALUE;
}
device->DeviceName = strdup(deviceName);
al_string_copy_cstr(&device->DeviceName, deviceName);
device->ExtraData = data;
return ALC_NO_ERROR;
}
@@ -291,7 +297,8 @@ static ALCboolean wave_start_playback(ALCdevice *device)
return ALC_FALSE;
}
if(!StartThread(&data->thread, WaveProc, device))
data->killNow = 0;
if(althrd_create(&data->thread, WaveProc, device) != althrd_success)
{
free(data->buffer);
data->buffer = NULL;
@@ -306,15 +313,13 @@ static void wave_stop_playback(ALCdevice *device)
wave_data *data = (wave_data*)device->ExtraData;
ALuint dataLen;
long size;
int res;
if(!data->thread)
if(data->killNow)
return;
data->killNow = 1;
StopThread(data->thread);
data->thread = NULL;
data->killNow = 0;
althrd_join(data->thread, &res);
free(data->buffer);
data->buffer = NULL;
@@ -39,10 +39,9 @@
typedef struct {
// MMSYSTEM Device
volatile ALboolean killNow;
HANDLE WaveThreadEvent;
HANDLE WaveThread;
DWORD WaveThreadID;
volatile LONG WaveBuffersCommitted;
althrd_t thread;
RefCount WaveBuffersCommitted;
WAVEHDR WaveBuffer[4];
union {
@@ -56,87 +55,102 @@ typedef struct {
} WinMMData;
static ALCchar **PlaybackDeviceList;
static ALuint NumPlaybackDevices;
static ALCchar **CaptureDeviceList;
static ALuint NumCaptureDevices;
TYPEDEF_VECTOR(al_string, vector_al_string)
static vector_al_string PlaybackDevices;
static vector_al_string CaptureDevices;
static void clear_devlist(vector_al_string *list)
{
VECTOR_FOR_EACH(al_string, *list, al_string_deinit);
VECTOR_RESIZE(*list, 0);
}
static void ProbePlaybackDevices(void)
{
al_string *iter, *end;
ALuint numdevs;
ALuint i;
for(i = 0;i < NumPlaybackDevices;i++)
free(PlaybackDeviceList[i]);
clear_devlist(&PlaybackDevices);
NumPlaybackDevices = waveOutGetNumDevs();
PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices);
for(i = 0;i < NumPlaybackDevices;i++)
numdevs = waveOutGetNumDevs();
VECTOR_RESERVE(PlaybackDevices, numdevs);
for(i = 0;i < numdevs;i++)
{
WAVEOUTCAPS WaveCaps;
WAVEOUTCAPSW WaveCaps;
al_string dname;
PlaybackDeviceList[i] = NULL;
if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
AL_STRING_INIT(dname);
if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
{
char name[1024];
ALuint count, j;
count = 0;
ALuint count = 0;
do {
if(count == 0)
snprintf(name, sizeof(name), "%s", WaveCaps.szPname);
else
snprintf(name, sizeof(name), "%s #%d", WaveCaps.szPname, count+1);
al_string_copy_wcstr(&dname, WaveCaps.szPname);
if(count != 0)
{
char str[64];
snprintf(str, sizeof(str), " #%d", count+1);
al_string_append_cstr(&dname, str);
}
count++;
for(j = 0;j < i;j++)
iter = VECTOR_ITER_BEGIN(PlaybackDevices);
end = VECTOR_ITER_END(PlaybackDevices);
for(;iter != end;iter++)
{
if(strcmp(name, PlaybackDeviceList[j]) == 0)
if(al_string_cmp(*iter, dname) == 0)
break;
}
} while(j != i);
} while(iter != end);
PlaybackDeviceList[i] = strdup(name);
TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
}
VECTOR_PUSH_BACK(PlaybackDevices, dname);
}
}
static void ProbeCaptureDevices(void)
{
al_string *iter, *end;
ALuint numdevs;
ALuint i;
for(i = 0;i < NumCaptureDevices;i++)
free(CaptureDeviceList[i]);
clear_devlist(&CaptureDevices);
NumCaptureDevices = waveInGetNumDevs();
CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);
for(i = 0;i < NumCaptureDevices;i++)
numdevs = waveInGetNumDevs();
VECTOR_RESERVE(CaptureDevices, numdevs);
for(i = 0;i < numdevs;i++)
{
WAVEINCAPS WaveInCaps;
WAVEINCAPSW WaveCaps;
al_string dname;
CaptureDeviceList[i] = NULL;
if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
AL_STRING_INIT(dname);
if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
{
char name[1024];
ALuint count, j;
count = 0;
ALuint count = 0;
do {
if(count == 0)
snprintf(name, sizeof(name), "%s", WaveInCaps.szPname);
else
snprintf(name, sizeof(name), "%s #%d", WaveInCaps.szPname, count+1);
al_string_copy_wcstr(&dname, WaveCaps.szPname);
if(count != 0)
{
char str[64];
snprintf(str, sizeof(str), " #%d", count+1);
al_string_append_cstr(&dname, str);
}
count++;
for(j = 0;j < i;j++)
iter = VECTOR_ITER_BEGIN(CaptureDevices);
end = VECTOR_ITER_END(CaptureDevices);
for(;iter != end;iter++)
{
if(strcmp(name, CaptureDeviceList[j]) == 0)
if(al_string_cmp(*iter, dname) == 0)
break;
}
} while(j != i);
} while(iter != end);
CaptureDeviceList[i] = strdup(name);
TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
}
VECTOR_PUSH_BACK(CaptureDevices, dname);
}
}
@@ -155,28 +169,19 @@ static void CALLBACK WaveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR in
if(msg != WOM_DONE)
return;
InterlockedDecrement(&data->WaveBuffersCommitted);
PostThreadMessage(data->WaveThreadID, msg, 0, param1);
DecrementRef(&data->WaveBuffersCommitted);
PostThreadMessage(data->thread, msg, 0, param1);
}
/*
PlaybackThreadProc
Used by "MMSYSTEM" Device. Called when a WaveOut buffer has used up its
audio data.
*/
FORCE_ALIGN static DWORD WINAPI PlaybackThreadProc(LPVOID param)
FORCE_ALIGN static int PlaybackThreadProc(void *arg)
{
ALCdevice *Device = (ALCdevice*)param;
ALCdevice *Device = (ALCdevice*)arg;
WinMMData *data = Device->ExtraData;
LPWAVEHDR WaveHdr;
ALuint FrameSize;
WAVEHDR *WaveHdr;
MSG msg;
FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
SetRTPriority();
SetThreadName(MIXER_THREAD_NAME);
althrd_setname(althrd_current(), MIXER_THREAD_NAME);
while(GetMessage(&msg, NULL, 0, 0))
{
@@ -185,24 +190,20 @@ FORCE_ALIGN static DWORD WINAPI PlaybackThreadProc(LPVOID param)
if(data->killNow)
{
if(data->WaveBuffersCommitted == 0)
if(ReadRef(&data->WaveBuffersCommitted) == 0)
break;
continue;
}
WaveHdr = ((LPWAVEHDR)msg.lParam);
aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength/FrameSize);
WaveHdr = ((WAVEHDR*)msg.lParam);
aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength /
data->Format.nBlockAlign);
// Send buffer back to play more data
waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR));
InterlockedIncrement(&data->WaveBuffersCommitted);
IncrementRef(&data->WaveBuffersCommitted);
}
// Signal Wave Thread completed event
if(data->WaveThreadEvent)
SetEvent(data->WaveThreadEvent);
ExitThread(0);
return 0;
}
@@ -220,26 +221,18 @@ static void CALLBACK WaveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR inst
if(msg != WIM_DATA)
return;
InterlockedDecrement(&data->WaveBuffersCommitted);
PostThreadMessage(data->WaveThreadID, msg, 0, param1);
DecrementRef(&data->WaveBuffersCommitted);
PostThreadMessage(data->thread, msg, 0, param1);
}
/*
CaptureThreadProc
Used by "MMSYSTEM" Device. Called when a WaveIn buffer had been filled with new
audio data.
*/
static DWORD WINAPI CaptureThreadProc(LPVOID param)
static int CaptureThreadProc(void *arg)
{
ALCdevice *Device = (ALCdevice*)param;
ALCdevice *Device = (ALCdevice*)arg;
WinMMData *data = Device->ExtraData;
LPWAVEHDR WaveHdr;
ALuint FrameSize;
WAVEHDR *WaveHdr;
MSG msg;
FrameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
SetThreadName("alsoft-record");
althrd_setname(althrd_current(), "alsoft-record");
while(GetMessage(&msg, NULL, 0, 0))
{
@@ -250,19 +243,15 @@ static DWORD WINAPI CaptureThreadProc(LPVOID param)
if(data->killNow)
break;
WaveHdr = ((LPWAVEHDR)msg.lParam);
WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData, WaveHdr->dwBytesRecorded/FrameSize);
WaveHdr = ((WAVEHDR*)msg.lParam);
WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData,
WaveHdr->dwBytesRecorded/data->Format.nBlockAlign);
// Send buffer back to capture more data
waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR));
InterlockedIncrement(&data->WaveBuffersCommitted);
IncrementRef(&data->WaveBuffersCommitted);
}
// Signal Wave Thread completed event
if(data->WaveThreadEvent)
SetEvent(data->WaveThreadEvent);
ExitThread(0);
return 0;
}
@@ -270,24 +259,26 @@ static DWORD WINAPI CaptureThreadProc(LPVOID param)
static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName)
{
WinMMData *data = NULL;
UINT DeviceID = 0;
const al_string *iter, *end;
UINT DeviceID;
MMRESULT res;
ALuint i = 0;
if(!PlaybackDeviceList)
if(VECTOR_SIZE(PlaybackDevices) == 0)
ProbePlaybackDevices();
// Find the Device ID matching the deviceName if valid
for(i = 0;i < NumPlaybackDevices;i++)
iter = VECTOR_ITER_BEGIN(PlaybackDevices);
end = VECTOR_ITER_END(PlaybackDevices);
for(;iter != end;iter++)
{
if(PlaybackDeviceList[i] &&
(!deviceName || strcmp(deviceName, PlaybackDeviceList[i]) == 0))
if(!al_string_empty(*iter) &&
(!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
{
DeviceID = i;
DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices));
break;
}
}
if(i == NumPlaybackDevices)
if(iter == end)
return ALC_INVALID_VALUE;
data = calloc(1, sizeof(*data));
@@ -329,20 +320,10 @@ retry_open:
goto failure;
}
data->WaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(data->WaveThreadEvent == NULL)
{
ERR("CreateEvent failed: %lu\n", GetLastError());
goto failure;
}
Device->DeviceName = strdup(PlaybackDeviceList[DeviceID]);
al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
return ALC_NO_ERROR;
failure:
if(data->WaveThreadEvent)
CloseHandle(data->WaveThreadEvent);
if(data->WaveHandle.Out)
waveOutClose(data->WaveHandle.Out);
@@ -356,9 +337,6 @@ static void WinMMClosePlayback(ALCdevice *device)
WinMMData *data = (WinMMData*)device->ExtraData;
// Close the Wave device
CloseHandle(data->WaveThreadEvent);
data->WaveThreadEvent = 0;
waveOutClose(data->WaveHandle.Out);
data->WaveHandle.Out = 0;
@@ -426,11 +404,11 @@ static ALCboolean WinMMStartPlayback(ALCdevice *device)
ALint BufferSize;
ALuint i;
data->WaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &data->WaveThreadID);
if(data->WaveThread == NULL)
data->killNow = AL_FALSE;
if(althrd_create(&data->thread, PlaybackThreadProc, device) != althrd_success)
return ALC_FALSE;
data->WaveBuffersCommitted = 0;
InitRef(&data->WaveBuffersCommitted, 0);
// Create 4 Buffers
BufferSize = device->UpdateSize*device->NumUpdates / 4;
@@ -441,12 +419,12 @@ static ALCboolean WinMMStartPlayback(ALCdevice *device)
{
memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
data->WaveBuffer[i].dwBufferLength = BufferSize;
data->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
(data->WaveBuffer[i-1].lpData +
data->WaveBuffer[i-1].dwBufferLength));
waveOutPrepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR));
waveOutWrite(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR));
InterlockedIncrement(&data->WaveBuffersCommitted);
IncrementRef(&data->WaveBuffersCommitted);
}
return ALC_TRUE;
@@ -458,19 +436,12 @@ static void WinMMStopPlayback(ALCdevice *device)
void *buffer = NULL;
int i;
if(data->WaveThread == NULL)
if(data->killNow)
return;
// Set flag to stop processing headers
data->killNow = AL_TRUE;
// Wait for signal that Wave Thread has been destroyed
WaitForSingleObjectEx(data->WaveThreadEvent, 5000, FALSE);
CloseHandle(data->WaveThread);
data->WaveThread = 0;
data->killNow = AL_FALSE;
althrd_join(data->thread, &i);
// Release the wave buffers
for(i = 0;i < 4;i++)
@@ -485,28 +456,31 @@ static void WinMMStopPlayback(ALCdevice *device)
static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
{
const al_string *iter, *end;
ALbyte *BufferData = NULL;
DWORD CapturedDataSize;
WinMMData *data = NULL;
UINT DeviceID = 0;
ALint BufferSize;
UINT DeviceID;
MMRESULT res;
ALuint i;
if(!CaptureDeviceList)
if(VECTOR_SIZE(CaptureDevices) == 0)
ProbeCaptureDevices();
// Find the Device ID matching the deviceName if valid
for(i = 0;i < NumCaptureDevices;i++)
iter = VECTOR_ITER_BEGIN(CaptureDevices);
end = VECTOR_ITER_END(CaptureDevices);
for(;iter != end;iter++)
{
if(CaptureDeviceList[i] &&
(!deviceName || strcmp(deviceName, CaptureDeviceList[i]) == 0))
if(!al_string_empty(*iter) &&
(!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
{
DeviceID = i;
DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices));
break;
}
}
if(i == NumCaptureDevices)
if(iter == end)
return ALC_INVALID_VALUE;
switch(Device->FmtChans)
@@ -560,13 +534,6 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
goto failure;
}
data->WaveThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(data->WaveThreadEvent == NULL)
{
ERR("CreateEvent failed: %lu\n", GetLastError());
goto failure;
}
// Allocate circular memory buffer for the captured audio
CapturedDataSize = Device->UpdateSize*Device->NumUpdates;
@@ -578,7 +545,7 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
if(!data->Ring)
goto failure;
data->WaveBuffersCommitted = 0;
InitRef(&data->WaveBuffersCommitted, 0);
// Create 4 Buffers of 50ms each
BufferSize = data->Format.nAvgBytesPerSec / 20;
@@ -592,27 +559,23 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
{
memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
data->WaveBuffer[i].dwBufferLength = BufferSize;
data->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
(data->WaveBuffer[i-1].lpData +
data->WaveBuffer[i-1].dwBufferLength));
data->WaveBuffer[i].dwFlags = 0;
data->WaveBuffer[i].dwLoops = 0;
waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
InterlockedIncrement(&data->WaveBuffersCommitted);
IncrementRef(&data->WaveBuffersCommitted);
}
data->WaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)Device, 0, &data->WaveThreadID);
if (data->WaveThread == NULL)
if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success)
goto failure;
Device->DeviceName = strdup(CaptureDeviceList[DeviceID]);
al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
return ALC_NO_ERROR;
failure:
if(data->WaveThread)
CloseHandle(data->WaveThread);
if(BufferData)
{
for(i = 0;i < 4;i++)
@@ -623,9 +586,6 @@ failure:
if(data->Ring)
DestroyRingBuffer(data->Ring);
if(data->WaveThreadEvent)
CloseHandle(data->WaveThreadEvent);
if(data->WaveHandle.In)
waveInClose(data->WaveHandle.In);
@@ -642,16 +602,13 @@ static void WinMMCloseCapture(ALCdevice *Device)
/* Tell the processing thread to quit and wait for it to do so. */
data->killNow = AL_TRUE;
PostThreadMessage(data->WaveThreadID, WM_QUIT, 0, 0);
PostThreadMessage(data->thread, WM_QUIT, 0, 0);
WaitForSingleObjectEx(data->WaveThreadEvent, 5000, FALSE);
althrd_join(data->thread, &i);
/* Make sure capture is stopped and all pending buffers are flushed. */
waveInReset(data->WaveHandle.In);
CloseHandle(data->WaveThread);
data->WaveThread = 0;
// Release the wave buffers
for(i = 0;i < 4;i++)
{
@@ -665,9 +622,6 @@ static void WinMMCloseCapture(ALCdevice *Device)
data->Ring = NULL;
// Close the Wave device
CloseHandle(data->WaveThreadEvent);
data->WaveThreadEvent = 0;
waveInClose(data->WaveHandle.In);
data->WaveHandle.In = 0;
@@ -701,6 +655,17 @@ static ALCuint WinMMAvailableSamples(ALCdevice *Device)
}
static inline void AppendAllDevicesList2(const al_string *name)
{
if(!al_string_empty(*name))
AppendAllDevicesList(al_string_get_cstr(*name));
}
static inline void AppendCaptureDeviceList2(const al_string *name)
{
if(!al_string_empty(*name))
AppendCaptureDeviceList(al_string_get_cstr(*name));
}
static const BackendFuncs WinMMFuncs = {
WinMMOpenPlayback,
WinMMClosePlayback,
@@ -718,52 +683,34 @@ static const BackendFuncs WinMMFuncs = {
ALCboolean alcWinMMInit(BackendFuncs *FuncList)
{
VECTOR_INIT(PlaybackDevices);
VECTOR_INIT(CaptureDevices);
*FuncList = WinMMFuncs;
return ALC_TRUE;
}
void alcWinMMDeinit()
{
ALuint i;
clear_devlist(&PlaybackDevices);
VECTOR_DEINIT(PlaybackDevices);
for(i = 0;i < NumPlaybackDevices;i++)
free(PlaybackDeviceList[i]);
free(PlaybackDeviceList);
PlaybackDeviceList = NULL;
NumPlaybackDevices = 0;
for(i = 0;i < NumCaptureDevices;i++)
free(CaptureDeviceList[i]);
free(CaptureDeviceList);
CaptureDeviceList = NULL;
NumCaptureDevices = 0;
clear_devlist(&CaptureDevices);
VECTOR_DEINIT(CaptureDevices);
}
void alcWinMMProbe(enum DevProbe type)
{
ALuint i;
switch(type)
{
case ALL_DEVICE_PROBE:
ProbePlaybackDevices();
for(i = 0;i < NumPlaybackDevices;i++)
{
if(PlaybackDeviceList[i])
AppendAllDevicesList(PlaybackDeviceList[i]);
}
VECTOR_FOR_EACH(const al_string, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
ProbeCaptureDevices();
for(i = 0;i < NumCaptureDevices;i++)
{
if(CaptureDeviceList[i])
AppendCaptureDeviceList(CaptureDeviceList[i]);
}
VECTOR_FOR_EACH(const al_string, CaptureDevices, AppendCaptureDeviceList2);
break;
}
}
@@ -27,93 +27,82 @@
#include <string.h>
#include "bs2b.h"
#include "alu.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* Single pole IIR filter.
* O[n] = a0*I[n] + a1*I[n-1] + b1*O[n-1]
*/
/* Lowpass filter */
#define lo_filter(in, out_1) (bs2b->a0_lo*(in) + bs2b->b1_lo*(out_1))
/* Highboost filter */
#define hi_filter(in, in_1, out_1) (bs2b->a0_hi*(in) + bs2b->a1_hi*(in_1) + bs2b->b1_hi*(out_1))
/* Set up all data. */
static void init(struct bs2b *bs2b)
{
double Fc_lo, Fc_hi;
double G_lo, G_hi;
double x;
float Fc_lo, Fc_hi;
float G_lo, G_hi;
float x, g;
if ((bs2b->srate > 192000) || (bs2b->srate < 2000))
bs2b->srate = BS2B_DEFAULT_SRATE;
bs2b->srate = clampi(bs2b->srate, 2000, 192000);
switch(bs2b->level)
{
case BS2B_LOW_CLEVEL: /* Low crossfeed level */
Fc_lo = 360.0;
Fc_hi = 501.0;
G_lo = 0.398107170553497;
G_hi = 0.205671765275719;
Fc_lo = 360.0f;
Fc_hi = 501.0f;
G_lo = 0.398107170553497f;
G_hi = 0.205671765275719f;
break;
case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */
Fc_lo = 500.0;
Fc_hi = 711.0;
G_lo = 0.459726988530872;
G_hi = 0.228208484414988;
Fc_lo = 500.0f;
Fc_hi = 711.0f;
G_lo = 0.459726988530872f;
G_hi = 0.228208484414988f;
break;
case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */
Fc_lo = 700.0;
Fc_hi = 1021.0;
G_lo = 0.530884444230988;
G_hi = 0.250105790667544;
Fc_lo = 700.0f;
Fc_hi = 1021.0f;
G_lo = 0.530884444230988f;
G_hi = 0.250105790667544f;
break;
case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */
Fc_lo = 360.0;
Fc_hi = 494.0;
G_lo = 0.316227766016838;
G_hi = 0.168236228897329;
Fc_lo = 360.0f;
Fc_hi = 494.0f;
G_lo = 0.316227766016838f;
G_hi = 0.168236228897329f;
break;
case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */
Fc_lo = 500.0;
Fc_hi = 689.0;
G_lo = 0.354813389233575;
G_hi = 0.187169483835901;
Fc_lo = 500.0f;
Fc_hi = 689.0f;
G_lo = 0.354813389233575f;
G_hi = 0.187169483835901f;
break;
default: /* High easy crossfeed level */
bs2b->level = BS2B_HIGH_ECLEVEL;
Fc_lo = 700.0;
Fc_hi = 975.0;
G_lo = 0.398107170553497;
G_hi = 0.205671765275719;
Fc_lo = 700.0f;
Fc_hi = 975.0f;
G_lo = 0.398107170553497f;
G_hi = 0.205671765275719f;
break;
} /* switch */
g = 1.0f / (1.0f - G_hi + G_lo);
/* $fc = $Fc / $s;
* $d = 1 / 2 / pi / $fc;
* $x = exp(-1 / $d);
*/
x = exp(-2.0 * M_PI * Fc_lo / bs2b->srate);
x = expf(-2.0f * F_PI * Fc_lo / bs2b->srate);
bs2b->b1_lo = x;
bs2b->a0_lo = G_lo * (1.0 - x);
bs2b->a0_lo = G_lo * (1.0f - x) * g;
x = exp(-2.0 * M_PI * Fc_hi / bs2b->srate);
x = expf(-2.0f * F_PI * Fc_hi / bs2b->srate);
bs2b->b1_hi = x;
bs2b->a0_hi = 1.0 - G_hi * (1.0 - x);
bs2b->a1_hi = -x;
bs2b->gain = 1.0f / (float)(1.0 - G_hi + G_lo);
bs2b->a0_hi = (1.0f - G_hi * (1.0f - x)) * g;
bs2b->a1_hi = -x * g;
} /* init */
/* Exported functions.
@@ -151,35 +140,4 @@ void bs2b_clear(struct bs2b *bs2b)
memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample));
} /* bs2b_clear */
void bs2b_cross_feed(struct bs2b *bs2b, float *sample)
{
/* Lowpass filter */
bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]);
bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]);
/* Highboost filter */
bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]);
bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]);
bs2b->last_sample.asis[0] = sample[0];
bs2b->last_sample.asis[1] = sample[1];
/* Crossfeed */
sample[0] = (float)(bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1]);
sample[1] = (float)(bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0]);
/* Bass boost cause allpass attenuation */
sample[0] *= bs2b->gain;
sample[1] *= bs2b->gain;
/* Clipping of overloaded samples */
#if 0
if (sample[0] > 1.0)
sample[0] = 1.0;
if (sample[0] < -1.0)
sample[0] = -1.0;
if (sample[1] > 1.0)
sample[1] = 1.0;
if (sample[1] < -1.0)
sample[1] = -1.0;
#endif
} /* bs2b_cross_feed */
extern inline void bs2b_cross_feed(struct bs2b *bs2b, float *restrict samples);
+32
View File
@@ -0,0 +1,32 @@
#ifndef AL_COMPAT_H
#define AL_COMPAT_H
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
WCHAR *strdupW(const WCHAR *str);
/* Opens a file with standard I/O. The filename is expected to be UTF-8. */
FILE *al_fopen(const char *fname, const char *mode);
#define HAVE_DYNLOAD 1
#else
#define al_fopen fopen
#if defined(HAVE_DLFCN_H) && !defined(IN_IDE_PARSER)
#define HAVE_DYNLOAD 1
#endif
#endif
#ifdef HAVE_DYNLOAD
void *LoadLib(const char *name);
void CloseLib(void *handle);
void *GetSymbol(void *handle, const char *name);
#endif
#endif /* AL_COMPAT_H */
@@ -59,7 +59,7 @@ static ALvoid ALautowahState_Destruct(ALautowahState *UNUSED(state))
static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device)
{
state->Frequency = device->Frequency;
state->Frequency = (ALfloat)device->Frequency;
return AL_TRUE;
}
@@ -71,8 +71,8 @@ static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, co
attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency;
releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency;
state->AttackRate = 1.0f / attackTime;
state->ReleaseRate = 1.0f / releaseTime;
state->AttackRate = powf(1.0f/GAIN_SILENCE_THRESHOLD, 1.0f/attackTime);
state->ReleaseRate = powf(GAIN_SILENCE_THRESHOLD/1.0f, 1.0f/releaseTime);
state->PeakGain = slot->EffectProps.Autowah.PeakGain;
state->Resonance = slot->EffectProps.Autowah.Resonance;
@@ -100,15 +100,15 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
/* Similar to compressor, we get the current amplitude of the
* incoming signal, and attack or release to reach it. */
amplitude = fabs(smp);
amplitude = fabsf(smp);
if(amplitude > gain)
gain = minf(gain+state->AttackRate, amplitude);
gain = minf(gain*state->AttackRate, amplitude);
else if(amplitude < gain)
gain = maxf(gain-state->ReleaseRate, amplitude);
gain = maxf(gain*state->ReleaseRate, amplitude);
gain = maxf(gain, GAIN_SILENCE_THRESHOLD);
/* FIXME: What range does the filter cover? */
cutoff = lerp(1000.0f, (ALfloat)LOWPASSFREQREF, minf(gain/state->PeakGain, 1.0f));
cutoff = lerp(20.0f, 20000.0f, minf(gain/state->PeakGain, 1.0f));
/* The code below is like calling ALfilterState_setParams with
* ALfilterType_LowPass. However, instead of passing a bandwidth,
@@ -151,10 +151,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
}
}
static void ALautowahState_Delete(ALautowahState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALautowahState)
DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState);
@@ -167,13 +164,13 @@ static ALeffectState *ALautowahStateFactory_create(ALautowahStateFactory *UNUSED
{
ALautowahState *state;
state = malloc(sizeof(*state));
state = ALautowahState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALautowahState, ALeffectState, state);
state->AttackRate = 0.0f;
state->ReleaseRate = 0.0f;
state->Resonance = 0.0f;
state->AttackRate = 1.0f;
state->ReleaseRate = 1.0f;
state->Resonance = 2.0f;
state->PeakGain = 1.0f;
state->GainCtrl = 1.0f;
@@ -30,6 +30,11 @@
#include "alu.h"
enum ChorusWaveForm {
CWF_Triangle = AL_CHORUS_WAVEFORM_TRIANGLE,
CWF_Sinusoid = AL_CHORUS_WAVEFORM_SINUSOID
};
typedef struct ALchorusState {
DERIVE_FROM_TYPE(ALeffectState);
@@ -44,7 +49,7 @@ typedef struct ALchorusState {
ALfloat Gain[2][MaxChannels];
/* effect parameters */
ALint waveform;
enum ChorusWaveForm waveform;
ALint delay;
ALfloat depth;
ALfloat feedback;
@@ -92,7 +97,15 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
ALfloat rate;
ALint phase;
state->waveform = Slot->EffectProps.Chorus.Waveform;
switch(Slot->EffectProps.Chorus.Waveform)
{
case AL_CHORUS_WAVEFORM_TRIANGLE:
state->waveform = CWF_Triangle;
break;
case AL_CHORUS_WAVEFORM_SINUSOID:
state->waveform = CWF_Sinusoid;
break;
}
state->depth = Slot->EffectProps.Chorus.Depth;
state->feedback = Slot->EffectProps.Chorus.Feedback;
state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency);
@@ -115,10 +128,10 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
state->lfo_range = fastf2u(frequency/rate + 0.5f);
switch(state->waveform)
{
case AL_CHORUS_WAVEFORM_TRIANGLE:
case CWF_Triangle:
state->lfo_scale = 4.0f / state->lfo_range;
break;
case AL_CHORUS_WAVEFORM_SINUSOID:
case CWF_Sinusoid:
state->lfo_scale = F_2PI / state->lfo_range;
break;
}
@@ -198,10 +211,15 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co
ALfloat temps[64][2];
ALuint td = minu(SamplesToDo-base, 64);
if(state->waveform == AL_CHORUS_WAVEFORM_TRIANGLE)
ProcessTriangle(state, td, SamplesIn+base, temps);
else if(state->waveform == AL_CHORUS_WAVEFORM_SINUSOID)
ProcessSinusoid(state, td, SamplesIn+base, temps);
switch(state->waveform)
{
case CWF_Triangle:
ProcessTriangle(state, td, SamplesIn+base, temps);
break;
case CWF_Sinusoid:
ProcessSinusoid(state, td, SamplesIn+base, temps);
break;
}
for(kt = 0;kt < MaxChannels;kt++)
{
@@ -224,10 +242,7 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co
}
}
static void ALchorusState_Delete(ALchorusState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
@@ -240,7 +255,7 @@ static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(f
{
ALchorusState *state;
state = malloc(sizeof(*state));
state = ALchorusState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALchorusState, ALeffectState, state);
@@ -249,6 +264,7 @@ static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(f
state->SampleBuffer[1] = NULL;
state->offset = 0;
state->lfo_range = 1;
state->waveform = CWF_Triangle;
return STATIC_CAST(ALeffectState, state);
}
@@ -84,12 +84,12 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples
{
smp = SamplesIn[it+base];
amplitude = fabs(smp);
amplitude = fabsf(smp);
if(amplitude > gain)
gain = minf(gain+state->AttackRate, amplitude);
else if(amplitude < gain)
gain = maxf(gain-state->ReleaseRate, amplitude);
output = 1.0 / clampf(gain, 0.5f, 2.0f);
output = 1.0f / clampf(gain, 0.5f, 2.0f);
temps[it] = smp * output;
}
@@ -133,10 +133,7 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples
}
}
static void ALcompressorState_Delete(ALcompressorState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
@@ -149,7 +146,7 @@ static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *
{
ALcompressorState *state;
state = malloc(sizeof(*state));
state = ALcompressorState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALcompressorState, ALeffectState, state);
@@ -76,10 +76,7 @@ static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesTo
}
}
static void ALdedicatedState_Delete(ALdedicatedState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState)
DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
@@ -93,7 +90,7 @@ ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(fa
ALdedicatedState *state;
ALsizei s;
state = malloc(sizeof(*state));
state = ALdedicatedState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALdedicatedState, ALeffectState, state);
@@ -170,10 +170,7 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples
}
}
static void ALdistortionState_Delete(ALdistortionState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
@@ -186,7 +183,7 @@ static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *
{
ALdistortionState *state;
state = malloc(sizeof(*state));
state = ALdistortionState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALdistortionState, ALeffectState, state);
@@ -97,7 +97,7 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL
ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
1.0f - Slot->EffectProps.Echo.Damping,
(ALfloat)LOWPASSFREQREF/frequency, 0.0f);
LOWPASSFREQREF/frequency, 0.0f);
gain = Slot->Gain;
dirGain = fabsf(lrpan);
@@ -161,10 +161,7 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const
state->Offset = offset;
}
static void ALechoState_Delete(ALechoState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALechoState)
DEFINE_ALEFFECTSTATE_VTABLE(ALechoState);
@@ -177,7 +174,7 @@ ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory))
{
ALechoState *state;
state = malloc(sizeof(*state));
state = ALechoState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALechoState, ALeffectState, state);
@@ -155,10 +155,7 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo
}
}
static void ALequalizerState_Delete(ALequalizerState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALequalizerState)
DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
@@ -172,7 +169,7 @@ ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(fa
ALequalizerState *state;
int it;
state = malloc(sizeof(*state));
state = ALequalizerState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALequalizerState, ALeffectState, state);
@@ -30,6 +30,11 @@
#include "alu.h"
enum FlangerWaveForm {
FWF_Triangle = AL_FLANGER_WAVEFORM_TRIANGLE,
FWF_Sinusoid = AL_FLANGER_WAVEFORM_SINUSOID
};
typedef struct ALflangerState {
DERIVE_FROM_TYPE(ALeffectState);
@@ -44,7 +49,7 @@ typedef struct ALflangerState {
ALfloat Gain[2][MaxChannels];
/* effect parameters */
ALint waveform;
enum FlangerWaveForm waveform;
ALint delay;
ALfloat depth;
ALfloat feedback;
@@ -92,7 +97,15 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
ALfloat rate;
ALint phase;
state->waveform = Slot->EffectProps.Flanger.Waveform;
switch(Slot->EffectProps.Flanger.Waveform)
{
case AL_FLANGER_WAVEFORM_TRIANGLE:
state->waveform = FWF_Triangle;
break;
case AL_FLANGER_WAVEFORM_SINUSOID:
state->waveform = FWF_Sinusoid;
break;
}
state->depth = Slot->EffectProps.Flanger.Depth;
state->feedback = Slot->EffectProps.Flanger.Feedback;
state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
@@ -115,10 +128,10 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
state->lfo_range = fastf2u(frequency/rate + 0.5f);
switch(state->waveform)
{
case AL_FLANGER_WAVEFORM_TRIANGLE:
case FWF_Triangle:
state->lfo_scale = 4.0f / state->lfo_range;
break;
case AL_FLANGER_WAVEFORM_SINUSOID:
case FWF_Sinusoid:
state->lfo_scale = F_2PI / state->lfo_range;
break;
}
@@ -198,10 +211,15 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo,
ALfloat temps[64][2];
ALuint td = minu(SamplesToDo-base, 64);
if(state->waveform == AL_FLANGER_WAVEFORM_TRIANGLE)
ProcessTriangle(state, td, SamplesIn+base, temps);
else if(state->waveform == AL_FLANGER_WAVEFORM_SINUSOID)
ProcessSinusoid(state, td, SamplesIn+base, temps);
switch(state->waveform)
{
case FWF_Triangle:
ProcessTriangle(state, td, SamplesIn+base, temps);
break;
case FWF_Sinusoid:
ProcessSinusoid(state, td, SamplesIn+base, temps);
break;
}
for(kt = 0;kt < MaxChannels;kt++)
{
@@ -224,10 +242,7 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo,
}
}
static void ALflangerState_Delete(ALflangerState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALflangerState)
DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
@@ -240,7 +255,7 @@ ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factor
{
ALflangerState *state;
state = malloc(sizeof(*state));
state = ALflangerState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALflangerState, ALeffectState, state);
@@ -249,6 +264,7 @@ ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factor
state->SampleBuffer[1] = NULL;
state->offset = 0;
state->lfo_range = 1;
state->waveform = FWF_Triangle;
return STATIC_CAST(ALeffectState, state);
}
@@ -171,10 +171,7 @@ static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesTo
}
}
static void ALmodulatorState_Delete(ALmodulatorState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState)
DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
@@ -187,7 +184,7 @@ static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UN
{
ALmodulatorState *state;
state = malloc(sizeof(*state));
state = ALmodulatorState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALmodulatorState, ALeffectState, state);
@@ -48,10 +48,20 @@ static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samp
(void)samplesOut;
}
/* This frees the memory used by the object, after it has been destructed. */
static void ALnullState_Delete(ALnullState *state)
/* This allocates memory to store the object, before it gets constructed.
* DECLARE_DEFAULT_ALLOCATORS can be used to declate a default method.
*/
static void *ALnullState_New(size_t size)
{
free(state);
return malloc(size);
}
/* This frees the memory used by the object, after it has been destructed.
* DECLARE_DEFAULT_ALLOCATORS can be used to declate a default method.
*/
static void ALnullState_Delete(void *ptr)
{
free(ptr);
}
/* Define the forwards and the ALeffectState vtable for this type. */
@@ -67,7 +77,7 @@ ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory))
{
ALnullState *state;
state = calloc(1, sizeof(*state));
state = ALnullState_New(sizeof(*state));
if(!state) return NULL;
/* Set vtables for inherited types. */
SET_VTABLE2(ALnullState, ALeffectState, state);
@@ -1096,7 +1096,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, cons
}
else
{
hfscale = (ALfloat)LOWPASSFREQREF / frequency;
hfscale = LOWPASSFREQREF / frequency;
ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
Slot->EffectProps.Reverb.GainHF,
hfscale, 0.0f);
@@ -1170,10 +1170,7 @@ static ALvoid ALreverbState_Destruct(ALreverbState *State)
State->SampleBuffer = NULL;
}
static void ALreverbState_Delete(ALreverbState *state)
{
free(state);
}
DECLARE_DEFAULT_ALLOCATORS(ALreverbState)
DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState);
@@ -1187,7 +1184,7 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f
ALreverbState *state;
ALuint index;
state = malloc(sizeof(ALreverbState));
state = ALreverbState_New(sizeof(*state));
if(!state) return NULL;
SET_VTABLE2(ALreverbState, ALeffectState, state);
+814
View File
@@ -0,0 +1,814 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2011 by authors.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#ifdef _WIN32
#ifdef __MINGW32__
#define _WIN32_IE 0x501
#else
#define _WIN32_IE 0x400
#endif
#endif
#include "config.h"
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifndef AL_NO_UID_DEFS
#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
#define INITGUID
#include <windows.h>
#ifdef HAVE_GUIDDEF_H
#include <guiddef.h>
#else
#include <initguid.h>
#endif
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71);
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71);
DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16);
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e);
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);
#ifdef HAVE_MMDEVAPI
#include <devpropdef.h>
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
#endif
#endif
#endif /* AL_NO_UID_DEFS */
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#ifdef HAVE_INTRIN_H
#include <intrin.h>
#endif
#ifdef HAVE_CPUID_H
#include <cpuid.h>
#endif
#ifdef HAVE_SYS_SYSCONF_H
#include <sys/sysconf.h>
#endif
#ifdef HAVE_FLOAT_H
#include <float.h>
#endif
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
#ifdef _WIN32_IE
#include <shlobj.h>
#endif
#include "alMain.h"
#include "alu.h"
#include "atomic.h"
#include "uintmap.h"
#include "vector.h"
#include "alstring.h"
#include "compat.h"
#include "threads.h"
extern inline ALuint NextPowerOf2(ALuint value);
extern inline ALint fastf2i(ALfloat f);
extern inline ALuint fastf2u(ALfloat f);
ALuint CPUCapFlags = 0;
void FillCPUCaps(ALuint capfilter)
{
ALuint caps = 0;
/* FIXME: We really should get this for all available CPUs in case different
* CPUs have different caps (is that possible on one machine?). */
#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \
defined(_M_IX86) || defined(_M_X64))
union {
unsigned int regs[4];
char str[sizeof(unsigned int[4])];
} cpuinf[3];
if(!__get_cpuid(0, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]))
ERR("Failed to get CPUID\n");
else
{
unsigned int maxfunc = cpuinf[0].regs[0];
unsigned int maxextfunc = 0;
if(__get_cpuid(0x80000000, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]))
maxextfunc = cpuinf[0].regs[0];
TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc);
TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8);
if(maxextfunc >= 0x80000004 &&
__get_cpuid(0x80000002, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]) &&
__get_cpuid(0x80000003, &cpuinf[1].regs[0], &cpuinf[1].regs[1], &cpuinf[1].regs[2], &cpuinf[1].regs[3]) &&
__get_cpuid(0x80000004, &cpuinf[2].regs[0], &cpuinf[2].regs[1], &cpuinf[2].regs[2], &cpuinf[2].regs[3]))
TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str);
if(maxfunc >= 1 &&
__get_cpuid(1, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]))
{
if((cpuinf[0].regs[3]&(1<<25)))
{
caps |= CPU_CAP_SSE;
if((cpuinf[0].regs[3]&(1<<26)))
{
caps |= CPU_CAP_SSE2;
if((cpuinf[0].regs[2]&(1<<19)))
caps |= CPU_CAP_SSE4_1;
}
}
}
}
#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \
defined(_M_IX86) || defined(_M_X64))
union {
int regs[4];
char str[sizeof(int[4])];
} cpuinf[3];
(__cpuid)(cpuinf[0].regs, 0);
if(cpuinf[0].regs[0] == 0)
ERR("Failed to get CPUID\n");
else
{
unsigned int maxfunc = cpuinf[0].regs[0];
unsigned int maxextfunc;
(__cpuid)(cpuinf[0].regs, 0x80000000);
maxextfunc = cpuinf[0].regs[0];
TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc);
TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8);
if(maxextfunc >= 0x80000004)
{
(__cpuid)(cpuinf[0].regs, 0x80000002);
(__cpuid)(cpuinf[1].regs, 0x80000003);
(__cpuid)(cpuinf[2].regs, 0x80000004);
TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str);
}
if(maxfunc >= 1)
{
(__cpuid)(cpuinf[0].regs, 1);
if((cpuinf[0].regs[3]&(1<<25)))
{
caps |= CPU_CAP_SSE;
if((cpuinf[0].regs[3]&(1<<26)))
{
caps |= CPU_CAP_SSE2;
if((cpuinf[0].regs[2]&(1<<19)))
caps |= CPU_CAP_SSE4_1;
}
}
}
}
#else
/* 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;
#elif defined(HAVE_SSE2)
#warning "Assuming SSE 2 run-time support!"
capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
#elif defined(HAVE_SSE)
#warning "Assuming SSE run-time support!"
capfilter |= CPU_CAP_SSE;
#endif
#endif
#ifdef HAVE_NEON
/* Assume Neon support if compiled with it */
caps |= CPU_CAP_NEON;
#endif
TRACE("Extensions:%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_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""),
((!capfilter) ? " -none-" : "")
);
CPUCapFlags = caps & capfilter;
}
void *al_malloc(size_t alignment, size_t size)
{
#if defined(HAVE_ALIGNED_ALLOC)
size = (size+(alignment-1))&~(alignment-1);
return aligned_alloc(alignment, size);
#elif defined(HAVE_POSIX_MEMALIGN)
void *ret;
if(posix_memalign(&ret, alignment, size) == 0)
return ret;
return NULL;
#elif defined(HAVE__ALIGNED_MALLOC)
return _aligned_malloc(size, alignment);
#else
char *ret = malloc(size+alignment);
if(ret != NULL)
{
*(ret++) = 0x00;
while(((ALintptrEXT)ret&(alignment-1)) != 0)
*(ret++) = 0x55;
}
return ret;
#endif
}
void *al_calloc(size_t alignment, size_t size)
{
void *ret = al_malloc(alignment, size);
if(ret) memset(ret, 0, size);
return ret;
}
void al_free(void *ptr)
{
#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN)
free(ptr);
#elif defined(HAVE__ALIGNED_MALLOC)
_aligned_free(ptr);
#else
if(ptr != NULL)
{
char *finder = ptr;
do {
--finder;
} while(*finder == 0x55);
free(finder);
}
#endif
}
void SetMixerFPUMode(FPUCtl *ctl)
{
#ifdef HAVE_FENV_H
fegetenv(STATIC_CAST(fenv_t, ctl));
#if defined(__GNUC__) && defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
__asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state));
#endif
#ifdef FE_TOWARDZERO
fesetround(FE_TOWARDZERO);
#endif
#if defined(__GNUC__) && defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
{
int sseState = ctl->sse_state;
sseState |= 0x6000; /* set round-to-zero */
sseState |= 0x8000; /* set flush-to-zero */
if((CPUCapFlags&CPU_CAP_SSE2))
sseState |= 0x0040; /* set denormals-are-zero */
__asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState));
}
#endif
#elif defined(HAVE___CONTROL87_2)
int mode;
__control87_2(0, 0, &ctl->state, NULL);
__control87_2(_RC_CHOP, _MCW_RC, &mode, NULL);
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
{
__control87_2(0, 0, NULL, &ctl->sse_state);
__control87_2(_RC_CHOP|_DN_FLUSH, _MCW_RC|_MCW_DN, NULL, &mode);
}
#endif
#elif defined(HAVE__CONTROLFP)
ctl->state = _controlfp(0, 0);
(void)_controlfp(_RC_CHOP, _MCW_RC);
#endif
}
void RestoreFPUMode(const FPUCtl *ctl)
{
#ifdef HAVE_FENV_H
fesetenv(STATIC_CAST(fenv_t, ctl));
#if defined(__GNUC__) && defined(HAVE_SSE)
if((CPUCapFlags&CPU_CAP_SSE))
__asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state));
#endif
#elif defined(HAVE___CONTROL87_2)
int mode;
__control87_2(ctl->state, _MCW_RC, &mode, NULL);
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
__control87_2(ctl->sse_state, _MCW_RC|_MCW_DN, NULL, &mode);
#endif
#elif defined(HAVE__CONTROLFP)
_controlfp(ctl->state, _MCW_RC);
#endif
}
#ifdef _WIN32
static WCHAR *FromUTF8(const char *str)
{
WCHAR *out = NULL;
int len;
if((len=MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) > 0)
{
out = calloc(sizeof(WCHAR), len);
MultiByteToWideChar(CP_UTF8, 0, str, -1, out, len);
}
return out;
}
void *LoadLib(const char *name)
{
HANDLE hdl = NULL;
WCHAR *wname;
wname = FromUTF8(name);
if(!wname)
ERR("Failed to convert UTF-8 filename: \"%s\"\n", name);
else
{
hdl = LoadLibraryW(wname);
free(wname);
}
return hdl;
}
void CloseLib(void *handle)
{ FreeLibrary((HANDLE)handle); }
void *GetSymbol(void *handle, const char *name)
{
void *ret;
ret = (void*)GetProcAddress((HANDLE)handle, name);
if(ret == NULL)
ERR("Failed to load %s\n", name);
return ret;
}
WCHAR *strdupW(const WCHAR *str)
{
const WCHAR *n;
WCHAR *ret;
size_t len;
n = str;
while(*n) n++;
len = n - str;
ret = calloc(sizeof(WCHAR), len+1);
if(ret != NULL)
memcpy(ret, str, sizeof(WCHAR)*len);
return ret;
}
FILE *al_fopen(const char *fname, const char *mode)
{
WCHAR *wname=NULL, *wmode=NULL;
FILE *file = NULL;
wname = FromUTF8(fname);
wmode = FromUTF8(mode);
if(!wname)
ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
else if(!wmode)
ERR("Failed to convert UTF-8 mode: \"%s\"\n", mode);
else
file = _wfopen(wname, wmode);
free(wname);
free(wmode);
return file;
}
#else
#ifdef HAVE_DLFCN_H
void *LoadLib(const char *name)
{
const char *err;
void *handle;
dlerror();
handle = dlopen(name, RTLD_NOW);
if((err=dlerror()) != NULL)
handle = NULL;
return handle;
}
void CloseLib(void *handle)
{ dlclose(handle); }
void *GetSymbol(void *handle, const char *name)
{
const char *err;
void *sym;
dlerror();
sym = dlsym(handle, name);
if((err=dlerror()) != NULL)
{
WARN("Failed to load %s: %s\n", name, err);
sym = NULL;
}
return sym;
}
#endif
#endif
void al_print(const char *type, const char *func, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(LogFile, "AL lib: %s %s: ", type, func);
vfprintf(LogFile, fmt, ap);
va_end(ap);
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] = "";
const char *str, *next;
FILE *f;
if(fname[0] == '/')
{
if((f=al_fopen(fname, "rb")) != NULL)
{
TRACE("Opened %s\n", fname);
return f;
}
WARN("Could not open %s\n", fname);
return NULL;
}
if((f=al_fopen(fname, "rb")) != NULL)
{
TRACE("Opened %s\n", fname);
return f;
}
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);
else if((str=getenv("HOME")) != NULL && str[0] != '\0')
snprintf(buffer, sizeof(buffer), "%s/.local/share/%s/%s", str, subdir, fname);
if(buffer[0])
{
if((f=al_fopen(buffer, "rb")) != NULL)
{
TRACE("Opened %s\n", buffer);
return f;
}
WARN("Could not open %s\n", buffer);
}
if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
str = "/usr/local/share/:/usr/share/";
next = str;
while((str=next) != NULL && str[0] != '\0')
{
size_t len;
next = strchr(str, ':');
if(!next)
len = strlen(str);
else
{
len = next - str;
next++;
}
if(len > sizeof(buffer)-1)
len = sizeof(buffer)-1;
strncpy(buffer, str, len);
buffer[len] = '\0';
snprintf(buffer+len, sizeof(buffer)-len, "/%s/%s", subdir, fname);
if((f=al_fopen(buffer, "rb")) != NULL)
{
TRACE("Opened %s\n", buffer);
return f;
}
WARN("Could not open %s\n", buffer);
}
return NULL;
}
#endif
void SetRTPriority(void)
{
ALboolean failed = AL_FALSE;
#ifdef _WIN32
if(RTPrioLevel > 0)
failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
#elif defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__)
if(RTPrioLevel > 0)
{
struct sched_param param;
/* Use the minimum real-time priority possible for now (on Linux this
* should be 1 for SCHED_RR) */
param.sched_priority = sched_get_priority_min(SCHED_RR);
failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, &param);
}
#else
/* Real-time priority not available */
failed = (RTPrioLevel>0);
#endif
if(failed)
ERR("Failed to set priority level for thread\n");
}
ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei 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);
void *temp;
/* Use the next power-of-2 size if we don't need to allocate the exact
* amount. This is preferred when regularly increasing the vector since
* it means fewer reallocations. Though it means it also wastes some
* memory. */
if(exact == AL_FALSE)
{
obj_count = 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,
* sizeof(*vector_) may not equal base_size). */
temp = realloc(*vecptr, base_size + obj_size*obj_count);
if(temp == NULL) return AL_FALSE;
*vecptr = temp;
(*vecptr)->Capacity = obj_count;
(*vecptr)->Size = old_size;
}
return AL_TRUE;
}
ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei 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))
return AL_FALSE;
(*vecptr)->Size = obj_count;
}
return AL_TRUE;
}
ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend)
{
vector_ *vecptr = (vector_*)ptr;
if(datstart != datend)
{
ptrdiff_t ins_elem = (*vecptr ? ((char*)ins_pos - ((char*)(*vecptr) + base_size)) :
((char*)ins_pos - (char*)NULL)) /
obj_size;
ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size;
assert(numins > 0);
if(INT_MAX-VECTOR_SIZE(*vecptr) <= 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)
{
memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size),
(char*)(*vecptr) + base_size + ((ins_elem )*obj_size),
((*vecptr)->Size-ins_elem)*obj_size);
}
memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size),
datstart, numins*obj_size);
(*vecptr)->Size += (ALsizei)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 ALboolean al_string_empty(const_al_string str);
extern inline const al_string_char_type *al_string_get_cstr(const_al_string str);
void al_string_clear(al_string *str)
{
/* Reserve one more character than the total size of the string. This is to
* ensure we have space to add a null terminator in the string data so it
* can be used as a C-style string. */
VECTOR_RESERVE(*str, 1);
VECTOR_RESIZE(*str, 0);
*VECTOR_ITER_END(*str) = 0;
}
static inline int al_string_compare(const al_string_char_type *str1, ALsizei str1len,
const al_string_char_type *str2, ALsizei str2len)
{
ALsizei complen = mini(str1len, str2len);
int ret = memcmp(str1, str2, complen);
if(ret == 0)
{
if(str1len > str2len) return 1;
if(str1len < str2len) return -1;
}
return ret;
}
int al_string_cmp(const_al_string str1, const_al_string str2)
{
return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
&VECTOR_FRONT(str2), al_string_length(str2));
}
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));
}
void al_string_copy(al_string *str, const_al_string from)
{
ALsizei len = VECTOR_SIZE(from);
VECTOR_RESERVE(*str, len+1);
VECTOR_RESIZE(*str, 0);
VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len);
*VECTOR_ITER_END(*str) = 0;
}
void al_string_copy_cstr(al_string *str, const al_string_char_type *from)
{
size_t len = strlen(from);
VECTOR_RESERVE(*str, len+1);
VECTOR_RESIZE(*str, 0);
VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len);
*VECTOR_ITER_END(*str) = 0;
}
void al_string_append_char(al_string *str, const al_string_char_type c)
{
VECTOR_RESERVE(*str, al_string_length(*str)+2);
VECTOR_PUSH_BACK(*str, c);
*VECTOR_ITER_END(*str) = 0;
}
void al_string_append_cstr(al_string *str, const al_string_char_type *from)
{
size_t len = strlen(from);
if(len != 0)
{
VECTOR_RESERVE(*str, al_string_length(*str)+len+1);
VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len);
*VECTOR_ITER_END(*str) = 0;
}
}
void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to)
{
if(to != from)
{
VECTOR_RESERVE(*str, al_string_length(*str)+(to-from)+1);
VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, to);
*VECTOR_ITER_END(*str) = 0;
}
}
#ifdef _WIN32
void al_string_copy_wcstr(al_string *str, const wchar_t *from)
{
int len;
if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
{
VECTOR_RESERVE(*str, len);
VECTOR_RESIZE(*str, len-1);
WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL);
*VECTOR_ITER_END(*str) = 0;
}
}
#endif
@@ -28,11 +28,7 @@
#include "alMain.h"
#include "alSource.h"
#include "alu.h"
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#include "hrtf.h"
/* Current data set limits defined by the makehrtf utility. */
@@ -62,39 +58,33 @@ struct Hrtf {
static const ALchar magicMarker00[8] = "MinPHR00";
static const ALchar magicMarker01[8] = "MinPHR01";
/* Define the default HRTF:
* ALubyte defaultAzCount [DefaultHrtf.evCount]
* ALushort defaultEvOffset [DefaultHrtf.evCount]
* ALshort defaultCoeffs [DefaultHrtf.irCount * defaultHrtf.irSize]
* ALubyte defaultDelays [DefaultHrtf.irCount]
*
* struct Hrtf DefaultHrtf
*/
#include "hrtf_tables.inc"
/* First value for pass-through coefficients (remaining are 0), used for omni-
* directional sounds. */
static const ALfloat PassthruCoeff = 32767.0f * 0.707106781187f/*sqrt(0.5)*/;
static struct Hrtf *LoadedHrtfs = NULL;
/* Calculate the elevation indices given the polar elevation in radians.
* This will return two indices between 0 and (Hrtf->evCount - 1) and an
* This will return two indices between 0 and (evcount - 1) and an
* interpolation factor between 0.0 and 1.0.
*/
static void CalcEvIndices(const struct Hrtf *Hrtf, ALfloat ev, ALuint *evidx, ALfloat *evmu)
static void CalcEvIndices(ALuint evcount, ALfloat ev, ALuint *evidx, ALfloat *evmu)
{
ev = (F_PI_2 + ev) * (Hrtf->evCount-1) / F_PI;
ev = (F_PI_2 + ev) * (evcount-1) / F_PI;
evidx[0] = fastf2u(ev);
evidx[1] = minu(evidx[0] + 1, Hrtf->evCount-1);
evidx[1] = minu(evidx[0] + 1, evcount-1);
*evmu = ev - evidx[0];
}
/* Calculate the azimuth indices given the polar azimuth in radians. This
* will return two indices between 0 and (Hrtf->azCount[ei] - 1) and an
* interpolation factor between 0.0 and 1.0.
* will return two indices between 0 and (azcount - 1) and an interpolation
* factor between 0.0 and 1.0.
*/
static void CalcAzIndices(const struct Hrtf *Hrtf, ALuint evidx, ALfloat az, ALuint *azidx, ALfloat *azmu)
static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *azmu)
{
az = (F_2PI + az) * Hrtf->azCount[evidx] / (F_2PI);
azidx[0] = fastf2u(az) % Hrtf->azCount[evidx];
azidx[1] = (azidx[0] + 1) % Hrtf->azCount[evidx];
az = (F_2PI + az) * azcount / (F_2PI);
azidx[0] = fastf2u(az) % azcount;
azidx[1] = (azidx[0] + 1) % azcount;
*azmu = az - floorf(az);
}
@@ -112,18 +102,17 @@ ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3],
oldGain = maxf(oldGain, 0.0001f);
gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
// Calculate the normalized listener to source angle change when there is
// enough gain to notice it.
// 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])
angleChange = acosf(olddir[0]*newdir[0] +
olddir[1]*newdir[1] +
olddir[2]*newdir[2]) / F_PI;
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
@@ -137,37 +126,30 @@ ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3],
* increase the apparent resolution of the HRIR data set. The coefficients
* are also normalized and attenuated by the specified gain.
*/
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays)
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays)
{
ALuint evidx[2], azidx[2];
ALuint lidx[4], ridx[4];
ALuint evidx[2], lidx[4], ridx[4];
ALfloat mu[3], blend[4];
ALuint i;
// Claculate elevation indices and interpolation factor.
CalcEvIndices(Hrtf, elevation, evidx, &mu[2]);
/* Claculate elevation indices and interpolation factor. */
CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]);
// Calculate azimuth indices and interpolation factor for the first
// elevation.
CalcAzIndices(Hrtf, evidx[0], azimuth, azidx, &mu[0]);
for(i = 0;i < 2;i++)
{
ALuint azcount = Hrtf->azCount[evidx[i]];
ALuint evoffset = Hrtf->evOffset[evidx[i]];
ALuint azidx[2];
// Calculate the first set of linear HRIR indices for left and right
// channels.
lidx[0] = Hrtf->evOffset[evidx[0]] + azidx[0];
lidx[1] = Hrtf->evOffset[evidx[0]] + azidx[1];
ridx[0] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[0]) % Hrtf->azCount[evidx[0]]);
ridx[1] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[1]) % Hrtf->azCount[evidx[0]]);
/* Calculate azimuth indices and interpolation factor for this elevation. */
CalcAzIndices(azcount, azimuth, azidx, &mu[i]);
// Calculate azimuth indices and interpolation factor for the second
// elevation.
CalcAzIndices(Hrtf, evidx[1], azimuth, azidx, &mu[1]);
// Calculate the second set of linear HRIR indices for left and right
// channels.
lidx[2] = Hrtf->evOffset[evidx[1]] + azidx[0];
lidx[3] = Hrtf->evOffset[evidx[1]] + azidx[1];
ridx[2] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[0]) % Hrtf->azCount[evidx[1]]);
ridx[3] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[1]) % Hrtf->azCount[evidx[1]]);
/* Calculate a set of linear HRIR indices for left and right channels. */
lidx[i*2 + 0] = evoffset + azidx[0];
lidx[i*2 + 1] = evoffset + azidx[1];
ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount);
ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount);
}
/* Calculate 4 blending weights for 2D bilinear interpolation. */
blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]);
@@ -176,12 +158,12 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
blend[3] = ( mu[1]) * ( mu[2]);
/* Calculate the HRIR delays using linear interpolation. */
delays[0] = fastf2u(Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3] +
0.5f) << HRTFDELAY_BITS;
delays[1] = fastf2u(Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3] +
0.5f) << HRTFDELAY_BITS;
delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) *
dirfact + 0.5f) << HRTFDELAY_BITS;
delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
dirfact + 0.5f) << HRTFDELAY_BITS;
/* Calculate the sample offsets for the HRIR indices. */
lidx[0] *= Hrtf->irSize;
@@ -199,17 +181,26 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
*/
if(gain > 0.0001f)
{
ALfloat c;
gain *= 1.0f/32767.0f;
for(i = 0;i < Hrtf->irSize;i++)
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;
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;
for(i = 1;i < Hrtf->irSize;i++)
{
coeffs[i][0] = (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]) * gain;
coeffs[i][1] = (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]) * gain;
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;
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;
}
}
else
@@ -229,39 +220,32 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
* specified gain. Stepping resolution and count is determined using the
* given delta factor between 0.0 and 1.0.
*/
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep)
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep)
{
ALuint evidx[2], azidx[2];
ALuint lidx[4], ridx[4];
ALuint evidx[2], lidx[4], ridx[4];
ALfloat mu[3], blend[4];
ALfloat left, right;
ALfloat step;
ALuint i;
// Claculate elevation indices and interpolation factor.
CalcEvIndices(Hrtf, elevation, evidx, &mu[2]);
/* Claculate elevation indices and interpolation factor. */
CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]);
// Calculate azimuth indices and interpolation factor for the first
// elevation.
CalcAzIndices(Hrtf, evidx[0], azimuth, azidx, &mu[0]);
for(i = 0;i < 2;i++)
{
ALuint azcount = Hrtf->azCount[evidx[i]];
ALuint evoffset = Hrtf->evOffset[evidx[i]];
ALuint azidx[2];
// Calculate the first set of linear HRIR indices for left and right
// channels.
lidx[0] = Hrtf->evOffset[evidx[0]] + azidx[0];
lidx[1] = Hrtf->evOffset[evidx[0]] + azidx[1];
ridx[0] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[0]) % Hrtf->azCount[evidx[0]]);
ridx[1] = Hrtf->evOffset[evidx[0]] + ((Hrtf->azCount[evidx[0]]-azidx[1]) % Hrtf->azCount[evidx[0]]);
/* Calculate azimuth indices and interpolation factor for this elevation. */
CalcAzIndices(azcount, azimuth, azidx, &mu[i]);
// Calculate azimuth indices and interpolation factor for the second
// elevation.
CalcAzIndices(Hrtf, evidx[1], azimuth, azidx, &mu[1]);
// Calculate the second set of linear HRIR indices for left and right
// channels.
lidx[2] = Hrtf->evOffset[evidx[1]] + azidx[0];
lidx[3] = Hrtf->evOffset[evidx[1]] + azidx[1];
ridx[2] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[0]) % Hrtf->azCount[evidx[1]]);
ridx[3] = Hrtf->evOffset[evidx[1]] + ((Hrtf->azCount[evidx[1]]-azidx[1]) % Hrtf->azCount[evidx[1]]);
/* Calculate a set of linear HRIR indices for left and right channels. */
lidx[i*2 + 0] = evoffset + azidx[0];
lidx[i*2 + 1] = evoffset + azidx[1];
ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount);
ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount);
}
// Calculate the stepping parameters.
delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f);
@@ -280,12 +264,12 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
left = (ALfloat)(delays[0] - (delayStep[0] * counter));
right = (ALfloat)(delays[1] - (delayStep[1] * counter));
delays[0] = fastf2u(Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3] +
0.5f) << HRTFDELAY_BITS;
delays[1] = fastf2u(Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3] +
0.5f) << HRTFDELAY_BITS;
delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) *
dirfact + 0.5f) << HRTFDELAY_BITS;
delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
dirfact + 0.5f) << HRTFDELAY_BITS;
delayStep[0] = fastf2i(step * (delays[0] - left));
delayStep[1] = fastf2i(step * (delays[1] - right));
@@ -308,20 +292,35 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
*/
if(gain > 0.0001f)
{
ALfloat c;
gain *= 1.0f/32767.0f;
for(i = 0;i < HRIR_LENGTH;i++)
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;
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;
coeffStep[i][0] = step * (coeffs[i][0] - left);
coeffStep[i][1] = step * (coeffs[i][1] - right);
for(i = 1;i < Hrtf->irSize;i++)
{
left = coeffs[i][0] - (coeffStep[i][0] * counter);
right = coeffs[i][1] - (coeffStep[i][1] * counter);
coeffs[i][0] = (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]) * gain;
coeffs[i][1] = (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]) * gain;
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;
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;
coeffStep[i][0] = step * (coeffs[i][0] - left);
coeffStep[i][1] = step * (coeffs[i][1] - right);
@@ -329,7 +328,7 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
}
else
{
for(i = 0;i < HRIR_LENGTH;i++)
for(i = 0;i < Hrtf->irSize;i++)
{
left = coeffs[i][0] - (coeffStep[i][0] * counter);
right = coeffs[i][1] - (coeffStep[i][1] * counter);
@@ -664,24 +663,25 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
static struct Hrtf *LoadHrtf(ALuint deviceRate)
{
const char *fnamelist = NULL;
const char *fnamelist = "default-%r.mhr";
if(!ConfigValueStr(NULL, "hrtf_tables", &fnamelist))
return NULL;
ConfigValueStr(NULL, "hrtf_tables", &fnamelist);
while(*fnamelist != '\0')
{
struct Hrtf *Hrtf = NULL;
char fname[PATH_MAX];
const char *next;
ALchar magic[8];
ALuint i;
FILE *f;
i = 0;
while(isspace(*fnamelist) || *fnamelist == ',')
fnamelist++;
i = 0;
while(*fnamelist != '\0' && *fnamelist != ',')
next = fnamelist;
while(*(fnamelist=next) != '\0' && *fnamelist != ',')
{
const char *next = strpbrk(fnamelist, "%,");
next = strpbrk(fnamelist, "%,");
while(fnamelist != next && *fnamelist && i < sizeof(fname))
fname[i++] = *(fnamelist++);
@@ -704,7 +704,6 @@ static struct Hrtf *LoadHrtf(ALuint deviceRate)
}
else
ERR("Invalid marker '%%%c'\n", *next);
fnamelist = next;
}
i = minu(i, sizeof(fname)-1);
fname[i] = '\0';
@@ -716,7 +715,7 @@ static struct Hrtf *LoadHrtf(ALuint deviceRate)
continue;
TRACE("Loading %s...\n", fname);
f = fopen(fname, "rb");
f = OpenDataFile(fname, "openal/hrtf");
if(f == NULL)
{
ERR("Could not open %s\n", fname);
@@ -759,52 +758,45 @@ static struct Hrtf *LoadHrtf(ALuint deviceRate)
return NULL;
}
const struct Hrtf *GetHrtf(ALCdevice *device)
const struct Hrtf *GetHrtf(enum DevFmtChannels chans, ALCuint srate)
{
if(device->FmtChans == DevFmtStereo)
if(chans == DevFmtStereo)
{
struct Hrtf *Hrtf = LoadedHrtfs;
while(Hrtf != NULL)
{
if(device->Frequency == Hrtf->sampleRate)
if(srate == Hrtf->sampleRate)
return Hrtf;
Hrtf = Hrtf->next;
}
Hrtf = LoadHrtf(device->Frequency);
Hrtf = LoadHrtf(srate);
if(Hrtf != NULL)
return Hrtf;
if(device->Frequency == DefaultHrtf.sampleRate)
return &DefaultHrtf;
}
ERR("Incompatible format: %s %uhz\n",
DevFmtChannelsString(device->FmtChans), device->Frequency);
ERR("Incompatible format: %s %uhz\n", DevFmtChannelsString(chans), srate);
return NULL;
}
void FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate)
ALCboolean FindHrtfFormat(enum DevFmtChannels *chans, ALCuint *srate)
{
const struct Hrtf *hrtf = &DefaultHrtf;
if(device->Frequency != DefaultHrtf.sampleRate)
const struct Hrtf *hrtf = LoadedHrtfs;
while(hrtf != NULL)
{
hrtf = LoadedHrtfs;
while(hrtf != NULL)
{
if(device->Frequency == hrtf->sampleRate)
break;
hrtf = hrtf->next;
}
if(*srate == hrtf->sampleRate)
break;
hrtf = hrtf->next;
}
if(hrtf == NULL)
hrtf = LoadHrtf(device->Frequency);
if(hrtf == NULL)
hrtf = &DefaultHrtf;
if(hrtf == NULL)
{
hrtf = LoadHrtf(*srate);
if(hrtf == NULL) return ALC_FALSE;
}
*chans = DevFmtStereo;
*srate = hrtf->sampleRate;
return ALC_TRUE;
}
void FreeHrtfs(void)
+28
View File
@@ -0,0 +1,28 @@
#ifndef ALC_HRTF_H
#define ALC_HRTF_H
#include "AL/al.h"
#include "AL/alc.h"
enum DevFmtChannels;
struct Hrtf;
#define HRIR_BITS (7)
#define HRIR_LENGTH (1<<HRIR_BITS)
#define HRIR_MASK (HRIR_LENGTH-1)
#define HRTFDELAY_BITS (20)
#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);
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);
#endif /* ALC_HRTF_H */
@@ -16,8 +16,10 @@
#include "alu.h"
/* Microsecond resolution */
#define TICKS_PER_SECOND (1000000)
extern inline ALboolean IsValidCtrlInput(int cc);
extern inline size_t Reader_read(Reader *self, void *buf, size_t len);
/* MIDI events */
#define SYSEX_EVENT (0xF0)
@@ -129,12 +131,9 @@ void MidiSynth_Construct(MidiSynth *self, ALCdevice *device)
self->Gain = 1.0f;
self->State = AL_INITIAL;
self->LastEvtTime = 0;
self->NextEvtTime = UINT64_MAX;
self->SamplesSinceLast = 0.0;
self->SamplesToNext = 0.0;
self->SamplesPerTick = (ALdouble)device->Frequency / TICKS_PER_SECOND;
self->ClockBase = 0;
self->SamplesDone = 0;
self->SampleRate = device->Frequency;
}
void MidiSynth_Destruct(MidiSynth *self)
@@ -195,29 +194,22 @@ void MidiSynth_stop(MidiSynth *self)
{
ResetEvtQueue(&self->EventQueue);
self->LastEvtTime = 0;
self->NextEvtTime = UINT64_MAX;
self->SamplesSinceLast = 0.0;
self->SamplesToNext = 0.0;
self->ClockBase = 0;
self->SamplesDone = 0;
}
extern inline void MidiSynth_reset(MidiSynth *self);
ALuint64 MidiSynth_getTime(const MidiSynth *self)
{
ALuint64 time = self->LastEvtTime + (self->SamplesSinceLast/self->SamplesPerTick);
return clampu64(time, self->LastEvtTime, self->NextEvtTime);
}
extern inline ALuint64 MidiSynth_getTime(const MidiSynth *self);
extern inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self);
void MidiSynth_setSampleRate(MidiSynth *self, ALdouble srate)
void MidiSynth_setSampleRate(MidiSynth *self, ALuint srate)
{
ALdouble sampletickrate = srate / TICKS_PER_SECOND;
self->SamplesSinceLast = self->SamplesSinceLast * sampletickrate / self->SamplesPerTick;
self->SamplesToNext = self->SamplesToNext * sampletickrate / self->SamplesPerTick;
self->SamplesPerTick = sampletickrate;
if(self->SampleRate != srate)
{
self->ClockBase += self->SamplesDone * MIDI_CLOCK_RES / self->SampleRate;
self->SamplesDone = 0;
self->SampleRate = srate;
}
}
extern inline void MidiSynth_update(MidiSynth *self, ALCdevice *device);
@@ -225,25 +217,11 @@ extern inline void MidiSynth_update(MidiSynth *self, ALCdevice *device);
ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2)
{
MidiEvent entry;
ALenum err;
entry.time = time;
entry.event = event;
entry.param.val[0] = param1;
entry.param.val[1] = param2;
err = InsertEvtQueue(&self->EventQueue, &entry);
if(err != AL_NO_ERROR) return err;
if(entry.time < self->NextEvtTime)
{
self->NextEvtTime = entry.time;
self->SamplesToNext = (self->NextEvtTime - self->LastEvtTime) * self->SamplesPerTick;
self->SamplesToNext -= self->SamplesSinceLast;
}
return AL_NO_ERROR;
return InsertEvtQueue(&self->EventQueue, &entry);
}
ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size)
@@ -261,18 +239,6 @@ ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *
err = InsertEvtQueue(&self->EventQueue, &entry);
if(err != AL_NO_ERROR)
{
free(entry.param.sysex.data);
return err;
}
if(entry.time < self->NextEvtTime)
{
self->NextEvtTime = entry.time;
self->SamplesToNext = (self->NextEvtTime - self->LastEvtTime) * self->SamplesPerTick;
self->SamplesToNext -= self->SamplesSinceLast;
}
return AL_NO_ERROR;
return err;
}
@@ -17,23 +17,28 @@ typedef struct Reader {
void *ptr;
int error;
} Reader;
#define READ(x_, buf_, len_) ((x_)->cb((buf_), (len_), (x_)->ptr))
#define READERR(x_) ((x_)->error)
inline size_t Reader_read(Reader *self, void *buf, size_t len)
{
size_t got = (!self->error) ? self->cb(buf, len, self->ptr) : 0;
if(got < len) self->error = 1;
return got;
}
#define READERR(x_) ((x_)->error)
ALboolean loadSf2(Reader *stream, struct ALsoundfont *sfont, ALCcontext *context);
#define MIDI_CLOCK_RES U64(1000000000)
struct MidiSynthVtable;
typedef struct MidiSynth {
EvtQueue EventQueue;
ALuint64 LastEvtTime;
ALuint64 NextEvtTime;
ALdouble SamplesSinceLast;
ALdouble SamplesToNext;
ALdouble SamplesPerTick;
ALuint64 ClockBase;
ALuint SamplesDone;
ALuint SampleRate;
/* NOTE: This rwlock is for the state and soundfont. The EventQueue and
* related must instead use the device lock as they're used in the mixer
@@ -59,14 +64,15 @@ inline void MidiSynth_setState(MidiSynth *self, ALenum state) { ExchangeInt(&sel
inline ALenum MidiSynth_getState(const MidiSynth *self) { return self->State; }
void MidiSynth_stop(MidiSynth *self);
inline void MidiSynth_reset(MidiSynth *self) { MidiSynth_stop(self); }
ALuint64 MidiSynth_getTime(const MidiSynth *self);
inline ALuint64 MidiSynth_getTime(const MidiSynth *self)
{ return self->ClockBase + (self->SamplesDone*MIDI_CLOCK_RES/self->SampleRate); }
inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self)
{
if(self->EventQueue.pos == self->EventQueue.size)
return UINT64_MAX;
return self->EventQueue.events[self->EventQueue.pos].time;
}
void MidiSynth_setSampleRate(MidiSynth *self, ALdouble srate);
void MidiSynth_setSampleRate(MidiSynth *self, ALuint srate);
inline void MidiSynth_update(MidiSynth *self, ALCdevice *device)
{ MidiSynth_setSampleRate(self, device->Frequency); }
ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2);
@@ -79,7 +85,6 @@ struct MidiSynthVtable {
ALenum (*const selectSoundfonts)(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
void (*const setGain)(MidiSynth *self, ALfloat gain);
void (*const setState)(MidiSynth *self, ALenum state);
void (*const stop)(MidiSynth *self);
void (*const reset)(MidiSynth *self);
@@ -87,26 +92,25 @@ struct MidiSynthVtable {
void (*const update)(MidiSynth *self, ALCdevice *device);
void (*const process)(MidiSynth *self, ALuint samples, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
void (*const Delete)(MidiSynth *self);
void (*const Delete)(void *ptr);
};
#define DEFINE_MIDISYNTH_VTABLE(T) \
DECLARE_THUNK(T, MidiSynth, void, Destruct) \
DECLARE_THUNK3(T, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) \
DECLARE_THUNK1(T, MidiSynth, void, setGain, ALfloat) \
DECLARE_THUNK1(T, MidiSynth, void, setState, ALenum) \
DECLARE_THUNK(T, MidiSynth, void, stop) \
DECLARE_THUNK(T, MidiSynth, void, reset) \
DECLARE_THUNK1(T, MidiSynth, void, update, ALCdevice*) \
DECLARE_THUNK2(T, MidiSynth, void, process, ALuint, ALfloatBUFFERSIZE*restrict) \
DECLARE_THUNK(T, MidiSynth, void, Delete) \
static void T##_MidiSynth_Delete(void *ptr) \
{ T##_Delete(STATIC_UPCAST(T, MidiSynth, (MidiSynth*)ptr)); } \
\
static const struct MidiSynthVtable T##_MidiSynth_vtable = { \
T##_MidiSynth_Destruct, \
\
T##_MidiSynth_selectSoundfonts, \
T##_MidiSynth_setGain, \
T##_MidiSynth_setState, \
T##_MidiSynth_stop, \
T##_MidiSynth_reset, \
T##_MidiSynth_update, \
@@ -116,6 +120,7 @@ static const struct MidiSynthVtable T##_MidiSynth_vtable = { \
}
MidiSynth *SSynth_create(ALCdevice *device);
MidiSynth *FSynth_create(ALCdevice *device);
MidiSynth *DSynth_create(ALCdevice *device);
@@ -22,12 +22,11 @@ static void DSynth_Construct(DSynth *self, ALCdevice *device);
static DECLARE_FORWARD(DSynth, MidiSynth, void, Destruct)
static DECLARE_FORWARD3(DSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*)
static DECLARE_FORWARD1(DSynth, MidiSynth, void, setGain, ALfloat)
static DECLARE_FORWARD1(DSynth, MidiSynth, void, setState, ALenum)
static DECLARE_FORWARD(DSynth, MidiSynth, void, stop)
static DECLARE_FORWARD(DSynth, MidiSynth, void, reset)
static DECLARE_FORWARD1(DSynth, MidiSynth, void, update, ALCdevice*)
static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
static void DSynth_Delete(DSynth *self);
DECLARE_DEFAULT_ALLOCATORS(DSynth)
DEFINE_MIDISYNTH_VTABLE(DSynth);
@@ -49,47 +48,29 @@ static void DSynth_processQueue(DSynth *self, ALuint64 time)
static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloatBUFFERSIZE*restrict UNUSED(DryBuffer))
{
MidiSynth *synth = STATIC_CAST(MidiSynth, self);
ALuint64 curtime;
if(synth->State != AL_PLAYING)
return;
synth->SamplesSinceLast += SamplesToDo;
synth->SamplesToNext -= SamplesToDo;
while(synth->SamplesToNext < 1.0f)
{
ALuint64 time = synth->NextEvtTime;
if(time == UINT64_MAX)
{
synth->SamplesToNext = 0.0;
break;
}
synth->SamplesDone += SamplesToDo;
synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES;
synth->SamplesDone %= synth->SampleRate;
synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
synth->LastEvtTime = time;
DSynth_processQueue(self, time);
synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
if(synth->NextEvtTime != UINT64_MAX)
synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
}
}
static void DSynth_Delete(DSynth *self)
{
free(self);
curtime = MidiSynth_getTime(synth);
DSynth_processQueue(self, maxi64(curtime-1, 0));
}
MidiSynth *DSynth_create(ALCdevice *device)
{
DSynth *synth = calloc(1, sizeof(*synth));
DSynth *synth = DSynth_New(sizeof(*synth));
if(!synth)
{
ERR("Failed to allocate DSynth\n");
return NULL;
}
memset(synth, 0, sizeof(*synth));
DSynth_Construct(synth, device);
return STATIC_CAST(MidiSynth, synth);
}
@@ -10,15 +10,115 @@
#include "alMain.h"
#include "alError.h"
#include "alMidi.h"
#include "alu.h"
#include "compat.h"
#include "evtqueue.h"
#include "rwlock.h"
#include "alu.h"
#ifdef HAVE_FLUIDSYNTH
#include <fluidsynth.h>
#ifdef HAVE_DYNLOAD
#define FLUID_FUNCS(MAGIC) \
MAGIC(new_fluid_synth); \
MAGIC(delete_fluid_synth); \
MAGIC(new_fluid_settings); \
MAGIC(delete_fluid_settings); \
MAGIC(fluid_settings_setint); \
MAGIC(fluid_settings_setnum); \
MAGIC(fluid_synth_noteon); \
MAGIC(fluid_synth_noteoff); \
MAGIC(fluid_synth_program_change); \
MAGIC(fluid_synth_pitch_bend); \
MAGIC(fluid_synth_channel_pressure); \
MAGIC(fluid_synth_cc); \
MAGIC(fluid_synth_sysex); \
MAGIC(fluid_synth_bank_select); \
MAGIC(fluid_synth_set_channel_type); \
MAGIC(fluid_synth_all_sounds_off); \
MAGIC(fluid_synth_system_reset); \
MAGIC(fluid_synth_set_gain); \
MAGIC(fluid_synth_set_sample_rate); \
MAGIC(fluid_synth_write_float); \
MAGIC(fluid_synth_add_sfloader); \
MAGIC(fluid_synth_sfload); \
MAGIC(fluid_synth_sfunload); \
MAGIC(fluid_synth_alloc_voice); \
MAGIC(fluid_synth_start_voice); \
MAGIC(fluid_voice_gen_set); \
MAGIC(fluid_voice_add_mod); \
MAGIC(fluid_mod_set_source1); \
MAGIC(fluid_mod_set_source2); \
MAGIC(fluid_mod_set_amount); \
MAGIC(fluid_mod_set_dest);
void *fsynth_handle = NULL;
#define DECL_FUNC(x) __typeof(x) *p##x
FLUID_FUNCS(DECL_FUNC)
#undef DECL_FUNC
#define new_fluid_synth pnew_fluid_synth
#define delete_fluid_synth pdelete_fluid_synth
#define new_fluid_settings pnew_fluid_settings
#define delete_fluid_settings pdelete_fluid_settings
#define fluid_settings_setint pfluid_settings_setint
#define fluid_settings_setnum pfluid_settings_setnum
#define fluid_synth_noteon pfluid_synth_noteon
#define fluid_synth_noteoff pfluid_synth_noteoff
#define fluid_synth_program_change pfluid_synth_program_change
#define fluid_synth_pitch_bend pfluid_synth_pitch_bend
#define fluid_synth_channel_pressure pfluid_synth_channel_pressure
#define fluid_synth_cc pfluid_synth_cc
#define fluid_synth_sysex pfluid_synth_sysex
#define fluid_synth_bank_select pfluid_synth_bank_select
#define fluid_synth_set_channel_type pfluid_synth_set_channel_type
#define fluid_synth_all_sounds_off pfluid_synth_all_sounds_off
#define fluid_synth_system_reset pfluid_synth_system_reset
#define fluid_synth_set_gain pfluid_synth_set_gain
#define fluid_synth_set_sample_rate pfluid_synth_set_sample_rate
#define fluid_synth_write_float pfluid_synth_write_float
#define fluid_synth_add_sfloader pfluid_synth_add_sfloader
#define fluid_synth_sfload pfluid_synth_sfload
#define fluid_synth_sfunload pfluid_synth_sfunload
#define fluid_synth_alloc_voice pfluid_synth_alloc_voice
#define fluid_synth_start_voice pfluid_synth_start_voice
#define fluid_voice_gen_set pfluid_voice_gen_set
#define fluid_voice_add_mod pfluid_voice_add_mod
#define fluid_mod_set_source1 pfluid_mod_set_source1
#define fluid_mod_set_source2 pfluid_mod_set_source2
#define fluid_mod_set_amount pfluid_mod_set_amount
#define fluid_mod_set_dest pfluid_mod_set_dest
static ALboolean LoadFSynth(void)
{
ALboolean ret = AL_TRUE;
if(!fsynth_handle)
{
fsynth_handle = LoadLib("libfluidsynth.so.1");
if(!fsynth_handle) return AL_FALSE;
#define LOAD_FUNC(x) do { \
p##x = GetSymbol(fsynth_handle, #x); \
if(!p##x) ret = AL_FALSE; \
} while(0)
FLUID_FUNCS(LOAD_FUNC)
#undef LOAD_FUNC
if(ret == AL_FALSE)
{
CloseLib(fsynth_handle);
fsynth_handle = NULL;
}
}
return ret;
}
#else
static inline ALboolean LoadFSynth(void) { return AL_TRUE; }
#endif
/* MIDI events */
#define SYSEX_EVENT (0xF0)
@@ -28,7 +128,7 @@
#define CTRL_ALLNOTESOFF (123)
static int getGenInput(ALenum input)
static int getModInput(ALenum input)
{
switch(input)
{
@@ -43,7 +143,7 @@ static int getGenInput(ALenum input)
return input&0x7F;
}
static int getGenFlags(ALenum input, ALenum type, ALenum form)
static int getModFlags(ALenum input, ALenum type, ALenum form)
{
int ret = 0;
@@ -69,7 +169,7 @@ static int getGenFlags(ALenum input, ALenum type, ALenum form)
return ret;
}
static enum fluid_gen_type getSf2Gen(ALenum gen)
static enum fluid_gen_type getModDest(ALenum gen)
{
switch(gen)
{
@@ -144,7 +244,7 @@ typedef struct FSample {
ALsizei NumMods;
} FSample;
static void FSample_Construct(FSample *self, ALfontsound *sound, ALsoundfont *sfont)
static void FSample_Construct(FSample *self, ALfontsound *sound)
{
fluid_sample_t *sample = STATIC_CAST(fluid_sample_t, self);
memset(sample->name, 0, sizeof(sample->name));
@@ -156,8 +256,8 @@ static void FSample_Construct(FSample *self, ALfontsound *sound, ALsoundfont *sf
sample->origpitch = sound->PitchKey;
sample->pitchadj = sound->PitchCorrection;
sample->sampletype = getSampleType(sound->SampleType);
sample->valid = 1;
sample->data = sfont->Samples;
sample->valid = !!sound->Buffer;
sample->data = sound->Buffer ? sound->Buffer->data : NULL;
sample->amplitude_that_reaches_noise_floor_is_valid = 0;
sample->amplitude_that_reaches_noise_floor = 0.0;
@@ -171,25 +271,30 @@ static void FSample_Construct(FSample *self, ALfontsound *sound, ALsoundfont *sf
self->Sound = sound;
self->NumMods = 0;
self->Mods = calloc(sound->ModulatorMap.size, sizeof(self->Mods[0]));
self->Mods = calloc(sound->ModulatorMap.size*4, sizeof(fluid_mod_t[4]));
if(self->Mods)
{
ALsizei i;
ALsizei i, j, k;
self->NumMods = sound->ModulatorMap.size;
for(i = 0;i < self->NumMods;i++)
for(i = j = 0;i < sound->ModulatorMap.size;i++)
{
ALsfmodulator *mod = sound->ModulatorMap.array[i].value;
fluid_mod_set_source1(&self->Mods[i], getGenInput(mod->Source[0].Input),
getGenFlags(mod->Source[0].Input, mod->Source[0].Type,
mod->Source[0].Form));
fluid_mod_set_source2(&self->Mods[i], getGenInput(mod->Source[1].Input),
getGenFlags(mod->Source[1].Input, mod->Source[1].Type,
mod->Source[1].Form));
fluid_mod_set_amount(&self->Mods[i], mod->Amount);
fluid_mod_set_dest(&self->Mods[i], getSf2Gen(mod->Dest));
self->Mods[i].next = NULL;
for(k = 0;k < 4;k++,mod++)
{
if(mod->Dest == AL_NONE)
continue;
fluid_mod_set_source1(&self->Mods[j], getModInput(mod->Source[0].Input),
getModFlags(mod->Source[0].Input, mod->Source[0].Type,
mod->Source[0].Form));
fluid_mod_set_source2(&self->Mods[j], getModInput(mod->Source[1].Input),
getModFlags(mod->Source[1].Input, mod->Source[1].Type,
mod->Source[1].Form));
fluid_mod_set_amount(&self->Mods[j], mod->Amount);
fluid_mod_set_dest(&self->Mods[j], getModDest(mod->Dest));
self->Mods[j++].next = NULL;
}
}
self->NumMods = j;
}
}
@@ -218,7 +323,7 @@ static int FPreset_getPreset(fluid_preset_t *preset);
static int FPreset_getBank(fluid_preset_t *preset);
static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int velocity);
static void FPreset_Construct(FPreset *self, ALsfpreset *preset, fluid_sfont_t *parent, ALsoundfont *sfont)
static void FPreset_Construct(FPreset *self, ALsfpreset *preset, fluid_sfont_t *parent)
{
STATIC_CAST(fluid_preset_t, self)->data = self;
STATIC_CAST(fluid_preset_t, self)->sfont = parent;
@@ -240,7 +345,7 @@ static void FPreset_Construct(FPreset *self, ALsfpreset *preset, fluid_sfont_t *
ALsizei i;
self->NumSamples = preset->NumSounds;
for(i = 0;i < self->NumSamples;i++)
FSample_Construct(&self->Samples[i], preset->Sounds[i], sfont);
FSample_Construct(&self->Samples[i], preset->Sounds[i]);
}
}
@@ -258,7 +363,6 @@ static void FPreset_Destruct(FPreset *self)
static ALboolean FPreset_canDelete(FPreset *self)
{
ALsizei i;
for(i = 0;i < self->NumSamples;i++)
{
if(fluid_sample_refcount(STATIC_CAST(fluid_sample_t, &self->Samples[i])) != 0)
@@ -298,8 +402,7 @@ static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int chan
continue;
voice = fluid_synth_alloc_voice(synth, STATIC_CAST(fluid_sample_t, sample), channel, key, vel);
if(voice == NULL)
return FLUID_FAILED;
if(voice == NULL) return FLUID_FAILED;
fluid_voice_gen_set(voice, GEN_MODLFOTOPITCH, sound->ModLfoToPitch);
fluid_voice_gen_set(voice, GEN_VIBLFOTOPITCH, sound->VibratoLfoToPitch);
@@ -384,7 +487,7 @@ static void FSfont_Construct(FSfont *self, ALsoundfont *sfont)
ALsizei i;
self->NumPresets = sfont->NumPresets;
for(i = 0;i < self->NumPresets;i++)
FPreset_Construct(&self->Presets[i], sfont->Presets[i], STATIC_CAST(fluid_sfont_t, self), sfont);
FPreset_Construct(&self->Presets[i], sfont->Presets[i], STATIC_CAST(fluid_sfont_t, self));
}
}
@@ -470,13 +573,12 @@ static void FSynth_Destruct(FSynth *self);
static ALboolean FSynth_init(FSynth *self, ALCdevice *device);
static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
static void FSynth_setGain(FSynth *self, ALfloat gain);
static void FSynth_setState(FSynth *self, ALenum state);
static void FSynth_stop(FSynth *self);
static void FSynth_reset(FSynth *self);
static void FSynth_update(FSynth *self, ALCdevice *device);
static void FSynth_processQueue(FSynth *self, ALuint64 time);
static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
static void FSynth_Delete(FSynth *self);
DECLARE_DEFAULT_ALLOCATORS(FSynth)
DEFINE_MIDISYNTH_VTABLE(FSynth);
static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename);
@@ -632,32 +734,15 @@ static void FSynth_setGain(FSynth *self, ALfloat gain)
}
static void FSynth_setState(FSynth *self, ALenum state)
{
MidiSynth_setState(STATIC_CAST(MidiSynth, self), state);
}
static void FSynth_stop(FSynth *self)
{
MidiSynth *synth = STATIC_CAST(MidiSynth, self);
ALuint64 curtime;
ALsizei chan;
/* Make sure all pending events are processed. */
while(!(synth->SamplesToNext >= 1.0))
{
ALuint64 time = synth->NextEvtTime;
if(time == UINT64_MAX)
break;
synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
synth->LastEvtTime = time;
FSynth_processQueue(self, time);
synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
if(synth->NextEvtTime != UINT64_MAX)
synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
}
curtime = MidiSynth_getTime(synth);
FSynth_processQueue(self, curtime);
/* All notes off */
for(chan = 0;chan < 16;chan++)
@@ -759,6 +844,7 @@ static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict
{
MidiSynth *synth = STATIC_CAST(MidiSynth, self);
ALenum state = synth->State;
ALuint64 curtime;
ALuint total = 0;
if(state == AL_INITIAL)
@@ -770,58 +856,59 @@ static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict
return;
}
curtime = MidiSynth_getTime(synth);
while(total < SamplesToDo)
{
if(synth->SamplesToNext >= 1.0)
{
ALuint todo = minu(SamplesToDo - total, fastf2u(synth->SamplesToNext));
ALuint64 time, diff;
ALint tonext;
fluid_synth_write_float(self->Synth, todo,
&DryBuffer[FrontLeft][total], 0, 1,
&DryBuffer[FrontRight][total], 0, 1);
total += todo;
synth->SamplesSinceLast += todo;
synth->SamplesToNext -= todo;
time = MidiSynth_getNextEvtTime(synth);
diff = maxu64(time, curtime) - curtime;
if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX)
{
/* If there's no pending event, or if it's more than 1 second
* away, do as many samples as we can. */
tonext = INT_MAX;
}
else
{
ALuint64 time = synth->NextEvtTime;
if(time == UINT64_MAX)
{
synth->SamplesSinceLast += SamplesToDo-total;
fluid_synth_write_float(self->Synth, SamplesToDo-total,
&DryBuffer[FrontLeft][total], 0, 1,
&DryBuffer[FrontRight][total], 0, 1);
break;
}
synth->SamplesSinceLast -= (time - synth->LastEvtTime) * synth->SamplesPerTick;
synth->SamplesSinceLast = maxd(synth->SamplesSinceLast, 0.0);
synth->LastEvtTime = time;
FSynth_processQueue(self, time);
synth->NextEvtTime = MidiSynth_getNextEvtTime(synth);
if(synth->NextEvtTime != UINT64_MAX)
synth->SamplesToNext += (synth->NextEvtTime - synth->LastEvtTime) * synth->SamplesPerTick;
/* Figure out how many samples until the next event. */
tonext = (ALint)((diff*synth->SampleRate + (MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES);
tonext -= total;
}
if(tonext > 0)
{
ALuint todo = minu(tonext, SamplesToDo-total);
fluid_synth_write_float(self->Synth, todo, DryBuffer[FrontLeft], total, 1,
DryBuffer[FrontRight], total, 1);
total += todo;
tonext -= todo;
}
if(total < SamplesToDo && tonext <= 0)
FSynth_processQueue(self, time);
}
}
static void FSynth_Delete(FSynth *self)
{
free(self);
synth->SamplesDone += SamplesToDo;
synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES;
synth->SamplesDone %= synth->SampleRate;
}
MidiSynth *FSynth_create(ALCdevice *device)
{
FSynth *synth = calloc(1, sizeof(*synth));
FSynth *synth;
if(!LoadFSynth())
return NULL;
synth = FSynth_New(sizeof(*synth));
if(!synth)
{
ERR("Failed to allocate FSynth\n");
return NULL;
}
memset(synth, 0, sizeof(*synth));
FSynth_Construct(synth, device);
if(FSynth_init(synth, device) == AL_FALSE)
@@ -15,31 +15,22 @@
static ALuint read_le32(Reader *stream)
{
ALubyte buf[4];
if(READ(stream, buf, 4) != 4)
{
READERR(stream) = 1;
if(Reader_read(stream, buf, 4) != 4)
return 0;
}
return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
}
static ALushort read_le16(Reader *stream)
{
ALubyte buf[2];
if(READ(stream, buf, 2) != 2)
{
READERR(stream) = 1;
if(Reader_read(stream, buf, 2) != 2)
return 0;
}
return (buf[1]<<8) | buf[0];
}
static ALubyte read_8(Reader *stream)
{
ALubyte buf[1];
if(READ(stream, buf, 1) != 1)
{
READERR(stream) = 1;
if(Reader_read(stream, buf, 1) != 1)
return 0;
}
return buf[0];
}
static void skip(Reader *stream, ALuint amt)
@@ -47,12 +38,7 @@ static void skip(Reader *stream, ALuint amt)
while(amt > 0 && !READERR(stream))
{
char buf[4096];
size_t got;
got = READ(stream, buf, minu(sizeof(buf), amt));
if(got == 0) READERR(stream) = 1;
amt -= got;
amt -= Reader_read(stream, buf, minu(sizeof(buf), amt));
}
}
@@ -166,8 +152,7 @@ typedef struct PresetHeader {
} PresetHeader;
static void PresetHeader_read(PresetHeader *self, Reader *stream)
{
if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
READERR(stream) = 1;
Reader_read(stream, self->mName, sizeof(self->mName));
self->mPreset = read_le16(stream);
self->mBank = read_le16(stream);
self->mZoneIdx = read_le16(stream);
@@ -182,13 +167,12 @@ typedef struct InstrumentHeader {
} InstrumentHeader;
static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream)
{
if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
READERR(stream) = 1;
Reader_read(stream, self->mName, sizeof(self->mName));
self->mZoneIdx = read_le16(stream);
}
typedef struct SampleHeader {
ALchar mName[20]; // 20 bytes
ALchar mName[20];
ALuint mStart;
ALuint mEnd;
ALuint mStartloop;
@@ -201,8 +185,7 @@ typedef struct SampleHeader {
} SampleHeader;
static void SampleHeader_read(SampleHeader *self, Reader *stream)
{
if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
READERR(stream) = 1;
Reader_read(stream, self->mName, sizeof(self->mName));
self->mStart = read_le32(stream);
self->mEnd = read_le32(stream);
self->mStartloop = read_le32(stream);
@@ -311,7 +294,8 @@ static void Soundfont_Destruct(Soundfont *self)
}
#define FOURCC(a,b,c,d) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a))
#define FOURCC(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
#define FOURCCFMT "%c%c%c%c"
#define FOURCCARGS(x) (char)((x)&0xff), (char)(((x)>>8)&0xff), (char)(((x)>>16)&0xff), (char)(((x)>>24)&0xff)
typedef struct RiffHdr {
ALuint mCode;
@@ -325,60 +309,42 @@ static void RiffHdr_read(RiffHdr *self, Reader *stream)
typedef struct GenModList {
Generator *gens;
ALsizei gens_size;
ALsizei gens_max;
Modulator *mods;
ALsizei mods_size;
ALsizei mods_max;
VECTOR(Generator) gens;
VECTOR(Modulator) mods;
} GenModList;
static void GenModList_Construct(GenModList *self)
{
self->gens = NULL;
self->gens_size = 0;
self->gens_max = 0;
self->mods = NULL;
self->mods_size = 0;
self->mods_max = 0;
VECTOR_INIT(self->gens);
VECTOR_INIT(self->mods);
}
static void GenModList_Destruct(GenModList *self)
{
free(self->gens);
self->gens = NULL;
self->gens_size = 0;
self->gens_max = 0;
free(self->mods);
self->mods = NULL;
self->mods_size = 0;
self->mods_max = 0;
VECTOR_DEINIT(self->mods);
VECTOR_DEINIT(self->gens);
}
static GenModList GenModList_clone(const GenModList *self)
{
GenModList ret;
ret.gens = malloc(self->gens_max * sizeof(ret.gens[0]));
memcpy(ret.gens, self->gens, self->gens_size * sizeof(ret.gens[0]));
ret.gens_size = self->gens_size;
ret.gens_max = self->gens_max;
GenModList_Construct(&ret);
ret.mods = malloc(self->mods_max * sizeof(ret.mods[0]));
memcpy(ret.mods, self->mods, self->mods_size * sizeof(ret.mods[0]));
ret.mods_size = self->mods_size;
ret.mods_max = self->mods_max;
VECTOR_INSERT(ret.gens, VECTOR_ITER_END(ret.gens),
VECTOR_ITER_BEGIN(self->gens), VECTOR_ITER_END(self->gens)
);
VECTOR_INSERT(ret.mods, VECTOR_ITER_END(ret.mods),
VECTOR_ITER_BEGIN(self->mods), VECTOR_ITER_END(self->mods)
);
return ret;
}
static void GenModList_insertGen(GenModList *self, const Generator *gen, ALboolean ispreset)
{
Generator *i = self->gens;
Generator *end = i + self->gens_size;
Generator *i = VECTOR_ITER_BEGIN(self->gens);
Generator *end = VECTOR_ITER_END(self->gens);
for(;i != end;i++)
{
if(i->mGenerator == gen->mGenerator)
@@ -396,32 +362,16 @@ static void GenModList_insertGen(GenModList *self, const Generator *gen, ALboole
gen->mGenerator == 58))
return;
if(self->gens_size == self->gens_max)
if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE)
{
void *temp = NULL;
ALsizei newsize;
newsize = (self->gens_max ? self->gens_max<<1 : 1);
if(newsize > self->gens_max)
temp = realloc(self->gens, newsize * sizeof(self->gens[0]));
if(!temp)
{
ERR("Failed to increase generator storage to %d elements (from %d)\n",
newsize, self->gens_max);
return;
}
self->gens = temp;
self->gens_max = newsize;
ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens));
return;
}
self->gens[self->gens_size] = *gen;
self->gens_size++;
}
static void GenModList_accumGen(GenModList *self, const Generator *gen)
{
Generator *i = self->gens;
Generator *end = i + self->gens_size;
Generator *i = VECTOR_ITER_BEGIN(self->gens);
Generator *end = VECTOR_ITER_END(self->gens);
for(;i != end;i++)
{
if(i->mGenerator == gen->mGenerator)
@@ -441,35 +391,19 @@ static void GenModList_accumGen(GenModList *self, const Generator *gen)
}
}
if(self->gens_size == self->gens_max)
if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE)
{
void *temp = NULL;
ALsizei newsize;
newsize = (self->gens_max ? self->gens_max<<1 : 1);
if(newsize > self->gens_max)
temp = realloc(self->gens, newsize * sizeof(self->gens[0]));
if(!temp)
{
ERR("Failed to increase generator storage to %d elements (from %d)\n",
newsize, self->gens_max);
return;
}
self->gens = temp;
self->gens_max = newsize;
ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens));
return;
}
self->gens[self->gens_size] = *gen;
if(gen->mGenerator < 60)
self->gens[self->gens_size].mAmount += DefaultGenValue[gen->mGenerator];
self->gens_size++;
VECTOR_BACK(self->gens).mAmount += DefaultGenValue[gen->mGenerator];
}
static void GenModList_insertMod(GenModList *self, const Modulator *mod)
{
Modulator *i = self->mods;
Modulator *end = i + self->mods_size;
Modulator *i = VECTOR_ITER_BEGIN(self->mods);
Modulator *end = VECTOR_ITER_END(self->mods);
for(;i != end;i++)
{
if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp &&
@@ -480,32 +414,16 @@ static void GenModList_insertMod(GenModList *self, const Modulator *mod)
}
}
if(self->mods_size == self->mods_max)
if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE)
{
void *temp = NULL;
ALsizei newsize;
newsize = (self->mods_max ? self->mods_max<<1 : 1);
if(newsize > self->mods_max)
temp = realloc(self->mods, newsize * sizeof(self->mods[0]));
if(!temp)
{
ERR("Failed to increase modulator storage to %d elements (from %d)\n",
newsize, self->mods_max);
return;
}
self->mods = temp;
self->mods_max = newsize;
ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods));
return;
}
self->mods[self->mods_size] = *mod;
self->mods_size++;
}
static void GenModList_accumMod(GenModList *self, const Modulator *mod)
{
Modulator *i = self->mods;
Modulator *end = i + self->mods_size;
Modulator *i = VECTOR_ITER_BEGIN(self->mods);
Modulator *end = VECTOR_ITER_END(self->mods);
for(;i != end;i++)
{
if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp &&
@@ -516,47 +434,32 @@ static void GenModList_accumMod(GenModList *self, const Modulator *mod)
}
}
if(self->mods_size == self->mods_max)
if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE)
{
void *temp = NULL;
ALsizei newsize;
newsize = (self->mods_max ? self->mods_max<<1 : 1);
if(newsize > self->mods_max)
temp = realloc(self->mods, newsize * sizeof(self->mods[0]));
if(!temp)
{
ERR("Failed to increase modulator storage to %d elements (from %d)\n",
newsize, self->mods_max);
return;
}
self->mods = temp;
self->mods_max = newsize;
ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods));
return;
}
self->mods[self->mods_size] = *mod;
if(mod->mSrcOp == 0x0502 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 960;
VECTOR_BACK(self->mods).mAmount += 960;
else if(mod->mSrcOp == 0x0102 && mod->mDstOp == 8 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += -2400;
VECTOR_BACK(self->mods).mAmount += -2400;
else if(mod->mSrcOp == 0x000D && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 50;
VECTOR_BACK(self->mods).mAmount += 50;
else if(mod->mSrcOp == 0x0081 && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 50;
VECTOR_BACK(self->mods).mAmount += 50;
else if(mod->mSrcOp == 0x0582 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 960;
VECTOR_BACK(self->mods).mAmount += 960;
else if(mod->mSrcOp == 0x028A && mod->mDstOp == 17 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 1000;
VECTOR_BACK(self->mods).mAmount += 1000;
else if(mod->mSrcOp == 0x058B && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 960;
VECTOR_BACK(self->mods).mAmount += 960;
else if(mod->mSrcOp == 0x00DB && mod->mDstOp == 16 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 200;
VECTOR_BACK(self->mods).mAmount += 200;
else if(mod->mSrcOp == 0x00DD && mod->mDstOp == 15 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 200;
VECTOR_BACK(self->mods).mAmount += 200;
/*else if(mod->mSrcOp == 0x020E && mod->mDstOp == ?initialpitch? && mod->mAmtSrcOp == 0x0010 && mod->mTransOp == 0)
self->mods[self->mods_size].mAmount += 12700;*/
self->mods_size++;
VECTOR_BACK(self->mods).mAmount += 12700;*/
}
@@ -569,7 +472,7 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
{
ALsizei i;
for(i = 0;i < sfont->phdr_size-1;i++)
for(i = 0;i < sfont->phdr_size;i++)
{
if(sfont->phdr[i].mZoneIdx >= sfont->pbag_size)
{
@@ -577,21 +480,15 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
sfont->phdr[i].mZoneIdx, sfont->pbag_size);
return AL_FALSE;
}
if(sfont->phdr[i+1].mZoneIdx < sfont->phdr[i].mZoneIdx)
if(i+1 < sfont->phdr_size && sfont->phdr[i+1].mZoneIdx < sfont->phdr[i].mZoneIdx)
{
WARN("Preset %d has invalid zone index (%d does not follow %d)\n", i+1,
sfont->phdr[i+1].mZoneIdx, sfont->phdr[i].mZoneIdx);
return AL_FALSE;
}
}
if(sfont->phdr[i].mZoneIdx >= sfont->pbag_size)
{
WARN("Preset %d has invalid zone index %d (max: %d)\n", i,
sfont->phdr[i].mZoneIdx, sfont->pbag_size);
return AL_FALSE;
}
for(i = 0;i < sfont->pbag_size-1;i++)
for(i = 0;i < sfont->pbag_size;i++)
{
if(sfont->pbag[i].mGenIdx >= sfont->pgen_size)
{
@@ -599,7 +496,7 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
sfont->pbag[i].mGenIdx, sfont->pgen_size);
return AL_FALSE;
}
if(sfont->pbag[i+1].mGenIdx < sfont->pbag[i].mGenIdx)
if(i+1 < sfont->pbag_size && sfont->pbag[i+1].mGenIdx < sfont->pbag[i].mGenIdx)
{
WARN("Preset zone %d has invalid generator index (%d does not follow %d)\n", i+1,
sfont->pbag[i+1].mGenIdx, sfont->pbag[i].mGenIdx);
@@ -611,28 +508,16 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
sfont->pbag[i].mModIdx, sfont->pmod_size);
return AL_FALSE;
}
if(sfont->pbag[i+1].mModIdx < sfont->pbag[i].mModIdx)
if(i+1 < sfont->pbag_size && sfont->pbag[i+1].mModIdx < sfont->pbag[i].mModIdx)
{
WARN("Preset zone %d has invalid modulator index (%d does not follow %d)\n", i+1,
sfont->pbag[i+1].mModIdx, sfont->pbag[i].mModIdx);
return AL_FALSE;
}
}
if(sfont->pbag[i].mGenIdx >= sfont->pgen_size)
{
WARN("Preset zone %d has invalid generator index %d (max: %d)\n", i,
sfont->pbag[i].mGenIdx, sfont->pgen_size);
return AL_FALSE;
}
if(sfont->pbag[i].mModIdx >= sfont->pmod_size)
{
WARN("Preset zone %d has invalid modulator index %d (max: %d)\n", i,
sfont->pbag[i].mModIdx, sfont->pmod_size);
return AL_FALSE;
}
for(i = 0;i < sfont->inst_size-1;i++)
for(i = 0;i < sfont->inst_size;i++)
{
if(sfont->inst[i].mZoneIdx >= sfont->ibag_size)
{
@@ -640,21 +525,15 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
sfont->inst[i].mZoneIdx, sfont->ibag_size);
return AL_FALSE;
}
if(sfont->inst[i+1].mZoneIdx < sfont->inst[i].mZoneIdx)
if(i+1 < sfont->inst_size && sfont->inst[i+1].mZoneIdx < sfont->inst[i].mZoneIdx)
{
WARN("Instrument %d has invalid zone index (%d does not follow %d)\n", i+1,
sfont->inst[i+1].mZoneIdx, sfont->inst[i].mZoneIdx);
return AL_FALSE;
}
}
if(sfont->inst[i].mZoneIdx >= sfont->ibag_size)
{
WARN("Instrument %d has invalid zone index %d (max: %d)\n", i,
sfont->inst[i].mZoneIdx, sfont->ibag_size);
return AL_FALSE;
}
for(i = 0;i < sfont->ibag_size-1;i++)
for(i = 0;i < sfont->ibag_size;i++)
{
if(sfont->ibag[i].mGenIdx >= sfont->igen_size)
{
@@ -662,7 +541,7 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
sfont->ibag[i].mGenIdx, sfont->igen_size);
return AL_FALSE;
}
if(sfont->ibag[i+1].mGenIdx < sfont->ibag[i].mGenIdx)
if(i+1 < sfont->ibag_size && sfont->ibag[i+1].mGenIdx < sfont->ibag[i].mGenIdx)
{
WARN("Instrument zone %d has invalid generator index (%d does not follow %d)\n", i+1,
sfont->ibag[i+1].mGenIdx, sfont->ibag[i].mGenIdx);
@@ -674,25 +553,13 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
sfont->ibag[i].mModIdx, sfont->imod_size);
return AL_FALSE;
}
if(sfont->ibag[i+1].mModIdx < sfont->ibag[i].mModIdx)
if(i+1 < sfont->ibag_size && sfont->ibag[i+1].mModIdx < sfont->ibag[i].mModIdx)
{
WARN("Instrument zone %d has invalid modulator index (%d does not follow %d)\n", i+1,
sfont->ibag[i+1].mModIdx, sfont->ibag[i].mModIdx);
return AL_FALSE;
}
}
if(sfont->ibag[i].mGenIdx >= sfont->igen_size)
{
WARN("Instrument zone %d has invalid generator index %d (max: %d)\n", i,
sfont->ibag[i].mGenIdx, sfont->igen_size);
return AL_FALSE;
}
if(sfont->ibag[i].mModIdx >= sfont->imod_size)
{
WARN("Instrument zone %d has invalid modulator index %d (max: %d)\n", i,
sfont->ibag[i].mModIdx, sfont->imod_size);
return AL_FALSE;
}
for(i = 0;i < sfont->shdr_size-1;i++)
@@ -710,21 +577,21 @@ static ALboolean ensureFontSanity(const Soundfont *sfont)
static ALboolean checkZone(const GenModList *zone, const PresetHeader *preset, const InstrumentHeader *inst, const SampleHeader *samp)
{
ALsizei i;
for(i = 0;i < zone->gens_size;i++)
Generator *gen = VECTOR_ITER_BEGIN(zone->gens);
Generator *gen_end = VECTOR_ITER_END(zone->gens);
for(;gen != gen_end;gen++)
{
if(zone->gens[i].mGenerator == 43 || zone->gens[i].mGenerator == 44)
if(gen->mGenerator == 43 || gen->mGenerator == 44)
{
int high = zone->gens[i].mAmount>>8;
int low = zone->gens[i].mAmount&0xff;
int high = gen->mAmount>>8;
int low = gen->mAmount&0xff;
if(!(low >= 0 && high <= 127 && high >= low))
{
TRACE("Preset \"%s\", inst \"%s\", sample \"%s\": invalid %s range %d...%d\n",
preset->mName, inst->mName, samp->mName,
(zone->gens[i].mGenerator == 43) ? "key" :
(zone->gens[i].mGenerator == 44) ? "velocity" : "(unknown)",
(gen->mGenerator == 43) ? "key" :
(gen->mGenerator == 44) ? "velocity" : "(unknown)",
low, high);
return AL_FALSE;
}
@@ -745,11 +612,8 @@ static ALenum getModSrcInput(int input)
if(input == 16) return AL_PITCHBEND_SENSITIVITY_SOFT;
if((input&0x80))
{
input ^= 0x80;
if(input > 0 && input < 120 && !(input == 6 || (input >= 32 && input <= 63) ||
(input >= 98 && input <= 101)))
return input;
input ^= 0x80;
if(IsValidCtrlInput(input^0x80))
return input^0x80;
}
ERR("Unhandled modulator source input: 0x%02x\n", input);
return AL_INVALID;
@@ -871,43 +735,43 @@ static void fillZone(ALfontsound *sound, ALCcontext *context, const GenModList *
0, /* 59 - */
};
const Generator *gen, *gen_end;
const Modulator *mod, *mod_end;
if(zone->mods)
mod = VECTOR_ITER_BEGIN(zone->mods);
mod_end = VECTOR_ITER_END(zone->mods);
for(;mod != mod_end;mod++)
{
ALsizei i;
for(i = 0;i < zone->mods_size;i++)
ALenum src0in = getModSrcInput(mod->mSrcOp&0xFF);
ALenum src0type = getModSrcType(mod->mSrcOp&0x0300);
ALenum src0form = getModSrcForm(mod->mSrcOp&0xFC00);
ALenum src1in = getModSrcInput(mod->mAmtSrcOp&0xFF);
ALenum src1type = getModSrcType(mod->mAmtSrcOp&0x0300);
ALenum src1form = getModSrcForm(mod->mAmtSrcOp&0xFC00);
ALenum trans = getModTransOp(mod->mTransOp);
ALenum dst = (mod->mDstOp < 60) ? Gen2Param[mod->mDstOp] : 0;
if(!dst || dst == AL_KEY_RANGE_SOFT || dst == AL_VELOCITY_RANGE_SOFT ||
dst == AL_LOOP_MODE_SOFT || dst == AL_EXCLUSIVE_CLASS_SOFT ||
dst == AL_BASE_KEY_SOFT)
ERR("Unhandled modulator destination: %d\n", mod->mDstOp);
else if(src0in != AL_INVALID && src0form != AL_INVALID && src0type != AL_INVALID &&
src1in != AL_INVALID && src1form != AL_INVALID && src0type != AL_INVALID &&
trans != AL_INVALID)
{
ALenum src0in = getModSrcInput(zone->mods[i].mSrcOp&0xFF);
ALenum src0type = getModSrcType(zone->mods[i].mSrcOp&0x0300);
ALenum src0form = getModSrcForm(zone->mods[i].mSrcOp&0xFC00);
ALenum src1in = getModSrcInput(zone->mods[i].mAmtSrcOp&0xFF);
ALenum src1type = getModSrcType(zone->mods[i].mAmtSrcOp&0x0300);
ALenum src1form = getModSrcForm(zone->mods[i].mAmtSrcOp&0xFC00);
ALenum trans = getModTransOp(zone->mods[i].mTransOp);
ALenum dst = (zone->mods[i].mDstOp < 60) ? Gen2Param[zone->mods[i].mDstOp] : 0;
if(!dst || dst == AL_KEY_RANGE_SOFT || dst == AL_VELOCITY_RANGE_SOFT ||
dst == AL_LOOP_MODE_SOFT || dst == AL_EXCLUSIVE_CLASS_SOFT ||
dst == AL_BASE_KEY_SOFT)
ERR("Unhandled modulator destination: %d\n", zone->mods[i].mDstOp);
else if(src0in != AL_INVALID && src0form != AL_INVALID && src0type != AL_INVALID &&
src1in != AL_INVALID && src1form != AL_INVALID && src0type != AL_INVALID &&
trans != AL_INVALID)
{
ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_INPUT_SOFT, src0in);
ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_TYPE_SOFT, src0type);
ALfontsound_setModStagei(sound, context, i, AL_SOURCE0_FORM_SOFT, src0form);
ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_INPUT_SOFT, src1in);
ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_TYPE_SOFT, src1type);
ALfontsound_setModStagei(sound, context, i, AL_SOURCE1_FORM_SOFT, src1form);
ALfontsound_setModStagei(sound, context, i, AL_AMOUNT_SOFT, zone->mods[i].mAmount);
ALfontsound_setModStagei(sound, context, i, AL_TRANSFORM_OP_SOFT, trans);
ALfontsound_setModStagei(sound, context, i, AL_DESTINATION_SOFT, dst);
}
ALsizei idx = (ALsizei)(mod - VECTOR_ITER_BEGIN(zone->mods));
ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_INPUT_SOFT, src0in);
ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_TYPE_SOFT, src0type);
ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_FORM_SOFT, src0form);
ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_INPUT_SOFT, src1in);
ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_TYPE_SOFT, src1type);
ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_FORM_SOFT, src1form);
ALfontsound_setModStagei(sound, context, idx, AL_AMOUNT_SOFT, mod->mAmount);
ALfontsound_setModStagei(sound, context, idx, AL_TRANSFORM_OP_SOFT, trans);
ALfontsound_setModStagei(sound, context, idx, AL_DESTINATION_SOFT, dst);
}
}
gen = zone->gens;
gen_end = gen + zone->gens_size;
gen = VECTOR_ITER_BEGIN(zone->gens);
gen_end = VECTOR_ITER_END(zone->gens);
for(;gen != gen_end;gen++)
{
ALint value = (ALshort)gen->mAmount;
@@ -961,12 +825,12 @@ static void fillZone(ALfontsound *sound, ALCcontext *context, const GenModList *
value = getLoopMode(value);
ALfontsound_setPropi(sound, context, param, value);
}
else if(gen->mGenerator < 256)
else
{
static ALboolean warned[256];
if(!warned[gen->mGenerator])
static ALuint warned[65536/32];
if(!(warned[gen->mGenerator/32]&(1<<(gen->mGenerator&31))))
{
warned[gen->mGenerator] = AL_TRUE;
warned[gen->mGenerator/32] |= 1<<(gen->mGenerator&31);
ERR("Unhandled generator %d\n", gen->mGenerator);
}
}
@@ -974,7 +838,7 @@ static void fillZone(ALfontsound *sound, ALCcontext *context, const GenModList *
}
}
static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCcontext *context, InstrumentHeader *inst, const PresetHeader *preset, const Soundfont *sfont, const GenModList *pzone)
static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCcontext *context, ALbuffer *buffer, InstrumentHeader *inst, const PresetHeader *preset, const Soundfont *sfont, const GenModList *pzone)
{
const Generator *gen, *gen_end;
const Modulator *mod, *mod_end;
@@ -1019,8 +883,8 @@ static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCco
temp = realloc(*sounds, (zone_end-zone + *sounds_size)*sizeof((*sounds)[0]));
if(!temp)
{
ERR("Failed reallocating fontsound storage to %ld elements (from %d)\n",
(zone_end-zone + *sounds_size), *sounds_size);
ERR("Failed reallocating fontsound storage to %d elements (from %d)\n",
(ALsizei)(zone_end-zone) + *sounds_size, *sounds_size);
return;
}
*sounds = temp;
@@ -1049,13 +913,13 @@ static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCco
}
samp = &sfont->shdr[gen->mAmount];
gen = pzone->gens;
gen_end = gen + pzone->gens_size;
gen = VECTOR_ITER_BEGIN(pzone->gens);
gen_end = VECTOR_ITER_END(pzone->gens);
for(;gen != gen_end;gen++)
GenModList_accumGen(&lzone, gen);
mod = pzone->mods;
mod_end = mod + pzone->mods_size;
mod = VECTOR_ITER_BEGIN(pzone->mods);
mod_end = VECTOR_ITER_END(pzone->mods);
for(;mod != mod_end;mod++)
GenModList_accumMod(&lzone, mod);
@@ -1067,6 +931,7 @@ static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCco
sound = NewFontsound(context);
(*sounds)[(*sounds_size)++] = sound;
ALfontsound_setPropi(sound, context, AL_BUFFER, buffer->id);
ALfontsound_setPropi(sound, context, AL_SAMPLE_START_SOFT, samp->mStart);
ALfontsound_setPropi(sound, context, AL_SAMPLE_END_SOFT, samp->mEnd);
ALfontsound_setPropi(sound, context, AL_SAMPLE_LOOP_START_SOFT, samp->mStartloop);
@@ -1088,10 +953,27 @@ static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCco
GenModList_Destruct(&gzone);
}
static size_t printStringChunk(Reader *stream, const RiffHdr *chnk, const char *title)
{
size_t len = 0;
if(chnk->mSize == 0 || (chnk->mSize&1))
ERR("Invalid "FOURCCFMT" size: %d\n", FOURCCARGS(chnk->mCode), chnk->mSize);
else
{
char *str = calloc(1, chnk->mSize+1);
len = Reader_read(stream, str, chnk->mSize);
TRACE("%s: %s\n", title, str);
free(str);
}
return len;
}
ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
{
ALsfpreset **presets = NULL;
ALsizei presets_size = 0;
ALbuffer *buffer = NULL;
ALuint ltype;
Soundfont sfont;
RiffHdr riff;
@@ -1102,36 +984,52 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&riff, stream);
if(riff.mCode != FOURCC('R','I','F','F'))
ERROR_GOTO(error, "Invalid Format, expected RIFF got '%c%c%c%c'\n", FOURCCARGS(riff.mCode));
ERROR_GOTO(error, "Invalid Format, expected RIFF got '"FOURCCFMT"'\n", FOURCCARGS(riff.mCode));
if((ltype=read_le32(stream)) != FOURCC('s','f','b','k'))
ERROR_GOTO(error, "Invalid Format, expected sfbk got '%c%c%c%c'\n", FOURCCARGS(ltype));
ERROR_GOTO(error, "Invalid Format, expected sfbk got '"FOURCCFMT"'\n", FOURCCARGS(ltype));
if(READERR(stream) != 0)
ERROR_GOTO(error, "Error reading file header\n");
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('L','I','S','T'))
ERROR_GOTO(error, "Invalid Format, expected LIST (INFO) got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected LIST (INFO) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((ltype=read_le32(stream)) != FOURCC('I','N','F','O'))
ERROR_GOTO(error, "Invalid Format, expected INFO got '%c%c%c%c'\n", FOURCCARGS(ltype));
ERROR_GOTO(error, "Invalid Format, expected INFO got '"FOURCCFMT"'\n", FOURCCARGS(ltype));
list.mSize -= 4;
while(list.mSize > 0 && !READERR(stream))
{
RiffHdr info;
RiffHdr chnk;
RiffHdr_read(&info, stream);
list.mSize -= 8;
if(info.mCode == FOURCC('i','f','i','l'))
if(list.mSize < 8)
{
if(info.mSize != 4)
ERR("Invalid ifil chunk size: %d\n", info.mSize);
WARN("Unexpected end of INFO list (%u extra bytes)\n", list.mSize);
skip(stream, list.mSize);
list.mSize = 0;
break;
}
RiffHdr_read(&chnk, stream);
list.mSize -= 8;
if(list.mSize < chnk.mSize)
{
WARN("INFO sub-chunk '"FOURCCFMT"' has %u bytes, but only %u bytes remain\n",
FOURCCARGS(chnk.mCode), chnk.mSize, list.mSize);
skip(stream, list.mSize);
list.mSize = 0;
break;
}
list.mSize -= chnk.mSize;
if(chnk.mCode == FOURCC('i','f','i','l'))
{
if(chnk.mSize != 4)
ERR("Invalid ifil chunk size: %d\n", chnk.mSize);
else
{
ALushort major = read_le16(stream);
ALushort minor = read_le16(stream);
list.mSize -= 4;
info.mSize -= 4;
chnk.mSize -= 4;
if(major != 2)
ERROR_GOTO(error, "Unsupported SF2 format version: %d.%02d\n", major, minor);
@@ -1140,24 +1038,48 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
sfont.ifil = (major<<16) | minor;
}
}
else if(info.mCode == FOURCC('i','r','o','m'))
else if(chnk.mCode == FOURCC('i','r','o','m'))
{
if(info.mSize == 0 || (info.mSize&1))
ERR("Invalid irom size: %d\n", info.mSize);
if(chnk.mSize == 0 || (chnk.mSize&1))
ERR("Invalid irom size: %d\n", chnk.mSize);
else
{
free(sfont.irom);
sfont.irom = calloc(1, info.mSize+1);
READ(stream, sfont.irom, info.mSize);
list.mSize -= info.mSize;
info.mSize -= info.mSize;
sfont.irom = calloc(1, chnk.mSize+1);
chnk.mSize -= Reader_read(stream, sfont.irom, chnk.mSize);
TRACE("SF2 ROM ID: %s\n", sfont.irom);
}
}
list.mSize -= info.mSize;
skip(stream, info.mSize);
else
{
static const struct {
ALuint code;
char title[16];
} listinfos[] = {
{ FOURCC('i','s','n','g'), "Engine ID" },
{ FOURCC('I','N','A','M'), "Name" },
{ FOURCC('I','C','R','D'), "Creation Date" },
{ FOURCC('I','E','N','G'), "Creator" },
{ FOURCC('I','P','R','D'), "Product ID" },
{ FOURCC('I','C','O','P'), "Copyright" },
{ FOURCC('I','C','M','T'), "Comment" },
{ FOURCC('I','S','F','T'), "Created With" },
{ 0, "" },
};
for(i = 0;listinfos[i].code;i++)
{
if(listinfos[i].code == chnk.mCode)
{
chnk.mSize -= printStringChunk(stream, &chnk, listinfos[i].title);
break;
}
}
if(!listinfos[i].code)
TRACE("Skipping INFO sub-chunk '"FOURCCFMT"' (%u bytes)\n", FOURCCARGS(chnk.mCode), chnk.mSize);
}
skip(stream, chnk.mSize);
}
if(READERR(stream) != 0)
@@ -1167,43 +1089,50 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('L','I','S','T'))
ERROR_GOTO(error, "Invalid Format, expected LIST (sdta) got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected LIST (sdta) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((ltype=read_le32(stream)) != FOURCC('s','d','t','a'))
ERROR_GOTO(error, "Invalid Format, expected sdta got '%c%c%c%c'\n", FOURCCARGS(ltype));
ERROR_GOTO(error, "Invalid Format, expected sdta got '"FOURCCFMT"'\n", FOURCCARGS(ltype));
list.mSize -= 4;
{
ALbyte *ptr;
RiffHdr smpl;
ALenum err;
RiffHdr_read(&smpl, stream);
if(smpl.mCode != FOURCC('s','m','p','l'))
ERROR_GOTO(error, "Invalid Format, expected smpl got '%c%c%c%c'\n", FOURCCARGS(smpl.mCode));
ERROR_GOTO(error, "Invalid Format, expected smpl got '"FOURCCFMT"'\n", FOURCCARGS(smpl.mCode));
list.mSize -= 8;
if(smpl.mSize > list.mSize)
ERROR_GOTO(error, "Invalid Format, sample chunk size mismatch\n");
list.mSize -= smpl.mSize;
if(!(ptr=realloc(soundfont->Samples, smpl.mSize)))
buffer = NewBuffer(context);
if(!buffer)
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, error);
soundfont->Samples = (ALshort*)ptr;
soundfont->NumSamples = smpl.mSize/2;
/* Sample rate is unimportant, the individual fontsounds will specify it. */
if((err=LoadData(buffer, 22050, AL_MONO16_SOFT, smpl.mSize/2, UserFmtMono, UserFmtShort, NULL, 1, AL_FALSE)) != AL_NO_ERROR)
SET_ERROR_AND_GOTO(context, err, error);
ptr = buffer->data;
if(IS_LITTLE_ENDIAN)
READ(stream, ptr, smpl.mSize);
smpl.mSize -= Reader_read(stream, ptr, smpl.mSize);
else
{
while(smpl.mSize > 0)
ALuint total = 0;
while(total < smpl.mSize && !READERR(stream))
{
ALbyte buf[4096];
ALuint todo = minu(smpl.mSize, sizeof(buf));
ALuint todo = minu(smpl.mSize-total, sizeof(buf));
ALuint i;
READ(stream, buf, todo);
smpl.mSize -= Reader_read(stream, buf, todo);
for(i = 0;i < todo;i++)
ptr[i] = buf[i^1];
ptr[total+i] = buf[i^1];
total += todo;
}
}
list.mSize -= smpl.mSize;
skip(stream, list.mSize);
}
@@ -1213,14 +1142,14 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('L','I','S','T'))
ERROR_GOTO(error, "Invalid Format, expected LIST (pdta) got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected LIST (pdta) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((ltype=read_le32(stream)) != FOURCC('p','d','t','a'))
ERROR_GOTO(error, "Invalid Format, expected pdta got '%c%c%c%c'\n", FOURCCARGS(ltype));
ERROR_GOTO(error, "Invalid Format, expected pdta got '"FOURCCFMT"'\n", FOURCCARGS(ltype));
//
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('p','h','d','r'))
ERROR_GOTO(error, "Invalid Format, expected phdr got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected phdr got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%38) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad phdr size: %u\n", list.mSize);
sfont.phdr_size = list.mSize/38;
@@ -1230,7 +1159,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('p','b','a','g'))
ERROR_GOTO(error, "Invalid Format, expected pbag got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected pbag got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%4) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad pbag size: %u\n", list.mSize);
sfont.pbag_size = list.mSize/4;
@@ -1240,7 +1169,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('p','m','o','d'))
ERROR_GOTO(error, "Invalid Format, expected pmod got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected pmod got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%10) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad pmod size: %u\n", list.mSize);
sfont.pmod_size = list.mSize/10;
@@ -1250,7 +1179,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('p','g','e','n'))
ERROR_GOTO(error, "Invalid Format, expected pgen got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected pgen got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%4) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad pgen size: %u\n", list.mSize);
sfont.pgen_size = list.mSize/4;
@@ -1261,7 +1190,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
//
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('i','n','s','t'))
ERROR_GOTO(error, "Invalid Format, expected inst got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected inst got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%22) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad inst size: %u\n", list.mSize);
sfont.inst_size = list.mSize/22;
@@ -1271,7 +1200,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('i','b','a','g'))
ERROR_GOTO(error, "Invalid Format, expected ibag got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected ibag got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%4) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad ibag size: %u\n", list.mSize);
sfont.ibag_size = list.mSize/4;
@@ -1281,7 +1210,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('i','m','o','d'))
ERROR_GOTO(error, "Invalid Format, expected imod got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected imod got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%10) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad imod size: %u\n", list.mSize);
sfont.imod_size = list.mSize/10;
@@ -1291,7 +1220,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('i','g','e','n'))
ERROR_GOTO(error, "Invalid Format, expected igen got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected igen got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%4) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad igen size: %u\n", list.mSize);
sfont.igen_size = list.mSize/4;
@@ -1302,7 +1231,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
//
RiffHdr_read(&list, stream);
if(list.mCode != FOURCC('s','h','d','r'))
ERROR_GOTO(error, "Invalid Format, expected shdr got '%c%c%c%c'\n", FOURCCARGS(list.mCode));
ERROR_GOTO(error, "Invalid Format, expected shdr got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode));
if((list.mSize%46) != 0 || list.mSize == 0)
ERROR_GOTO(error, "Invalid Format, bad shdr size: %u\n", list.mSize);
sfont.shdr_size = list.mSize/46;
@@ -1316,9 +1245,11 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
if(!ensureFontSanity(&sfont))
goto error;
presets = calloc(1, (sfont.phdr_size-1)*sizeof(presets[0]));
presets = calloc(1, (soundfont->NumPresets+sfont.phdr_size-1)*sizeof(presets[0]));
if(!presets)
ERROR_GOTO(error, "Error allocating presets\n");
memcpy(presets, soundfont->Presets, soundfont->NumPresets*sizeof(presets[0]));
presets_size = soundfont->NumPresets;
for(i = 0;i < sfont.phdr_size-1;i++)
{
@@ -1382,8 +1313,10 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
ERR("Generator %ld has invalid instrument ID (%d of %d)\n",
(long)(gen-sfont.pgen), gen->mAmount, sfont.inst_size-1);
else
processInstrument(&sounds, &sounds_size, context,
&sfont.inst[gen->mAmount], &sfont.phdr[i], &sfont, &lzone);
processInstrument(
&sounds, &sounds_size, context, buffer, &sfont.inst[gen->mAmount],
&sfont.phdr[i], &sfont, &lzone
);
break;
}
GenModList_insertGen(&lzone, gen, AL_TRUE);
@@ -1410,7 +1343,7 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
GenModList_Destruct(&gzone);
}
for(i = 0;i < presets_size;i++)
for(i = soundfont->NumPresets;i < presets_size;i++)
IncrementRef(&presets[i]->ref);
presets = ExchangePtr((XchgPtr*)&soundfont->Presets, presets);
ExchangeInt(&soundfont->NumPresets, presets_size);
@@ -1418,6 +1351,12 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
free(presets);
Soundfont_Destruct(&sfont);
/* If the buffer ends up unused, delete it. */
if(ReadRef(&buffer->ref) == 0)
{
TRACE("Deleting unused buffer...\n");
DeleteBuffer(context->Device, buffer);
}
return AL_TRUE;
@@ -1425,12 +1364,14 @@ error:
if(presets)
{
ALCdevice *device = context->Device;
for(i = 0;i < presets_size;i++)
DeletePreset(presets[i], device);
for(i = soundfont->NumPresets;i < presets_size;i++)
DeletePreset(device, presets[i]);
free(presets);
}
Soundfont_Destruct(&sfont);
if(buffer)
DeleteBuffer(context->Device, buffer);
return AL_FALSE;
}
+140
View File
@@ -0,0 +1,140 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "alMain.h"
#include "alError.h"
#include "evtqueue.h"
#include "alu.h"
#include "midi/base.h"
typedef struct SSynth {
DERIVE_FROM_TYPE(MidiSynth);
} SSynth;
static void SSynth_mixSamples(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
static void SSynth_Construct(SSynth *self, ALCdevice *device);
static void SSynth_Destruct(SSynth *self);
static DECLARE_FORWARD3(SSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*)
static DECLARE_FORWARD1(SSynth, MidiSynth, void, setGain, ALfloat)
static DECLARE_FORWARD(SSynth, MidiSynth, void, stop)
static DECLARE_FORWARD(SSynth, MidiSynth, void, reset)
static void SSynth_update(SSynth *self, ALCdevice *device);
static void SSynth_process(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
DECLARE_DEFAULT_ALLOCATORS(SSynth)
DEFINE_MIDISYNTH_VTABLE(SSynth);
static void SSynth_Construct(SSynth *self, ALCdevice *device)
{
MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
SET_VTABLE2(SSynth, MidiSynth, self);
}
static void SSynth_Destruct(SSynth* UNUSED(self))
{
}
static void SSynth_update(SSynth* UNUSED(self), ALCdevice* UNUSED(device))
{
}
static void SSynth_mixSamples(SSynth* UNUSED(self), ALuint UNUSED(SamplesToDo), ALfloatBUFFERSIZE *restrict UNUSED(DryBuffer))
{
}
static void SSynth_processQueue(SSynth *self, ALuint64 time)
{
EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue;
while(queue->pos < queue->size && queue->events[queue->pos].time <= time)
queue->pos++;
}
static void SSynth_process(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE])
{
MidiSynth *synth = STATIC_CAST(MidiSynth, self);
ALenum state = synth->State;
ALuint64 curtime;
ALuint total = 0;
if(state == AL_INITIAL)
return;
if(state != AL_PLAYING)
{
SSynth_mixSamples(self, SamplesToDo, DryBuffer);
return;
}
curtime = MidiSynth_getTime(synth);
while(total < SamplesToDo)
{
ALuint64 time, diff;
ALint tonext;
time = MidiSynth_getNextEvtTime(synth);
diff = maxu64(time, curtime) - curtime;
if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX)
{
/* If there's no pending event, or if it's more than 1 second
* away, do as many samples as we can. */
tonext = INT_MAX;
}
else
{
/* Figure out how many samples until the next event. */
tonext = (ALint)((diff*synth->SampleRate + (MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES);
tonext -= total;
/* For efficiency reasons, try to mix a multiple of 64 samples
* (~1ms @ 44.1khz) before processing the next event. */
tonext = (tonext+63) & ~63;
}
if(tonext > 0)
{
ALuint todo = mini(tonext, SamplesToDo-total);
SSynth_mixSamples(self, todo, DryBuffer);
total += todo;
tonext -= todo;
}
if(total < SamplesToDo && tonext <= 0)
SSynth_processQueue(self, time);
}
synth->SamplesDone += SamplesToDo;
synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES;
synth->SamplesDone %= synth->SampleRate;
}
MidiSynth *SSynth_create(ALCdevice *device)
{
SSynth *synth;
/* This option is temporary. Once this synth is in a more usable state, a
* more generic selector should be used. */
if(!GetConfigValueBool("midi", "internal-synth", 0))
{
TRACE("Not using internal MIDI synth\n");
return NULL;
}
synth = SSynth_New(sizeof(*synth));
if(!synth)
{
ERR("Failed to allocate SSynth\n");
return NULL;
}
SSynth_Construct(synth, device);
return STATIC_CAST(MidiSynth, synth);
}
@@ -34,7 +34,68 @@
#include "alListener.h"
#include "alAuxEffectSlot.h"
#include "alu.h"
#include "bs2b.h"
#include "mixer_defs.h"
extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
static inline HrtfMixerFunc SelectHrtfMixer(void)
{
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return MixHrtf_SSE;
#endif
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return MixHrtf_Neon;
#endif
return MixHrtf_C;
}
static inline MixerFunc SelectMixer(void)
{
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
return Mix_SSE;
#endif
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
return Mix_Neon;
#endif
return Mix_C;
}
static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
{
if(increment == FRACTIONONE)
return Resample_copy32_C;
switch(Resampler)
{
case PointResampler:
return Resample_point32_C;
case LinearResampler:
#ifdef HAVE_SSE4_1
if((CPUCapFlags&CPU_CAP_SSE4_1))
return Resample_lerp32_SSE41;
#endif
#ifdef HAVE_SSE2
if((CPUCapFlags&CPU_CAP_SSE2))
return Resample_lerp32_SSE2;
#endif
return Resample_lerp32_C;
case CubicResampler:
return Resample_cubic32_C;
case ResamplerMax:
/* Shouldn't happen */
break;
}
return Resample_point32_C;
}
static inline ALfloat Sample_ALbyte(ALbyte val)
@@ -60,7 +121,7 @@ DECL_TEMPLATE(ALfloat)
#undef DECL_TEMPLATE
static void LoadData(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples)
static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples)
{
switch(srctype)
{
@@ -76,7 +137,7 @@ static void LoadData(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtTy
}
}
static void SilenceData(ALfloat *dst, ALuint samples)
static void SilenceSamples(ALfloat *dst, ALuint samples)
{
ALuint i;
for(i = 0;i < samples;i++)
@@ -84,21 +145,47 @@ static void SilenceData(ALfloat *dst, ALuint samples)
}
static void DoFilter(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src,
ALuint numsamples)
static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
ALfloat *restrict dst, const ALfloat *restrict src,
ALuint numsamples, enum ActiveFilters type)
{
ALuint i;
for(i = 0;i < numsamples;i++)
dst[i] = ALfilterState_processSingle(filter, src[i]);
dst[i] = ALfilterState_processSingleC(filter, src[i]);
switch(type)
{
case AF_None:
break;
case AF_LowPass:
ALfilterState_process(lpfilter, dst, src, numsamples);
return dst;
case AF_HighPass:
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);
ALfilterState_process(lpfilter, temp, src+i, todo);
ALfilterState_process(hpfilter, dst+i, temp, todo);
i += todo;
}
return dst;
}
return src;
}
ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
{
MixerFunc Mix;
HrtfMixerFunc HrtfMix;
ResamplerFunc Resample;
ALsource *Source = src->Source;
ALbufferlistitem *BufferListItem;
ALuint DataPosInt, DataPosFrac;
ALuint BuffersPlayed;
ALboolean Looping;
ALuint increment;
enum Resampler Resampler;
@@ -110,20 +197,19 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
ALuint chan, j;
/* Get source info */
State = Source->state;
BuffersPlayed = Source->BuffersPlayed;
DataPosInt = Source->position;
DataPosFrac = Source->position_fraction;
Looping = Source->Looping;
increment = Source->Params.Step;
Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler;
NumChannels = Source->NumChannels;
SampleSize = Source->SampleSize;
State = Source->state;
BufferListItem = ATOMIC_LOAD(&Source->current_buffer);
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;
/* Get current buffer queue item */
BufferListItem = Source->queue;
for(j = 0;j < BuffersPlayed;j++)
BufferListItem = BufferListItem->next;
Mix = SelectMixer();
HrtfMix = SelectHrtfMixer();
Resample = SelectResampler(Resampler, increment);
OutPos = 0;
do {
@@ -132,7 +218,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
ALuint SrcBufferSize, DstBufferSize;
/* Figure out how many buffer samples will be needed */
DataSize64 = SamplesToDo-OutPos+1;
DataSize64 = SamplesToDo-OutPos;
DataSize64 *= increment;
DataSize64 += DataPosFrac+FRACTIONMASK;
DataSize64 >>= FRACTIONBITS;
@@ -144,7 +230,6 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
DataSize64 = SrcBufferSize;
DataSize64 -= BufferPadding+BufferPrePadding;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= increment;
DataSize64 -= DataPosFrac;
DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
@@ -157,13 +242,13 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
for(chan = 0;chan < NumChannels;chan++)
{
ALfloat *SrcData = Device->SampleData1;
ALfloat *ResampledData = Device->SampleData2;
const ALfloat *ResampledData;
ALfloat *SrcData = Device->SourceData;
ALuint SrcDataSize = 0;
if(Source->SourceType == AL_STATIC)
{
const ALbuffer *ALBuffer = Source->queue->buffer;
const ALbuffer *ALBuffer = BufferListItem->buffer;
const ALubyte *Data = ALBuffer->data;
ALuint DataSize;
ALuint pos;
@@ -180,7 +265,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
DataSize = BufferPrePadding - DataPosInt;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
SilenceData(&SrcData[SrcDataSize], DataSize);
SilenceSamples(&SrcData[SrcDataSize], DataSize);
SrcDataSize += DataSize;
pos = 0;
@@ -190,11 +275,11 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
* rest of the temp buffer */
DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SrcDataSize += SrcBufferSize - SrcDataSize;
}
else
@@ -217,7 +302,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
DataSize = BufferPrePadding - DataPosInt;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
SilenceData(&SrcData[SrcDataSize], DataSize);
SilenceSamples(&SrcData[SrcDataSize], DataSize);
SrcDataSize += DataSize;
pos = 0;
@@ -228,8 +313,8 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
DataSize = LoopEnd - pos;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
DataSize = LoopEnd-LoopStart;
@@ -237,8 +322,8 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
{
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
LoadData(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
LoadSamples(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
}
}
@@ -256,25 +341,25 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
pos = BufferPrePadding - DataPosInt;
while(pos > 0)
{
if(!tmpiter->prev && !Looping)
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);
SilenceData(&SrcData[SrcDataSize], DataSize);
SilenceSamples(&SrcData[SrcDataSize], DataSize);
SrcDataSize += DataSize;
pos = 0;
break;
}
if(tmpiter->prev)
tmpiter = tmpiter->prev;
else
{
while(tmpiter->next)
tmpiter = tmpiter->next;
}
if(tmpiter->buffer)
{
if((ALuint)tmpiter->buffer->SampleLen > pos)
@@ -305,55 +390,72 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
pos -= pos;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
LoadData(&SrcData[SrcDataSize], Data, NumChannels,
ALBuffer->FmtType, DataSize);
LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
}
}
tmpiter = tmpiter->next;
if(!tmpiter && Looping)
tmpiter = Source->queue;
tmpiter = ATOMIC_LOAD(&Source->queue);
else if(!tmpiter)
{
SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SrcDataSize += SrcBufferSize - SrcDataSize;
}
}
}
/* Now resample, then filter and mix to the appropriate outputs. */
Source->Params.Resample(&SrcData[BufferPrePadding], DataPosFrac,
increment, ResampledData, DstBufferSize);
ResampledData = Resample(
&SrcData[BufferPrePadding], DataPosFrac, increment,
Device->ResampledData, DstBufferSize
);
{
DirectParams *directparms = &Source->Params.Direct;
DirectParams *parms = &src->Direct;
const ALfloat *samples;
DoFilter(&directparms->LpFilter[chan], SrcData, ResampledData,
DstBufferSize);
Source->Params.DryMix(directparms, SrcData, chan, OutPos,
SamplesToDo, DstBufferSize);
samples = DoFilters(
&parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
Device->FilteredData, ResampledData, DstBufferSize,
parms->Filters[chan].ActiveType
);
if(!src->IsHrtf)
Mix(samples, MaxChannels, parms->OutBuffer, parms->Mix.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);
}
for(j = 0;j < Device->NumAuxSends;j++)
{
SendParams *sendparms = &Source->Params.Send[j];
if(!sendparms->OutBuffer)
SendParams *parms = &src->Send[j];
const ALfloat *samples;
if(!parms->OutBuffer)
continue;
DoFilter(&sendparms->LpFilter[chan], SrcData, ResampledData,
DstBufferSize);
Source->Params.WetMix(sendparms, SrcData, OutPos,
SamplesToDo, DstBufferSize);
samples = DoFilters(
&parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass,
Device->FilteredData, ResampledData, DstBufferSize,
parms->Filters[chan].ActiveType
);
Mix(samples, 1, parms->OutBuffer, &parms->Gain,
parms->Counter, OutPos, DstBufferSize);
}
}
/* Update positions */
for(j = 0;j < DstBufferSize;j++)
{
DataPosFrac += increment;
DataPosInt += DataPosFrac>>FRACTIONBITS;
DataPosFrac &= FRACTIONMASK;
}
DataPosFrac += increment*DstBufferSize;
DataPosInt += DataPosFrac>>FRACTIONBITS;
DataPosFrac &= FRACTIONMASK;
OutPos += DstBufferSize;
src->Offset += DstBufferSize;
src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize;
for(j = 0;j < Device->NumAuxSends;j++)
src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize;
/* Handle looping sources */
while(1)
@@ -374,6 +476,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
if(Looping && Source->SourceType == AL_STATIC)
{
assert(LoopEnd > LoopStart);
DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
break;
}
@@ -381,24 +484,18 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
if(DataSize > DataPosInt)
break;
if(BufferListItem->next)
if(!(BufferListItem=BufferListItem->next))
{
BufferListItem = BufferListItem->next;
BuffersPlayed++;
}
else if(Looping)
{
BufferListItem = Source->queue;
BuffersPlayed = 0;
}
else
{
State = AL_STOPPED;
BufferListItem = Source->queue;
BuffersPlayed = Source->BuffersInQueue;
DataPosInt = 0;
DataPosFrac = 0;
break;
if(Looping)
BufferListItem = ATOMIC_LOAD(&Source->queue);
else
{
State = AL_STOPPED;
BufferListItem = NULL;
DataPosInt = 0;
DataPosFrac = 0;
break;
}
}
DataPosInt -= DataSize;
@@ -407,15 +504,7 @@ ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
/* Update source info */
Source->state = State;
Source->BuffersPlayed = BuffersPlayed;
ATOMIC_STORE(&Source->current_buffer, BufferListItem);
Source->position = DataPosInt;
Source->position_fraction = DataPosFrac;
Source->Hrtf.Offset += OutPos;
if(State == AL_PLAYING)
Source->Hrtf.Counter = maxu(Source->Hrtf.Counter, OutPos) - OutPos;
else
{
Source->Hrtf.Counter = 0;
Source->Hrtf.Moving = AL_FALSE;
}
}
@@ -15,28 +15,33 @@ static inline ALfloat lerp32(const ALfloat *vals, ALuint frac)
static inline ALfloat cubic32(const ALfloat *vals, ALuint frac)
{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); }
void Resample_copy32_C(const ALfloat *data, ALuint UNUSED(frac),
ALuint increment, ALfloat *restrict OutBuffer, ALuint BufferSize)
const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
ALuint increment, ALfloat *restrict dst, ALuint numsamples)
{
assert(increment==FRACTIONONE);
memcpy(OutBuffer, data, (BufferSize+1)*sizeof(ALfloat));
#if defined(HAVE_SSE) || defined(HAVE_NEON)
/* Avoid copying the source data if it's aligned like the destination. */
if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
return src;
#endif
memcpy(dst, src, numsamples*sizeof(ALfloat));
return dst;
}
#define DECL_TEMPLATE(Sampler) \
void Resample_##Sampler##_C(const ALfloat *data, ALuint frac, \
ALuint increment, ALfloat *restrict OutBuffer, ALuint BufferSize) \
const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \
ALuint increment, ALfloat *restrict dst, ALuint numsamples) \
{ \
ALuint pos = 0; \
ALuint i; \
\
for(i = 0;i < BufferSize+1;i++) \
for(i = 0;i < numsamples;i++) \
{ \
OutBuffer[i] = Sampler(data + pos, frac); \
dst[i] = Sampler(src, frac); \
\
frac += increment; \
pos += frac>>FRACTIONBITS; \
src += frac>>FRACTIONBITS; \
frac &= FRACTIONMASK; \
} \
return dst; \
}
DECL_TEMPLATE(point32)
@@ -46,13 +51,26 @@ DECL_TEMPLATE(cubic32)
#undef DECL_TEMPLATE
static inline void ApplyCoeffsStep(const ALuint IrSize,
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples)
{
ALuint i;
for(i = 0;i < numsamples;i++)
*(dst++) = ALfilterState_processSingle(filter, *(src++));
}
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
const ALfloat (*restrict CoeffStep)[2])
const ALfloat (*restrict CoeffStep)[2],
ALfloat left, ALfloat right)
{
ALuint c;
for(c = 0;c < IrSize;c++)
{
const ALuint off = (Offset+c)&HRIR_MASK;
Values[off][0] += Coeffs[c][0] * left;
Values[off][1] += Coeffs[c][1] * right;
Coeffs[c][0] += CoeffStep[c][0];
Coeffs[c][1] += CoeffStep[c][1];
}
@@ -77,49 +95,32 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
#undef SUFFIX
void MixDirect_C(const DirectParams *params, const ALfloat *restrict data, ALuint srcchan,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
ALfloat *restrict ClickRemoval = params->ClickRemoval;
ALfloat *restrict PendingClicks = params->PendingClicks;
ALfloat DrySend;
ALuint pos;
ALfloat gain, step;
ALuint c;
for(c = 0;c < MaxChannels;c++)
for(c = 0;c < OutChans;c++)
{
DrySend = params->Gains[srcchan][c];
if(!(DrySend > GAIN_SILENCE_THRESHOLD))
continue;
ALuint pos = 0;
gain = Gains[c].Current;
step = Gains[c].Step;
if(step != 1.0f && Counter > 0)
{
for(;pos < BufferSize && pos < Counter;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
gain *= step;
}
if(pos == Counter)
gain = Gains[c].Target;
Gains[c].Current = gain;
}
if(OutPos == 0)
ClickRemoval[c] -= data[0]*DrySend;
for(pos = 0;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
if(OutPos+pos == SamplesToDo)
PendingClicks[c] += data[pos]*DrySend;
if(!(gain > GAIN_SILENCE_THRESHOLD))
continue;
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
void MixSend_C(const SendParams *params, const ALfloat *restrict data,
ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)
{
ALfloat (*restrict OutBuffer)[BUFFERSIZE] = params->OutBuffer;
ALfloat *restrict ClickRemoval = params->ClickRemoval;
ALfloat *restrict PendingClicks = params->PendingClicks;
ALfloat WetSend;
ALuint pos;
WetSend = params->Gain;
if(!(WetSend > GAIN_SILENCE_THRESHOLD))
return;
if(OutPos == 0)
ClickRemoval[0] -= data[0] * WetSend;
for(pos = 0;pos < BufferSize;pos++)
OutBuffer[0][OutPos+pos] += data[pos] * WetSend;
if(OutPos+pos == SamplesToDo)
PendingClicks[0] += data[pos] * WetSend;
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef MIXER_DEFS_H
#define MIXER_DEFS_H
#include "AL/alc.h"
#include "AL/al.h"
#include "alMain.h"
#include "alu.h"
struct MixGains;
struct 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);
/* C mixers */
void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
ALuint BufferSize);
void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
/* SSE mixers */
void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
ALuint BufferSize);
void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
/* SSE resamplers */
inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size)
{
ALuint i;
pos_arr[0] = 0;
frac_arr[0] = frac;
for(i = 1;i < size;i++)
{
ALuint frac_tmp = frac_arr[i-1] + increment;
pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS);
frac_arr[i] = frac_tmp&FRACTIONMASK;
}
}
const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
const ALfloat *Resample_lerp32_SSE41(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,
const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
ALuint BufferSize);
void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
#endif /* MIXER_DEFS_H */
+93
View File
@@ -0,0 +1,93 @@
#include "config.h"
#include "alMain.h"
#include "alSource.h"
#include "hrtf.h"
#include "mixer_defs.h"
#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 ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint irSize,
ALfloat (*restrict Coeffs)[2],
const ALfloat (*restrict CoeffStep)[2],
ALfloat left, ALfloat right);
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint irSize,
ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right);
void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
const HrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize)
{
alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
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);
}
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++)
{
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],
(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],
(Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
Delay[0] += hrtfparams->DelayStep[0];
Delay[1] += hrtfparams->DelayStep[1];
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
Offset++;
ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->CoeffStep, left, right);
OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutPos++;
}
Delay[0] >>= HRTFDELAY_BITS;
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->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];
OutPos++;
}
}
#undef MixHrtf
#undef MERGE
#undef REAL_MERGE
+118
View File
@@ -0,0 +1,118 @@
#include "config.h"
#include <arm_neon.h>
#include "AL/al.h"
#include "AL/alc.h"
#include "alMain.h"
#include "alu.h"
#include "hrtf.h"
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
const ALfloat (*restrict CoeffStep)[2],
ALfloat left, ALfloat right)
{
ALuint c;
float32x4_t leftright4;
{
float32x2_t leftright2 = vdup_n_f32(0.0);
leftright2 = vset_lane_f32(left, leftright2, 0);
leftright2 = vset_lane_f32(right, leftright2, 1);
leftright4 = vcombine_f32(leftright2, leftright2);
}
for(c = 0;c < IrSize;c += 2)
{
const ALuint o0 = (Offset+c)&HRIR_MASK;
const ALuint o1 = (o0+1)&HRIR_MASK;
float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
vld1_f32((float32_t*)&Values[o1][0]));
float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
float32x4_t deltas = vld1q_f32(&CoeffStep[c][0]);
vals = vmlaq_f32(vals, coefs, leftright4);
coefs = vaddq_f32(coefs, deltas);
vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
vst1q_f32(&Coeffs[c][0], coefs);
}
}
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right)
{
ALuint c;
float32x4_t leftright4;
{
float32x2_t leftright2 = vdup_n_f32(0.0);
leftright2 = vset_lane_f32(left, leftright2, 0);
leftright2 = vset_lane_f32(right, leftright2, 1);
leftright4 = vcombine_f32(leftright2, leftright2);
}
for(c = 0;c < IrSize;c += 2)
{
const ALuint o0 = (Offset+c)&HRIR_MASK;
const ALuint o1 = (o0+1)&HRIR_MASK;
float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
vld1_f32((float32_t*)&Values[o1][0]));
float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
vals = vmlaq_f32(vals, coefs, leftright4);
vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
}
}
#define SUFFIX Neon
#include "mixer_inc.c"
#undef SUFFIX
void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
ALfloat gain, step;
float32x4_t gain4;
ALuint c;
for(c = 0;c < OutChans;c++)
{
ALuint pos = 0;
gain = Gains[c].Current;
step = Gains[c].Step;
if(step != 1.0f && Counter > 0)
{
for(;pos < BufferSize && pos < Counter;pos++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
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++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
if(!(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));
vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
}
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
+202
View File
@@ -0,0 +1,202 @@
#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"
#include "AL/alc.h"
#include "alMain.h"
#include "alu.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
#include "mixer_defs.h"
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
const ALfloat (*restrict CoeffStep)[2],
ALfloat left, ALfloat right)
{
const __m128 lrlr = _mm_setr_ps(left, right, left, right);
__m128 coeffs, deltas, imp0, imp1;
__m128 vals = _mm_setzero_ps();
ALuint i;
if((Offset&1))
{
const ALuint o0 = Offset&HRIR_MASK;
const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK;
coeffs = _mm_load_ps(&Coeffs[0][0]);
deltas = _mm_load_ps(&CoeffStep[0][0]);
vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]);
imp0 = _mm_mul_ps(lrlr, coeffs);
coeffs = _mm_add_ps(coeffs, deltas);
vals = _mm_add_ps(imp0, vals);
_mm_store_ps(&Coeffs[0][0], coeffs);
_mm_storel_pi((__m64*)&Values[o0][0], vals);
for(i = 1;i < IrSize-1;i += 2)
{
const ALuint o2 = (Offset+i)&HRIR_MASK;
coeffs = _mm_load_ps(&Coeffs[i+1][0]);
deltas = _mm_load_ps(&CoeffStep[i+1][0]);
vals = _mm_load_ps(&Values[o2][0]);
imp1 = _mm_mul_ps(lrlr, coeffs);
coeffs = _mm_add_ps(coeffs, deltas);
imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2));
vals = _mm_add_ps(imp0, vals);
_mm_store_ps(&Coeffs[i+1][0], coeffs);
_mm_store_ps(&Values[o2][0], vals);
imp0 = imp1;
}
vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]);
imp0 = _mm_movehl_ps(imp0, imp0);
vals = _mm_add_ps(imp0, vals);
_mm_storel_pi((__m64*)&Values[o1][0], vals);
}
else
{
for(i = 0;i < IrSize;i += 2)
{
const ALuint o = (Offset + i)&HRIR_MASK;
coeffs = _mm_load_ps(&Coeffs[i][0]);
deltas = _mm_load_ps(&CoeffStep[i][0]);
vals = _mm_load_ps(&Values[o][0]);
imp0 = _mm_mul_ps(lrlr, coeffs);
coeffs = _mm_add_ps(coeffs, deltas);
vals = _mm_add_ps(imp0, vals);
_mm_store_ps(&Coeffs[i][0], coeffs);
_mm_store_ps(&Values[o][0], vals);
}
}
}
static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
ALfloat left, ALfloat right)
{
const __m128 lrlr = _mm_setr_ps(left, right, left, right);
__m128 vals = _mm_setzero_ps();
__m128 coeffs;
ALuint i;
if((Offset&1))
{
const ALuint o0 = Offset&HRIR_MASK;
const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK;
__m128 imp0, imp1;
coeffs = _mm_load_ps(&Coeffs[0][0]);
vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]);
imp0 = _mm_mul_ps(lrlr, coeffs);
vals = _mm_add_ps(imp0, vals);
_mm_storel_pi((__m64*)&Values[o0][0], vals);
for(i = 1;i < IrSize-1;i += 2)
{
const ALuint o2 = (Offset+i)&HRIR_MASK;
coeffs = _mm_load_ps(&Coeffs[i+1][0]);
vals = _mm_load_ps(&Values[o2][0]);
imp1 = _mm_mul_ps(lrlr, coeffs);
imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2));
vals = _mm_add_ps(imp0, vals);
_mm_store_ps(&Values[o2][0], vals);
imp0 = imp1;
}
vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]);
imp0 = _mm_movehl_ps(imp0, imp0);
vals = _mm_add_ps(imp0, vals);
_mm_storel_pi((__m64*)&Values[o1][0], vals);
}
else
{
for(i = 0;i < IrSize;i += 2)
{
const ALuint o = (Offset + i)&HRIR_MASK;
coeffs = _mm_load_ps(&Coeffs[i][0]);
vals = _mm_load_ps(&Values[o][0]);
vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs));
_mm_store_ps(&Values[o][0], vals);
}
}
}
#define SUFFIX SSE
#include "mixer_inc.c"
#undef SUFFIX
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;
ALuint c;
for(c = 0;c < OutChans;c++)
{
ALuint pos = 0;
gain = Gains[c].Current;
step = Gains[c].Step;
if(step != 1.0f && Counter > 0)
{
/* Mix with applying gain steps in aligned multiples of 4. */
if(BufferSize-pos > 3 && Counter-pos > 3)
{
gain4 = _mm_setr_ps(
gain,
gain * step,
gain * step * step,
gain * step * step * step
);
step4 = _mm_set1_ps(step * step * step * step);
do {
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
gain4 = _mm_mul_ps(gain4, step4);
_mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
pos += 4;
} while(BufferSize-pos > 3 && Counter-pos > 3);
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++)
{
OutBuffer[c][OutPos+pos] += data[pos]*gain;
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++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
if(!(gain > GAIN_SILENCE_THRESHOLD))
continue;
gain4 = _mm_set1_ps(gain);
for(;BufferSize-pos > 3;pos += 4)
{
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
_mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
}
for(;pos < BufferSize;pos++)
OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
+78
View File
@@ -0,0 +1,78 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2014 by Timothy Arceri <t_arceri@yahoo.com.au>.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <xmmintrin.h>
#include <emmintrin.h>
#include "alu.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
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));
for(i = 0;numsamples-i > 3;i += 4)
{
const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]);
const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]);
/* val1 + (val2-val1)*mu */
const __m128 r0 = _mm_sub_ps(val2, val1);
const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0));
_mm_store_ps(&dst[i], out);
frac4 = _mm_add_epi32(frac4, increment4);
pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
frac4 = _mm_and_si128(frac4, fracMask4);
_mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
}
pos = pos_.i[0];
frac = _mm_cvtsi128_si32(frac4);
for(;i < numsamples;i++)
{
dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
+82
View File
@@ -0,0 +1,82 @@
/**
* OpenAL cross platform audio library
* Copyright (C) 2014 by Timothy Arceri <t_arceri@yahoo.com.au>.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#include "alu.h"
#include "mixer_defs.h"
const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
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));
for(i = 0;numsamples-i > 3;i += 4)
{
const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]);
const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]);
/* val1 + (val2-val1)*mu */
const __m128 r0 = _mm_sub_ps(val2, val1);
const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0));
_mm_store_ps(&dst[i], out);
frac4 = _mm_add_epi32(frac4, increment4);
pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
frac4 = _mm_and_si128(frac4, fracMask4);
pos_.i[0] = _mm_extract_epi32(pos4, 0);
pos_.i[1] = _mm_extract_epi32(pos4, 1);
pos_.i[2] = _mm_extract_epi32(pos4, 2);
pos_.i[3] = _mm_extract_epi32(pos4, 3);
}
pos = pos_.i[0];
frac = _mm_cvtsi128_si32(frac4);
for(;i < numsamples;i++)
{
dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
frac += increment;
pos += frac>>FRACTIONBITS;
frac &= FRACTIONMASK;
}
return dst;
}
+87
View File
@@ -0,0 +1,87 @@
#ifndef AL_VECTOR_H
#define AL_VECTOR_H
#include <stdlib.h>
#include <AL/al.h>
/* "Base" vector type, designed to alias with the actual vector types. */
typedef struct vector__s {
ALsizei Capacity;
ALsizei Size;
} *vector_;
#define TYPEDEF_VECTOR(T, N) typedef struct { \
ALsizei Capacity; \
ALsizei Size; \
T Data[]; \
} _##N; \
typedef _##N* N; \
typedef const _##N* const_##N;
#define VECTOR(T) struct { \
ALsizei Capacity; \
ALsizei Size; \
T Data[]; \
}*
#define VECTOR_INIT(_x) do { (_x) = NULL; } while(0)
#define VECTOR_INIT_STATIC() NULL
#define VECTOR_DEINIT(_x) do { free((_x)); (_x) = NULL; } while(0)
/* 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);
#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);
#define VECTOR_RESIZE(_x, _c) (vector_resize((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c)))
#define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0)
#define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0)
#define VECTOR_ITER_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL)
#define VECTOR_ITER_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL)
ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend);
#ifdef __GNUC__
#define TYPE_CHECK(T1, T2) __builtin_types_compatible_p(T1, T2)
#define VECTOR_INSERT(_x, _i, _s, _e) __extension__({ \
ALboolean _r; \
static_assert(TYPE_CHECK(__typeof((_x)->Data[0]), __typeof(*(_i))), "Incompatible insertion iterator"); \
static_assert(TYPE_CHECK(__typeof((_x)->Data[0]), __typeof(*(_s))), "Incompatible insertion source type"); \
static_assert(TYPE_CHECK(__typeof(*(_s)), __typeof(*(_e))), "Incompatible iterator sources"); \
_r = vector_insert((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e)); \
_r; \
})
#else
#define VECTOR_INSERT(_x, _i, _s, _e) (vector_insert((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e)))
#endif
#define VECTOR_PUSH_BACK(_x, _obj) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), VECTOR_SIZE(_x)+1, AL_FALSE) && \
(((_x)->Data[(_x)->Size++] = (_obj)),AL_TRUE))
#define VECTOR_POP_BACK(_x) ((void)((_x)->Size--))
#define VECTOR_BACK(_x) ((_x)->Data[(_x)->Size-1])
#define VECTOR_FRONT(_x) ((_x)->Data[0])
#define VECTOR_ELEM(_x, _o) ((_x)->Data[(_o)])
#define VECTOR_FOR_EACH(_t, _x, _f) do { \
_t *_iter = VECTOR_ITER_BEGIN((_x)); \
_t *_end = VECTOR_ITER_END((_x)); \
for(;_iter != _end;++_iter) \
_f(_iter); \
} while(0)
#define VECTOR_FIND_IF(_i, _t, _x, _f) do { \
_t *_iter = VECTOR_ITER_BEGIN((_x)); \
_t *_end = VECTOR_ITER_END((_x)); \
for(;_iter != _end;++_iter) \
{ \
if(_f(_iter)) \
break; \
} \
(_i) = _iter; \
} while(0)
#endif /* AL_VECTOR_H */
@@ -4,7 +4,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libopenal
LOCAL_CFLAGS := -DAL_ALEXT_PROTOTYPES -DAL_BUILD_LIBRARY -DAL_LIBTYPE_STATIC -D_GNU_SOURCE=1 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -std=c99 -Drestrict=__restrict
LOCAL_CFLAGS := -DAL_ALEXT_PROTOTYPES -DAL_BUILD_LIBRARY -D_GNU_SOURCE=1 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -std=c99 -Drestrict=__restrict
LOCAL_CPPFLAGS := ${LOCAL_CFLAGS}
@@ -18,12 +18,15 @@ LOCAL_SRC_FILES := \
Alc/mixer_neon.c \
Alc/mixer_inc.c \
Alc/mixer_sse.c \
Alc/mixer_sse2.c \
Alc/mixer_sse41.c \
, $(subst $(LOCAL_PATH)/,,\
${LOCAL_PATH}/Alc/backends/base.c \
${LOCAL_PATH}/Alc/backends/loopback.c \
${LOCAL_PATH}/Alc/backends/null.c \
${LOCAL_PATH}/Alc/backends/opensl.c \
${LOCAL_PATH}/Alc/backends/wave.c \
$(wildcard ${LOCAL_PATH}/common/*.c) \
$(wildcard ${LOCAL_PATH}/Alc/midi/*.c) \
$(wildcard ${LOCAL_PATH}/Alc/effects/*.c) \
$(wildcard ${LOCAL_PATH}/Alc/*.c) \
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,8 @@
#include "alMain.h"
#include "alEffect.h"
#include "align.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -22,7 +24,7 @@ struct ALeffectStateVtable {
void (*const update)(ALeffectState *state, ALCdevice *device, const struct ALeffectslot *slot);
void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE]);
void (*const Delete)(struct ALeffectState *state);
void (*const Delete)(void *ptr);
};
#define DEFINE_ALEFFECTSTATE_VTABLE(T) \
@@ -30,7 +32,8 @@ DECLARE_THUNK(T, ALeffectState, void, Destruct) \
DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
DECLARE_THUNK2(T, ALeffectState, void, update, ALCdevice*, const ALeffectslot*) \
DECLARE_THUNK3(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict) \
DECLARE_THUNK(T, ALeffectState, void, Delete) \
static void T##_ALeffectState_Delete(void *ptr) \
{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \
\
static const struct ALeffectStateVtable T##_ALeffectState_vtable = { \
T##_ALeffectState_Destruct, \
@@ -68,13 +71,10 @@ typedef struct ALeffectslot {
volatile ALfloat Gain;
volatile ALboolean AuxSendAuto;
volatile ALenum NeedsUpdate;
ATOMIC(ALenum) NeedsUpdate;
ALeffectState *EffectState;
ALIGN(16) ALfloat WetBuffer[1][BUFFERSIZE];
ALfloat ClickRemoval[1];
ALfloat PendingClicks[1];
alignas(16) ALfloat WetBuffer[1][BUFFERSIZE];
RefCount ref;
@@ -22,6 +22,7 @@ enum UserFmtType {
UserFmtMulaw,
UserFmtAlaw,
UserFmtIMA4,
UserFmtMSADPCM,
};
enum UserFmtChannels {
UserFmtMono = AL_MONO_SOFT,
@@ -33,8 +34,8 @@ enum UserFmtChannels {
UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */
};
ALuint BytesFromUserFmt(enum UserFmtType type);
ALuint ChannelsFromUserFmt(enum UserFmtChannels chans);
ALuint BytesFromUserFmt(enum UserFmtType type) DECL_CONST;
ALuint ChannelsFromUserFmt(enum UserFmtChannels chans) DECL_CONST;
inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
{
return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
@@ -58,8 +59,8 @@ enum FmtChannels {
};
#define MAX_INPUT_CHANNELS (8)
ALuint BytesFromFmt(enum FmtType type);
ALuint ChannelsFromFmt(enum FmtChannels chans);
ALuint BytesFromFmt(enum FmtType type) DECL_CONST;
ALuint ChannelsFromFmt(enum FmtChannels chans) DECL_CONST;
inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
{
return ChannelsFromFmt(chans) * BytesFromFmt(type);
@@ -79,10 +80,14 @@ typedef struct ALbuffer {
enum UserFmtChannels OriginalChannels;
enum UserFmtType OriginalType;
ALsizei OriginalSize;
ALsizei OriginalAlign;
ALsizei LoopStart;
ALsizei LoopEnd;
ALsizei UnpackAlign;
ALsizei PackAlign;
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
RefCount ref;
@@ -92,6 +97,11 @@ typedef struct ALbuffer {
ALuint id;
} ALbuffer;
ALbuffer *NewBuffer(ALCcontext *context);
void DeleteBuffer(ALCdevice *device, ALbuffer *buffer);
ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc);
inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
{ return (struct ALbuffer*)LookupUIntMapKey(&device->BufferMap, id); }
inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
@@ -7,7 +7,8 @@
extern "C" {
#endif
#define LOWPASSFREQREF (5000)
#define LOWPASSFREQREF (5000.0f)
#define HIGHPASSFREQREF (250.0f)
/* Filters implementation is based on the "Cookbook formulae for audio *
@@ -15,12 +16,18 @@ extern "C" {
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */
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. */
ALfilterType_Peaking,
/** Low-pass cut-off filter, specifying a cut-off frequency and bandwidth. */
ALfilterType_LowPass,
/** High-pass cut-off filter, specifying a cut-off frequency and bandwidth. */
ALfilterType_HighPass,
/** Band-pass filter, specifying a center frequency and bandwidth. */
ALfilterType_BandPass,
} ALfilterType;
@@ -29,10 +36,13 @@ typedef struct ALfilterState {
ALfloat y[2]; /* History of two last output samples */
ALfloat a[3]; /* Transfer function coefficients "a" */
ALfloat b[3]; /* Transfer function coefficients "b" */
void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples);
} ALfilterState;
#define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__))
void ALfilterState_clear(ALfilterState *filter);
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_scale, ALfloat bandwidth);
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth);
inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample)
{
@@ -51,14 +61,7 @@ inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample
return outsmp;
}
inline ALfloat ALfilterState_processSingleC(const ALfilterState *filter, ALfloat sample)
{
return filter->b[0] * sample +
filter->b[1] * filter->x[0] +
filter->b[2] * filter->x[1] -
filter->a[1] * filter->y[0] -
filter->a[2] * filter->y[1];
}
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples);
typedef struct ALfilter {
@@ -67,6 +70,9 @@ typedef struct ALfilter {
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
void (*SetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val);
void (*SetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals);
@@ -6,6 +6,7 @@
#include <stdarg.h>
#include <assert.h>
#include <math.h>
#include <limits.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
@@ -19,8 +20,22 @@
#include "AL/alc.h"
#include "AL/alext.h"
#if defined(_WIN64)
#define SZFMT "%I64u"
#elif defined(_WIN32)
#define SZFMT "%u"
#else
#define SZFMT "%zu"
#endif
#include "static_assert.h"
#include "align.h"
#include "atomic.h"
#include "uintmap.h"
#include "vector.h"
#include "alstring.h"
#ifndef ALC_SOFT_HRTF
#define ALC_SOFT_HRTF 1
@@ -29,54 +44,25 @@
#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_MIDI_PRESET_SOFT 0x9997
#define AL_MIDI_BANK_SOFT 0x9996
#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
#define AL_SOURCE0_INPUT_SOFT 0x998F
#define AL_SOURCE0_TYPE_SOFT 0x998E
#define AL_SOURCE0_FORM_SOFT 0x998D
#define AL_SOURCE1_INPUT_SOFT 0x998C
#define AL_SOURCE1_TYPE_SOFT 0x998B
#define AL_SOURCE1_FORM_SOFT 0x998A
#define AL_AMOUNT_SOFT 0x9989
#define AL_TRANSFORM_OP_SOFT 0x9988
#define AL_DESTINATION_SOFT 0x9987
/* Sounce Input */
#define AL_ONE_SOFT 0x0080
#define AL_NOTEON_VELOCITY_SOFT 0x0082
#define AL_NOTEON_KEY_SOFT 0x0083
/* AL_KEYPRESSURE_SOFT */
/* AL_CHANNELPRESSURE_SOFT */
/* AL_PITCHBEND_SOFT */
#define AL_PITCHBEND_SENSITIVITY_SOFT 0x0090
/* CC 0...127 */
/* Source Type */
#define AL_UNORM_SOFT 0x0000
#define AL_UNORM_REV_SOFT 0x0100
#define AL_SNORM_SOFT 0x0200
#define AL_SNORM_REV_SOFT 0x0300
/* Source Form */
#define AL_LINEAR_SOFT 0x0000
#define AL_CONCAVE_SOFT 0x0400
#define AL_CONVEX_SOFT 0x0800
#define AL_SWITCH_SOFT 0x0C00
/* Transform op */
/* AL_LINEAR_SOFT */
#define AL_ABSOLUTE_SOFT 0x0002
/* Fontsound properties */
/* AL_BUFFER */
#define AL_SAMPLE_START_SOFT 0x2000
#define AL_SAMPLE_END_SOFT 0x2001
#define AL_SAMPLE_LOOP_START_SOFT 0x2002
@@ -125,11 +111,55 @@
#define AL_LOOP_MODE_SOFT 0x0036
#define AL_TUNING_SCALE_SOFT 0x0038
#define AL_EXCLUSIVE_CLASS_SOFT 0x0039
#define AL_LOOP_CONTINUOUS_SOFT 0x0001
#define AL_LOOP_UNTIL_RELEASE_SOFT 0x0003
/* Sample Types */
/* AL_MONO_SOFT */
#define AL_RIGHT_SOFT 0x0002
#define AL_LEFT_SOFT 0x0004
#define AL_FORMAT_TYPE_SOFT 0x1991
/* 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
@@ -137,13 +167,10 @@
#define AL_PROGRAMCHANGE_SOFT 0x00C0
#define AL_CHANNELPRESSURE_SOFT 0x00D0
#define AL_PITCHBEND_SOFT 0x00E0
typedef void (AL_APIENTRY*LPALGENSOUNDFONTSSOFT)(ALsizei n, ALuint *ids);
typedef void (AL_APIENTRY*LPALDELETESOUNDFONTSSOFT)(ALsizei n, const ALuint *ids);
typedef ALboolean (AL_APIENTRY*LPALISSOUNDFONTSOFT)(ALuint id);
typedef void (AL_APIENTRY*LPALSOUNDFONTSAMPLESSOFT)(ALuint sfid, ALenum type, ALsizei count, const ALvoid *samples);
typedef void (AL_APIENTRY*LPALGETSOUNDFONTSAMPLESSOFT)(ALuint id, ALsizei offset, ALsizei count, ALenum type, ALvoid *samples);
typedef ALvoid* (AL_APIENTRY*LPALSOUNDFONTMAPSAMPLESSOFT)(ALuint sfid, ALsizei offset, ALsizei length);
typedef void (AL_APIENTRY*LPALSOUNDFONTUNMAPSAMPLESSOFT)(ALuint sfid);
typedef void (AL_APIENTRY*LPALGETSOUNDFONTIVSOFT)(ALuint id, ALenum param, ALint *values);
typedef void (AL_APIENTRY*LPALSOUNDFONTPRESETSSOFT)(ALuint id, ALsizei count, const ALuint *pids);
typedef void (AL_APIENTRY*LPALGENPRESETSSOFT)(ALsizei n, ALuint *ids);
@@ -178,10 +205,6 @@ typedef void (AL_APIENTRY*LPALLOADSOUNDFONTSOFT)(ALuint id, size_t(*cb)(ALvoid*,
AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids);
AL_API void AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids);
AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id);
AL_API void AL_APIENTRY alSoundfontSamplesSOFT(ALuint sfid, ALenum type, ALsizei count, const ALvoid *samples);
AL_API void AL_APIENTRY alGetSoundfontSamplesSOFT(ALuint id, ALsizei offset, ALsizei count, ALenum type, ALvoid *samples);
AL_API ALvoid* AL_APIENTRY alSoundfontMapSamplesSOFT(ALuint sfid, ALsizei offset, ALsizei length);
AL_API void AL_APIENTRY alSoundfontUnmapSamplesSOFT(ALuint sfid);
AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values);
AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids);
@@ -218,13 +241,14 @@ AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_
#endif
#endif
#ifndef ALC_SOFT_pause_device
#define ALC_SOFT_pause_device 1
typedef void (ALC_APIENTRY*LPALCDEVICEPAUSESOFT)(ALCdevice *device);
typedef void (ALC_APIENTRY*LPALCDEVICERESUMESOFT)(ALCdevice *device);
#ifndef ALC_SOFT_device_clock
#define ALC_SOFT_device_clock 1
typedef int64_t ALCint64SOFT;
typedef uint64_t ALCuint64SOFT;
#define ALC_DEVICE_CLOCK_SOFT 0x1600
typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values);
#ifdef AL_ALEXT_PROTOTYPES
ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device);
ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device);
ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values);
#endif
#endif
@@ -233,11 +257,6 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device);
/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
* recent versions (at least 4.5.1) do recognize GCC's __restrict. */
#define restrict __restrict
/* KDevelop won't see the ALIGN macro from config.h when viewing files that
* don't include it directly (e.g. headers). */
#ifndef ALIGN
#define ALIGN(x)
#endif
#endif
@@ -273,10 +292,12 @@ typedef ptrdiff_t ALsizeiptrEXT;
#endif
#endif
#ifdef HAVE_GCC_FORMAT
#define PRINTF_STYLE(x, y) __attribute__((format(printf, (x), (y))))
#ifdef __GNUC__
#define DECL_CONST __attribute__((const))
#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z))))
#else
#define PRINTF_STYLE(x, y)
#define DECL_CONST
#define DECL_FORMAT(x, y, z)
#endif
#if defined(__GNUC__) && defined(__i386__)
@@ -289,6 +310,20 @@ typedef ptrdiff_t ALsizeiptrEXT;
#define FORCE_ALIGN
#endif
#ifdef HAVE_C99_VLA
#define DECL_VLA(T, _name, _size) T _name[(_size)]
#else
#define DECL_VLA(T, _name, _size) T *_name = alloca((_size) * sizeof(T))
#endif
#ifndef PATH_MAX
#ifdef MAX_PATH
#define PATH_MAX MAX_PATH
#else
#define PATH_MAX 4096
#endif
#endif
static const union {
ALuint u;
@@ -301,8 +336,15 @@ static const union {
#define DERIVE_FROM_TYPE(t) t t##_parent
#define STATIC_CAST(to, obj) (&(obj)->to##_parent)
#ifdef __GNUC__
#define STATIC_UPCAST(to, from, obj) __extension__({ \
static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \
"Invalid upcast object from type"); \
(to*)((char*)(obj) - offsetof(to, from##_parent)); \
})
#else
#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent)))
#endif
#define DECLARE_FORWARD(T1, T2, rettype, func) \
rettype T1##_##func(T1 *obj) \
@@ -343,6 +385,9 @@ 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_DEFAULT_ALLOCATORS(T) \
static void* T##_New(size_t size) { return malloc(size); } \
static void T##_Delete(void *ptr) { free(ptr); }
/* Helper to extract an argument list for VCALL. Not used directly. */
#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
@@ -437,12 +482,6 @@ 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 alcMMDevApiInit(BackendFuncs *func_list);
void alcMMDevApiDeinit(void);
void alcMMDevApiProbe(enum DevProbe type);
ALCboolean alcDSoundInit(BackendFuncs *func_list);
void alcDSoundDeinit(void);
void alcDSoundProbe(enum DevProbe type);
ALCboolean alcWinMMInit(BackendFuncs *FuncList);
void alcWinMMDeinit(void);
void alcWinMMProbe(enum DevProbe type);
@@ -526,8 +565,8 @@ enum DevFmtChannels {
DevFmtChannelsDefault = DevFmtStereo
};
ALuint BytesFromDevFmt(enum DevFmtType type);
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans);
ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST;
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST;
inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type)
{
return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type);
@@ -559,7 +598,7 @@ enum DeviceType {
struct ALCdevice_struct
{
volatile RefCount ref;
RefCount ref;
ALCboolean Connected;
enum DeviceType Type;
@@ -570,9 +609,9 @@ struct ALCdevice_struct
enum DevFmtChannels FmtChans;
enum DevFmtType FmtType;
ALCchar *DeviceName;
al_string DeviceName;
volatile ALCenum LastError;
ATOMIC(ALCenum) LastError;
// Maximum number of sources that can be created
ALuint MaxNoOfSources;
@@ -623,28 +662,38 @@ struct ALCdevice_struct
ALfloat SpeakerAngle[MaxChannels];
ALuint NumChan;
/* Temp storage used for mixing. +1 for the predictive sample. */
ALIGN(16) ALfloat SampleData1[BUFFERSIZE+1];
ALIGN(16) ALfloat SampleData2[BUFFERSIZE+1];
ALuint64 ClockBase;
ALuint SamplesDone;
/* Temp storage used for each source when mixing. */
alignas(16) ALfloat SourceData[BUFFERSIZE];
alignas(16) ALfloat ResampledData[BUFFERSIZE];
alignas(16) ALfloat FilteredData[BUFFERSIZE];
// Dry path buffer mix
ALIGN(16) ALfloat DryBuffer[MaxChannels][BUFFERSIZE];
alignas(16) ALfloat DryBuffer[MaxChannels][BUFFERSIZE];
ALIGN(16) ALfloat ClickRemoval[MaxChannels];
ALIGN(16) ALfloat PendingClicks[MaxChannels];
/* Running count of the mixer invocations, in 31.1 fixed point. This
* actually increments *twice* when mixing, first at the start and then at
* the end, so the bottom bit indicates if the device is currently mixing
* and the upper bits indicates how many mixes have been done.
*/
RefCount MixCount;
/* Default effect slot */
struct ALeffectslot *DefaultSlot;
// Contexts created on this device
ALCcontext *volatile ContextList;
ATOMIC(ALCcontext*) ContextList;
struct ALCbackend *Backend;
BackendFuncs *Funcs;
void *ExtraData; // For the backend's use
void *ExtraData; // For the backend's use
ALCdevice *volatile next;
/* Memory space used by the default slot (Playback devices only) */
alignas(16) ALCbyte _slot_mem[];
};
// Frequency was requested by the app or config file
@@ -669,6 +718,10 @@ struct ALCdevice_struct
#define INVALID_OFFSET (~0u)
/* Nanosecond resolution for the device clock time. */
#define DEVICE_CLOCK_RES U64(1000000000)
/* Must be less than 15 characters (16 including terminating null) for
* compatibility with pthread_setname_np limitations. */
#define MIXER_THREAD_NAME "alsoft-mixer"
@@ -676,16 +729,16 @@ struct ALCdevice_struct
struct ALCcontext_struct
{
volatile RefCount ref;
RefCount ref;
struct ALlistener *Listener;
UIntMap SourceMap;
UIntMap EffectSlotMap;
volatile ALenum LastError;
ATOMIC(ALenum) LastError;
volatile ALenum UpdateSources;
ATOMIC(ALenum) UpdateSources;
volatile enum DistanceModel DistanceModel;
volatile ALboolean SourceDistanceModel;
@@ -695,18 +748,19 @@ struct ALCcontext_struct
volatile ALfloat SpeedOfSound;
volatile ALenum DeferUpdates;
struct ALsource **ActiveSources;
ALsizei ActiveSourceCount;
ALsizei MaxActiveSources;
struct ALactivesource **ActiveSources;
ALsizei ActiveSourceCount;
ALsizei MaxActiveSources;
struct ALeffectslot **ActiveEffectSlots;
ALsizei ActiveEffectSlotCount;
ALsizei MaxActiveEffectSlots;
VECTOR(struct ALeffectslot*) ActiveAuxSlots;
ALCdevice *Device;
const ALCchar *ExtensionList;
ALCcontext *volatile next;
/* Memory space used by the listener */
alignas(16) ALCbyte _listener_mem[];
};
ALCcontext *GetContextRef(void);
@@ -771,31 +825,17 @@ void SetRTPriority(void);
void SetDefaultChannelOrder(ALCdevice *device);
void SetDefaultWFXChannelOrder(ALCdevice *device);
const ALCchar *DevFmtTypeString(enum DevFmtType type);
const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans);
#define HRIR_BITS (7)
#define HRIR_LENGTH (1<<HRIR_BITS)
#define HRIR_MASK (HRIR_LENGTH-1)
#define HRTFDELAY_BITS (20)
#define HRTFDELAY_FRACONE (1<<HRTFDELAY_BITS)
#define HRTFDELAY_MASK (HRTFDELAY_FRACONE-1)
const struct Hrtf *GetHrtf(ALCdevice *device);
void FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate);
void FreeHrtfs(void);
ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]);
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep);
const ALCchar *DevFmtTypeString(enum DevFmtType type) DECL_CONST;
const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST;
extern FILE *LogFile;
#ifdef __GNUC__
#if defined(__GNUC__) && !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, ...) PRINTF_STYLE(3,4);
#define AL_PRINT(T, MSG, ...) al_print((T), __FUNCTION__, MSG, __VA_ARGS__)
void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4);
#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__)
#endif
enum LogLevel {
@@ -835,11 +875,13 @@ extern ALuint CPUCapFlags;
enum {
CPU_CAP_SSE = 1<<0,
CPU_CAP_SSE2 = 1<<1,
CPU_CAP_NEON = 1<<2,
CPU_CAP_SSE4_1 = 1<<2,
CPU_CAP_NEON = 1<<3,
};
void FillCPUCaps(ALuint capfilter);
FILE *OpenDataFile(const char *fname, const char *subdir);
/* Small hack to use a pointer-to-array type as a normal argument type.
* Shouldn't be used directly. */
@@ -32,7 +32,9 @@ typedef struct ALenvelope {
typedef struct ALfontsound {
volatile RefCount ref;
RefCount ref;
struct ALbuffer *Buffer;
ALint MinKey, MaxKey;
ALint MinVelocity, MaxVelocity;
@@ -85,32 +87,28 @@ typedef struct ALfontsound {
ALenum SampleType;
struct ALfontsound *Link;
/* NOTE: Each map entry contains *four* (4) ALsfmodulator objects. */
UIntMap ModulatorMap;
ALuint id;
} ALfontsound;
void ALfontsound_Destruct(ALfontsound *self);
void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value);
void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value);
ALfontsound *NewFontsound(ALCcontext *context);
void DeleteFontsound(ALCdevice *device, ALfontsound *sound);
inline struct ALfontsound *LookupFontsound(ALCdevice *device, ALuint id)
{ return (struct ALfontsound*)LookupUIntMapKey(&device->FontsoundMap, id); }
inline struct ALfontsound *RemoveFontsound(ALCdevice *device, ALuint id)
{ return (struct ALfontsound*)RemoveUIntMapKey(&device->FontsoundMap, id); }
inline struct ALsfmodulator *LookupModulator(ALfontsound *sound, ALuint id)
{ return (struct ALsfmodulator*)LookupUIntMapKey(&sound->ModulatorMap, id); }
inline struct ALsfmodulator *RemoveModulator(ALfontsound *sound, ALuint id)
{ return (struct ALsfmodulator*)RemoveUIntMapKey(&sound->ModulatorMap, id); }
void ReleaseALFontsounds(ALCdevice *device);
typedef struct ALsfpreset {
volatile RefCount ref;
RefCount ref;
ALint Preset; /* a.k.a. MIDI program number */
ALint Bank; /* MIDI bank 0...127, or percussion (bank 128) */
@@ -122,7 +120,7 @@ typedef struct ALsfpreset {
} ALsfpreset;
ALsfpreset *NewPreset(ALCcontext *context);
void DeletePreset(ALsfpreset *preset, ALCdevice *device);
void DeletePreset(ALCdevice *device, ALsfpreset *preset);
inline struct ALsfpreset *LookupPreset(ALCdevice *device, ALuint id)
{ return (struct ALsfpreset*)LookupUIntMapKey(&device->PresetMap, id); }
@@ -133,22 +131,16 @@ void ReleaseALPresets(ALCdevice *device);
typedef struct ALsoundfont {
volatile RefCount ref;
RefCount ref;
ALsfpreset **Presets;
ALsizei NumPresets;
ALshort *Samples;
ALint NumSamples;
RWLock Lock;
volatile ALenum Mapped;
ALuint id;
} ALsoundfont;
void ALsoundfont_Construct(ALsoundfont *self);
void ALsoundfont_Destruct(ALsoundfont *self);
ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context);
void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device);
@@ -159,6 +151,20 @@ inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id)
void ReleaseALSoundfonts(ALCdevice *device);
inline ALboolean IsValidCtrlInput(int cc)
{
/* These correspond to MIDI functions, not real controller values. */
if(cc == 0 || cc == 6 || cc == 32 || cc == 38 || (cc >= 98 && cc <= 101) || cc >= 120)
return AL_FALSE;
/* These are the LSB components of CC0...CC31, which are automatically used when
* reading the MSB controller value. */
if(cc >= 32 && cc <= 63)
return AL_FALSE;
/* All the rest are okay! */
return AL_TRUE;
}
#ifdef __cplusplus
}
#endif
@@ -5,17 +5,12 @@
#include "alMain.h"
#include "alu.h"
#include "alFilter.h"
#include "alBuffer.h"
#include "hrtf.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SRC_HISTORY_BITS (6)
#define SRC_HISTORY_LENGTH (1<<SRC_HISTORY_BITS)
#define SRC_HISTORY_MASK (SRC_HISTORY_LENGTH-1)
extern enum Resampler DefaultResampler;
extern const ALsizei ResamplerPadding[ResamplerMax];
@@ -23,62 +18,31 @@ extern const ALsizei ResamplerPrePadding[ResamplerMax];
typedef struct ALbufferlistitem {
struct ALbuffer *buffer;
struct ALbufferlistitem *next;
struct ALbufferlistitem *prev;
struct ALbuffer *buffer;
struct ALbufferlistitem *volatile next;
struct ALbufferlistitem *volatile prev;
} ALbufferlistitem;
typedef struct HrtfState {
ALboolean Moving;
ALuint Counter;
ALIGN(16) ALfloat History[MAX_INPUT_CHANNELS][SRC_HISTORY_LENGTH];
ALIGN(16) ALfloat Values[MAX_INPUT_CHANNELS][HRIR_LENGTH][2];
ALuint Offset;
} HrtfState;
typedef struct HrtfParams {
ALfloat Gain;
ALfloat Dir[3];
ALIGN(16) ALfloat Coeffs[MAX_INPUT_CHANNELS][HRIR_LENGTH][2];
ALIGN(16) ALfloat CoeffStep[HRIR_LENGTH][2];
ALuint Delay[MAX_INPUT_CHANNELS][2];
ALint DelayStep[2];
ALuint IrSize;
} HrtfParams;
typedef struct ALactivesource {
struct ALsource *Source;
typedef struct DirectParams {
ALfloat (*OutBuffer)[BUFFERSIZE];
ALfloat *ClickRemoval;
ALfloat *PendingClicks;
/** Method to update mixing parameters. */
ALvoid (*Update)(struct ALactivesource *self, const ALCcontext *context);
struct {
HrtfParams Params;
HrtfState *State;
} Hrtf;
/** Current target parameters used for mixing. */
ALint Step;
/* A mixing matrix. First subscript is the channel number of the input data
* (regardless of channel configuration) and the second is the channel
* target (eg. FrontLeft). Not used with HRTF. */
ALfloat Gains[MAX_INPUT_CHANNELS][MaxChannels];
ALboolean IsHrtf;
ALfilterState LpFilter[MAX_INPUT_CHANNELS];
} DirectParams;
ALuint Offset; /* Number of output samples mixed since starting. */
typedef struct SendParams {
ALfloat (*OutBuffer)[BUFFERSIZE];
ALfloat *ClickRemoval;
ALfloat *PendingClicks;
/* Gain control, which applies to all input channels to a single (mono)
* output buffer. */
ALfloat Gain;
ALfilterState LpFilter[MAX_INPUT_CHANNELS];
} SendParams;
DirectParams Direct;
SendParams Send[MAX_SENDS];
} ALactivesource;
typedef struct ALsource
{
typedef struct ALsource {
/** Source properties. */
volatile ALfloat Pitch;
volatile ALfloat Gain;
@@ -107,6 +71,8 @@ typedef struct ALsource
volatile ALfloat RoomRolloffFactor;
volatile ALfloat DopplerFactor;
volatile ALfloat Radius;
enum Resampler Resampler;
/**
@@ -132,49 +98,37 @@ typedef struct ALsource
ALuint position_fraction;
/** Source Buffer Queue info. */
ALbufferlistitem *queue;
ALuint BuffersInQueue;
ALuint BuffersPlayed;
ATOMIC(ALbufferlistitem*) queue;
ATOMIC(ALbufferlistitem*) current_buffer;
RWLock queue_lock;
/** Current buffer sample info. */
ALuint NumChannels;
ALuint SampleSize;
/** Direct filter and auxiliary send info. */
ALfloat DirectGain;
ALfloat DirectGainHF;
struct {
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Direct;
struct {
struct ALeffectslot *Slot;
ALfloat Gain;
ALfloat GainHF;
ALfloat HFReference;
ALfloat GainLF;
ALfloat LFReference;
} Send[MAX_SENDS];
/** HRTF info. */
HrtfState Hrtf;
/** Current target parameters used for mixing. */
struct {
ResamplerFunc Resample;
DryMixerFunc DryMix;
WetMixerFunc WetMix;
ALint Step;
DirectParams Direct;
SendParams Send[MAX_SENDS];
} Params;
/** Source needs to update its mixing parameters. */
volatile ALenum NeedsUpdate;
/** Method to update mixing parameters. */
ALvoid (*Update)(struct ALsource *self, const ALCcontext *context);
ATOMIC(ALenum) NeedsUpdate;
/** Self ID */
ALuint id;
} ALsource;
#define ALsource_Update(s,a) ((s)->Update(s,a))
inline struct ALsource *LookupSource(ALCcontext *context, ALuint id)
{ return (struct ALsource*)LookupUIntMapKey(&context->SourceMap, id); }
@@ -1,8 +1,6 @@
#ifndef _ALU_H_
#define _ALU_H_
#include "alMain.h"
#include <limits.h>
#include <math.h>
#ifdef HAVE_FLOAT_H
@@ -12,6 +10,13 @@
#include <ieeefp.h>
#endif
#include "alMain.h"
#include "alBuffer.h"
#include "alFilter.h"
#include "hrtf.h"
#include "align.h"
#define F_PI (3.14159265358979323846f)
#define F_PI_2 (1.57079632679489661923f)
@@ -25,29 +30,103 @@
#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)
#ifdef __cplusplus
extern "C" {
#endif
struct ALsource;
struct ALbuffer;
struct DirectParams;
struct SendParams;
typedef void (*ResamplerFunc)(const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint dstlen);
typedef ALvoid (*DryMixerFunc)(const struct DirectParams *params,
const ALfloat *restrict data, ALuint srcchan,
ALuint OutPos, ALuint SamplesToDo,
ALuint BufferSize);
typedef ALvoid (*WetMixerFunc)(const struct SendParams *params,
const ALfloat *restrict data,
ALuint OutPos, ALuint SamplesToDo,
ALuint BufferSize);
enum ActiveFilters {
AF_None = 0,
AF_LowPass = 1,
AF_HighPass = 2,
AF_BandPass = AF_LowPass | AF_HighPass
};
#define GAIN_SILENCE_THRESHOLD (0.00001f)
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;
ALfloat Target;
} MixGains;
typedef struct DirectParams {
ALfloat (*OutBuffer)[BUFFERSIZE];
/* If not 'moving', gain/coefficients are set directly without fading. */
ALboolean Moving;
/* Stepping counter for gain/coefficient fading. */
ALuint Counter;
struct {
enum ActiveFilters ActiveType;
ALfilterState LowPass;
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;
} DirectParams;
typedef struct SendParams {
ALfloat (*OutBuffer)[BUFFERSIZE];
ALboolean Moving;
ALuint Counter;
struct {
enum ActiveFilters ActiveType;
ALfilterState LowPass;
ALfilterState HighPass;
} Filters[MAX_INPUT_CHANNELS];
/* Gain control, which applies to all input channels to a single (mono)
* output buffer. */
MixGains Gain;
} SendParams;
typedef const ALfloat* (*ResamplerFunc)(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,
ALuint Counter, ALuint OutPos, ALuint BufferSize);
typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
ALuint Counter, ALuint Offset, ALuint OutPos,
const ALuint IrSize, const HrtfParams *hrtfparams,
HrtfState *hrtfstate, ALuint BufferSize);
#define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
@@ -137,10 +216,10 @@ inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxC
}
ALvoid CalcSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
ALvoid CalcNonAttnSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
ALvoid CalcSourceParams(struct ALactivesource *src, const ALCcontext *ALContext);
ALvoid CalcNonAttnSourceParams(struct ALactivesource *src, const ALCcontext *ALContext);
ALvoid MixSource(struct ALsource *Source, ALCdevice *Device, ALuint SamplesToDo);
ALvoid MixSource(struct ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo);
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
/* Caller must lock the device. */
@@ -51,24 +51,21 @@ struct bs2b {
int srate; /* Sample rate (Hz) */
/* Lowpass IIR filter coefficients */
double a0_lo;
double b1_lo;
float a0_lo;
float b1_lo;
/* Highboost IIR filter coefficients */
double a0_hi;
double a1_hi;
double b1_hi;
/* Global gain against overloading */
float gain;
float a0_hi;
float a1_hi;
float b1_hi;
/* Buffer of last filtered sample.
* [0] - first channel, [1] - second channel
*/
struct t_last_sample {
double asis[2];
double lo[2];
double hi[2];
float asis[2];
float lo[2];
float hi[2];
} last_sample;
};
@@ -93,11 +90,36 @@ void bs2b_clear(struct bs2b *bs2b);
/* Crossfeeds one stereo sample that are pointed by sample.
* [0] - first channel, [1] - second channel.
* Returns crossfided samle by sample pointer.
* Returns crossfided sample by sample pointer.
*/
inline void bs2b_cross_feed(struct bs2b *bs2b, float *restrict sample)
{
/* Single pole IIR filter.
* O[n] = a0*I[n] + a1*I[n-1] + b1*O[n-1]
*/
/* sample poits to floats */
void bs2b_cross_feed(struct bs2b *bs2b, float *sample);
/* Lowpass filter */
#define lo_filter(in, out_1) (bs2b->a0_lo*(in) + bs2b->b1_lo*(out_1))
/* Highboost filter */
#define hi_filter(in, in_1, out_1) (bs2b->a0_hi*(in) + bs2b->a1_hi*(in_1) + bs2b->b1_hi*(out_1))
/* Lowpass filter */
bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]);
bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]);
/* Highboost filter */
bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]);
bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]);
bs2b->last_sample.asis[0] = sample[0];
bs2b->last_sample.asis[1] = sample[1];
/* Crossfeed */
sample[0] = bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1];
sample[1] = bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0];
#undef hi_filter
#undef lo_filter
} /* bs2b_cross_feed */
#ifdef __cplusplus
} /* extern "C" */
@@ -0,0 +1,9 @@
#ifndef SAMPLE_CVT_H
#define SAMPLE_CVT_H
#include "AL/al.h"
#include "alBuffer.h"
void ConvertData(ALvoid *dst, enum UserFmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei numchans, ALsizei len, ALsizei align);
#endif /* SAMPLE_CVT_H */
@@ -35,8 +35,8 @@
extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
static ALenum AddEffectSlotArray(ALCcontext *Context, ALsizei count, const ALuint *slots);
static ALvoid RemoveEffectSlotArray(ALCcontext *Context, ALeffectslot *slot);
static ALenum AddEffectSlotArray(ALCcontext *Context, ALeffectslot **start, ALsizei count);
static void RemoveEffectSlotArray(ALCcontext *Context, const ALeffectslot *slot);
static UIntMap EffectStateFactoryMap;
@@ -52,14 +52,20 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type)
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *context;
VECTOR(ALeffectslot*) slotvec;
ALsizei cur;
ALenum err;
context = GetContextRef();
if(!context) return;
VECTOR_INIT(slotvec);
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(!VECTOR_RESERVE(slotvec, n))
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
for(cur = 0;cur < n;cur++)
{
ALeffectslot *slot = al_calloc(16, sizeof(ALeffectslot));
@@ -84,9 +90,11 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
SET_ERROR_AND_GOTO(context, err, done);
}
VECTOR_PUSH_BACK(slotvec, slot);
effectslots[cur] = slot->id;
}
err = AddEffectSlotArray(context, n, effectslots);
err = AddEffectSlotArray(context, VECTOR_ITER_BEGIN(slotvec), n);
if(err != AL_NO_ERROR)
{
alDeleteAuxiliaryEffectSlots(cur, effectslots);
@@ -94,6 +102,8 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
}
done:
VECTOR_DEINIT(slotvec);
ALCcontext_DecRef(context);
}
@@ -112,7 +122,7 @@ AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *
{
if((slot=LookupEffectSlot(context, effectslots[i])) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(slot->ref != 0)
if(ReadRef(&slot->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
@@ -173,7 +183,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
err = InitializeEffect(device, slot, effect);
if(err != AL_NO_ERROR)
SET_ERROR_AND_GOTO(context, err, done);
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
break;
case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
@@ -181,7 +191,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->AuxSendAuto = value;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
break;
default:
@@ -236,7 +246,7 @@ AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
slot->Gain = value;
slot->NeedsUpdate = AL_TRUE;
ATOMIC_STORE(&slot->NeedsUpdate, AL_TRUE);
break;
default:
@@ -375,56 +385,32 @@ done:
}
static ALvoid RemoveEffectSlotArray(ALCcontext *context, ALeffectslot *slot)
static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsizei count)
{
ALeffectslot **slotlist, **slotlistend;
ALenum err = AL_NO_ERROR;
LockContext(context);
slotlist = context->ActiveEffectSlots;
slotlistend = slotlist + context->ActiveEffectSlotCount;
while(slotlist != slotlistend)
{
if(*slotlist == slot)
{
*slotlist = *(--slotlistend);
context->ActiveEffectSlotCount--;
break;
}
slotlist++;
}
if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_ITER_END(context->ActiveAuxSlots), start, start+count))
err = AL_OUT_OF_MEMORY;
UnlockContext(context);
return err;
}
static ALenum AddEffectSlotArray(ALCcontext *context, ALsizei count, const ALuint *slots)
static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
{
ALsizei i;
ALeffectslot **iter;
LockContext(context);
if(count > context->MaxActiveEffectSlots-context->ActiveEffectSlotCount)
#define MATCH_SLOT(_i) (slot == *(_i))
VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT);
if(iter != VECTOR_ITER_END(context->ActiveAuxSlots))
{
ALsizei newcount;
void *temp = NULL;
newcount = context->MaxActiveEffectSlots ? (context->MaxActiveEffectSlots<<1) : 1;
if(newcount > context->MaxActiveEffectSlots)
temp = realloc(context->ActiveEffectSlots,
newcount * sizeof(*context->ActiveEffectSlots));
if(!temp)
{
UnlockContext(context);
return AL_OUT_OF_MEMORY;
}
context->ActiveEffectSlots = temp;
context->MaxActiveEffectSlots = newcount;
}
for(i = 0;i < count;i++)
{
ALeffectslot *slot = LookupEffectSlot(context, slots[i]);
assert(slot != NULL);
context->ActiveEffectSlots[context->ActiveEffectSlotCount++] = slot;
*iter = VECTOR_BACK(context->ActiveAuxSlots);
VECTOR_POP_BACK(context->ActiveAuxSlots);
}
#undef MATCH_SLOT
UnlockContext(context);
return AL_NO_ERROR;
}
@@ -499,7 +485,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
/* FIXME: This should be done asynchronously, but since the EffectState
* object was changed, it needs an update before its Process method can
* be called. */
EffectSlot->NeedsUpdate = AL_FALSE;
ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_FALSE);
V(EffectSlot->EffectState,update)(Device, EffectSlot);
ALCdevice_Unlock(Device);
@@ -515,7 +501,7 @@ ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *e
ALCdevice_Lock(Device);
memcpy(&EffectSlot->EffectProps, &effect->Props, sizeof(effect->Props));
ALCdevice_Unlock(Device);
EffectSlot->NeedsUpdate = AL_TRUE;
ATOMIC_STORE(&EffectSlot->NeedsUpdate, AL_TRUE);
}
}
@@ -536,15 +522,13 @@ ALenum InitEffectSlot(ALeffectslot *slot)
slot->Gain = 1.0;
slot->AuxSendAuto = AL_TRUE;
slot->NeedsUpdate = AL_FALSE;
ATOMIC_INIT(&slot->NeedsUpdate, AL_FALSE);
for(c = 0;c < 1;c++)
{
for(i = 0;i < BUFFERSIZE;i++)
slot->WetBuffer[c][i] = 0.0f;
slot->ClickRemoval[c] = 0.0f;
slot->PendingClicks[c] = 0.0f;
}
slot->ref = 0;
InitRef(&slot->ref, 0);
return AL_NO_ERROR;
}
File diff suppressed because it is too large Load Diff
@@ -35,6 +35,7 @@ ALboolean TrapALError = AL_FALSE;
ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
{
ALenum curerr = AL_NO_ERROR;
if(TrapALError)
{
#ifdef _WIN32
@@ -45,7 +46,7 @@ ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
raise(SIGTRAP);
#endif
}
CompExchangeInt(&Context->LastError, AL_NO_ERROR, errorCode);
ATOMIC_COMPARE_EXCHANGE_STRONG(ALenum, &Context->LastError, &curerr, errorCode);
}
AL_API ALenum AL_APIENTRY alGetError(void)
@@ -68,7 +69,7 @@ AL_API ALenum AL_APIENTRY alGetError(void)
return AL_INVALID_OPERATION;
}
errorCode = ExchangeInt(&Context->LastError, AL_NO_ERROR);
errorCode = ATOMIC_EXCHANGE(ALenum, &Context->LastError, AL_NO_ERROR);
ALCcontext_DecRef(Context);
@@ -38,7 +38,9 @@
const struct EffectList EffectList[] = {
{ "eaxreverb", EAXREVERB, "AL_EFFECT_EAXREVERB", AL_EFFECT_EAXREVERB },
{ "reverb", REVERB, "AL_EFFECT_REVERB", AL_EFFECT_REVERB },
#if 0
{ "autowah", AUTOWAH, "AL_EFFECT_AUTOWAH", AL_EFFECT_AUTOWAH },
#endif
{ "chorus", CHORUS, "AL_EFFECT_CHORUS", AL_EFFECT_CHORUS },
{ "compressor", COMPRESSOR, "AL_EFFECT_COMPRESSOR", AL_EFFECT_COMPRESSOR },
{ "distortion", DISTORTION, "AL_EFFECT_DISTORTION", AL_EFFECT_DISTORTION },
@@ -32,7 +32,6 @@
extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample);
extern inline ALfloat ALfilterState_processSingleC(const ALfilterState *filter, ALfloat sample);
static void InitFilterParams(ALfilter *filter, ALenum type);
@@ -146,7 +145,8 @@ AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint value)
{
if(param == AL_FILTER_TYPE)
{
if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS)
if(value == AL_FILTER_NULL || value == AL_FILTER_LOWPASS ||
value == AL_FILTER_HIGHPASS || value == AL_FILTER_BANDPASS)
InitFilterParams(ALFilter, value);
else
alSetError(Context, AL_INVALID_VALUE);
@@ -336,7 +336,7 @@ void ALfilterState_clear(ALfilterState *filter)
filter->y[1] = 0.0f;
}
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_scale, ALfloat bandwidth)
void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth)
{
ALfloat alpha;
ALfloat w0;
@@ -344,50 +344,28 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g
// Limit gain to -100dB
gain = maxf(gain, 0.00001f);
w0 = F_2PI * freq_scale;
w0 = F_2PI * freq_mult;
/* 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;
alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f);
filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha);
filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cosf(w0) );
filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha);
filter->a[0] = (gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha;
filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cosf(w0) );
filter->a[2] = (gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha;
break;
case ALfilterType_LowShelf:
alpha = sinf(w0) / 2.0f * sqrtf((gain + 1.0f / gain) *
(1.0f / 0.75f - 1.0f) + 2.0f);
filter->b[0] = gain * ((gain + 1.0f) -
(gain - 1.0f) * cosf(w0) +
2.0f * sqrtf(gain) * alpha);
filter->b[1] = 2.0f * gain * ((gain - 1.0f) -
(gain + 1.0f) * cosf(w0));
filter->b[2] = gain * ((gain + 1.0f) -
(gain - 1.0f) * cosf(w0) -
2.0f * sqrtf(gain) * alpha);
filter->a[0] = (gain + 1.0f) +
(gain - 1.0f) * cosf(w0) +
2.0f * sqrtf(gain) * alpha;
filter->a[1] = -2.0f * ((gain - 1.0f) +
(gain + 1.0f) * cosf(w0));
filter->a[2] = (gain + 1.0f) +
(gain - 1.0f) * cosf(w0) -
2.0f * sqrtf(gain) * alpha;
alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f);
filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha);
filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cosf(w0) );
filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha);
filter->a[0] = (gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha;
filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cosf(w0) );
filter->a[2] = (gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha;
break;
case ALfilterType_Peaking:
alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
@@ -434,6 +412,8 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g
filter->a[2] /= filter->a[0];
filter->a[1] /= filter->a[0];
filter->a[0] /= filter->a[0];
filter->process = ALfilterState_processC;
}
@@ -492,6 +472,126 @@ static void lp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, A
}
static void hp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_HIGHPASS_GAIN:
if(!(val >= AL_HIGHPASS_MIN_GAIN && val <= AL_HIGHPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->Gain = val;
break;
case AL_HIGHPASS_GAINLF:
if(!(val >= AL_HIGHPASS_MIN_GAINLF && val <= AL_HIGHPASS_MAX_GAINLF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainLF = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void hp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
hp_SetParamf(filter, context, param, vals[0]);
}
static void hp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void hp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
case AL_HIGHPASS_GAIN:
*val = filter->Gain;
break;
case AL_HIGHPASS_GAINLF:
*val = filter->GainLF;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void hp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
hp_GetParamf(filter, context, param, vals);
}
static void bp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_SetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val)
{
switch(param)
{
case AL_BANDPASS_GAIN:
if(!(val >= AL_BANDPASS_MIN_GAIN && val <= AL_BANDPASS_MAX_GAIN))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->Gain = val;
break;
case AL_BANDPASS_GAINHF:
if(!(val >= AL_BANDPASS_MIN_GAINHF && val <= AL_BANDPASS_MAX_GAINHF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainHF = val;
break;
case AL_BANDPASS_GAINLF:
if(!(val >= AL_BANDPASS_MIN_GAINLF && val <= AL_BANDPASS_MAX_GAINLF))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
filter->GainLF = val;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void bp_SetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals)
{
bp_SetParamf(filter, context, param, vals[0]);
}
static void bp_GetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_GetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(vals))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void bp_GetParamf(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val)
{
switch(param)
{
case AL_BANDPASS_GAIN:
*val = filter->Gain;
break;
case AL_BANDPASS_GAINHF:
*val = filter->GainHF;
break;
case AL_BANDPASS_GAINLF:
*val = filter->GainLF;
break;
default:
SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
}
}
static void bp_GetParamfv(ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals)
{
bp_GetParamf(filter, context, param, vals);
}
static void null_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
static void null_SetParamiv(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), const ALint *UNUSED(vals))
@@ -533,6 +633,9 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
{
filter->Gain = AL_LOWPASS_DEFAULT_GAIN;
filter->GainHF = AL_LOWPASS_DEFAULT_GAINHF;
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = 1.0f;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = lp_SetParami;
filter->SetParamiv = lp_SetParamiv;
@@ -543,8 +646,48 @@ static void InitFilterParams(ALfilter *filter, ALenum type)
filter->GetParamf = lp_GetParamf;
filter->GetParamfv = lp_GetParamfv;
}
else if(type == AL_FILTER_HIGHPASS)
{
filter->Gain = AL_HIGHPASS_DEFAULT_GAIN;
filter->GainHF = 1.0f;
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = AL_HIGHPASS_DEFAULT_GAINLF;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = hp_SetParami;
filter->SetParamiv = hp_SetParamiv;
filter->SetParamf = hp_SetParamf;
filter->SetParamfv = hp_SetParamfv;
filter->GetParami = hp_GetParami;
filter->GetParamiv = hp_GetParamiv;
filter->GetParamf = hp_GetParamf;
filter->GetParamfv = hp_GetParamfv;
}
else if(type == AL_FILTER_BANDPASS)
{
filter->Gain = AL_BANDPASS_DEFAULT_GAIN;
filter->GainHF = AL_BANDPASS_DEFAULT_GAINHF;
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = AL_BANDPASS_DEFAULT_GAINLF;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = bp_SetParami;
filter->SetParamiv = bp_SetParamiv;
filter->SetParamf = bp_SetParamf;
filter->SetParamfv = bp_SetParamfv;
filter->GetParami = bp_GetParami;
filter->GetParamiv = bp_GetParamiv;
filter->GetParamf = bp_GetParamf;
filter->GetParamfv = bp_GetParamfv;
}
else
{
filter->Gain = 1.0f;
filter->GainHF = 1.0f;
filter->HFReference = LOWPASSFREQREF;
filter->GainLF = 1.0f;
filter->LFReference = HIGHPASSFREQREF;
filter->SetParami = null_SetParami;
filter->SetParamiv = null_SetParamiv;
filter->SetParamf = null_SetParamf;
@@ -8,6 +8,7 @@
#include "alMidi.h"
#include "alError.h"
#include "alThunk.h"
#include "alBuffer.h"
#include "midi/base.h"
@@ -15,13 +16,21 @@
extern inline struct ALfontsound *LookupFontsound(ALCdevice *device, ALuint id);
extern inline struct ALfontsound *RemoveFontsound(ALCdevice *device, ALuint id);
static void ALfontsound_Construct(ALfontsound *self);
void ALfontsound_Destruct(ALfontsound *self);
static void ALfontsound_Destruct(ALfontsound *self);
void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value);
static ALsfmodulator *ALfontsound_getModStage(ALfontsound *self, ALsizei stage);
void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value);
static void ALfontsound_getModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint *values);
static inline struct ALsfmodulator *LookupModulator(ALfontsound *sound, ALuint id)
{
ALsfmodulator *mod = LookupUIntMapKey(&sound->ModulatorMap, id>>2);
if(mod) mod += id&3;
return mod;
}
AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids)
{
@@ -69,19 +78,14 @@ AL_API ALvoid AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids)
/* Check for valid ID */
if((inst=LookupFontsound(device, ids[i])) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(inst->ref != 0)
if(ReadRef(&inst->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
for(i = 0;i < n;i++)
{
if((inst=RemoveFontsound(device, ids[i])) == NULL)
continue;
ALfontsound_Destruct(inst);
memset(inst, 0, sizeof(*inst));
free(inst);
if((inst=LookupFontsound(device, ids[i])) != NULL)
DeleteFontsound(device, inst);
}
done:
@@ -115,7 +119,7 @@ AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value)
device = context->Device;
if(!(sound=LookupFontsound(device, id)))
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(sound->ref != 0)
if(ReadRef(&sound->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
ALfontsound_setPropi(sound, context, param, value);
@@ -136,7 +140,7 @@ AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1,
device = context->Device;
if(!(sound=LookupFontsound(device, id)))
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(sound->ref != 0)
if(ReadRef(&sound->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
switch(param)
{
@@ -231,7 +235,7 @@ AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *
device = context->Device;
if(!(sound=LookupFontsound(device, id)))
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(sound->ref != 0)
if(ReadRef(&sound->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
switch(param)
{
@@ -257,6 +261,10 @@ AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *val
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
switch(param)
{
case AL_BUFFER:
values[0] = (sound->Buffer ? sound->Buffer->id : 0);
break;
case AL_MOD_LFO_TO_PITCH_SOFT:
values[0] = sound->ModLfoToPitch;
break;
@@ -505,10 +513,22 @@ ALfontsound *NewFontsound(ALCcontext *context)
return sound;
}
void DeleteFontsound(ALCdevice *device, ALfontsound *sound)
{
RemoveFontsound(device, sound->id);
ALfontsound_Destruct(sound);
memset(sound, 0, sizeof(*sound));
free(sound);
}
static void ALfontsound_Construct(ALfontsound *self)
{
self->ref = 0;
InitRef(&self->ref, 0);
self->Buffer = NULL;
self->MinKey = 0;
self->MaxKey = 127;
@@ -580,13 +600,16 @@ static void ALfontsound_Construct(ALfontsound *self)
self->id = 0;
}
void ALfontsound_Destruct(ALfontsound *self)
static void ALfontsound_Destruct(ALfontsound *self)
{
ALsizei i;
FreeThunkEntry(self->id);
self->id = 0;
if(self->Buffer)
DecrementRef(&self->Buffer->ref);
self->Buffer = NULL;
if(self->Link)
DecrementRef(&self->Link->ref);
self->Link = NULL;
@@ -602,9 +625,26 @@ void ALfontsound_Destruct(ALfontsound *self)
void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value)
{
ALfontsound *link;
ALbuffer *buffer;
switch(param)
{
case AL_BUFFER:
buffer = value ? LookupBuffer(context->Device, value) : NULL;
if(value && !buffer)
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
else if(buffer)
{
/* Buffer must have a non-0 length, and must be mono. */
if(buffer->SampleLen <= 0 || buffer->FmtChannels != FmtMono)
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
}
if(buffer) IncrementRef(&buffer->ref);
if((buffer=ExchangePtr((XchgPtr*)&self->Buffer, buffer)) != NULL)
DecrementRef(&buffer->ref);
break;
case AL_MOD_LFO_TO_PITCH_SOFT:
self->ModLfoToPitch = value;
break;
@@ -787,17 +827,13 @@ void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param,
break;
case AL_FONTSOUND_LINK_SOFT:
if(!value)
link = NULL;
else
{
link = LookupFontsound(context->Device, value);
if(!link)
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
}
link = value ? LookupFontsound(context->Device, value) : NULL;
if(value && !link)
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
if(link) IncrementRef(&link->ref);
link = ExchangePtr((XchgPtr*)&self->Link, link);
if(link) DecrementRef(&link->ref);
if((link=ExchangePtr((XchgPtr*)&self->Link, link)) != NULL)
DecrementRef(&link->ref);
break;
default:
@@ -812,15 +848,18 @@ static ALsfmodulator *ALfontsound_getModStage(ALfontsound *self, ALsizei stage)
{
static const ALsfmodulator moddef = {
{ { AL_ONE_SOFT, AL_UNORM_SOFT, AL_LINEAR_SOFT },
{ AL_ONE_SOFT, AL_UNORM_SOFT, AL_LINEAR_SOFT }
},
{ AL_ONE_SOFT, AL_UNORM_SOFT, AL_LINEAR_SOFT } },
0,
AL_LINEAR_SOFT,
AL_NONE
};
ret = malloc(sizeof(*ret));
*ret = moddef;
InsertUIntMapEntry(&self->ModulatorMap, stage, ret);
ret = malloc(sizeof(ALsfmodulator[4]));
ret[0] = moddef;
ret[1] = moddef;
ret[2] = moddef;
ret[3] = moddef;
InsertUIntMapEntry(&self->ModulatorMap, stage>>2, ret);
ret += stage&3;
}
return ret;
}
@@ -829,7 +868,7 @@ void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei st
{
ALint srcidx = 0;
if(self->ref != 0)
if(ReadRef(&self->ref) != 0)
SET_ERROR_AND_RETURN(context, AL_INVALID_OPERATION);
switch(param)
{
@@ -841,10 +880,7 @@ void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei st
value == AL_NOTEON_KEY_SOFT || value == AL_KEYPRESSURE_SOFT ||
value == AL_CHANNELPRESSURE_SOFT || value == AL_PITCHBEND_SOFT ||
value == AL_PITCHBEND_SENSITIVITY_SOFT ||
(value > 0 && value < 120 && !(value == 6 || (value >= 32 && value <= 63) ||
(value >= 98 && value <= 101))
)
))
IsValidCtrlInput(value)))
SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
ALfontsound_getModStage(self, stage)->Source[srcidx].Input = value;
break;
@@ -40,7 +40,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->Gain = value;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
break;
case AL_METERS_PER_UNIT:
@@ -48,7 +48,7 @@ AL_API ALvoid AL_APIENTRY alListenerf(ALenum param, ALfloat value)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->Listener->MetersPerUnit = value;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
break;
default:
@@ -77,7 +77,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
context->Listener->Position[0] = value1;
context->Listener->Position[1] = value2;
context->Listener->Position[2] = value3;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
UnlockContext(context);
break;
@@ -89,7 +89,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
context->Listener->Velocity[0] = value1;
context->Listener->Velocity[1] = value2;
context->Listener->Velocity[2] = value3;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
UnlockContext(context);
break;
@@ -142,7 +142,7 @@ AL_API ALvoid AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
context->Listener->Up[0] = values[3];
context->Listener->Up[1] = values[4];
context->Listener->Up[2] = values[5];
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
UnlockContext(context);
break;
@@ -19,7 +19,9 @@
MidiSynth *SynthCreate(ALCdevice *device)
{
MidiSynth *synth = FSynth_create(device);
MidiSynth *synth = NULL;
if(!synth) synth = SSynth_create(device);
if(!synth) synth = FSynth_create(device);
if(!synth) synth = DSynth_create(device);
return synth;
}
@@ -99,18 +101,12 @@ AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, A
ALCdevice *device;
ALCcontext *context;
ALenum err;
ALsizei i;
context = GetContextRef();
if(!context) return;
if(!data || size < 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
for(i = 0;i < size;i++)
{
if((data[i]&0x80))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
}
device = context->Device;
ALCdevice_Lock(device);
@@ -133,7 +129,7 @@ AL_API void AL_APIENTRY alMidiPlaySOFT(void)
synth = context->Device->Synth;
WriteLock(&synth->Lock);
V(synth,setState)(AL_PLAYING);
MidiSynth_setState(synth, AL_PLAYING);
WriteUnlock(&synth->Lock);
ALCcontext_DecRef(context);
@@ -149,7 +145,7 @@ AL_API void AL_APIENTRY alMidiPauseSOFT(void)
synth = context->Device->Synth;
WriteLock(&synth->Lock);
V(synth,setState)(AL_PAUSED);
MidiSynth_setState(synth, AL_PAUSED);
WriteUnlock(&synth->Lock);
ALCcontext_DecRef(context);
@@ -168,7 +164,7 @@ AL_API void AL_APIENTRY alMidiStopSOFT(void)
synth = device->Synth;
WriteLock(&synth->Lock);
V(synth,setState)(AL_STOPPED);
MidiSynth_setState(synth, AL_STOPPED);
ALCdevice_Lock(device);
V0(synth,stop)();
@@ -191,7 +187,7 @@ AL_API void AL_APIENTRY alMidiResetSOFT(void)
synth = device->Synth;
WriteLock(&synth->Lock);
V(synth,setState)(AL_INITIAL);
MidiSynth_setState(synth, AL_INITIAL);
ALCdevice_Lock(device);
V0(synth,reset)();
@@ -16,7 +16,7 @@ extern inline struct ALsfpreset *LookupPreset(ALCdevice *device, ALuint id);
extern inline struct ALsfpreset *RemovePreset(ALCdevice *device, ALuint id);
static void ALsfpreset_Construct(ALsfpreset *self);
void ALsfpreset_Destruct(ALsfpreset *self);
static void ALsfpreset_Destruct(ALsfpreset *self);
AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids)
@@ -65,15 +65,14 @@ AL_API ALvoid AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids)
/* Check for valid ID */
if((preset=LookupPreset(device, ids[i])) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(preset->ref != 0)
if(ReadRef(&preset->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
for(i = 0;i < n;i++)
{
if((preset=LookupPreset(device, ids[i])) == NULL)
continue;
DeletePreset(preset, device);
if((preset=LookupPreset(device, ids[i])) != NULL)
DeletePreset(device, preset);
}
done:
@@ -107,7 +106,7 @@ AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value)
device = context->Device;
if((preset=LookupPreset(device, id)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(preset->ref != 0)
if(ReadRef(&preset->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
switch(param)
{
@@ -151,7 +150,7 @@ AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *val
device = context->Device;
if((preset=LookupPreset(device, id)) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(preset->ref != 0)
if(ReadRef(&preset->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
switch(param)
{
@@ -220,7 +219,7 @@ AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const A
if(count < 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(preset->ref != 0)
if(ReadRef(&preset->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
if(count == 0)
@@ -282,7 +281,7 @@ ALsfpreset *NewPreset(ALCcontext *context)
return preset;
}
void DeletePreset(ALsfpreset *preset, ALCdevice *device)
void DeletePreset(ALCdevice *device, ALsfpreset *preset)
{
RemovePreset(device, preset->id);
@@ -294,7 +293,7 @@ void DeletePreset(ALsfpreset *preset, ALCdevice *device)
static void ALsfpreset_Construct(ALsfpreset *self)
{
self->ref = 0;
InitRef(&self->ref, 0);
self->Preset = 0;
self->Bank = 0;
@@ -305,7 +304,7 @@ static void ALsfpreset_Construct(ALsfpreset *self)
self->id = 0;
}
void ALsfpreset_Destruct(ALsfpreset *self)
static void ALsfpreset_Destruct(ALsfpreset *self)
{
ALsizei i;
@@ -4,11 +4,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "alMain.h"
#include "alMidi.h"
#include "alThunk.h"
#include "alError.h"
#include <alBuffer.h>
#include "midi/base.h"
@@ -16,8 +18,8 @@
extern inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id);
extern inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id);
void ALsoundfont_Construct(ALsoundfont *self);
void ALsoundfont_Destruct(ALsoundfont *self);
static void ALsoundfont_Construct(ALsoundfont *self);
static void ALsoundfont_Destruct(ALsoundfont *self);
void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device);
ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context);
static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr);
@@ -91,7 +93,7 @@ AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids)
}
else if((sfont=LookupSfont(device, ids[i])) == NULL)
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(sfont->Mapped != AL_FALSE || sfont->ref != 0)
if(ReadRef(&sfont->ref) != 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
@@ -136,137 +138,6 @@ AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id)
return ret;
}
AL_API ALvoid AL_APIENTRY alSoundfontSamplesSOFT(ALuint id, ALenum type, ALsizei count, const ALvoid *samples)
{
ALCdevice *device;
ALCcontext *context;
ALsoundfont *sfont;
void *ptr;
context = GetContextRef();
if(!context) return;
device = context->Device;
if(id == 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
if(!(sfont=LookupSfont(device, id)))
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(type != AL_SHORT_SOFT)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(count <= 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
WriteLock(&sfont->Lock);
if(sfont->ref != 0)
alSetError(context, AL_INVALID_OPERATION);
else if(sfont->Mapped)
alSetError(context, AL_INVALID_OPERATION);
else if(!(ptr=realloc(sfont->Samples, count * sizeof(ALshort))))
alSetError(context, AL_OUT_OF_MEMORY);
else
{
sfont->Samples = ptr;
sfont->NumSamples = count;
if(samples != NULL)
memcpy(sfont->Samples, samples, count * sizeof(ALshort));
}
WriteUnlock(&sfont->Lock);
done:
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetSoundfontSamplesSOFT(ALuint id, ALsizei offset, ALsizei count, ALenum type, ALvoid *samples)
{
ALCdevice *device;
ALCcontext *context;
ALsoundfont *sfont;
context = GetContextRef();
if(!context) return;
device = context->Device;
if(id == 0)
sfont = ALsoundfont_getDefSoundfont(context);
else if(!(sfont=LookupSfont(device, id)))
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(type != AL_SHORT_SOFT)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(offset < 0 || count <= 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
ReadLock(&sfont->Lock);
if(offset >= sfont->NumSamples || count > (sfont->NumSamples-offset))
alSetError(context, AL_INVALID_VALUE);
else if(sfont->Mapped)
alSetError(context, AL_INVALID_OPERATION);
else
{
/* TODO: Allow conversion. */
memcpy(samples, sfont->Samples + offset*sizeof(ALshort), count * sizeof(ALshort));
}
ReadUnlock(&sfont->Lock);
done:
ALCcontext_DecRef(context);
}
AL_API ALvoid* AL_APIENTRY alSoundfontMapSamplesSOFT(ALuint id, ALsizei offset, ALsizei length)
{
ALCdevice *device;
ALCcontext *context;
ALsoundfont *sfont;
ALvoid *ptr = NULL;
context = GetContextRef();
if(!context) return NULL;
device = context->Device;
if(id == 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
if(!(sfont=LookupSfont(device, id)))
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(offset < 0 || (ALuint)offset > sfont->NumSamples*sizeof(ALshort))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if(length <= 0 || (ALuint)length > (sfont->NumSamples*sizeof(ALshort) - offset))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
ReadLock(&sfont->Lock);
if(sfont->ref != 0)
alSetError(context, AL_INVALID_OPERATION);
else if(ExchangeInt(&sfont->Mapped, AL_TRUE) == AL_TRUE)
alSetError(context, AL_INVALID_OPERATION);
else
ptr = (ALbyte*)sfont->Samples + offset;
ReadUnlock(&sfont->Lock);
done:
ALCcontext_DecRef(context);
return ptr;
}
AL_API ALvoid AL_APIENTRY alSoundfontUnmapSamplesSOFT(ALuint id)
{
ALCdevice *device;
ALCcontext *context;
ALsoundfont *sfont;
context = GetContextRef();
if(!context) return;
device = context->Device;
if(id == 0)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
if(!(sfont=LookupSfont(device, id)))
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
if(ExchangeInt(&sfont->Mapped, AL_FALSE) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
done:
ALCcontext_DecRef(context);
}
AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values)
{
ALCdevice *device;
@@ -293,14 +164,6 @@ AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *val
values[i] = sfont->Presets[i]->id;
break;
case AL_SAMPLE_LENGTH_SOFT:
values[0] = sfont->NumSamples;
break;
case AL_FORMAT_TYPE_SOFT:
values[0] = AL_SHORT_SOFT;
break;
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -329,7 +192,7 @@ AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const A
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
WriteLock(&sfont->Lock);
if(sfont->ref != 0)
if(ReadRef(&sfont->ref) != 0)
{
WriteUnlock(&sfont->Lock);
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
@@ -350,6 +213,7 @@ AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const A
{
if(!(presets[i]=LookupPreset(device, pids[i])))
{
free(presets);
WriteUnlock(&sfont->Lock);
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
}
@@ -389,12 +253,7 @@ AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_
SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
WriteLock(&sfont->Lock);
if(sfont->ref != 0)
{
WriteUnlock(&sfont->Lock);
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
}
if(sfont->Mapped)
if(ReadRef(&sfont->ref) != 0)
{
WriteUnlock(&sfont->Lock);
SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
@@ -416,23 +275,19 @@ done:
}
void ALsoundfont_Construct(ALsoundfont *self)
static void ALsoundfont_Construct(ALsoundfont *self)
{
self->ref = 0;
InitRef(&self->ref, 0);
self->Presets = NULL;
self->NumPresets = 0;
self->Samples = NULL;
self->NumSamples = 0;
RWLockInit(&self->Lock);
self->Mapped = AL_FALSE;
self->id = 0;
}
void ALsoundfont_Destruct(ALsoundfont *self)
static void ALsoundfont_Destruct(ALsoundfont *self)
{
ALsizei i;
@@ -447,16 +302,13 @@ void ALsoundfont_Destruct(ALsoundfont *self)
free(self->Presets);
self->Presets = NULL;
self->NumPresets = 0;
free(self->Samples);
self->Samples = NULL;
self->NumSamples = 0;
}
ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context)
{
ALCdevice *device = context->Device;
const char *fname;
al_string fname = AL_STRING_INIT_STATIC();
const char *namelist;
if(device->DefaultSfont)
return device->DefaultSfont;
@@ -464,25 +316,44 @@ ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context)
device->DefaultSfont = calloc(1, sizeof(device->DefaultSfont[0]));
ALsoundfont_Construct(device->DefaultSfont);
fname = getenv("ALSOFT_SOUNDFONT");
if((fname && fname[0]) || ConfigValueStr("midi", "soundfont", &fname))
namelist = getenv("ALSOFT_SOUNDFONT");
if(!namelist || !namelist[0])
ConfigValueStr("midi", "soundfont", &namelist);
while(namelist && namelist[0])
{
const char *next, *end;
FILE *f;
f = fopen(fname, "rb");
while(*namelist && (isspace(*namelist) || *namelist == ','))
namelist++;
if(!*namelist)
break;
next = strchr(namelist, ',');
end = next ? next++ : (namelist+strlen(namelist));
while(--end != namelist && isspace(*end)) {
}
if(end == namelist)
continue;
al_string_append_range(&fname, namelist, end+1);
namelist = next;
f = OpenDataFile(al_string_get_cstr(fname), "openal/soundfonts");
if(f == NULL)
ERR("Failed to open %s\n", fname);
ERR("Failed to open %s\n", al_string_get_cstr(fname));
else
{
Reader reader;
reader.cb = ALsoundfont_read;
reader.ptr = f;
reader.error = 0;
TRACE("Loading %s\n", fname);
TRACE("Loading %s\n", al_string_get_cstr(fname));
loadSf2(&reader, device->DefaultSfont, context);
fclose(f);
}
al_string_clear(&fname);
}
AL_STRING_DEINIT(fname);
return device->DefaultSfont;
}
@@ -491,8 +362,10 @@ void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device)
{
ALsfpreset **presets;
ALsizei num_presets;
VECTOR(ALbuffer*) buffers;
ALsizei i;
VECTOR_INIT(buffers);
presets = ExchangePtr((XchgPtr*)&self->Presets, NULL);
num_presets = ExchangeInt(&self->NumPresets, 0);
@@ -506,7 +379,8 @@ void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device)
sounds = ExchangePtr((XchgPtr*)&preset->Sounds, NULL);
num_sounds = ExchangeInt(&preset->NumSounds, 0);
DeletePreset(preset, device);
DeletePreset(device, preset);
preset = NULL;
for(j = 0;j < num_sounds;j++)
@@ -519,12 +393,21 @@ void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device)
deleting = AL_FALSE;
for(j = 0;j < num_sounds;j++)
{
if(sounds[j] && sounds[j]->ref == 0)
if(sounds[j] && ReadRef(&sounds[j]->ref) == 0)
{
deleting = AL_TRUE;
RemoveFontsound(device, sounds[j]->id);
ALfontsound_Destruct(sounds[j]);
free(sounds[j]);
if(sounds[j]->Buffer)
{
ALbuffer *buffer = sounds[j]->Buffer;
ALbuffer **iter;
#define MATCH_BUFFER(_i) (buffer == *(_i))
VECTOR_FIND_IF(iter, ALbuffer*, buffers, MATCH_BUFFER);
if(iter == VECTOR_ITER_END(buffers))
VECTOR_PUSH_BACK(buffers, buffer);
#undef MATCH_BUFFER
}
DeleteFontsound(device, sounds[j]);
sounds[j] = NULL;
}
}
@@ -534,6 +417,14 @@ void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device)
ALsoundfont_Destruct(self);
free(self);
#define DELETE_BUFFER(iter) do { \
assert(ReadRef(&(*(iter))->ref) == 0); \
DeleteBuffer(device, *(iter)); \
} while(0)
VECTOR_FOR_EACH(ALbuffer*, buffers, DELETE_BUFFER);
VECTOR_DEINIT(buffers);
#undef DELETE_BUFFER
}
@@ -56,7 +56,7 @@ AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
{
case AL_SOURCE_DISTANCE_MODEL:
context->SourceDistanceModel = AL_TRUE;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
break;
default:
@@ -78,7 +78,7 @@ AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
{
case AL_SOURCE_DISTANCE_MODEL:
context->SourceDistanceModel = AL_FALSE;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
break;
default:
@@ -643,7 +643,7 @@ AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->DopplerFactor = value;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
done:
ALCcontext_DecRef(context);
@@ -660,7 +660,7 @@ AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->DopplerVelocity = value;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
done:
ALCcontext_DecRef(context);
@@ -677,7 +677,7 @@ AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat value)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
context->SpeedOfSound = value;
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
done:
ALCcontext_DecRef(context);
@@ -698,7 +698,7 @@ AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
context->DistanceModel = value;
if(!context->SourceDistanceModel)
context->UpdateSources = AL_TRUE;
ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
done:
ALCcontext_DecRef(context);
@@ -715,7 +715,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
if(!context->DeferUpdates)
{
ALboolean UpdateSources;
ALsource **src, **src_end;
ALactivesource **src, **src_end;
ALeffectslot **slot, **slot_end;
FPUCtl oldMode;
@@ -725,30 +725,34 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
context->DeferUpdates = AL_TRUE;
/* Make sure all pending updates are performed */
UpdateSources = ExchangeInt(&context->UpdateSources, AL_FALSE);
UpdateSources = ATOMIC_EXCHANGE(ALenum, &context->UpdateSources, AL_FALSE);
src = context->ActiveSources;
src_end = src + context->ActiveSourceCount;
while(src != src_end)
{
if((*src)->state != AL_PLAYING)
ALsource *source = (*src)->Source;
if(source->state != AL_PLAYING && source->state != AL_PAUSED)
{
context->ActiveSourceCount--;
*src = *(--src_end);
ALactivesource *temp = *(--src_end);
*src_end = *src;
*src = temp;
--(context->ActiveSourceCount);
continue;
}
if(ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) || UpdateSources)
ALsource_Update(*src, context);
if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || UpdateSources)
(*src)->Update(*src, context);
src++;
}
slot = context->ActiveEffectSlots;
slot_end = slot + context->ActiveEffectSlotCount;
slot = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
slot_end = VECTOR_ITER_END(context->ActiveAuxSlots);
while(slot != slot_end)
{
if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
V((*slot)->EffectState,update)(context->Device, *slot);
slot++;
}
@@ -780,7 +784,11 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
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)
File diff suppressed because it is too large Load Diff
@@ -1,28 +1,40 @@
# OpenAL config file. Options that are not under a block or are under the
# [general] block are for general, non-backend-specific options. Blocks may
# appear multiple times, and duplicated options will take the last value
# specified.
# OpenAL config file.
#
# Option blocks may appear multiple times, and duplicated options will take the
# last value specified. Environment variables may be specified within option
# values, and are automatically substituted when the config file is loaded.
# Environment variable names may only contain alpha-numeric characters (a-z,
# A-Z, 0-9) and underscores (_), and are prefixed with $. For example,
# specifying "$HOME/file.ext" would typically result in something like
# "/home/user/file.ext". To specify an actual "$" character, use "$$".
#
# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
# specific override settings in ~/.alsoftrc.
# For Windows, these settings should go into %AppData%\alsoft.ini
# 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
# possible). Note: options that are left unset may default to app- or system-
# specified values. These are the current available settings:
##
## General stuff
##
[general]
## disable-cpu-exts:
# Disables use of the listed CPU extensions. Certain methods may utilize CPU
# extensions when detected, and this option is useful for preventing those
# extensions from being used. The available extensions are: sse, sse2, neon.
# Specifying 'all' disables use of all extensions.
# 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.
#disable-cpu-exts =
## 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
#channels = stereo
#channels =
## sample-type:
# Sets the output sample type. Currently, all mixing is done with 32-bit float
@@ -45,15 +57,19 @@
## hrtf_tables
# Specifies a comma-separated list of files containing HRTF data sets. The
# listed data sets can be used in place of or in addiiton to the the built-in
# set. The format of the files are described in hrtf.txt. The filenames may
# contain these markers, which will be replaced as needed:
# format of the files are described in hrtf.txt. The filenames may contain
# these markers, which will be replaced as needed:
# %r - Device sampling rate
# %% - Percent sign (%)
# So if this is set to "kemar-%r-diffuse.mhr", it will try to open
# "kemar-44100-diffuse.mhr" if the device is using 44100hz output, or
# "kemar-48000-diffuse.mhr" if the device is using 48000hz output, etc.
#hrtf_tables =
# The listed files are relative to system-dependant data directories. On
# Windows this is:
# $AppData\openal\hrtf
# And on other systems, it's (in order):
# $XDG_DATA_HOME/openal/hrtf (defaults to $HOME/.local/share/openal/hrtf)
# $XDG_DATA_DIRS/openal/hrtf (defaults to /usr/local/share/openal/hrtf and
# /usr/share/openal/hrtf)
# An absolute path may also be specified, if the given file is elsewhere.
#hrtf_tables = default-%r.mhr
## cf_level:
# Sets the crossfeed level for stereo output. Valid values are:
@@ -77,8 +93,9 @@
#wide-stereo = false
## frequency:
# Sets the output frequency.
#frequency = 44100
# 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:
# Selects the resampler used when mixing sources. Valid values are:
@@ -117,11 +134,11 @@
## 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 (eg. 'oss,' will list OSS first
# followed by all other available backends, while 'oss' will list OSS only).
# Backends prepended with - won't be available for use (eg. '-oss,' will allow
# all available backends except OSS). An empty list means the default.
#drivers = pulse,alsa,core,oss,solaris,sndio,qsa,mmdevapi,dsound,winmm,port,opensl,null,wave
# 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
@@ -190,7 +207,13 @@
## soundfont:
# A default soundfont (sf2 format). Used when an app requests the system
# default.
# 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:
View File
@@ -0,0 +1,9 @@
#include <sys/types.h>
#define KB ((off_t)(1024))
#define MB ((off_t)(KB*1024))
#define GB ((off_t)(MB*1024))
int tb[((GB+GB+GB) > GB) ? 1 : -1];
int main()
{ return 0; }
@@ -0,0 +1,39 @@
# - Check if the _FILE_OFFSET_BITS macro is needed for large files
# CHECK_FILE_OFFSET_BITS()
#
# The following variables may be set before calling this macro to
# modify the way the check is run:
#
# CMAKE_REQUIRED_FLAGS = string of compile command line flags
# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
# CMAKE_REQUIRED_INCLUDES = list of include directories
# Copyright (c) 2009, Chris Robinson
#
# Redistribution and use is allowed according to the terms of the LGPL license.
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_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_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
IF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
SET(_FILE_OFFSET_BITS 64 CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files - 64")
ELSE(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
SET(_FILE_OFFSET_BITS "" CACHE INTERNAL "_FILE_OFFSET_BITS macro needed for large files")
MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files - not needed")
ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64 AND __WITH_FILE_OFFSET_BITS_64)
ENDIF(NOT DEFINED _FILE_OFFSET_BITS)
ENDMACRO(CHECK_FILE_OFFSET_BITS)
@@ -0,0 +1,73 @@
# - Find alsa
# Find the alsa libraries (asound)
#
# This module defines the following variables:
# ALSA_FOUND - True if ALSA_INCLUDE_DIR & ALSA_LIBRARY are found
# ALSA_LIBRARIES - Set when ALSA_LIBRARY is found
# ALSA_INCLUDE_DIRS - Set when ALSA_INCLUDE_DIR is found
#
# ALSA_INCLUDE_DIR - where to find asoundlib.h, etc.
# ALSA_LIBRARY - the asound library
# ALSA_VERSION_STRING - the version of alsa found (since CMake 2.8.8)
#
#=============================================================================
# Copyright 2009-2011 Kitware, Inc.
# Copyright 2009-2011 Philip Lowman <philip@yhbt.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * The names of Kitware, Inc., the Insight Consortium, or the names of
# any consortium members, or of any contributors, may not be used to
# endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
find_path(ALSA_INCLUDE_DIR NAMES alsa/asoundlib.h
DOC "The ALSA (asound) include directory"
)
find_library(ALSA_LIBRARY NAMES asound
DOC "The ALSA (asound) library"
)
if(ALSA_INCLUDE_DIR AND EXISTS "${ALSA_INCLUDE_DIR}/alsa/version.h")
file(STRINGS "${ALSA_INCLUDE_DIR}/alsa/version.h" alsa_version_str REGEX "^#define[\t ]+SND_LIB_VERSION_STR[\t ]+\".*\"")
string(REGEX REPLACE "^.*SND_LIB_VERSION_STR[\t ]+\"([^\"]*)\".*$" "\\1" ALSA_VERSION_STRING "${alsa_version_str}")
unset(alsa_version_str)
endif()
# handle the QUIETLY and REQUIRED arguments and set ALSA_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ALSA
REQUIRED_VARS ALSA_LIBRARY ALSA_INCLUDE_DIR
VERSION_VAR ALSA_VERSION_STRING)
if(ALSA_FOUND)
set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
set( ALSA_INCLUDE_DIRS ${ALSA_INCLUDE_DIR} )
endif()
mark_as_advanced(ALSA_INCLUDE_DIR ALSA_LIBRARY)
@@ -0,0 +1,21 @@
# - Find AudioIO includes and libraries
#
# AUDIOIO_FOUND - True if AUDIOIO_INCLUDE_DIR is found
# AUDIOIO_INCLUDE_DIRS - Set when AUDIOIO_INCLUDE_DIR is found
#
# AUDIOIO_INCLUDE_DIR - where to find sys/audioio.h, etc.
#
find_path(AUDIOIO_INCLUDE_DIR
NAMES sys/audioio.h
DOC "The AudioIO include directory"
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(AudioIO REQUIRED_VARS AUDIOIO_INCLUDE_DIR)
if(AUDIOIO_FOUND)
set(AUDIOIO_INCLUDE_DIRS ${AUDIOIO_INCLUDE_DIR})
endif()
mark_as_advanced(AUDIOIO_INCLUDE_DIR)
@@ -0,0 +1,33 @@
# - Find DirectSound includes and libraries
#
# DSOUND_FOUND - True if DSOUND_INCLUDE_DIR & DSOUND_LIBRARY are found
# DSOUND_LIBRARIES - Set when DSOUND_LIBRARY is found
# DSOUND_INCLUDE_DIRS - Set when DSOUND_INCLUDE_DIR is found
#
# DSOUND_INCLUDE_DIR - where to find dsound.h, etc.
# DSOUND_LIBRARY - the dsound library
#
find_path(DSOUND_INCLUDE_DIR
PATHS "${DXSDK_DIR}/include"
NAMES dsound.h
DOC "The DirectSound include directory"
)
find_library(DSOUND_LIBRARY
PATHS "${DXSDK_DIR}/lib"
NAMES dsound
DOC "The DirectSound library"
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DSound
REQUIRED_VARS DSOUND_LIBRARY DSOUND_INCLUDE_DIR
)
if(DSOUND_FOUND)
set(DSOUND_LIBRARIES ${DSOUND_LIBRARY})
set(DSOUND_INCLUDE_DIRS ${DSOUND_INCLUDE_DIR})
endif()
mark_as_advanced(DSOUND_INCLUDE_DIR DSOUND_LIBRARY)
@@ -0,0 +1,173 @@
# vim: ts=2 sw=2
# - Try to find the required ffmpeg components(default: AVFORMAT, AVUTIL, AVCODEC)
#
# Once done this will define
# FFMPEG_FOUND - System has the all required components.
# FFMPEG_INCLUDE_DIRS - Include directory necessary for using the required components headers.
# FFMPEG_LIBRARIES - Link these to use the required ffmpeg components.
# FFMPEG_DEFINITIONS - Compiler switches required for using the required ffmpeg components.
#
# For each of the components it will additionaly set.
# - AVCODEC
# - AVDEVICE
# - AVFORMAT
# - AVUTIL
# - POSTPROC
# - SWSCALE
# - SWRESAMPLE
# the following variables will be defined
# <component>_FOUND - System has <component>
# <component>_INCLUDE_DIRS - Include directory necessary for using the <component> headers
# <component>_LIBRARIES - Link these to use <component>
# <component>_DEFINITIONS - Compiler switches required for using <component>
# <component>_VERSION - The components version
#
# Copyright (c) 2006, Matthias Kretz, <kretz@kde.org>
# Copyright (c) 2008, Alexander Neundorf, <neundorf@kde.org>
# Copyright (c) 2011, Michael Jansen, <kde@michael-jansen.biz>
#
# Redistribution and use is allowed according to the terms of the BSD license.
include(FindPackageHandleStandardArgs)
if(NOT FFmpeg_FIND_COMPONENTS)
set(FFmpeg_FIND_COMPONENTS AVFORMAT AVCODEC AVUTIL)
endif()
#
### Macro: set_component_found
#
# Marks the given component as found if both *_LIBRARIES AND *_INCLUDE_DIRS is present.
#
macro(set_component_found _component)
if(${_component}_LIBRARIES AND ${_component}_INCLUDE_DIRS)
# message(STATUS " - ${_component} found.")
set(${_component}_FOUND TRUE)
else()
# message(STATUS " - ${_component} not found.")
endif()
endmacro()
#
### Macro: find_component
#
# Checks for the given component by invoking pkgconfig and then looking up the libraries and
# include directories.
#
macro(find_component _component _pkgconfig _library _header)
if(NOT WIN32)
# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_${_component} ${_pkgconfig})
endif()
endif()
find_path(${_component}_INCLUDE_DIRS ${_header}
HINTS
${FFMPEGSDK_INC}
${PC_LIB${_component}_INCLUDEDIR}
${PC_LIB${_component}_INCLUDE_DIRS}
PATH_SUFFIXES
ffmpeg
)
find_library(${_component}_LIBRARIES NAMES ${_library}
HINTS
${FFMPEGSDK_LIB}
${PC_LIB${_component}_LIBDIR}
${PC_LIB${_component}_LIBRARY_DIRS}
)
STRING(REGEX REPLACE "/.*" "/version.h" _ver_header ${_header})
if(EXISTS "${${_component}_INCLUDE_DIRS}/${_ver_header}")
file(STRINGS "${${_component}_INCLUDE_DIRS}/${_ver_header}" version_str REGEX "^#define[\t ]+LIB${_component}_VERSION_M.*")
foreach(_str "${version_str}")
if(NOT version_maj)
string(REGEX REPLACE "^.*LIB${_component}_VERSION_MAJOR[\t ]+([0-9]*).*$" "\\1" version_maj "${_str}")
endif()
if(NOT version_min)
string(REGEX REPLACE "^.*LIB${_component}_VERSION_MINOR[\t ]+([0-9]*).*$" "\\1" version_min "${_str}")
endif()
if(NOT version_mic)
string(REGEX REPLACE "^.*LIB${_component}_VERSION_MICRO[\t ]+([0-9]*).*$" "\\1" version_mic "${_str}")
endif()
endforeach()
unset(version_str)
set(${_component}_VERSION "${version_maj}.${version_min}.${version_mic}" CACHE STRING "The ${_component} version number.")
unset(version_maj)
unset(version_min)
unset(version_mic)
endif(EXISTS "${${_component}_INCLUDE_DIRS}/${_ver_header}")
set(${_component}_VERSION ${PC_${_component}_VERSION} CACHE STRING "The ${_component} version number.")
set(${_component}_DEFINITIONS ${PC_${_component}_CFLAGS_OTHER} CACHE STRING "The ${_component} CFLAGS.")
set_component_found(${_component})
mark_as_advanced(
${_component}_INCLUDE_DIRS
${_component}_LIBRARIES
${_component}_DEFINITIONS
${_component}_VERSION)
endmacro()
set(FFMPEGSDK $ENV{FFMPEG_HOME})
if(FFMPEGSDK)
set(FFMPEGSDK_INC "${FFMPEGSDK}/include")
set(FFMPEGSDK_LIB "${FFMPEGSDK}/lib")
endif()
# Check for all possible components.
find_component(AVCODEC libavcodec avcodec libavcodec/avcodec.h)
find_component(AVFORMAT libavformat avformat libavformat/avformat.h)
find_component(AVDEVICE libavdevice avdevice libavdevice/avdevice.h)
find_component(AVUTIL libavutil avutil libavutil/avutil.h)
find_component(SWSCALE libswscale swscale libswscale/swscale.h)
find_component(SWRESAMPLE libswresample swresample libswresample/swresample.h)
find_component(POSTPROC libpostproc postproc libpostproc/postprocess.h)
# Check if the required components were found and add their stuff to the FFMPEG_* vars.
foreach(_component ${FFmpeg_FIND_COMPONENTS})
if(${_component}_FOUND)
# message(STATUS "Required component ${_component} present.")
set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${${_component}_LIBRARIES})
set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} ${${_component}_DEFINITIONS})
list(APPEND FFMPEG_INCLUDE_DIRS ${${_component}_INCLUDE_DIRS})
else()
# message(STATUS "Required component ${_component} missing.")
endif()
endforeach()
# Build the include path and library list with duplicates removed.
if(FFMPEG_INCLUDE_DIRS)
list(REMOVE_DUPLICATES FFMPEG_INCLUDE_DIRS)
endif()
if(FFMPEG_LIBRARIES)
list(REMOVE_DUPLICATES FFMPEG_LIBRARIES)
endif()
# cache the vars.
set(FFMPEG_INCLUDE_DIRS ${FFMPEG_INCLUDE_DIRS} CACHE STRING "The FFmpeg include directories." FORCE)
set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} CACHE STRING "The FFmpeg libraries." FORCE)
set(FFMPEG_DEFINITIONS ${FFMPEG_DEFINITIONS} CACHE STRING "The FFmpeg cflags." FORCE)
mark_as_advanced(FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARIES FFMPEG_DEFINITIONS)
# Now set the noncached _FOUND vars for the components.
foreach(_component AVCODEC AVDEVICE AVFORMAT AVUTIL POSTPROCESS SWRESAMPLE SWSCALE)
set_component_found(${_component})
endforeach ()
# Compile the list of required vars
set(_FFmpeg_REQUIRED_VARS FFMPEG_LIBRARIES FFMPEG_INCLUDE_DIRS)
foreach(_component ${FFmpeg_FIND_COMPONENTS})
list(APPEND _FFmpeg_REQUIRED_VARS ${_component}_LIBRARIES ${_component}_INCLUDE_DIRS)
endforeach()
# Give a nice error message if some of the required vars are missing.
find_package_handle_standard_args(FFmpeg DEFAULT_MSG ${_FFmpeg_REQUIRED_VARS})
@@ -6,11 +6,6 @@
# FLUIDSYNTH_FOUND - True if fluidsynth found.
IF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
# Already in cache, be silent
SET(FluidSynth_FIND_QUIETLY TRUE)
ENDIF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h)
FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth )
@@ -19,5 +14,6 @@ MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR )
# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth DEFAULT_MSG FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth
REQUIRED_VARS FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR)
@@ -0,0 +1,21 @@
# - Find OSS includes
#
# OSS_FOUND - True if OSS_INCLUDE_DIR is found
# OSS_INCLUDE_DIRS - Set when OSS_INCLUDE_DIR is found
#
# OSS_INCLUDE_DIR - where to find sys/soundcard.h, etc.
#
find_path(OSS_INCLUDE_DIR
NAMES sys/soundcard.h
DOC "The OSS include directory"
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OSS REQUIRED_VARS OSS_INCLUDE_DIR)
if(OSS_FOUND)
set(OSS_INCLUDE_DIRS ${OSS_INCLUDE_DIR})
endif()
mark_as_advanced(OSS_INCLUDE_DIR)

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