mirror of
https://github.com/love2d/love-android.git
synced 2026-08-24 06:27:27 +02:00
updated OpenAL-Soft to version 1.16.0
This commit is contained in:
+4
-3
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
+116
-147
@@ -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);
|
||||
|
||||
+40
-38
@@ -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);
|
||||
}
|
||||
+9
-9
@@ -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 */
|
||||
+4
-1
@@ -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:
|
||||
+392
-374
File diff suppressed because it is too large
Load Diff
+12
-14
@@ -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;
|
||||
}
|
||||
+629
-490
File diff suppressed because it is too large
Load Diff
+49
-43
@@ -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;
|
||||
}
|
||||
+21
-74
@@ -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);
|
||||
+29
-35
@@ -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);
|
||||
|
||||
+6
-3
@@ -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;
|
||||
+182
-193
@@ -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 */
|
||||
|
||||
+26
-34
@@ -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, ¶m);
|
||||
@@ -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)
|
||||
{
|
||||
+9
-9
@@ -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");
|
||||
|
||||
+10
-10
@@ -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));
|
||||
|
||||
+44
-39
@@ -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;
|
||||
+138
-191
@@ -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);
|
||||
@@ -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 */
|
||||
+12
-15
@@ -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;
|
||||
|
||||
+29
-13
@@ -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);
|
||||
}
|
||||
+4
-7
@@ -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);
|
||||
|
||||
+2
-5
@@ -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);
|
||||
|
||||
+2
-5
@@ -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);
|
||||
|
||||
+3
-6
@@ -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);
|
||||
|
||||
+2
-5
@@ -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);
|
||||
|
||||
+29
-13
@@ -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);
|
||||
}
|
||||
+2
-5
@@ -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);
|
||||
|
||||
+14
-4
@@ -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);
|
||||
+3
-6
@@ -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);
|
||||
|
||||
@@ -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, ¶m);
|
||||
}
|
||||
#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)
|
||||
@@ -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);
|
||||
}
|
||||
+168
-81
@@ -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)
|
||||
+245
-304
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
+7
-7
@@ -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;
|
||||
|
||||
+14
-4
@@ -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)
|
||||
+16
-10
@@ -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);
|
||||
+155
-113
@@ -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. */
|
||||
+22
-16
@@ -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
|
||||
+32
-78
@@ -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); }
|
||||
+101
-22
@@ -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. */
|
||||
+36
-14
@@ -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
-51
@@ -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
+3
-2
@@ -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);
|
||||
|
||||
+2
@@ -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 },
|
||||
+183
-40
@@ -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;
|
||||
+70
-34
@@ -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;
|
||||
+5
-5
@@ -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;
|
||||
|
||||
+7
-11
@@ -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)();
|
||||
+10
-11
@@ -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;
|
||||
|
||||
+62
-171
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+463
-259
File diff suppressed because it is too large
Load Diff
+24
-16
@@ -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:
|
||||
@@ -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})
|
||||
+2
-6
@@ -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
Reference in New Issue
Block a user