aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alc/ALc.c1470
-rw-r--r--Alc/ALu.c1456
-rw-r--r--Alc/alcConfig.c121
-rw-r--r--Alc/alcRing.c276
-rw-r--r--Alc/alstring.h20
-rw-r--r--Alc/backends/alsa.c77
-rw-r--r--Alc/backends/base.c25
-rw-r--r--Alc/backends/base.h5
-rw-r--r--Alc/backends/coreaudio.c15
-rw-r--r--Alc/backends/dsound.c138
-rw-r--r--Alc/backends/jack.c610
-rw-r--r--Alc/backends/loopback.c11
-rw-r--r--Alc/backends/mmdevapi.c805
-rw-r--r--Alc/backends/null.c13
-rw-r--r--Alc/backends/opensl.c23
-rw-r--r--Alc/backends/oss.c28
-rw-r--r--Alc/backends/portaudio.c417
-rw-r--r--Alc/backends/pulseaudio.c389
-rw-r--r--Alc/backends/qsa.c460
-rw-r--r--Alc/backends/sndio.c7
-rw-r--r--Alc/backends/solaris.c214
-rw-r--r--Alc/backends/wave.c325
-rw-r--r--Alc/backends/winmm.c717
-rw-r--r--Alc/bs2b.c137
-rw-r--r--Alc/bsinc.c981
-rw-r--r--Alc/effects/autowah.c26
-rw-r--r--Alc/effects/chorus.c26
-rw-r--r--Alc/effects/compressor.c25
-rw-r--r--Alc/effects/dedicated.c42
-rw-r--r--Alc/effects/distortion.c38
-rw-r--r--Alc/effects/echo.c34
-rw-r--r--Alc/effects/equalizer.c53
-rw-r--r--Alc/effects/flanger.c26
-rw-r--r--Alc/effects/modulator.c33
-rw-r--r--Alc/effects/null.c5
-rw-r--r--Alc/effects/reverb.c826
-rw-r--r--Alc/evtqueue.h31
-rw-r--r--Alc/helpers.c851
-rw-r--r--Alc/hrtf.c608
-rw-r--r--Alc/hrtf.h24
-rw-r--r--Alc/midi/base.c239
-rw-r--r--Alc/midi/base.h128
-rw-r--r--Alc/midi/dummy.c76
-rw-r--r--Alc/midi/fluidsynth.c822
-rw-r--r--Alc/midi/sf2load.c1364
-rw-r--r--Alc/midi/soft.c141
-rw-r--r--Alc/mixer.c462
-rw-r--r--Alc/mixer_c.c132
-rw-r--r--Alc/mixer_defs.h70
-rw-r--r--Alc/mixer_inc.c56
-rw-r--r--Alc/mixer_neon.c105
-rw-r--r--Alc/mixer_sse.c214
-rw-r--r--Alc/mixer_sse2.c9
-rw-r--r--Alc/mixer_sse3.c162
-rw-r--r--Alc/mixer_sse41.c148
-rw-r--r--Alc/panning.c797
-rw-r--r--Alc/vector.h82
-rw-r--r--CMakeLists.txt508
-rw-r--r--COPYING23
-rw-r--r--ChangeLog158
-rw-r--r--OpenAL32/Include/alAuxEffectSlot.h6
-rw-r--r--OpenAL32/Include/alBuffer.h13
-rw-r--r--OpenAL32/Include/alEffect.h1
-rw-r--r--OpenAL32/Include/alFilter.h45
-rw-r--r--OpenAL32/Include/alListener.h9
-rw-r--r--OpenAL32/Include/alMain.h446
-rw-r--r--OpenAL32/Include/alMidi.h166
-rw-r--r--OpenAL32/Include/alSource.h47
-rw-r--r--OpenAL32/Include/alu.h239
-rw-r--r--OpenAL32/Include/bs2b.h61
-rw-r--r--OpenAL32/alAuxEffectSlot.c45
-rw-r--r--OpenAL32/alBuffer.c124
-rw-r--r--OpenAL32/alEffect.c18
-rw-r--r--OpenAL32/alError.c9
-rw-r--r--OpenAL32/alExtension.c6
-rw-r--r--OpenAL32/alFilter.c94
-rw-r--r--OpenAL32/alFontsound.c972
-rw-r--r--OpenAL32/alListener.c46
-rw-r--r--OpenAL32/alMidi.c223
-rw-r--r--OpenAL32/alPreset.c340
-rw-r--r--OpenAL32/alSoundfont.c564
-rw-r--r--OpenAL32/alSource.c1314
-rw-r--r--OpenAL32/alState.c189
-rw-r--r--OpenAL32/alThunk.c42
-rw-r--r--README10
-rw-r--r--XCompile-Android.txt39
-rw-r--r--XCompile.txt17
-rw-r--r--alsoftrc.sample248
-rw-r--r--cmake/CheckFileOffsetBits.c9
-rw-r--r--cmake/CheckFileOffsetBits.cmake39
-rw-r--r--cmake/CheckSharedFunctionExists.cmake14
-rw-r--r--cmake/FindDSound.cmake6
-rw-r--r--cmake/FindFluidSynth.cmake19
-rw-r--r--cmake/FindJACK.cmake60
-rw-r--r--cmake/FindSDL_sound.cmake387
-rw-r--r--common/atomic.c13
-rw-r--r--common/rwlock.c41
-rw-r--r--common/threads.c10
-rw-r--r--config.h.in40
-rw-r--r--env-vars.txt10
-rw-r--r--examples/alffplay.c77
-rw-r--r--examples/alhrtf.c248
-rw-r--r--examples/alloopback.c6
-rw-r--r--examples/altonegen.c271
-rw-r--r--hrtf.txt2
-rw-r--r--hrtf/default-48000.mhrbin0 -> 53853 bytes
-rw-r--r--include/AL/alext.h65
-rw-r--r--include/AL/efx-presets.h2
-rw-r--r--include/align.h8
-rw-r--r--include/atomic.h448
-rw-r--r--include/math_defs.h19
-rw-r--r--include/rwlock.h10
-rw-r--r--include/static_assert.h4
-rw-r--r--include/threads.h4
-rw-r--r--utils/alsoft-config/mainwindow.cpp433
-rw-r--r--utils/alsoft-config/mainwindow.h4
-rw-r--r--utils/alsoft-config/mainwindow.ui560
-rw-r--r--utils/bsincgen.c374
-rw-r--r--utils/makehrtf.c99
-rw-r--r--utils/openal-info.c30
120 files changed, 13460 insertions, 12269 deletions
diff --git a/Alc/ALc.c b/Alc/ALc.c
index 7c8c2322..d6d23eba 100644
--- a/Alc/ALc.c
+++ b/Alc/ALc.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -35,7 +35,6 @@
#include "alBuffer.h"
#include "alAuxEffectSlot.h"
#include "alError.h"
-#include "alMidi.h"
#include "bs2b.h"
#include "alu.h"
@@ -44,7 +43,6 @@
#include "alstring.h"
#include "backends/base.h"
-#include "midi/base.h"
/************************************************
@@ -59,8 +57,11 @@ struct BackendInfo {
BackendFuncs Funcs;
};
-#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
static struct BackendInfo BackendList[] = {
+#ifdef HAVE_JACK
+ { "jack", ALCjackBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
+#endif
#ifdef HAVE_PULSEAUDIO
{ "pulse", ALCpulseBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
@@ -74,7 +75,7 @@ static struct BackendInfo BackendList[] = {
{ "oss", ALCossBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_SOLARIS
- { "solaris", NULL, alc_solaris_init, alc_solaris_deinit, alc_solaris_probe, EmptyFuncs },
+ { "solaris", ALCsolarisBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_SNDIO
{ "sndio", NULL, alc_sndio_init, alc_sndio_deinit, alc_sndio_probe, EmptyFuncs },
@@ -89,10 +90,10 @@ static struct BackendInfo BackendList[] = {
{ "dsound", ALCdsoundBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_WINMM
- { "winmm", NULL, alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs },
+ { "winmm", ALCwinmmBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_PORTAUDIO
- { "port", NULL, alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs },
+ { "port", ALCportBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
#ifdef HAVE_OPENSL
{ "opensl", NULL, alc_opensl_init, alc_opensl_deinit, alc_opensl_probe, EmptyFuncs },
@@ -100,7 +101,7 @@ static struct BackendInfo BackendList[] = {
{ "null", ALCnullBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#ifdef HAVE_WAVE
- { "wave", NULL, alc_wave_init, alc_wave_deinit, alc_wave_probe, EmptyFuncs },
+ { "wave", ALCwaveBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs },
#endif
{ NULL, NULL, NULL, NULL, NULL, EmptyFuncs }
@@ -157,6 +158,9 @@ static const ALCfunction alcFunctions[] = {
DECL(alcDevicePauseSOFT),
DECL(alcDeviceResumeSOFT),
+ DECL(alcGetStringiSOFT),
+ DECL(alcResetDeviceSOFT),
+
DECL(alcGetInteger64vSOFT),
DECL(alEnable),
@@ -290,44 +294,6 @@ static const ALCfunction alcFunctions[] = {
DECL(alGetSource3i64SOFT),
DECL(alGetSourcei64vSOFT),
- DECL(alGenSoundfontsSOFT),
- DECL(alDeleteSoundfontsSOFT),
- DECL(alIsSoundfontSOFT),
- DECL(alSoundfontSamplesSOFT),
- DECL(alGetSoundfontSamplesSOFT),
- DECL(alSoundfontMapSamplesSOFT),
- DECL(alSoundfontUnmapSamplesSOFT),
- DECL(alGetSoundfontivSOFT),
- DECL(alSoundfontPresetsSOFT),
- DECL(alGenPresetsSOFT),
- DECL(alDeletePresetsSOFT),
- DECL(alIsPresetSOFT),
- DECL(alPresetiSOFT),
- DECL(alPresetivSOFT),
- DECL(alGetPresetivSOFT),
- DECL(alPresetFontsoundsSOFT),
- DECL(alGenFontsoundsSOFT),
- DECL(alDeleteFontsoundsSOFT),
- DECL(alIsFontsoundSOFT),
- DECL(alFontsoundiSOFT),
- DECL(alFontsound2iSOFT),
- DECL(alFontsoundivSOFT),
- DECL(alGetFontsoundivSOFT),
- DECL(alFontsoundModulatoriSOFT),
- DECL(alGetFontsoundModulatorivSOFT),
- DECL(alMidiSoundfontSOFT),
- DECL(alMidiSoundfontvSOFT),
- DECL(alMidiEventSOFT),
- DECL(alMidiSysExSOFT),
- DECL(alMidiPlaySOFT),
- DECL(alMidiPauseSOFT),
- DECL(alMidiStopSOFT),
- DECL(alMidiResetSOFT),
- DECL(alMidiGainSOFT),
- DECL(alGetInteger64SOFT),
- DECL(alGetInteger64vSOFT),
- DECL(alLoadSoundfontSOFT),
-
{ NULL, NULL }
};
#undef DECL
@@ -379,6 +345,19 @@ static const ALCenums enumeration[] = {
DECL(ALC_UNSIGNED_INT_SOFT),
DECL(ALC_FLOAT_SOFT),
+ DECL(ALC_HRTF_SOFT),
+ DECL(ALC_DONT_CARE_SOFT),
+ DECL(ALC_HRTF_STATUS_SOFT),
+ DECL(ALC_HRTF_DISABLED_SOFT),
+ DECL(ALC_HRTF_ENABLED_SOFT),
+ DECL(ALC_HRTF_DENIED_SOFT),
+ DECL(ALC_HRTF_REQUIRED_SOFT),
+ DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT),
+ DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT),
+ DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT),
+ DECL(ALC_HRTF_SPECIFIER_SOFT),
+ DECL(ALC_HRTF_ID_SOFT),
+
DECL(ALC_NO_ERROR),
DECL(ALC_INVALID_DEVICE),
DECL(ALC_INVALID_CONTEXT),
@@ -419,6 +398,7 @@ static const ALCenums enumeration[] = {
DECL(AL_STREAMING),
DECL(AL_UNDETERMINED),
DECL(AL_METERS_PER_UNIT),
+ DECL(AL_LOOP_POINTS_SOFT),
DECL(AL_DIRECT_CHANNELS_SOFT),
DECL(AL_DIRECT_FILTER),
@@ -501,6 +481,14 @@ static const ALCenums enumeration[] = {
DECL(AL_7POINT1_8_SOFT),
DECL(AL_7POINT1_16_SOFT),
DECL(AL_7POINT1_32F_SOFT),
+ DECL(AL_FORMAT_BFORMAT2D_8),
+ DECL(AL_FORMAT_BFORMAT2D_16),
+ DECL(AL_FORMAT_BFORMAT2D_FLOAT32),
+ DECL(AL_FORMAT_BFORMAT2D_MULAW),
+ DECL(AL_FORMAT_BFORMAT3D_8),
+ DECL(AL_FORMAT_BFORMAT3D_16),
+ DECL(AL_FORMAT_BFORMAT3D_FLOAT32),
+ DECL(AL_FORMAT_BFORMAT3D_MULAW),
DECL(AL_MONO_SOFT),
DECL(AL_STEREO_SOFT),
@@ -592,7 +580,9 @@ static const ALCenums enumeration[] = {
DECL(AL_EFFECT_PITCH_SHIFTER),
#endif
DECL(AL_EFFECT_RING_MODULATOR),
+#if 0
DECL(AL_EFFECT_AUTOWAH),
+#endif
DECL(AL_EFFECT_COMPRESSOR),
DECL(AL_EFFECT_EQUALIZER),
DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT),
@@ -666,10 +656,12 @@ static const ALCenums enumeration[] = {
DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF),
DECL(AL_RING_MODULATOR_WAVEFORM),
+#if 0
DECL(AL_AUTOWAH_ATTACK_TIME),
DECL(AL_AUTOWAH_PEAK_GAIN),
DECL(AL_AUTOWAH_RELEASE_TIME),
DECL(AL_AUTOWAH_RESONANCE),
+#endif
DECL(AL_COMPRESSOR_ONOFF),
@@ -714,20 +706,20 @@ static ALCchar *alcCaptureDefaultDeviceSpecifier;
/* Default context extensions */
static const ALchar alExtList[] =
- "AL_EXT_ALAW AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 "
- "AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW "
- "AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model "
- "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_buffer_samples "
- "AL_SOFT_buffer_sub_data AL_SOFT_deferred_updates AL_SOFT_direct_channels "
- "AL_SOFT_loop_points AL_SOFTX_MSADPCM AL_SOFT_source_latency "
- "AL_SOFTX_source_length";
+ "AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE "
+ "AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS "
+ "AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET "
+ "AL_EXT_source_distance_model AL_LOKI_quadriphonic AL_SOFT_block_alignment "
+ "AL_SOFT_buffer_samples AL_SOFT_buffer_sub_data AL_SOFT_deferred_updates "
+ "AL_SOFT_direct_channels AL_SOFT_loop_points AL_SOFT_MSADPCM "
+ "AL_SOFT_source_latency AL_SOFT_source_length";
-static volatile ALCenum LastNullDeviceError = ALC_NO_ERROR;
+static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR);
/* Thread-local current context */
static altss_t LocalContext;
/* Process-wide current context */
-static ALCcontext *volatile GlobalContext = NULL;
+static ATOMIC(ALCcontext*) GlobalContext = ATOMIC_INIT_STATIC(NULL);
/* Mixing thread piority level */
ALint RTPrioLevel;
@@ -748,6 +740,11 @@ static alonce_flag alc_config_once = AL_ONCE_FLAG_INIT;
/* Default effect that applies to sources that don't have an effect on send 0 */
static ALeffect DefaultEffect;
+/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process
+ * updates.
+ */
+static ALCboolean SuspendDefers = ALC_TRUE;
+
/************************************************
* ALC information
@@ -758,8 +755,8 @@ static const ALCchar alcNoDeviceExtList[] =
static const ALCchar alcExtensionList[] =
"ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
"ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX "
- "ALC_EXT_thread_local_context ALC_SOFTX_device_clock ALC_SOFTX_HRTF "
- "ALC_SOFT_loopback ALC_SOFTX_midi_interface ALC_SOFTX_pause_device";
+ "ALC_EXT_thread_local_context ALC_SOFTX_device_clock ALC_SOFT_HRTF "
+ "ALC_SOFT_loopback ALC_SOFT_pause_device";
static const ALCint alcMajorVersion = 1;
static const ALCint alcMinorVersion = 1;
@@ -770,7 +767,7 @@ static const ALCint alcEFXMinorVersion = 0;
/************************************************
* Device lists
************************************************/
-static ALCdevice *volatile DeviceList = NULL;
+static ATOMIC(ALCdevice*) DeviceList = ATOMIC_INIT_STATIC(NULL);
static almtx_t ListLock;
static inline void LockLists(void)
@@ -908,9 +905,23 @@ static void alc_initconfig(void)
}
ReadALConfig();
+ str = getenv("__ALSOFT_SUSPEND_CONTEXT");
+ if(str && *str)
+ {
+ if(strcasecmp(str, "ignore") == 0)
+ {
+ SuspendDefers = ALC_FALSE;
+ TRACE("Selected context suspend behavior, \"ignore\"\n");
+ }
+ else
+ ERR("Unhandled context suspend behavior setting: \"%s\"\n", str);
+ }
+
capfilter = 0;
#if defined(HAVE_SSE4_1)
- capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1;
+ capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
+#elif defined(HAVE_SSE3)
+ capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
#elif defined(HAVE_SSE2)
capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
#elif defined(HAVE_SSE)
@@ -919,7 +930,7 @@ static void alc_initconfig(void)
#ifdef HAVE_NEON
capfilter |= CPU_CAP_NEON;
#endif
- if(ConfigValueStr(NULL, "disable-cpu-exts", &str))
+ if(ConfigValueStr(NULL, NULL, "disable-cpu-exts", &str))
{
if(strcasecmp(str, "all") == 0)
capfilter = 0;
@@ -944,6 +955,8 @@ static void alc_initconfig(void)
capfilter &= ~CPU_CAP_SSE;
else if(len == 4 && strncasecmp(str, "sse2", len) == 0)
capfilter &= ~CPU_CAP_SSE2;
+ else if(len == 4 && strncasecmp(str, "sse3", len) == 0)
+ capfilter &= ~CPU_CAP_SSE3;
else if(len == 6 && strncasecmp(str, "sse4.1", len) == 0)
capfilter &= ~CPU_CAP_SSE4_1;
else if(len == 4 && strncasecmp(str, "neon", len) == 0)
@@ -960,27 +973,9 @@ static void alc_initconfig(void)
#else
RTPrioLevel = 0;
#endif
- ConfigValueInt(NULL, "rt-prio", &RTPrioLevel);
-
- if(ConfigValueStr(NULL, "resampler", &str))
- {
- if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
- DefaultResampler = PointResampler;
- else if(strcasecmp(str, "linear") == 0)
- DefaultResampler = LinearResampler;
- else if(strcasecmp(str, "cubic") == 0)
- DefaultResampler = CubicResampler;
- else
- {
- char *end;
+ ConfigValueInt(NULL, NULL, "rt-prio", &RTPrioLevel);
- n = strtol(str, &end, 0);
- if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == CubicResampler))
- DefaultResampler = n;
- else
- WARN("Invalid resampler: %s\n", str);
- }
- }
+ aluInitMixer();
str = getenv("ALSOFT_TRAP_ERROR");
if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1))
@@ -993,21 +988,21 @@ static void alc_initconfig(void)
str = getenv("ALSOFT_TRAP_AL_ERROR");
if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1))
TrapALError = AL_TRUE;
- TrapALError = GetConfigValueBool(NULL, "trap-al-error", TrapALError);
+ TrapALError = GetConfigValueBool(NULL, NULL, "trap-al-error", TrapALError);
str = getenv("ALSOFT_TRAP_ALC_ERROR");
if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1))
TrapALCError = ALC_TRUE;
- TrapALCError = GetConfigValueBool(NULL, "trap-alc-error", TrapALCError);
+ TrapALCError = GetConfigValueBool(NULL, NULL, "trap-alc-error", TrapALCError);
}
- if(ConfigValueFloat("reverb", "boost", &valf))
+ if(ConfigValueFloat(NULL, "reverb", "boost", &valf))
ReverbBoost *= powf(10.0f, valf / 20.0f);
- EmulateEAXReverb = GetConfigValueBool("reverb", "emulate-eax", AL_FALSE);
+ EmulateEAXReverb = GetConfigValueBool(NULL, "reverb", "emulate-eax", AL_FALSE);
if(((devs=getenv("ALSOFT_DRIVERS")) && devs[0]) ||
- ConfigValueStr(NULL, "drivers", &devs))
+ ConfigValueStr(NULL, NULL, "drivers", &devs))
{
int n;
size_t len;
@@ -1122,7 +1117,7 @@ static void alc_initconfig(void)
V0(factory,init)();
}
- if(ConfigValueStr(NULL, "excludefx", &str))
+ if(ConfigValueStr(NULL, NULL, "excludefx", &str))
{
size_t len;
const char *next = str;
@@ -1148,7 +1143,7 @@ static void alc_initconfig(void)
InitEffect(&DefaultEffect);
str = getenv("ALSOFT_DEFAULT_REVERB");
- if((str && str[0]) || ConfigValueStr(NULL, "default-reverb", &str))
+ if((str && str[0]) || ConfigValueStr(NULL, NULL, "default-reverb", &str))
LoadReverbPreset(str, &DefaultEffect);
}
#define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig)
@@ -1169,7 +1164,7 @@ static void alc_cleanup(void)
free(alcCaptureDefaultDeviceSpecifier);
alcCaptureDefaultDeviceSpecifier = NULL;
- if((dev=ExchangePtr((XchgPtr*)&DeviceList, NULL)) != NULL)
+ if((dev=ATOMIC_EXCHANGE(ALCdevice*, &DeviceList, NULL)) != NULL)
{
ALCuint num = 0;
do {
@@ -1228,48 +1223,33 @@ static void alc_deinit(void)
/************************************************
* Device enumeration
************************************************/
-static void ProbeDevices(al_string *list, enum DevProbe type)
+static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum DevProbe type)
{
DO_INITCONFIG();
LockLists();
al_string_clear(list);
- if(type == ALL_DEVICE_PROBE && (PlaybackBackend.Probe || PlaybackBackend.getFactory))
- {
- if(!PlaybackBackend.getFactory)
- PlaybackBackend.Probe(type);
- else
- {
- ALCbackendFactory *factory = PlaybackBackend.getFactory();
- V(factory,probe)(type);
- }
- }
- else if(type == CAPTURE_DEVICE_PROBE && (CaptureBackend.Probe || CaptureBackend.getFactory))
+ if(!backendinfo->getFactory)
+ backendinfo->Probe(type);
+ else
{
- if(!CaptureBackend.getFactory)
- CaptureBackend.Probe(type);
- else
- {
- ALCbackendFactory *factory = CaptureBackend.getFactory();
- V(factory,probe)(type);
- }
+ ALCbackendFactory *factory = backendinfo->getFactory();
+ V(factory,probe)(type);
}
+
UnlockLists();
}
static void ProbeAllDevicesList(void)
-{ ProbeDevices(&alcAllDevicesList, ALL_DEVICE_PROBE); }
+{ ProbeDevices(&alcAllDevicesList, &PlaybackBackend, ALL_DEVICE_PROBE); }
static void ProbeCaptureDeviceList(void)
-{ ProbeDevices(&alcCaptureDeviceList, CAPTURE_DEVICE_PROBE); }
+{ ProbeDevices(&alcCaptureDeviceList, &CaptureBackend, CAPTURE_DEVICE_PROBE); }
static void AppendDevice(const ALCchar *name, al_string *devnames)
{
size_t len = strlen(name);
if(len > 0)
- {
- al_string_append_range(devnames, name, name+len);
- al_string_append_char(devnames, '\0');
- }
+ al_string_append_range(devnames, name, name+len+1);
}
void AppendAllDevicesList(const ALCchar *name)
{ AppendDevice(name, &alcAllDevicesList); }
@@ -1302,9 +1282,10 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans)
case DevFmtStereo: return "Stereo";
case DevFmtQuad: return "Quadraphonic";
case DevFmtX51: return "5.1 Surround";
- case DevFmtX51Side: return "5.1 Side";
+ case DevFmtX51Rear: return "5.1 Surround (Rear)";
case DevFmtX61: return "6.1 Surround";
case DevFmtX71: return "7.1 Surround";
+ case DevFmtBFormat3D: return "B-Format 3D";
}
return "(unknown channels)";
}
@@ -1332,9 +1313,10 @@ ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
case DevFmtStereo: return 2;
case DevFmtQuad: return 4;
case DevFmtX51: return 6;
- case DevFmtX51Side: return 6;
+ case DevFmtX51Rear: return 6;
case DevFmtX61: return 7;
case DevFmtX71: return 8;
+ case DevFmtBFormat3D: return 4;
}
return 0;
}
@@ -1421,19 +1403,15 @@ DECL_CONST static ALCboolean IsValidALCChannels(ALCenum channels)
/************************************************
* Miscellaneous ALC helpers
************************************************/
+enum HrtfRequestMode {
+ Hrtf_Default = 0,
+ Hrtf_Enable = 1,
+ Hrtf_Disable = 2,
+};
+
extern inline void LockContext(ALCcontext *context);
extern inline void UnlockContext(ALCcontext *context);
-ALint64 ALCdevice_GetLatencyDefault(ALCdevice *UNUSED(device))
-{
- return 0;
-}
-
-ALint64 ALCdevice_GetLatency(ALCdevice *device)
-{
- return V0(device->Backend,getLatency)();
-}
-
void ALCdevice_Lock(ALCdevice *device)
{
V0(device->Backend,lock)();
@@ -1453,52 +1431,65 @@ void SetDefaultWFXChannelOrder(ALCdevice *device)
{
ALuint i;
- for(i = 0;i < MaxChannels;i++)
- device->ChannelOffsets[i] = INVALID_OFFSET;
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ device->ChannelName[i] = InvalidChannel;
switch(device->FmtChans)
{
- case DevFmtMono: device->ChannelOffsets[FrontCenter] = 0;
- break;
- case DevFmtStereo: device->ChannelOffsets[FrontLeft] = 0;
- device->ChannelOffsets[FrontRight] = 1;
- break;
- case DevFmtQuad: device->ChannelOffsets[FrontLeft] = 0;
- device->ChannelOffsets[FrontRight] = 1;
- device->ChannelOffsets[BackLeft] = 2;
- device->ChannelOffsets[BackRight] = 3;
- break;
- case DevFmtX51: device->ChannelOffsets[FrontLeft] = 0;
- device->ChannelOffsets[FrontRight] = 1;
- device->ChannelOffsets[FrontCenter] = 2;
- device->ChannelOffsets[LFE] = 3;
- device->ChannelOffsets[BackLeft] = 4;
- device->ChannelOffsets[BackRight] = 5;
- break;
- case DevFmtX51Side: device->ChannelOffsets[FrontLeft] = 0;
- device->ChannelOffsets[FrontRight] = 1;
- device->ChannelOffsets[FrontCenter] = 2;
- device->ChannelOffsets[LFE] = 3;
- device->ChannelOffsets[SideLeft] = 4;
- device->ChannelOffsets[SideRight] = 5;
- break;
- case DevFmtX61: device->ChannelOffsets[FrontLeft] = 0;
- device->ChannelOffsets[FrontRight] = 1;
- device->ChannelOffsets[FrontCenter] = 2;
- device->ChannelOffsets[LFE] = 3;
- device->ChannelOffsets[BackCenter] = 4;
- device->ChannelOffsets[SideLeft] = 5;
- device->ChannelOffsets[SideRight] = 6;
- break;
- case DevFmtX71: device->ChannelOffsets[FrontLeft] = 0;
- device->ChannelOffsets[FrontRight] = 1;
- device->ChannelOffsets[FrontCenter] = 2;
- device->ChannelOffsets[LFE] = 3;
- device->ChannelOffsets[BackLeft] = 4;
- device->ChannelOffsets[BackRight] = 5;
- device->ChannelOffsets[SideLeft] = 6;
- device->ChannelOffsets[SideRight] = 7;
- break;
+ case DevFmtMono:
+ device->ChannelName[0] = FrontCenter;
+ break;
+ case DevFmtStereo:
+ device->ChannelName[0] = FrontLeft;
+ device->ChannelName[1] = FrontRight;
+ break;
+ case DevFmtQuad:
+ device->ChannelName[0] = FrontLeft;
+ device->ChannelName[1] = FrontRight;
+ device->ChannelName[2] = BackLeft;
+ device->ChannelName[3] = BackRight;
+ break;
+ case DevFmtX51:
+ device->ChannelName[0] = FrontLeft;
+ device->ChannelName[1] = FrontRight;
+ device->ChannelName[2] = FrontCenter;
+ device->ChannelName[3] = LFE;
+ device->ChannelName[4] = SideLeft;
+ device->ChannelName[5] = SideRight;
+ break;
+ case DevFmtX51Rear:
+ device->ChannelName[0] = FrontLeft;
+ device->ChannelName[1] = FrontRight;
+ device->ChannelName[2] = FrontCenter;
+ device->ChannelName[3] = LFE;
+ device->ChannelName[4] = BackLeft;
+ device->ChannelName[5] = BackRight;
+ break;
+ case DevFmtX61:
+ device->ChannelName[0] = FrontLeft;
+ device->ChannelName[1] = FrontRight;
+ device->ChannelName[2] = FrontCenter;
+ device->ChannelName[3] = LFE;
+ device->ChannelName[4] = BackCenter;
+ device->ChannelName[5] = SideLeft;
+ device->ChannelName[6] = SideRight;
+ break;
+ case DevFmtX71:
+ device->ChannelName[0] = FrontLeft;
+ device->ChannelName[1] = FrontRight;
+ device->ChannelName[2] = FrontCenter;
+ device->ChannelName[3] = LFE;
+ device->ChannelName[4] = BackLeft;
+ device->ChannelName[5] = BackRight;
+ device->ChannelName[6] = SideLeft;
+ device->ChannelName[7] = SideRight;
+ break;
+ case DevFmtBFormat3D:
+ device->ChannelName[0] = BFormatW;
+ device->ChannelName[1] = BFormatX;
+ device->ChannelName[2] = BFormatY;
+ device->ChannelName[3] = BFormatZ;
+ break;
}
}
@@ -1510,37 +1501,114 @@ void SetDefaultChannelOrder(ALCdevice *device)
{
ALuint i;
- for(i = 0;i < MaxChannels;i++)
- device->ChannelOffsets[i] = INVALID_OFFSET;
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ device->ChannelName[i] = InvalidChannel;
switch(device->FmtChans)
{
- case DevFmtX51: device->ChannelOffsets[FrontLeft] = 0;
- device->ChannelOffsets[FrontRight] = 1;
- device->ChannelOffsets[BackLeft] = 2;
- device->ChannelOffsets[BackRight] = 3;
- device->ChannelOffsets[FrontCenter] = 4;
- device->ChannelOffsets[LFE] = 5;
- return;
- case DevFmtX71: device->ChannelOffsets[FrontLeft] = 0;
- device->ChannelOffsets[FrontRight] = 1;
- device->ChannelOffsets[BackLeft] = 2;
- device->ChannelOffsets[BackRight] = 3;
- device->ChannelOffsets[FrontCenter] = 4;
- device->ChannelOffsets[LFE] = 5;
- device->ChannelOffsets[SideLeft] = 6;
- device->ChannelOffsets[SideRight] = 7;
- return;
+ case DevFmtX51Rear:
+ device->ChannelName[0] = FrontLeft;
+ device->ChannelName[1] = FrontRight;
+ device->ChannelName[2] = BackLeft;
+ device->ChannelName[3] = BackRight;
+ device->ChannelName[4] = FrontCenter;
+ device->ChannelName[5] = LFE;
+ return;
+ case DevFmtX71:
+ device->ChannelName[0] = FrontLeft;
+ device->ChannelName[1] = FrontRight;
+ device->ChannelName[2] = BackLeft;
+ device->ChannelName[3] = BackRight;
+ device->ChannelName[4] = FrontCenter;
+ device->ChannelName[5] = LFE;
+ device->ChannelName[6] = SideLeft;
+ device->ChannelName[7] = SideRight;
+ return;
/* Same as WFX order */
case DevFmtMono:
case DevFmtStereo:
case DevFmtQuad:
- case DevFmtX51Side:
+ case DevFmtX51:
case DevFmtX61:
+ case DevFmtBFormat3D:
+ SetDefaultWFXChannelOrder(device);
break;
}
- SetDefaultWFXChannelOrder(device);
+}
+
+extern inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan);
+
+
+/* ALCcontext_DeferUpdates
+ *
+ * Defers/suspends updates for the given context's listener and sources. This
+ * does *NOT* stop mixing, but rather prevents certain property changes from
+ * taking effect.
+ */
+void ALCcontext_DeferUpdates(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+ FPUCtl oldMode;
+
+ SetMixerFPUMode(&oldMode);
+
+ V0(device->Backend,lock)();
+ if(!context->DeferUpdates)
+ {
+ context->DeferUpdates = AL_TRUE;
+
+ /* Make sure all pending updates are performed */
+ UpdateContextSources(context);
+#define UPDATE_SLOT(iter) do { \
+ if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
+ V((*iter)->EffectState,update)(device, *iter); \
+} while(0)
+ VECTOR_FOR_EACH(ALeffectslot*, context->ActiveAuxSlots, UPDATE_SLOT);
+#undef UPDATE_SLOT
+ }
+ V0(device->Backend,unlock)();
+
+ RestoreFPUMode(&oldMode);
+}
+
+/* ALCcontext_ProcessUpdates
+ *
+ * Resumes update processing after being deferred.
+ */
+void ALCcontext_ProcessUpdates(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+
+ V0(device->Backend,lock)();
+ if(context->DeferUpdates)
+ {
+ ALsizei pos;
+
+ context->DeferUpdates = AL_FALSE;
+
+ LockUIntMapRead(&context->SourceMap);
+ for(pos = 0;pos < context->SourceMap.size;pos++)
+ {
+ ALsource *Source = context->SourceMap.array[pos].value;
+ ALenum new_state;
+
+ if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
+ Source->Offset >= 0.0)
+ {
+ WriteLock(&Source->queue_lock);
+ ApplyOffset(Source);
+ WriteUnlock(&Source->queue_lock);
+ }
+
+ new_state = Source->new_state;
+ Source->new_state = AL_NONE;
+ if(new_state)
+ SetSourceState(Source, context, new_state);
+ }
+ UnlockUIntMapRead(&context->SourceMap);
+ }
+ V0(device->Backend,unlock)();
}
@@ -1562,9 +1630,9 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode)
}
if(device)
- device->LastError = errorCode;
+ ATOMIC_STORE(&device->LastError, errorCode);
else
- LastNullDeviceError = errorCode;
+ ATOMIC_STORE(&LastNullDeviceError, errorCode);
}
@@ -1588,10 +1656,14 @@ static inline void UpdateClockBase(ALCdevice *device)
static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
{
ALCcontext *context;
+ enum HrtfRequestMode hrtf_appreq = Hrtf_Default;
+ enum HrtfRequestMode hrtf_userreq = Hrtf_Default;
enum DevFmtChannels oldChans;
enum DevFmtType oldType;
ALCuint oldFreq;
FPUCtl oldMode;
+ ALCsizei hrtf_id = -1;
+ size_t size;
// Check for attributes
if(device->Type == Loopback)
@@ -1663,12 +1735,17 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(attrList[attrIdx] == ALC_HRTF_SOFT)
{
- if(attrList[attrIdx + 1] != ALC_FALSE)
- device->Flags |= DEVICE_HRTF_REQUEST;
+ if(attrList[attrIdx + 1] == ALC_FALSE)
+ hrtf_appreq = Hrtf_Disable;
+ else if(attrList[attrIdx + 1] == ALC_TRUE)
+ hrtf_appreq = Hrtf_Enable;
else
- device->Flags &= ~DEVICE_HRTF_REQUEST;
+ hrtf_appreq = Hrtf_Default;
}
+ if(attrList[attrIdx] == ALC_HRTF_ID_SOFT)
+ hrtf_id = attrList[attrIdx + 1];
+
attrIdx += 2;
}
@@ -1678,15 +1755,15 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
return ALC_INVALID_VALUE;
}
- ConfigValueUInt(NULL, "sends", &numSends);
+ ConfigValueUInt(NULL, NULL, "sends", &numSends);
numSends = minu(MAX_SENDS, numSends);
if((device->Flags&DEVICE_RUNNING))
V0(device->Backend,stop)();
device->Flags &= ~DEVICE_RUNNING;
- if(freq != device->Frequency)
- UpdateClockBase(device);
+ UpdateClockBase(device);
+
device->Frequency = freq;
device->FmtChans = schans;
device->FmtType = stype;
@@ -1732,29 +1809,34 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(attrList[attrIdx] == ALC_HRTF_SOFT)
{
- if(attrList[attrIdx + 1] != ALC_FALSE)
- device->Flags |= DEVICE_HRTF_REQUEST;
+ if(attrList[attrIdx + 1] == ALC_FALSE)
+ hrtf_appreq = Hrtf_Disable;
+ else if(attrList[attrIdx + 1] == ALC_TRUE)
+ hrtf_appreq = Hrtf_Enable;
else
- device->Flags &= ~DEVICE_HRTF_REQUEST;
+ hrtf_appreq = Hrtf_Default;
}
+ if(attrList[attrIdx] == ALC_HRTF_ID_SOFT)
+ hrtf_id = attrList[attrIdx + 1];
+
attrIdx += 2;
}
- ConfigValueUInt(NULL, "frequency", &freq);
+ ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "frequency", &freq);
freq = maxu(freq, MIN_OUTPUT_RATE);
- ConfigValueUInt(NULL, "sends", &numSends);
+ ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &numSends);
numSends = minu(MAX_SENDS, numSends);
+ UpdateClockBase(device);
+
device->UpdateSize = (ALuint64)device->UpdateSize * freq /
device->Frequency;
/* SSE and Neon do best with the update size being a multiple of 4 */
if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0)
device->UpdateSize = (device->UpdateSize+3)&~3;
- if(freq != device->Frequency)
- UpdateClockBase(device);
device->Frequency = freq;
device->NumMonoSources = numMono;
device->NumStereoSources = numStereo;
@@ -1764,42 +1846,90 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if((device->Flags&DEVICE_RUNNING))
return ALC_NO_ERROR;
- UpdateClockBase(device);
+ al_free(device->DryBuffer);
+ device->DryBuffer = NULL;
- oldFreq = device->Frequency;
- oldChans = device->FmtChans;
- oldType = device->FmtType;
-
- TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u update size x%d\n",
- (device->Flags&DEVICE_CHANNELS_REQUEST)?"*":"",
- DevFmtChannelsString(device->FmtChans),
- (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)?"*":"",
- DevFmtTypeString(device->FmtType),
- (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"",
- device->Frequency,
- device->UpdateSize, device->NumUpdates);
+ UpdateClockBase(device);
+ device->Hrtf_Status = ALC_HRTF_DISABLED_SOFT;
if(device->Type != Loopback)
{
- int nohrtf = !(device->Flags&DEVICE_HRTF_REQUEST);
- if(GetConfigValueBool(NULL, "hrtf", !nohrtf))
- device->Flags |= DEVICE_HRTF_REQUEST;
- else
- device->Flags &= ~DEVICE_HRTF_REQUEST;
+ const char *hrtf;
+ if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf", &hrtf))
+ {
+ if(strcasecmp(hrtf, "true") == 0)
+ hrtf_userreq = Hrtf_Enable;
+ else if(strcasecmp(hrtf, "false") == 0)
+ hrtf_userreq = Hrtf_Disable;
+ else if(strcasecmp(hrtf, "auto") != 0)
+ ERR("Unexpected hrtf value: %s\n", hrtf);
+ }
+
+ if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable))
+ {
+ if(VECTOR_SIZE(device->Hrtf_List) == 0)
+ {
+ VECTOR_DEINIT(device->Hrtf_List);
+ device->Hrtf_List = EnumerateHrtf(device->DeviceName);
+ }
+ if(VECTOR_SIZE(device->Hrtf_List) > 0)
+ {
+ device->FmtChans = DevFmtStereo;
+ if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List))
+ device->Frequency = GetHrtfSampleRate(VECTOR_ELEM(device->Hrtf_List, hrtf_id).hrtf);
+ else
+ device->Frequency = GetHrtfSampleRate(VECTOR_ELEM(device->Hrtf_List, 0).hrtf);
+ device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST;
+ }
+ else
+ {
+ hrtf_userreq = hrtf_appreq = Hrtf_Default;
+ device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
+ }
+ }
}
- if((device->Flags&DEVICE_HRTF_REQUEST))
+ else if(hrtf_appreq == Hrtf_Enable)
{
- enum DevFmtChannels chans;
- ALCuint freq;
- if(FindHrtfFormat(device, &chans, &freq))
+ size_t i;
+ /* Loopback device. We don't need to match to a specific HRTF entry
+ * here. If the requested ID matches, we'll pick that later, if not,
+ * we'll try to auto-select one anyway. */
+ if(device->FmtChans != DevFmtStereo)
+ i = VECTOR_SIZE(device->Hrtf_List);
+ else
{
- device->Frequency = freq;
- device->FmtChans = chans;
- device->Flags |= DEVICE_CHANNELS_REQUEST |
- DEVICE_FREQUENCY_REQUEST;
+ if(VECTOR_SIZE(device->Hrtf_List) == 0)
+ {
+ VECTOR_DEINIT(device->Hrtf_List);
+ device->Hrtf_List = EnumerateHrtf(device->DeviceName);
+ }
+ for(i = 0;i < VECTOR_SIZE(device->Hrtf_List);i++)
+ {
+ const struct Hrtf *hrtf = VECTOR_ELEM(device->Hrtf_List, i).hrtf;
+ if(GetHrtfSampleRate(hrtf) == device->Frequency)
+ break;
+ }
+ }
+ if(i == VECTOR_SIZE(device->Hrtf_List))
+ {
+ ERR("Requested format not HRTF compatible: %s, %uhz\n",
+ DevFmtChannelsString(device->FmtChans), device->Frequency);
+ hrtf_appreq = Hrtf_Default;
+ device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
}
}
+ oldFreq = device->Frequency;
+ oldChans = device->FmtChans;
+ oldType = device->FmtType;
+
+ TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u update size x%d\n",
+ (device->Flags&DEVICE_CHANNELS_REQUEST)?"*":"", DevFmtChannelsString(device->FmtChans),
+ (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)?"*":"", DevFmtTypeString(device->FmtType),
+ (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"", device->Frequency,
+ device->UpdateSize, device->NumUpdates
+ );
+
if(V0(device->Backend,reset)() == ALC_FALSE)
return ALC_INVALID_DEVICE;
@@ -1822,61 +1952,170 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
}
TRACE("Post-reset: %s, %s, %uhz, %u update size x%d\n",
- DevFmtChannelsString(device->FmtChans),
- DevFmtTypeString(device->FmtType), device->Frequency,
- device->UpdateSize, device->NumUpdates);
-
- aluInitPanning(device);
-
- V(device->Synth,update)(device);
+ DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
+ device->Frequency, device->UpdateSize, device->NumUpdates
+ );
- device->Hrtf = NULL;
- if((device->Flags&DEVICE_HRTF_REQUEST))
+ if((device->UpdateSize&3) != 0)
{
- device->Hrtf = GetHrtf(device);
- if(!device->Hrtf)
- device->Flags &= ~DEVICE_HRTF_REQUEST;
+ if((CPUCapFlags&CPU_CAP_SSE))
+ WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize);
+ if((CPUCapFlags&CPU_CAP_NEON))
+ WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize);
}
- TRACE("HRTF %s\n", device->Hrtf?"enabled":"disabled");
- if(!device->Hrtf && device->Bs2bLevel > 0 && device->Bs2bLevel <= 6)
+ device->Hrtf = NULL;
+ device->Hrtf_Mode = DisabledHrtf;
+ al_string_clear(&device->Hrtf_Name);
+ if(device->FmtChans != DevFmtStereo)
{
- if(!device->Bs2b)
- {
- device->Bs2b = calloc(1, sizeof(*device->Bs2b));
- bs2b_clear(device->Bs2b);
- }
- bs2b_set_srate(device->Bs2b, device->Frequency);
- bs2b_set_level(device->Bs2b, device->Bs2bLevel);
- TRACE("BS2B level %d\n", device->Bs2bLevel);
+ if(hrtf_appreq == Hrtf_Enable)
+ device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
+
+ free(device->Bs2b);
+ device->Bs2b = NULL;
}
else
{
- free(device->Bs2b);
- device->Bs2b = NULL;
- TRACE("BS2B disabled\n");
+ bool headphones = device->IsHeadphones;
+ enum HrtfMode hrtf_mode = FullHrtf;
+ ALCenum hrtf_status = device->Hrtf_Status;
+ const char *mode;
+ int bs2blevel;
+ int usehrtf;
+
+ if(device->Type != Loopback)
+ {
+ if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode))
+ {
+ if(strcasecmp(mode, "headphones") == 0)
+ headphones = true;
+ else if(strcasecmp(mode, "speakers") == 0)
+ headphones = false;
+ else if(strcasecmp(mode, "auto") != 0)
+ ERR("Unexpected stereo-mode: %s\n", mode);
+ }
+
+ if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode))
+ {
+ if(strcasecmp(mode, "full") == 0)
+ hrtf_mode = FullHrtf;
+ else if(strcasecmp(mode, "basic") == 0)
+ hrtf_mode = BasicHrtf;
+ else
+ ERR("Unexpected hrtf-mode: %s\n", mode);
+ }
+ }
+
+
+ if(hrtf_userreq == Hrtf_Default)
+ {
+ usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) ||
+ (hrtf_appreq == Hrtf_Enable);
+ if(headphones && hrtf_appreq != Hrtf_Disable)
+ hrtf_status = ALC_HRTF_HEADPHONES_DETECTED_SOFT;
+ else if(usehrtf)
+ hrtf_status = ALC_HRTF_ENABLED_SOFT;
+ }
+ else
+ {
+ usehrtf = (hrtf_userreq == Hrtf_Enable);
+ if(!usehrtf)
+ hrtf_status = ALC_HRTF_DENIED_SOFT;
+ else
+ hrtf_status = ALC_HRTF_REQUIRED_SOFT;
+ }
+
+ if(!usehrtf)
+ device->Hrtf_Status = hrtf_status;
+ else
+ {
+ size_t i;
+
+ device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
+ if(VECTOR_SIZE(device->Hrtf_List) == 0)
+ {
+ VECTOR_DEINIT(device->Hrtf_List);
+ device->Hrtf_List = EnumerateHrtf(device->DeviceName);
+ }
+
+ if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List))
+ {
+ const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id);
+ if(GetHrtfSampleRate(entry->hrtf) == device->Frequency)
+ {
+ device->Hrtf = entry->hrtf;
+ al_string_copy(&device->Hrtf_Name, entry->name);
+ }
+ }
+ if(!device->Hrtf)
+ {
+ for(i = 0;i < VECTOR_SIZE(device->Hrtf_List);i++)
+ {
+ const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i);
+ if(GetHrtfSampleRate(entry->hrtf) == device->Frequency)
+ {
+ device->Hrtf = entry->hrtf;
+ al_string_copy(&device->Hrtf_Name, entry->name);
+ break;
+ }
+ }
+ }
+ }
+ if(device->Hrtf)
+ {
+ device->Hrtf_Mode = hrtf_mode;
+ device->Hrtf_Status = hrtf_status;
+ TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name));
+ free(device->Bs2b);
+ device->Bs2b = NULL;
+ }
+ else
+ {
+ TRACE("HRTF disabled\n");
+
+ bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) ||
+ (hrtf_appreq == Hrtf_Enable)) ? 5 : 0;
+ if(device->Type != Loopback)
+ ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel);
+ if(bs2blevel > 0 && bs2blevel <= 6)
+ {
+ if(!device->Bs2b)
+ {
+ device->Bs2b = calloc(1, sizeof(*device->Bs2b));
+ bs2b_clear(device->Bs2b);
+ }
+ bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency);
+ TRACE("BS2B enabled\n");
+ }
+ else
+ {
+ free(device->Bs2b);
+ device->Bs2b = NULL;
+ TRACE("BS2B disabled\n");
+ }
+ }
}
- device->Flags &= ~DEVICE_WIDE_STEREO;
- if(device->Type != Loopback && !device->Hrtf && GetConfigValueBool(NULL, "wide-stereo", AL_FALSE))
- device->Flags |= DEVICE_WIDE_STEREO;
+ aluInitPanning(device);
- if(!device->Hrtf && (device->UpdateSize&3))
+ /* With HRTF, allocate two extra channels for the post-filter output. */
+ size = sizeof(device->DryBuffer[0]) * (device->NumChannels + (device->Hrtf ? 2 : 0));
+ device->DryBuffer = al_calloc(16, size);
+ if(!device->DryBuffer)
{
- if((CPUCapFlags&CPU_CAP_SSE))
- WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize);
- if((CPUCapFlags&CPU_CAP_NEON))
- WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize);
+ ERR("Failed to allocate "SZFMT" bytes for mix buffer\n", size);
+ return ALC_INVALID_DEVICE;
}
SetMixerFPUMode(&oldMode);
- ALCdevice_Lock(device);
- context = device->ContextList;
+ V0(device->Backend,lock)();
+ context = ATOMIC_LOAD(&device->ContextList);
while(context)
{
ALsizei pos;
- context->UpdateSources = AL_FALSE;
+ ATOMIC_STORE(&context->UpdateSources, AL_FALSE);
LockUIntMapRead(&context->EffectSlotMap);
for(pos = 0;pos < context->EffectSlotMap.size;pos++)
{
@@ -1885,11 +2124,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE)
{
UnlockUIntMapRead(&context->EffectSlotMap);
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
return ALC_INVALID_DEVICE;
}
- slot->NeedsUpdate = AL_FALSE;
+ ATOMIC_STORE(&slot->NeedsUpdate, AL_FALSE);
V(slot->EffectState,update)(device, slot);
}
UnlockUIntMapRead(&context->EffectSlotMap);
@@ -1908,24 +2147,28 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
source->Send[s].GainHF = 1.0f;
s++;
}
- source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&source->NeedsUpdate, AL_TRUE);
}
UnlockUIntMapRead(&context->SourceMap);
- for(pos = 0;pos < context->ActiveSourceCount;pos++)
+ for(pos = 0;pos < context->VoiceCount;pos++)
{
- ALactivesource *src = context->ActiveSources[pos];
- ALsource *source = src->Source;
+ ALvoice *voice = &context->Voices[pos];
+ ALsource *source = voice->Source;
ALuint s = device->NumAuxSends;
+
while(s < MAX_SENDS)
{
- src->Send[s].Moving = AL_FALSE;
- src->Send[s].Counter = 0;
+ voice->Send[s].Moving = AL_FALSE;
+ voice->Send[s].Counter = 0;
s++;
}
- src->Update(src, context);
- source->NeedsUpdate = AL_FALSE;
+ if(source)
+ {
+ ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
+ voice->Update(voice, source, context);
+ }
}
context = context->next;
@@ -1936,14 +2179,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE)
{
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
return ALC_INVALID_DEVICE;
}
- slot->NeedsUpdate = AL_FALSE;
+ ATOMIC_STORE(&slot->NeedsUpdate, AL_FALSE);
V(slot->EffectState,update)(device, slot);
}
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
RestoreFPUMode(&oldMode);
if(!(device->Flags&DEVICE_PAUSED))
@@ -1969,9 +2212,6 @@ static ALCvoid FreeDevice(ALCdevice *device)
DELETE_OBJ(device->Backend);
device->Backend = NULL;
- DELETE_OBJ(device->Synth);
- device->Synth = NULL;
-
if(device->DefaultSlot)
{
ALeffectState *state = device->DefaultSlot->EffectState;
@@ -1979,10 +2219,6 @@ static ALCvoid FreeDevice(ALCdevice *device)
DELETE_OBJ(state);
}
- if(device->DefaultSfont)
- ALsoundfont_deleteSoundfont(device->DefaultSfont, device);
- device->DefaultSfont = NULL;
-
if(device->BufferMap.size > 0)
{
WARN("(%p) Deleting %d Buffer(s)\n", device, device->BufferMap.size);
@@ -2004,32 +2240,17 @@ static ALCvoid FreeDevice(ALCdevice *device)
}
ResetUIntMap(&device->FilterMap);
- if(device->SfontMap.size > 0)
- {
- WARN("(%p) Deleting %d Soundfont(s)\n", device, device->SfontMap.size);
- ReleaseALSoundfonts(device);
- }
- ResetUIntMap(&device->SfontMap);
-
- if(device->PresetMap.size > 0)
- {
- WARN("(%p) Deleting %d Preset(s)\n", device, device->PresetMap.size);
- ReleaseALPresets(device);
- }
- ResetUIntMap(&device->PresetMap);
-
- if(device->FontsoundMap.size > 0)
- {
- WARN("(%p) Deleting %d Fontsound(s)\n", device, device->FontsoundMap.size);
- ReleaseALFontsounds(device);
- }
- ResetUIntMap(&device->FontsoundMap);
+ AL_STRING_DEINIT(device->Hrtf_Name);
+ FreeHrtfList(&device->Hrtf_List);
free(device->Bs2b);
device->Bs2b = NULL;
AL_STRING_DEINIT(device->DeviceName);
+ al_free(device->DryBuffer);
+ device->DryBuffer = NULL;
+
al_free(device);
}
@@ -2053,22 +2274,26 @@ void ALCdevice_DecRef(ALCdevice *device)
*
* Checks if the device handle is valid, and increments its ref count if so.
*/
-static ALCdevice *VerifyDevice(ALCdevice *device)
+static ALCboolean VerifyDevice(ALCdevice **device)
{
ALCdevice *tmpDevice;
- if(!device)
- return NULL;
-
LockLists();
- tmpDevice = DeviceList;
- while(tmpDevice && tmpDevice != device)
+ tmpDevice = ATOMIC_LOAD(&DeviceList);
+ while(tmpDevice)
+ {
+ if(tmpDevice == *device)
+ {
+ ALCdevice_IncRef(tmpDevice);
+ UnlockLists();
+ return ALC_TRUE;
+ }
tmpDevice = tmpDevice->next;
-
- if(tmpDevice)
- ALCdevice_IncRef(tmpDevice);
+ }
UnlockLists();
- return tmpDevice;
+
+ *device = NULL;
+ return ALC_FALSE;
}
@@ -2078,35 +2303,29 @@ static ALCdevice *VerifyDevice(ALCdevice *device)
*/
static ALvoid InitContext(ALCcontext *Context)
{
- ALint i, j;
-
+ ALlistener *listener = Context->Listener;
//Initialise listener
- Context->Listener->Gain = 1.0f;
- Context->Listener->MetersPerUnit = 1.0f;
- Context->Listener->Position[0] = 0.0f;
- Context->Listener->Position[1] = 0.0f;
- Context->Listener->Position[2] = 0.0f;
- Context->Listener->Velocity[0] = 0.0f;
- Context->Listener->Velocity[1] = 0.0f;
- Context->Listener->Velocity[2] = 0.0f;
- Context->Listener->Forward[0] = 0.0f;
- Context->Listener->Forward[1] = 0.0f;
- Context->Listener->Forward[2] = -1.0f;
- Context->Listener->Up[0] = 0.0f;
- Context->Listener->Up[1] = 1.0f;
- Context->Listener->Up[2] = 0.0f;
- for(i = 0;i < 4;i++)
- {
- for(j = 0;j < 4;j++)
- Context->Listener->Params.Matrix[i][j] = ((i==j) ? 1.0f : 0.0f);
- }
- for(i = 0;i < 3;i++)
- Context->Listener->Params.Velocity[i] = 0.0f;
+ listener->Gain = 1.0f;
+ listener->MetersPerUnit = 1.0f;
+ aluVectorSet(&listener->Position, 0.0f, 0.0f, 0.0f, 1.0f);
+ aluVectorSet(&listener->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
+ listener->Forward[0] = 0.0f;
+ listener->Forward[1] = 0.0f;
+ listener->Forward[2] = -1.0f;
+ listener->Up[0] = 0.0f;
+ listener->Up[1] = 1.0f;
+ listener->Up[2] = 0.0f;
+ aluMatrixdSet(&listener->Params.Matrix,
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0
+ );
+ aluVectorSet(&listener->Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
//Validate Context
- Context->LastError = AL_NO_ERROR;
- Context->UpdateSources = AL_FALSE;
- Context->ActiveSourceCount = 0;
+ ATOMIC_INIT(&Context->LastError, AL_NO_ERROR);
+ ATOMIC_INIT(&Context->UpdateSources, AL_FALSE);
InitUIntMap(&Context->SourceMap, Context->Device->MaxNoOfSources);
InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax);
@@ -2127,10 +2346,8 @@ static ALvoid InitContext(ALCcontext *Context)
* Cleans up the context, and destroys any remaining objects the app failed to
* delete. Called once there's no more references on the context.
*/
-static ALCvoid FreeContext(ALCcontext *context)
+static void FreeContext(ALCcontext *context)
{
- ALsizei i;
-
TRACE("%p\n", context);
if(context->SourceMap.size > 0)
@@ -2147,15 +2364,10 @@ static ALCvoid FreeContext(ALCcontext *context)
}
ResetUIntMap(&context->EffectSlotMap);
- for(i = 0;i < context->MaxActiveSources;i++)
- {
- al_free(context->ActiveSources[i]);
- context->ActiveSources[i] = NULL;
- }
- free(context->ActiveSources);
- context->ActiveSources = NULL;
- context->ActiveSourceCount = 0;
- context->MaxActiveSources = 0;
+ al_free(context->Voices);
+ context->Voices = NULL;
+ context->VoiceCount = 0;
+ context->MaxVoices = 0;
VECTOR_DEINIT(context->ActiveAuxSlots);
@@ -2164,7 +2376,7 @@ static ALCvoid FreeContext(ALCcontext *context)
//Invalidate context
memset(context, 0, sizeof(ALCcontext));
- free(context);
+ al_free(context);
}
/* ReleaseContext
@@ -2174,7 +2386,8 @@ static ALCvoid FreeContext(ALCcontext *context)
*/
static void ReleaseContext(ALCcontext *context, ALCdevice *device)
{
- ALCcontext *volatile*tmp_ctx;
+ ALCcontext *nextctx;
+ ALCcontext *origctx;
if(altss_get(LocalContext) == context)
{
@@ -2183,16 +2396,20 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device)
ALCcontext_DecRef(context);
}
- if(CompExchangePtr((XchgPtr*)&GlobalContext, context, NULL) == context)
+ origctx = context;
+ if(ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &GlobalContext, &origctx, NULL))
ALCcontext_DecRef(context);
ALCdevice_Lock(device);
- tmp_ctx = &device->ContextList;
- while(*tmp_ctx)
+ origctx = context;
+ nextctx = context->next;
+ if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &device->ContextList, &origctx, nextctx))
{
- if(CompExchangePtr((XchgPtr*)tmp_ctx, context, context->next) == context)
- break;
- tmp_ctx = &(*tmp_ctx)->next;
+ ALCcontext *list;
+ do {
+ list = origctx;
+ origctx = context;
+ } while(!COMPARE_EXCHANGE(&list->next, &origctx, nextctx));
}
ALCdevice_Unlock(device);
@@ -2224,30 +2441,31 @@ static void ReleaseThreadCtx(void *ptr)
*
* Checks that the given context is valid, and increments its reference count.
*/
-static ALCcontext *VerifyContext(ALCcontext *context)
+static ALCboolean VerifyContext(ALCcontext **context)
{
ALCdevice *dev;
LockLists();
- dev = DeviceList;
+ dev = ATOMIC_LOAD(&DeviceList);
while(dev)
{
- ALCcontext *tmp_ctx = dev->ContextList;
- while(tmp_ctx)
+ ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList);
+ while(ctx)
{
- if(tmp_ctx == context)
+ if(ctx == *context)
{
- ALCcontext_IncRef(tmp_ctx);
+ ALCcontext_IncRef(ctx);
UnlockLists();
- return tmp_ctx;
+ return ALC_TRUE;
}
- tmp_ctx = tmp_ctx->next;
+ ctx = ctx->next;
}
dev = dev->next;
}
UnlockLists();
- return NULL;
+ *context = NULL;
+ return ALC_FALSE;
}
@@ -2266,7 +2484,7 @@ ALCcontext *GetContextRef(void)
else
{
LockLists();
- context = GlobalContext;
+ context = ATOMIC_LOAD(&GlobalContext);
if(context)
ALCcontext_IncRef(context);
UnlockLists();
@@ -2288,13 +2506,13 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
{
ALCenum errorCode;
- if(VerifyDevice(device))
+ if(VerifyDevice(&device))
{
- errorCode = ExchangeInt(&device->LastError, ALC_NO_ERROR);
+ errorCode = ATOMIC_EXCHANGE(ALCenum, &device->LastError, ALC_NO_ERROR);
ALCdevice_DecRef(device);
}
else
- errorCode = ExchangeInt(&LastNullDeviceError, ALC_NO_ERROR);
+ errorCode = ATOMIC_EXCHANGE(ALCenum, &LastNullDeviceError, ALC_NO_ERROR);
return errorCode;
}
@@ -2302,18 +2520,38 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
/* alcSuspendContext
*
- * Not functional
+ * Suspends updates for the given context
*/
-ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *UNUSED(context))
+ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context)
{
+ if(!SuspendDefers)
+ return;
+
+ if(!VerifyContext(&context))
+ alcSetError(NULL, ALC_INVALID_CONTEXT);
+ else
+ {
+ ALCcontext_DeferUpdates(context);
+ ALCcontext_DecRef(context);
+ }
}
/* alcProcessContext
*
- * Not functional
+ * Resumes processing updates for the given context
*/
-ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *UNUSED(context))
+ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context)
{
+ if(!SuspendDefers)
+ return;
+
+ if(!VerifyContext(&context))
+ alcSetError(NULL, ALC_INVALID_CONTEXT);
+ else
+ {
+ ALCcontext_ProcessUpdates(context);
+ ALCcontext_DecRef(context);
+ }
}
@@ -2356,7 +2594,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
break;
case ALC_ALL_DEVICES_SPECIFIER:
- if(VerifyDevice(Device))
+ if(VerifyDevice(&Device))
{
value = al_string_get_cstr(Device->DeviceName);
ALCdevice_DecRef(Device);
@@ -2369,7 +2607,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
break;
case ALC_CAPTURE_DEVICE_SPECIFIER:
- if(VerifyDevice(Device))
+ if(VerifyDevice(&Device))
{
value = al_string_get_cstr(Device->DeviceName);
ALCdevice_DecRef(Device);
@@ -2390,7 +2628,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
if(al_string_empty(alcAllDevicesList))
ProbeAllDevicesList();
- Device = VerifyDevice(Device);
+ VerifyDevice(&Device);
free(alcDefaultAllDevicesSpecifier);
alcDefaultAllDevicesSpecifier = strdup(al_string_get_cstr(alcAllDevicesList));
@@ -2405,10 +2643,10 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
if(al_string_empty(alcCaptureDeviceList))
ProbeCaptureDeviceList();
- Device = VerifyDevice(Device);
+ VerifyDevice(&Device);
free(alcCaptureDefaultDeviceSpecifier);
- alcCaptureDefaultDeviceSpecifier = strdup(al_string_get_cstr(alcAllDevicesList));
+ alcCaptureDefaultDeviceSpecifier = strdup(al_string_get_cstr(alcCaptureDeviceList));
if(!alcCaptureDefaultDeviceSpecifier)
alcSetError(Device, ALC_OUT_OF_MEMORY);
@@ -2417,7 +2655,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
break;
case ALC_EXTENSIONS:
- if(!VerifyDevice(Device))
+ if(!VerifyDevice(&Device))
value = alcNoDeviceExtList;
else
{
@@ -2426,8 +2664,20 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para
}
break;
+ case ALC_HRTF_SPECIFIER_SOFT:
+ if(!VerifyDevice(&Device))
+ alcSetError(NULL, ALC_INVALID_DEVICE);
+ else
+ {
+ LockLists();
+ value = (Device->Hrtf ? al_string_get_cstr(Device->Hrtf_Name) : "");
+ UnlockLists();
+ ALCdevice_DecRef(Device);
+ }
+ break;
+
default:
- Device = VerifyDevice(Device);
+ VerifyDevice(&Device);
alcSetError(Device, ALC_INVALID_ENUM);
if(Device) ALCdevice_DecRef(Device);
break;
@@ -2483,9 +2733,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC
switch(param)
{
case ALC_CAPTURE_SAMPLES:
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
values[0] = V0(device->Backend,availableSamples)();
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
return 1;
case ALC_CONNECTED:
@@ -2519,11 +2769,11 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC
return 1;
case ALC_ATTRIBUTES_SIZE:
- values[0] = 15;
+ values[0] = 17;
return 1;
case ALC_ALL_ATTRIBUTES:
- if(size < 15)
+ if(size < 17)
{
alcSetError(device, ALC_INVALID_VALUE);
return 0;
@@ -2562,6 +2812,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC
values[i++] = ALC_HRTF_SOFT;
values[i++] = (device->Hrtf ? ALC_TRUE : ALC_FALSE);
+ values[i++] = ALC_HRTF_STATUS_SOFT;
+ values[i++] = device->Hrtf_Status;
+
values[i++] = 0;
return i;
@@ -2625,6 +2878,16 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC
values[0] = (device->Hrtf ? ALC_TRUE : ALC_FALSE);
return 1;
+ case ALC_HRTF_STATUS_SOFT:
+ values[0] = device->Hrtf_Status;
+ return 1;
+
+ case ALC_NUM_HRTF_SPECIFIERS_SOFT:
+ FreeHrtfList(&device->Hrtf_List);
+ device->Hrtf_List = EnumerateHrtf(device->DeviceName);
+ values[0] = (ALCint)VECTOR_SIZE(device->Hrtf_List);
+ return 1;
+
default:
alcSetError(device, ALC_INVALID_ENUM);
return 0;
@@ -2638,7 +2901,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC
*/
ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
{
- device = VerifyDevice(device);
+ VerifyDevice(&device);
if(size <= 0 || values == NULL)
alcSetError(device, ALC_INVALID_VALUE);
else
@@ -2651,7 +2914,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
ALCint *ivals;
ALsizei i;
- device = VerifyDevice(device);
+ VerifyDevice(&device);
if(size <= 0 || values == NULL)
alcSetError(device, ALC_INVALID_VALUE);
else if(!device || device->Type == Capture)
@@ -2667,11 +2930,11 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
switch(pname)
{
case ALC_ATTRIBUTES_SIZE:
- *values = 17;
+ *values = 19;
break;
case ALC_ALL_ATTRIBUTES:
- if(size < 17)
+ if(size < 19)
alcSetError(device, ALC_INVALID_VALUE);
else
{
@@ -2710,6 +2973,9 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
values[i++] = ALC_HRTF_SOFT;
values[i++] = (device->Hrtf ? ALC_TRUE : ALC_FALSE);
+ values[i++] = ALC_HRTF_STATUS_SOFT;
+ values[i++] = device->Hrtf_Status;
+
values[i++] = ALC_DEVICE_CLOCK_SOFT;
values[i++] = device->ClockBase +
(device->SamplesDone * DEVICE_CLOCK_RES / device->Frequency);
@@ -2748,7 +3014,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A
{
ALCboolean bResult = ALC_FALSE;
- device = VerifyDevice(device);
+ VerifyDevice(&device);
if(!extName)
alcSetError(device, ALC_INVALID_VALUE);
@@ -2788,7 +3054,7 @@ ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar
if(!funcName)
{
- device = VerifyDevice(device);
+ VerifyDevice(&device);
alcSetError(device, ALC_INVALID_VALUE);
if(device) ALCdevice_DecRef(device);
}
@@ -2814,7 +3080,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e
if(!enumName)
{
- device = VerifyDevice(device);
+ VerifyDevice(&device);
alcSetError(device, ALC_INVALID_VALUE);
if(device) ALCdevice_DecRef(device);
}
@@ -2840,7 +3106,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
ALCenum err;
LockLists();
- if(!(device=VerifyDevice(device)) || device->Type == Capture || !device->Connected)
+ if(!VerifyDevice(&device) || device->Type == Capture || !device->Connected)
{
UnlockLists();
alcSetError(device, ALC_INVALID_DEVICE);
@@ -2848,7 +3114,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
return NULL;
}
- device->LastError = ALC_NO_ERROR;
+ ATOMIC_STORE(&device->LastError, ALC_NO_ERROR);
if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR)
{
@@ -2856,15 +3122,15 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
alcSetError(device, err);
if(err == ALC_INVALID_DEVICE)
{
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
aluHandleDisconnect(device);
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
}
ALCdevice_DecRef(device);
return NULL;
}
- ALContext = calloc(1, sizeof(ALCcontext)+sizeof(ALlistener));
+ ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener));
if(ALContext)
{
InitRef(&ALContext->ref, 1);
@@ -2872,13 +3138,13 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
VECTOR_INIT(ALContext->ActiveAuxSlots);
- ALContext->MaxActiveSources = 256;
- ALContext->ActiveSources = calloc(ALContext->MaxActiveSources,
- sizeof(ALContext->ActiveSources[0]));
+ ALContext->VoiceCount = 0;
+ ALContext->MaxVoices = 256;
+ ALContext->Voices = al_calloc(16, ALContext->MaxVoices * sizeof(ALContext->Voices[0]));
}
- if(!ALContext || !ALContext->ActiveSources)
+ if(!ALContext || !ALContext->Voices)
{
- if(!device->ContextList)
+ if(!ATOMIC_LOAD(&device->ContextList))
{
V0(device->Backend,stop)();
device->Flags &= ~DEVICE_RUNNING;
@@ -2887,12 +3153,12 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
if(ALContext)
{
- free(ALContext->ActiveSources);
- ALContext->ActiveSources = NULL;
+ al_free(ALContext->Voices);
+ ALContext->Voices = NULL;
VECTOR_DEINIT(ALContext->ActiveAuxSlots);
- free(ALContext);
+ al_free(ALContext);
ALContext = NULL;
}
@@ -2905,9 +3171,12 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin
ALCdevice_IncRef(device);
InitContext(ALContext);
- do {
- ALContext->next = device->ContextList;
- } while(CompExchangePtr((XchgPtr*)&device->ContextList, ALContext->next, ALContext) != ALContext->next);
+ {
+ ALCcontext *head = ATOMIC_LOAD(&device->ContextList);
+ do {
+ ALContext->next = head;
+ } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCcontext*, &device->ContextList, &head, ALContext));
+ }
UnlockLists();
ALCdevice_DecRef(device);
@@ -2930,7 +3199,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
if(Device)
{
ReleaseContext(context, Device);
- if(!Device->ContextList)
+ if(!ATOMIC_LOAD(&Device->ContextList))
{
V0(Device->Backend,stop)();
Device->Flags &= ~DEVICE_RUNNING;
@@ -2946,11 +3215,8 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
*/
ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
{
- ALCcontext *Context;
-
- Context = altss_get(LocalContext);
- if(!Context) Context = GlobalContext;
-
+ ALCcontext *Context = altss_get(LocalContext);
+ if(!Context) Context = ATOMIC_LOAD(&GlobalContext);
return Context;
}
@@ -2960,9 +3226,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
*/
ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
{
- ALCcontext *Context;
- Context = altss_get(LocalContext);
- return Context;
+ return altss_get(LocalContext);
}
@@ -2974,13 +3238,13 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
{
/* context must be valid or NULL */
- if(context && !(context=VerifyContext(context)))
+ if(context && !VerifyContext(&context))
{
alcSetError(NULL, ALC_INVALID_CONTEXT);
return ALC_FALSE;
}
/* context's reference count is already incremented */
- context = ExchangePtr((XchgPtr*)&GlobalContext, context);
+ context = ATOMIC_EXCHANGE(ALCcontext*, &GlobalContext, context);
if(context) ALCcontext_DecRef(context);
if((context=altss_get(LocalContext)) != NULL)
@@ -3001,7 +3265,7 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
ALCcontext *old;
/* context must be valid or NULL */
- if(context && !(context=VerifyContext(context)))
+ if(context && !VerifyContext(&context))
{
alcSetError(NULL, ALC_INVALID_CONTEXT);
return ALC_FALSE;
@@ -3023,7 +3287,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context)
{
ALCdevice *Device;
- if(!(Context=VerifyContext(Context)))
+ if(!VerifyContext(&Context))
{
alcSetError(NULL, ALC_INVALID_CONTEXT);
return NULL;
@@ -3053,7 +3317,16 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
return NULL;
}
- if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0))
+ if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0
+#ifdef _WIN32
+ /* Some old Windows apps hardcode these expecting OpenAL to use a
+ * specific audio API, even when they're not enumerated. Creative's
+ * router effectively ignores them too.
+ */
+ || strcasecmp(deviceName, "DirectSound3D") == 0 || strcasecmp(deviceName, "DirectSound") == 0
+ || strcasecmp(deviceName, "MMSYSTEM") == 0
+#endif
+ ))
deviceName = NULL;
device = al_calloc(16, sizeof(ALCdevice)+sizeof(ALeffectslot));
@@ -3067,14 +3340,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
InitRef(&device->ref, 1);
device->Connected = ALC_TRUE;
device->Type = Playback;
- device->LastError = ALC_NO_ERROR;
+ ATOMIC_INIT(&device->LastError, ALC_NO_ERROR);
device->Flags = 0;
device->Bs2b = NULL;
- device->Bs2bLevel = 0;
+ VECTOR_INIT(device->Hrtf_List);
+ AL_STRING_INIT(device->Hrtf_Name);
+ device->Hrtf_Mode = DisabledHrtf;
AL_STRING_INIT(device->DeviceName);
+ device->DryBuffer = NULL;
- device->ContextList = NULL;
+ ATOMIC_INIT(&device->ContextList, NULL);
device->ClockBase = 0;
device->SamplesDone = 0;
@@ -3086,14 +3362,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
InitUIntMap(&device->BufferMap, ~0);
InitUIntMap(&device->EffectMap, ~0);
InitUIntMap(&device->FilterMap, ~0);
- InitUIntMap(&device->SfontMap, ~0);
- InitUIntMap(&device->PresetMap, ~0);
- InitUIntMap(&device->FontsoundMap, ~0);
//Set output format
device->FmtChans = DevFmtChannelsDefault;
device->FmtType = DevFmtTypeDefault;
device->Frequency = DEFAULT_OUTPUT_RATE;
+ device->IsHeadphones = AL_FALSE;
device->NumUpdates = 4;
device->UpdateSize = 1024;
@@ -3113,7 +3387,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
}
- if(ConfigValueStr(NULL, "channels", &fmt))
+ if(ConfigValueStr(deviceName, NULL, "channels", &fmt))
{
static const struct {
const char name[16];
@@ -3125,6 +3399,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
{ "surround51", DevFmtX51 },
{ "surround61", DevFmtX61 },
{ "surround71", DevFmtX71 },
+ { "surround51rear", DevFmtX51Rear },
};
size_t i;
@@ -3140,7 +3415,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
if(i == COUNTOF(chanlist))
ERR("Unsupported channels: %s\n", fmt);
}
- if(ConfigValueStr(NULL, "sample-type", &fmt))
+ if(ConfigValueStr(deviceName, NULL, "sample-type", &fmt))
{
static const struct {
const char name[16];
@@ -3168,57 +3443,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
if(i == COUNTOF(typelist))
ERR("Unsupported sample-type: %s\n", fmt);
}
-#define DEVICE_FORMAT_REQUEST (DEVICE_CHANNELS_REQUEST|DEVICE_SAMPLE_TYPE_REQUEST)
- if((device->Flags&DEVICE_FORMAT_REQUEST) != DEVICE_FORMAT_REQUEST &&
- ConfigValueStr(NULL, "format", &fmt))
- {
- static const struct {
- const char name[32];
- enum DevFmtChannels channels;
- enum DevFmtType type;
- } formats[] = {
- { "AL_FORMAT_MONO32", DevFmtMono, DevFmtFloat },
- { "AL_FORMAT_STEREO32", DevFmtStereo, DevFmtFloat },
- { "AL_FORMAT_QUAD32", DevFmtQuad, DevFmtFloat },
- { "AL_FORMAT_51CHN32", DevFmtX51, DevFmtFloat },
- { "AL_FORMAT_61CHN32", DevFmtX61, DevFmtFloat },
- { "AL_FORMAT_71CHN32", DevFmtX71, DevFmtFloat },
-
- { "AL_FORMAT_MONO16", DevFmtMono, DevFmtShort },
- { "AL_FORMAT_STEREO16", DevFmtStereo, DevFmtShort },
- { "AL_FORMAT_QUAD16", DevFmtQuad, DevFmtShort },
- { "AL_FORMAT_51CHN16", DevFmtX51, DevFmtShort },
- { "AL_FORMAT_61CHN16", DevFmtX61, DevFmtShort },
- { "AL_FORMAT_71CHN16", DevFmtX71, DevFmtShort },
-
- { "AL_FORMAT_MONO8", DevFmtMono, DevFmtByte },
- { "AL_FORMAT_STEREO8", DevFmtStereo, DevFmtByte },
- { "AL_FORMAT_QUAD8", DevFmtQuad, DevFmtByte },
- { "AL_FORMAT_51CHN8", DevFmtX51, DevFmtByte },
- { "AL_FORMAT_61CHN8", DevFmtX61, DevFmtByte },
- { "AL_FORMAT_71CHN8", DevFmtX71, DevFmtByte }
- };
- size_t i;
-
- ERR("Option 'format' is deprecated, please use 'channels' and 'sample-type'\n");
- for(i = 0;i < COUNTOF(formats);i++)
- {
- if(strcasecmp(fmt, formats[i].name) == 0)
- {
- if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
- device->FmtChans = formats[i].channels;
- if(!(device->Flags&DEVICE_SAMPLE_TYPE_REQUEST))
- device->FmtType = formats[i].type;
- device->Flags |= DEVICE_FORMAT_REQUEST;
- break;
- }
- }
- if(i == COUNTOF(formats))
- ERR("Unsupported format: %s\n", fmt);
- }
-#undef DEVICE_FORMAT_REQUEST
- if(ConfigValueUInt(NULL, "frequency", &device->Frequency))
+ if(ConfigValueUInt(deviceName, NULL, "frequency", &device->Frequency))
{
device->Flags |= DEVICE_FREQUENCY_REQUEST;
if(device->Frequency < MIN_OUTPUT_RATE)
@@ -3226,41 +3452,29 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
device->Frequency = maxu(device->Frequency, MIN_OUTPUT_RATE);
}
- ConfigValueUInt(NULL, "periods", &device->NumUpdates);
+ ConfigValueUInt(deviceName, NULL, "periods", &device->NumUpdates);
device->NumUpdates = clampu(device->NumUpdates, 2, 16);
- ConfigValueUInt(NULL, "period_size", &device->UpdateSize);
+ ConfigValueUInt(deviceName, NULL, "period_size", &device->UpdateSize);
device->UpdateSize = clampu(device->UpdateSize, 64, 8192);
- if((CPUCapFlags&CPU_CAP_SSE))
+ if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0)
device->UpdateSize = (device->UpdateSize+3)&~3;
- ConfigValueUInt(NULL, "sources", &device->MaxNoOfSources);
+ ConfigValueUInt(deviceName, NULL, "sources", &device->MaxNoOfSources);
if(device->MaxNoOfSources == 0) device->MaxNoOfSources = 256;
- ConfigValueUInt(NULL, "slots", &device->AuxiliaryEffectSlotMax);
+ ConfigValueUInt(deviceName, NULL, "slots", &device->AuxiliaryEffectSlotMax);
if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4;
- ConfigValueUInt(NULL, "sends", &device->NumAuxSends);
+ ConfigValueUInt(deviceName, NULL, "sends", &device->NumAuxSends);
if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS;
- ConfigValueInt(NULL, "cf_level", &device->Bs2bLevel);
-
device->NumStereoSources = 1;
device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources;
- device->Synth = SynthCreate(device);
- if(!device->Synth)
- {
- DELETE_OBJ(device->Backend);
- al_free(device);
- alcSetError(NULL, ALC_OUT_OF_MEMORY);
- return NULL;
- }
-
// Find a playback device to open
if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR)
{
- DELETE_OBJ(device->Synth);
DELETE_OBJ(device->Backend);
al_free(device);
alcSetError(NULL, err);
@@ -3284,9 +3498,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
}
}
- do {
- device->next = DeviceList;
- } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
+ {
+ ALCdevice *head = ATOMIC_LOAD(&DeviceList);
+ do {
+ device->next = head;
+ } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device));
+ }
TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName));
return device;
@@ -3296,36 +3513,48 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
*
* Closes the given device.
*/
-ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *Device)
+ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
{
- ALCdevice *volatile*list;
+ ALCdevice *list, *origdev, *nextdev;
ALCcontext *ctx;
LockLists();
- list = &DeviceList;
- while(*list && *list != Device)
- list = &(*list)->next;
-
- if(!*list || (*list)->Type == Capture)
+ list = ATOMIC_LOAD(&DeviceList);
+ do {
+ if(list == device)
+ break;
+ } while((list=list->next) != NULL);
+ if(!list || list->Type == Capture)
{
- alcSetError(*list, ALC_INVALID_DEVICE);
+ alcSetError(list, ALC_INVALID_DEVICE);
UnlockLists();
return ALC_FALSE;
}
- *list = (*list)->next;
+ origdev = device;
+ nextdev = device->next;
+ if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &origdev, nextdev))
+ {
+ do {
+ list = origdev;
+ origdev = device;
+ } while(!COMPARE_EXCHANGE(&list->next, &origdev, nextdev));
+ }
UnlockLists();
- while((ctx=Device->ContextList) != NULL)
+ ctx = ATOMIC_LOAD(&device->ContextList);
+ while(ctx != NULL)
{
+ ALCcontext *next = ctx->next;
WARN("Releasing context %p\n", ctx);
- ReleaseContext(ctx, Device);
+ ReleaseContext(ctx, device);
+ ctx = next;
}
- if((Device->Flags&DEVICE_RUNNING))
- V0(Device->Backend,stop)();
- Device->Flags &= ~DEVICE_RUNNING;
+ if((device->Flags&DEVICE_RUNNING))
+ V0(device->Backend,stop)();
+ device->Flags &= ~DEVICE_RUNNING;
- ALCdevice_DecRef(Device);
+ ALCdevice_DecRef(device);
return ALC_TRUE;
}
@@ -3368,14 +3597,15 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
device->Connected = ALC_TRUE;
device->Type = Capture;
+ VECTOR_INIT(device->Hrtf_List);
+ AL_STRING_INIT(device->Hrtf_Name);
+
AL_STRING_INIT(device->DeviceName);
+ device->DryBuffer = NULL;
InitUIntMap(&device->BufferMap, ~0);
InitUIntMap(&device->EffectMap, ~0);
InitUIntMap(&device->FilterMap, ~0);
- InitUIntMap(&device->SfontMap, ~0);
- InitUIntMap(&device->PresetMap, ~0);
- InitUIntMap(&device->FontsoundMap, ~0);
if(!CaptureBackend.getFactory)
device->Backend = create_backend_wrapper(device, &CaptureBackend.Funcs,
@@ -3402,6 +3632,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
alcSetError(NULL, ALC_INVALID_ENUM);
return NULL;
}
+ device->IsHeadphones = AL_FALSE;
device->UpdateSize = samples;
device->NumUpdates = 1;
@@ -3413,52 +3644,70 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName,
return NULL;
}
- do {
- device->next = DeviceList;
- } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
+ {
+ ALCdevice *head = ATOMIC_LOAD(&DeviceList);
+ do {
+ device->next = head;
+ } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device));
+ }
TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName));
return device;
}
-ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *Device)
+ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
{
- ALCdevice *volatile*list;
+ ALCdevice *list, *next, *nextdev;
LockLists();
- list = &DeviceList;
- while(*list && *list != Device)
- list = &(*list)->next;
-
- if(!*list || (*list)->Type != Capture)
+ list = ATOMIC_LOAD(&DeviceList);
+ do {
+ if(list == device)
+ break;
+ } while((list=list->next) != NULL);
+ if(!list || list->Type != Capture)
{
- alcSetError(*list, ALC_INVALID_DEVICE);
+ alcSetError(list, ALC_INVALID_DEVICE);
UnlockLists();
return ALC_FALSE;
}
- *list = (*list)->next;
+ next = device;
+ nextdev = device->next;
+ if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &next, nextdev))
+ {
+ do {
+ list = next;
+ next = device;
+ } while(!COMPARE_EXCHANGE(&list->next, &next, nextdev));
+ }
UnlockLists();
- ALCdevice_DecRef(Device);
+ ALCdevice_DecRef(device);
return ALC_TRUE;
}
ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
{
- if(!(device=VerifyDevice(device)) || device->Type != Capture)
+ if(!VerifyDevice(&device) || device->Type != Capture)
alcSetError(device, ALC_INVALID_DEVICE);
else
{
- ALCdevice_Lock(device);
- if(device->Connected)
+ V0(device->Backend,lock)();
+ if(!device->Connected)
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else if(!(device->Flags&DEVICE_RUNNING))
{
- if(!(device->Flags&DEVICE_RUNNING))
- V0(device->Backend,start)();
- device->Flags |= DEVICE_RUNNING;
+ if(V0(device->Backend,start)())
+ device->Flags |= DEVICE_RUNNING;
+ else
+ {
+ aluHandleDisconnect(device);
+ alcSetError(device, ALC_INVALID_DEVICE);
+ }
}
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
}
if(device) ALCdevice_DecRef(device);
@@ -3466,15 +3715,15 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
{
- if(!(device=VerifyDevice(device)) || device->Type != Capture)
+ if(!VerifyDevice(&device) || device->Type != Capture)
alcSetError(device, ALC_INVALID_DEVICE);
else
{
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
if((device->Flags&DEVICE_RUNNING))
V0(device->Backend,stop)();
device->Flags &= ~DEVICE_RUNNING;
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
}
if(device) ALCdevice_DecRef(device);
@@ -3482,16 +3731,16 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
{
- if(!(device=VerifyDevice(device)) || device->Type != Capture)
+ if(!VerifyDevice(&device) || device->Type != Capture)
alcSetError(device, ALC_INVALID_DEVICE);
else
{
ALCenum err = ALC_INVALID_VALUE;
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples)
err = V(device->Backend,captureSamples)(buffer, samples);
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
if(err != ALC_NO_ERROR)
alcSetError(device, err);
@@ -3533,14 +3782,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
InitRef(&device->ref, 1);
device->Connected = ALC_TRUE;
device->Type = Loopback;
- device->LastError = ALC_NO_ERROR;
+ ATOMIC_INIT(&device->LastError, ALC_NO_ERROR);
device->Flags = 0;
+ VECTOR_INIT(device->Hrtf_List);
+ AL_STRING_INIT(device->Hrtf_Name);
device->Bs2b = NULL;
- device->Bs2bLevel = 0;
+ device->Hrtf_Mode = DisabledHrtf;
AL_STRING_INIT(device->DeviceName);
+ device->DryBuffer = NULL;
- device->ContextList = NULL;
+ ATOMIC_INIT(&device->ContextList, NULL);
device->ClockBase = 0;
device->SamplesDone = 0;
@@ -3552,9 +3804,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
InitUIntMap(&device->BufferMap, ~0);
InitUIntMap(&device->EffectMap, ~0);
InitUIntMap(&device->FilterMap, ~0);
- InitUIntMap(&device->SfontMap, ~0);
- InitUIntMap(&device->PresetMap, ~0);
- InitUIntMap(&device->FontsoundMap, ~0);
factory = ALCloopbackFactory_getFactory();
device->Backend = V(factory,createBackend)(device, ALCbackend_Loopback);
@@ -3572,33 +3821,29 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN
device->Frequency = DEFAULT_OUTPUT_RATE;
device->FmtChans = DevFmtChannelsDefault;
device->FmtType = DevFmtTypeDefault;
+ device->IsHeadphones = AL_FALSE;
- ConfigValueUInt(NULL, "sources", &device->MaxNoOfSources);
+ ConfigValueUInt(NULL, NULL, "sources", &device->MaxNoOfSources);
if(device->MaxNoOfSources == 0) device->MaxNoOfSources = 256;
- ConfigValueUInt(NULL, "slots", &device->AuxiliaryEffectSlotMax);
+ ConfigValueUInt(NULL, NULL, "slots", &device->AuxiliaryEffectSlotMax);
if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4;
- ConfigValueUInt(NULL, "sends", &device->NumAuxSends);
+ ConfigValueUInt(NULL, NULL, "sends", &device->NumAuxSends);
if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS;
device->NumStereoSources = 1;
device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources;
- device->Synth = SynthCreate(device);
- if(!device->Synth)
- {
- DELETE_OBJ(device->Backend);
- al_free(device);
- alcSetError(NULL, ALC_OUT_OF_MEMORY);
- return NULL;
- }
-
// Open the "backend"
V(device->Backend,open)("Loopback");
- do {
- device->next = DeviceList;
- } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next);
+
+ {
+ ALCdevice *head = ATOMIC_LOAD(&DeviceList);
+ do {
+ device->next = head;
+ } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device));
+ }
TRACE("Created device %p\n", device);
return device;
@@ -3612,7 +3857,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device
{
ALCboolean ret = ALC_FALSE;
- if(!(device=VerifyDevice(device)) || device->Type != Loopback)
+ if(!VerifyDevice(&device) || device->Type != Loopback)
alcSetError(device, ALC_INVALID_DEVICE);
else if(freq <= 0)
alcSetError(device, ALC_INVALID_VALUE);
@@ -3635,7 +3880,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device
*/
FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
{
- if(!(device=VerifyDevice(device)) || device->Type != Loopback)
+ if(!VerifyDevice(&device) || device->Type != Loopback)
alcSetError(device, ALC_INVALID_DEVICE);
else if(samples < 0 || (samples > 0 && buffer == NULL))
alcSetError(device, ALC_INVALID_VALUE);
@@ -3655,7 +3900,7 @@ FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, AL
*/
ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device)
{
- if(!(device=VerifyDevice(device)) || device->Type != Playback)
+ if(!VerifyDevice(&device) || device->Type != Playback)
alcSetError(device, ALC_INVALID_DEVICE);
else
{
@@ -3675,7 +3920,7 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device)
*/
ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
{
- if(!(device=VerifyDevice(device)) || device->Type != Playback)
+ if(!VerifyDevice(&device) || device->Type != Playback)
alcSetError(device, ALC_INVALID_DEVICE);
else
{
@@ -3683,16 +3928,16 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
if((device->Flags&DEVICE_PAUSED))
{
device->Flags &= ~DEVICE_PAUSED;
- if(device->ContextList != NULL)
+ if(ATOMIC_LOAD(&device->ContextList) != NULL)
{
if(V0(device->Backend,start)() != ALC_FALSE)
device->Flags |= DEVICE_RUNNING;
else
{
alcSetError(device, ALC_INVALID_DEVICE);
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
aluHandleDisconnect(device);
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
}
}
}
@@ -3700,3 +3945,72 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device)
}
if(device) ALCdevice_DecRef(device);
}
+
+
+/************************************************
+ * ALC HRTF functions
+ ************************************************/
+
+/* alcGetStringiSOFT
+ *
+ * Gets a string parameter at the given index.
+ */
+ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index)
+{
+ const ALCchar *str = NULL;
+
+ if(!VerifyDevice(&device) || device->Type == Capture)
+ alcSetError(device, ALC_INVALID_DEVICE);
+ else switch(paramName)
+ {
+ case ALC_HRTF_SPECIFIER_SOFT:
+ if(index >= 0 && (size_t)index < VECTOR_SIZE(device->Hrtf_List))
+ str = al_string_get_cstr(VECTOR_ELEM(device->Hrtf_List, index).name);
+ else
+ alcSetError(device, ALC_INVALID_VALUE);
+ break;
+
+ default:
+ alcSetError(device, ALC_INVALID_ENUM);
+ break;
+ }
+ if(device) ALCdevice_DecRef(device);
+
+ return str;
+}
+
+/* alcResetDeviceSOFT
+ *
+ * Resets the given device output, using the specified attribute list.
+ */
+ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs)
+{
+ ALCenum err;
+
+ LockLists();
+ if(!VerifyDevice(&device) || device->Type == Capture || !device->Connected)
+ {
+ UnlockLists();
+ alcSetError(device, ALC_INVALID_DEVICE);
+ if(device) ALCdevice_DecRef(device);
+ return ALC_FALSE;
+ }
+
+ if((err=UpdateDeviceParams(device, attribs)) != ALC_NO_ERROR)
+ {
+ UnlockLists();
+ alcSetError(device, err);
+ if(err == ALC_INVALID_DEVICE)
+ {
+ V0(device->Backend,lock)();
+ aluHandleDisconnect(device);
+ V0(device->Backend,unlock)();
+ }
+ ALCdevice_DecRef(device);
+ return ALC_FALSE;
+ }
+ UnlockLists();
+ ALCdevice_DecRef(device);
+
+ return ALC_TRUE;
+}
diff --git a/Alc/ALu.c b/Alc/ALu.c
index 488a7273..91c2aa7f 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -38,15 +38,13 @@
#include "mixer_defs.h"
-#include "midi/base.h"
+#include "backends/base.h"
-static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
- "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
-
struct ChanMap {
enum Channel channel;
ALfloat angle;
+ ALfloat elevation;
};
/* Cone scalar */
@@ -80,216 +78,400 @@ extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
-extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu);
-
-static 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;
-}
-
+extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac);
+extern inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac);
+
+extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w);
+
+extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
+ ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3);
+extern inline void aluMatrixfSet(aluMatrixf *matrix,
+ ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
+ ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
+ ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
+ ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33);
+
+extern inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
+ ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3);
+extern inline void aluMatrixdSet(aluMatrixd *matrix,
+ ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
+ ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
+ ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
+ ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33);
+
+
+/* NOTE: HRTF is set up a bit special in the device. By default, the device's
+ * DryBuffer, NumChannels, ChannelName, and Channel fields correspond to the
+ * output mixing format, and the DryBuffer is then converted and written to the
+ * backend's audio buffer.
+ *
+ * With HRTF, these fields correspond to a virtual format (typically B-Format),
+ * and the actual output is stored in DryBuffer[NumChannels] for the left
+ * channel and DryBuffer[NumChannels+1] for the right. As a final output step,
+ * the virtual channels will have HRTF applied and written to the actual
+ * output. Things like effects and B-Format decoding will want to write to the
+ * virtual channels so that they can be mixed with HRTF in full 3D.
+ *
+ * Sources that get mixed using HRTF directly (or that want to skip HRTF
+ * completely) will need to offset the output buffer so that they skip the
+ * virtual output and write to the actual output channels. This is the reason
+ * you'll see
+ *
+ * voice->Direct.OutBuffer += voice->Direct.OutChannels;
+ * voice->Direct.OutChannels = 2;
+ *
+ * at various points in the code where HRTF is explicitly used or bypassed.
+ */
-static HrtfMixerFunc SelectHrtfMixer(void)
+static inline HrtfMixerFunc SelectHrtfMixer(void)
{
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
- return MixDirect_Hrtf_SSE;
+ return MixHrtf_SSE;
#endif
#ifdef HAVE_NEON
if((CPUCapFlags&CPU_CAP_NEON))
- return MixDirect_Hrtf_Neon;
+ return MixHrtf_Neon;
#endif
- return MixDirect_Hrtf_C;
+ return MixHrtf_C;
}
-static DryMixerFunc SelectDirectMixer(void)
-{
-#ifdef HAVE_SSE
- if((CPUCapFlags&CPU_CAP_SSE))
- return MixDirect_SSE;
-#endif
-#ifdef HAVE_NEON
- if((CPUCapFlags&CPU_CAP_NEON))
- return MixDirect_Neon;
-#endif
- return MixDirect_C;
+static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
+{
+ outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
+ outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
+ outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
}
-static WetMixerFunc SelectSendMixer(void)
+static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2)
{
-#ifdef HAVE_SSE
- if((CPUCapFlags&CPU_CAP_SSE))
- return MixSend_SSE;
-#endif
-#ifdef HAVE_NEON
- if((CPUCapFlags&CPU_CAP_NEON))
- return MixSend_Neon;
-#endif
+ return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2];
+}
- return MixSend_C;
+static inline ALfloat aluNormalize(ALfloat *vec)
+{
+ ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
+ if(length > 0.0f)
+ {
+ ALfloat inv_length = 1.0f/length;
+ vec[0] *= inv_length;
+ vec[1] *= inv_length;
+ vec[2] *= inv_length;
+ }
+ return length;
}
-static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
+static inline void aluCrossproductd(const ALdouble *inVector1, const ALdouble *inVector2, ALdouble *outVector)
{
outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
}
-static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
+static inline ALdouble aluNormalized(ALdouble *vec)
+{
+ ALdouble length = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
+ if(length > 0.0)
+ {
+ ALdouble inv_length = 1.0/length;
+ vec[0] *= inv_length;
+ vec[1] *= inv_length;
+ vec[2] *= inv_length;
+ }
+ return length;
+}
+
+static inline ALvoid aluMatrixdFloat3(ALfloat *vec, ALfloat w, const aluMatrixd *mtx)
+{
+ ALdouble v[4] = { vec[0], vec[1], vec[2], w };
+
+ vec[0] = (ALfloat)(v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]);
+ vec[1] = (ALfloat)(v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]);
+ vec[2] = (ALfloat)(v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]);
+}
+
+static inline ALvoid aluMatrixdDouble3(ALdouble *vec, ALdouble w, const aluMatrixd *mtx)
+{
+ ALdouble v[4] = { vec[0], vec[1], vec[2], w };
+
+ vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0];
+ vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1];
+ vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2];
+}
+
+static inline aluVector aluMatrixdVector(const aluMatrixd *mtx, const aluVector *vec)
{
- return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
- inVector1[2]*inVector2[2];
+ aluVector v;
+ v.v[0] = (ALfloat)(vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]);
+ v.v[1] = (ALfloat)(vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]);
+ v.v[2] = (ALfloat)(vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]);
+ v.v[3] = (ALfloat)(vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]);
+ return v;
}
-static inline void aluNormalize(ALfloat *inVector)
+
+/* Prepares the interpolator for a given rate (determined by increment). A
+ * result of AL_FALSE indicates that the filter output will completely cut
+ * the input signal.
+ *
+ * With a bit of work, and a trade of memory for CPU cost, this could be
+ * modified for use with an interpolated increment for buttery-smooth pitch
+ * changes.
+ */
+static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
{
- ALfloat lengthsqr = aluDotproduct(inVector, inVector);
- if(lengthsqr > 0.0f)
+ static const ALfloat scaleBase = 1.510578918e-01f, scaleRange = 1.177936623e+00f;
+ static const ALuint m[BSINC_SCALE_COUNT] = { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 };
+ static const ALuint to[4][BSINC_SCALE_COUNT] =
+ {
+ { 0, 24, 408, 792, 1176, 1560, 1944, 2328, 2648, 2968, 3288, 3544, 3800, 4056, 4248, 4440 },
+ { 4632, 5016, 5400, 5784, 6168, 6552, 6936, 7320, 7640, 7960, 8280, 8536, 8792, 9048, 9240, 0 },
+ { 0, 9432, 9816, 10200, 10584, 10968, 11352, 11736, 12056, 12376, 12696, 12952, 13208, 13464, 13656, 13848 },
+ { 14040, 14424, 14808, 15192, 15576, 15960, 16344, 16728, 17048, 17368, 17688, 17944, 18200, 18456, 18648, 0 }
+ };
+ static const ALuint tm[2][BSINC_SCALE_COUNT] =
{
- ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
- inVector[0] *= inv_length;
- inVector[1] *= inv_length;
- inVector[2] *= inv_length;
+ { 0, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 },
+ { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 0 }
+ };
+ ALfloat sf;
+ ALuint si, pi;
+ ALboolean uncut = AL_TRUE;
+
+ if(increment > FRACTIONONE)
+ {
+ sf = (ALfloat)FRACTIONONE / increment;
+ if(sf < scaleBase)
+ {
+ /* Signal has been completely cut. The return result can be used
+ * to skip the filter (and output zeros) as an optimization.
+ */
+ sf = 0.0f;
+ si = 0;
+ uncut = AL_FALSE;
+ }
+ else
+ {
+ sf = (BSINC_SCALE_COUNT - 1) * (sf - scaleBase) * scaleRange;
+ si = fastf2u(sf);
+ /* The interpolation factor is fit to this diagonally-symmetric
+ * curve to reduce the transition ripple caused by interpolating
+ * different scales of the sinc function.
+ */
+ sf = 1.0f - cosf(asinf(sf - si));
+ }
}
+ else
+ {
+ sf = 0.0f;
+ si = BSINC_SCALE_COUNT - 1;
+ }
+
+ state->sf = sf;
+ state->m = m[si];
+ state->l = -(ALint)((m[si] / 2) - 1);
+ /* The CPU cost of this table re-mapping could be traded for the memory
+ * cost of a complete table map (1024 elements large).
+ */
+ for(pi = 0;pi < BSINC_PHASE_COUNT;pi++)
+ {
+ state->coeffs[pi].filter = &bsincTab[to[0][si] + tm[0][si]*pi];
+ state->coeffs[pi].scDelta = &bsincTab[to[1][si] + tm[1][si]*pi];
+ state->coeffs[pi].phDelta = &bsincTab[to[2][si] + tm[0][si]*pi];
+ state->coeffs[pi].spDelta = &bsincTab[to[3][si] + tm[1][si]*pi];
+ }
+ return uncut;
}
-static inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*restrict matrix)[4])
+
+/* Calculates the fade time from the changes in gain and listener to source
+ * angle between updates. The result is a the time, in seconds, for the
+ * transition to complete.
+ */
+static ALfloat CalcFadeTime(ALfloat oldGain, ALfloat newGain, const aluVector *olddir, const aluVector *newdir)
{
- ALfloat temp[4] = {
- vector[0], vector[1], vector[2], w
- };
+ ALfloat gainChange, angleChange, change;
+
+ /* Calculate the normalized dB gain change. */
+ newGain = maxf(newGain, 0.0001f);
+ oldGain = maxf(oldGain, 0.0001f);
+ gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
+
+ /* Calculate the angle change only when there is enough gain to notice it. */
+ angleChange = 0.0f;
+ if(gainChange > 0.0001f || newGain > 0.0001f)
+ {
+ /* No angle change when the directions are equal or degenerate (when
+ * both have zero length).
+ */
+ if(newdir->v[0] != olddir->v[0] || newdir->v[1] != olddir->v[1] || newdir->v[2] != olddir->v[2])
+ {
+ ALfloat dotp = aluDotproduct(olddir, newdir);
+ angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI;
+ }
+ }
+
+ /* Use the largest of the two changes, and apply a significance shaping
+ * function to it. The result is then scaled to cover a 15ms transition
+ * range.
+ */
+ change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
+ return minf(change, 1.0f) * 0.015f;
+}
+
+
+static void UpdateDryStepping(DirectParams *params, ALuint num_chans, ALuint steps)
+{
+ ALfloat delta;
+ ALuint i, j;
+
+ if(steps < 2)
+ {
+ for(i = 0;i < num_chans;i++)
+ {
+ MixGains *gains = params->Gains[i];
+ for(j = 0;j < params->OutChannels;j++)
+ {
+ gains[j].Current = gains[j].Target;
+ gains[j].Step = 0.0f;
+ }
+ }
+ params->Counter = 0;
+ return;
+ }
+
+ delta = 1.0f / (ALfloat)steps;
+ for(i = 0;i < num_chans;i++)
+ {
+ MixGains *gains = params->Gains[i];
+ for(j = 0;j < params->OutChannels;j++)
+ {
+ ALfloat diff = gains[j].Target - gains[j].Current;
+ if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD)
+ gains[j].Step = diff * delta;
+ else
+ {
+ gains[j].Current = gains[j].Target;
+ gains[j].Step = 0.0f;
+ }
+ }
+ }
+ params->Counter = steps;
+}
+
+static void UpdateWetStepping(SendParams *params, ALuint num_chans, ALuint steps)
+{
+ ALfloat delta;
+ ALuint i;
- vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
- vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
- vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
+ if(steps < 2)
+ {
+ for(i = 0;i < num_chans;i++)
+ {
+ params->Gains[i].Current = params->Gains[i].Target;
+ params->Gains[i].Step = 0.0f;
+ }
+ params->Counter = 0;
+ return;
+ }
+
+ delta = 1.0f / (ALfloat)steps;
+ for(i = 0;i < num_chans;i++)
+ {
+ ALfloat diff = params->Gains[i].Target - params->Gains[i].Current;
+ if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD)
+ params->Gains[i].Step = diff * delta;
+ else
+ {
+ params->Gains[i].Current = params->Gains[i].Target;
+ params->Gains[i].Step = 0.0f;
+ }
+ }
+ params->Counter = steps;
}
static ALvoid CalcListenerParams(ALlistener *Listener)
{
- ALfloat N[3], V[3], U[3], P[3];
+ ALdouble N[3], V[3], U[3], P[3];
/* AT then UP */
N[0] = Listener->Forward[0];
N[1] = Listener->Forward[1];
N[2] = Listener->Forward[2];
- aluNormalize(N);
+ aluNormalized(N);
V[0] = Listener->Up[0];
V[1] = Listener->Up[1];
V[2] = Listener->Up[2];
- aluNormalize(V);
+ aluNormalized(V);
/* Build and normalize right-vector */
- aluCrossproduct(N, V, U);
- aluNormalize(U);
-
- Listener->Params.Matrix[0][0] = U[0];
- Listener->Params.Matrix[0][1] = V[0];
- Listener->Params.Matrix[0][2] = -N[0];
- Listener->Params.Matrix[0][3] = 0.0f;
- Listener->Params.Matrix[1][0] = U[1];
- Listener->Params.Matrix[1][1] = V[1];
- Listener->Params.Matrix[1][2] = -N[1];
- Listener->Params.Matrix[1][3] = 0.0f;
- Listener->Params.Matrix[2][0] = U[2];
- Listener->Params.Matrix[2][1] = V[2];
- Listener->Params.Matrix[2][2] = -N[2];
- Listener->Params.Matrix[2][3] = 0.0f;
- Listener->Params.Matrix[3][0] = 0.0f;
- Listener->Params.Matrix[3][1] = 0.0f;
- Listener->Params.Matrix[3][2] = 0.0f;
- Listener->Params.Matrix[3][3] = 1.0f;
-
- P[0] = Listener->Position[0];
- P[1] = Listener->Position[1];
- P[2] = Listener->Position[2];
- aluMatrixVector(P, 1.0f, Listener->Params.Matrix);
- Listener->Params.Matrix[3][0] = -P[0];
- Listener->Params.Matrix[3][1] = -P[1];
- Listener->Params.Matrix[3][2] = -P[2];
-
- Listener->Params.Velocity[0] = Listener->Velocity[0];
- Listener->Params.Velocity[1] = Listener->Velocity[1];
- Listener->Params.Velocity[2] = Listener->Velocity[2];
- aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix);
+ aluCrossproductd(N, V, U);
+ aluNormalized(U);
+
+ aluMatrixdSet(&Listener->Params.Matrix,
+ U[0], V[0], -N[0], 0.0,
+ U[1], V[1], -N[1], 0.0,
+ U[2], V[2], -N[2], 0.0,
+ 0.0, 0.0, 0.0, 1.0
+ );
+
+ P[0] = Listener->Position.v[0];
+ P[1] = Listener->Position.v[1];
+ P[2] = Listener->Position.v[2];
+ aluMatrixdDouble3(P, 1.0, &Listener->Params.Matrix);
+ aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f);
+
+ Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &Listener->Velocity);
}
-ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
+ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
{
- static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
- static const struct ChanMap StereoMap[2] = {
- { FrontLeft, DEG2RAD(-30.0f) },
- { FrontRight, DEG2RAD( 30.0f) }
- };
- static const struct ChanMap StereoWideMap[2] = {
- { FrontLeft, DEG2RAD(-90.0f) },
- { FrontRight, DEG2RAD( 90.0f) }
- };
- static const struct ChanMap RearMap[2] = {
- { BackLeft, DEG2RAD(-150.0f) },
- { BackRight, DEG2RAD( 150.0f) }
- };
- static const struct ChanMap QuadMap[4] = {
- { FrontLeft, DEG2RAD( -45.0f) },
- { FrontRight, DEG2RAD( 45.0f) },
- { BackLeft, DEG2RAD(-135.0f) },
- { BackRight, DEG2RAD( 135.0f) }
- };
- static const struct ChanMap X51Map[6] = {
- { FrontLeft, DEG2RAD( -30.0f) },
- { FrontRight, DEG2RAD( 30.0f) },
- { FrontCenter, DEG2RAD( 0.0f) },
- { LFE, 0.0f },
- { BackLeft, DEG2RAD(-110.0f) },
- { BackRight, DEG2RAD( 110.0f) }
- };
- static const struct ChanMap X61Map[7] = {
- { FrontLeft, DEG2RAD(-30.0f) },
- { FrontRight, DEG2RAD( 30.0f) },
- { FrontCenter, DEG2RAD( 0.0f) },
- { LFE, 0.0f },
- { BackCenter, DEG2RAD(180.0f) },
- { SideLeft, DEG2RAD(-90.0f) },
- { SideRight, DEG2RAD( 90.0f) }
- };
- static const struct ChanMap X71Map[8] = {
- { FrontLeft, DEG2RAD( -30.0f) },
- { FrontRight, DEG2RAD( 30.0f) },
- { FrontCenter, DEG2RAD( 0.0f) },
- { LFE, 0.0f },
- { BackLeft, DEG2RAD(-150.0f) },
- { BackRight, DEG2RAD( 150.0f) },
- { SideLeft, DEG2RAD( -90.0f) },
- { SideRight, DEG2RAD( 90.0f) }
+ static const struct ChanMap MonoMap[1] = {
+ { FrontCenter, 0.0f, 0.0f }
+ }, StereoMap[2] = {
+ { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
+ { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
+ }, StereoWideMap[2] = {
+ { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
+ { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
+ }, RearMap[2] = {
+ { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
+ { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
+ }, QuadMap[4] = {
+ { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
+ { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
+ { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
+ { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
+ }, X51Map[6] = {
+ { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
+ { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
+ { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
+ { LFE, 0.0f, 0.0f },
+ { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
+ { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
+ }, X61Map[7] = {
+ { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
+ { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
+ { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
+ { LFE, 0.0f, 0.0f },
+ { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
+ { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
+ { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
+ }, X71Map[8] = {
+ { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
+ { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
+ { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
+ { LFE, 0.0f, 0.0f },
+ { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
+ { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
+ { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
+ { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
};
ALCdevice *Device = ALContext->Device;
- const ALsource *ALSource = src->Source;
ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
ALbufferlistitem *BufferListItem;
enum FmtChannels Channels;
@@ -297,14 +479,14 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
ALfloat WetGain[MAX_SENDS];
ALfloat WetGainHF[MAX_SENDS];
ALfloat WetGainLF[MAX_SENDS];
- ALint NumSends, Frequency;
+ ALuint NumSends, Frequency;
+ ALboolean Relative;
const struct ChanMap *chans = NULL;
- enum Resampler Resampler;
- ALint num_channels = 0;
+ ALuint num_channels = 0;
ALboolean DirectChannels;
- ALfloat hwidth = 0.0f;
+ ALboolean isbformat = AL_FALSE;
ALfloat Pitch;
- ALint i, j, c;
+ ALuint i, j, c;
/* Get device properties */
NumSends = Device->NumAuxSends;
@@ -318,24 +500,25 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
MinVolume = ALSource->MinGain;
MaxVolume = ALSource->MaxGain;
Pitch = ALSource->Pitch;
- Resampler = ALSource->Resampler;
+ Relative = ALSource->HeadRelative;
DirectChannels = ALSource->DirectChannels;
- src->Direct.OutBuffer = Device->DryBuffer;
+ voice->Direct.OutBuffer = Device->DryBuffer;
+ voice->Direct.OutChannels = Device->NumChannels;
for(i = 0;i < NumSends;i++)
{
ALeffectslot *Slot = ALSource->Send[i].Slot;
if(!Slot && i == 0)
Slot = Device->DefaultSlot;
if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
- src->Send[i].OutBuffer = NULL;
+ voice->Send[i].OutBuffer = NULL;
else
- src->Send[i].OutBuffer = Slot->WetBuffer;
+ voice->Send[i].OutBuffer = Slot->WetBuffer;
}
/* Calculate the stepping value */
Channels = FmtMono;
- BufferListItem = ALSource->queue;
+ BufferListItem = ATOMIC_LOAD(&ALSource->queue);
while(BufferListItem != NULL)
{
ALbuffer *ALBuffer;
@@ -343,14 +526,10 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
{
Pitch = Pitch * ALBuffer->Frequency / Frequency;
if(Pitch > (ALfloat)MAX_PITCH)
- src->Step = MAX_PITCH<<FRACTIONBITS;
+ voice->Step = MAX_PITCH<<FRACTIONBITS;
else
- {
- src->Step = fastf2i(Pitch*FRACTIONONE);
- if(src->Step == 0)
- src->Step = 1;
- }
- src->Resample = SelectResampler(Resampler, src->Step);
+ voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
+ BsincPrepare(voice->Step, &voice->SincState);
Channels = ALBuffer->FmtChannels;
break;
@@ -379,21 +558,13 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
break;
case FmtStereo:
- if(!(Device->Flags&DEVICE_WIDE_STEREO))
- {
- /* HACK: Place the stereo channels at +/-90 degrees when using non-
- * HRTF stereo output. This helps reduce the "monoization" caused
- * by them panning towards the center. */
- if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
- chans = StereoWideMap;
- else
- chans = StereoMap;
- }
- else
- {
+ /* HACK: Place the stereo channels at +/-90 degrees when using non-
+ * HRTF stereo output. This helps reduce the "monoization" caused
+ * by them panning towards the center. */
+ if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
chans = StereoWideMap;
- hwidth = DEG2RAD(60.0f);
- }
+ else
+ chans = StereoMap;
num_channels = 2;
break;
@@ -421,237 +592,242 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
chans = X71Map;
num_channels = 8;
break;
+
+ case FmtBFormat2D:
+ num_channels = 3;
+ isbformat = AL_TRUE;
+ DirectChannels = AL_FALSE;
+ break;
+
+ case FmtBFormat3D:
+ num_channels = 4;
+ isbformat = AL_TRUE;
+ DirectChannels = AL_FALSE;
+ break;
}
- if(DirectChannels != AL_FALSE)
+ if(isbformat)
{
- for(c = 0;c < num_channels;c++)
+ ALfloat N[3], V[3], U[3];
+ aluMatrixf matrix;
+ ALfloat scale;
+
+ /* AT then UP */
+ N[0] = ALSource->Orientation[0][0];
+ N[1] = ALSource->Orientation[0][1];
+ N[2] = ALSource->Orientation[0][2];
+ aluNormalize(N);
+ V[0] = ALSource->Orientation[1][0];
+ V[1] = ALSource->Orientation[1][1];
+ V[2] = ALSource->Orientation[1][2];
+ aluNormalize(V);
+ if(!Relative)
{
- ALfloat *restrict Target = src->Direct.Mix.Gains[c].Target;
- for(j = 0;j < MaxChannels;j++)
- Target[j] = 0.0f;
+ const aluMatrixd *lmatrix = &ALContext->Listener->Params.Matrix;
+ aluMatrixdFloat3(N, 0.0f, lmatrix);
+ aluMatrixdFloat3(V, 0.0f, lmatrix);
}
+ /* Build and normalize right-vector */
+ aluCrossproduct(N, V, U);
+ aluNormalize(U);
+
+ /* Build a rotate + conversion matrix (B-Format -> N3D), and include
+ * scaling for first-order content. */
+ scale = Device->AmbiScale * 1.732050808f;
+ aluMatrixfSet(&matrix,
+ 1.414213562f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale,
+ 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale,
+ 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale
+ );
for(c = 0;c < num_channels;c++)
{
- ALfloat *restrict Target = src->Direct.Mix.Gains[c].Target;
- for(i = 0;i < (ALint)Device->NumChan;i++)
- {
- enum Channel chan = Device->Speaker2Chan[i];
- if(chan == chans[c].channel)
- {
- Target[chan] = DryGain;
- break;
- }
- }
- }
+ MixGains *gains = voice->Direct.Gains[c];
+ ALfloat Target[MAX_OUTPUT_CHANNELS];
- if(!src->Direct.Moving)
- {
- for(i = 0;i < num_channels;i++)
- {
- ALfloat *restrict Current = src->Direct.Mix.Gains[i].Current;
- ALfloat *restrict Step = src->Direct.Mix.Gains[i].Step;
- ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
- for(j = 0;j < MaxChannels;j++)
- {
- Current[j] = Target[j];
- Step[j] = 1.0f;
- }
- }
- src->Direct.Counter = 0;
- src->Direct.Moving = AL_TRUE;
+ ComputeBFormatGains(Device, matrix.m[c], DryGain, Target);
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ gains[i].Target = Target[i];
}
- else
+ UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
+ voice->Direct.Moving = AL_TRUE;
+
+ voice->IsHrtf = AL_FALSE;
+
+ for(i = 0;i < NumSends;i++)
{
- for(i = 0;i < num_channels;i++)
- {
- ALfloat *restrict Current = src->Direct.Mix.Gains[i].Current;
- ALfloat *restrict Step = src->Direct.Mix.Gains[i].Step;
- ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
- for(j = 0;j < MaxChannels;j++)
- {
- ALfloat cur = maxf(Current[j], FLT_EPSILON);
- ALfloat trg = maxf(Target[j], FLT_EPSILON);
- if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
- Step[j] = powf(trg/cur, 1.0f/64.0f);
- else
- Step[j] = 1.0f;
- Current[j] = cur;
- }
- }
- src->Direct.Counter = 64;
+ /* Only the first channel of B-Format buffers (W) goes to auxiliary
+ * sends. It also needs to be scaled by sqrt(2) to account for the
+ * signal being scaled by sqrt(1/2).
+ */
+ voice->Send[i].Gains[0].Target = WetGain[i] * 1.414213562f;
+ for(c = 1;c < num_channels;c++)
+ voice->Send[i].Gains[c].Target = 0.0f;
+ UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0));
+ voice->Send[i].Moving = AL_TRUE;
}
-
- src->IsHrtf = AL_FALSE;
- src->Dry.Mix = SelectDirectMixer();
}
- else if(Device->Hrtf)
+ else
{
- for(c = 0;c < num_channels;c++)
+ if(DirectChannels)
{
- if(chans[c].channel == LFE)
+ if(Device->Hrtf)
{
- /* Skip LFE */
- src->Direct.Mix.Hrtf.Params[c].Delay[0] = 0;
- src->Direct.Mix.Hrtf.Params[c].Delay[1] = 0;
- for(i = 0;i < HRIR_LENGTH;i++)
+ /* DirectChannels with HRTF enabled. Skip the virtual channels
+ * and write FrontLeft and FrontRight inputs to the first and
+ * second outputs.
+ */
+ voice->Direct.OutBuffer += voice->Direct.OutChannels;
+ voice->Direct.OutChannels = 2;
+ for(c = 0;c < num_channels;c++)
{
- src->Direct.Mix.Hrtf.Params[c].Coeffs[i][0] = 0.0f;
- src->Direct.Mix.Hrtf.Params[c].Coeffs[i][1] = 0.0f;
+ MixGains *gains = voice->Direct.Gains[c];
+
+ for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
+ gains[j].Target = 0.0f;
+
+ if(chans[c].channel == FrontLeft)
+ gains[0].Target = DryGain;
+ else if(chans[c].channel == FrontRight)
+ gains[1].Target = DryGain;
}
}
- else
+ else for(c = 0;c < num_channels;c++)
{
- /* Get the static HRIR coefficients and delays for this
- * channel. */
- GetLerpedHrtfCoeffs(Device->Hrtf,
- 0.0f, chans[c].angle, DryGain,
- src->Direct.Mix.Hrtf.Params[c].Coeffs,
- src->Direct.Mix.Hrtf.Params[c].Delay);
- }
- }
- src->Direct.Counter = 0;
- src->Direct.Moving = AL_TRUE;
- src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
+ MixGains *gains = voice->Direct.Gains[c];
+ int idx;
- src->IsHrtf = AL_TRUE;
- src->Dry.HrtfMix = SelectHrtfMixer();
- }
- else
- {
- for(i = 0;i < num_channels;i++)
- {
- ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
- for(j = 0;j < MaxChannels;j++)
- Target[j] = 0.0f;
- }
-
- DryGain *= lerp(1.0f, 1.0f/sqrtf((float)Device->NumChan), hwidth/F_PI);
- for(c = 0;c < num_channels;c++)
- {
- ALfloat *restrict Target = src->Direct.Mix.Gains[c].Target;
- /* Special-case LFE */
- if(chans[c].channel == LFE)
- {
- Target[chans[c].channel] = DryGain;
- continue;
+ for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
+ gains[j].Target = 0.0f;
+ if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
+ gains[idx].Target = DryGain;
}
- ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain, Target);
- }
+ UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
+ voice->Direct.Moving = AL_TRUE;
- if(!src->Direct.Moving)
+ voice->IsHrtf = AL_FALSE;
+ }
+ else if(Device->Hrtf_Mode == FullHrtf)
{
- for(i = 0;i < num_channels;i++)
+ /* Full HRTF rendering. Skip the virtual channels and render each
+ * input channel to the real outputs.
+ */
+ voice->Direct.OutBuffer += voice->Direct.OutChannels;
+ voice->Direct.OutChannels = 2;
+ for(c = 0;c < num_channels;c++)
{
- ALfloat *restrict Current = src->Direct.Mix.Gains[i].Current;
- ALfloat *restrict Step = src->Direct.Mix.Gains[i].Step;
- ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
- for(j = 0;j < MaxChannels;j++)
+ if(chans[c].channel == LFE)
{
- Current[j] = Target[j];
- Step[j] = 1.0f;
+ /* Skip LFE */
+ voice->Direct.Hrtf[c].Params.Delay[0] = 0;
+ voice->Direct.Hrtf[c].Params.Delay[1] = 0;
+ for(i = 0;i < HRIR_LENGTH;i++)
+ {
+ voice->Direct.Hrtf[c].Params.Coeffs[i][0] = 0.0f;
+ voice->Direct.Hrtf[c].Params.Coeffs[i][1] = 0.0f;
+ }
+ }
+ else
+ {
+ /* Get the static HRIR coefficients and delays for this
+ * channel. */
+ GetLerpedHrtfCoeffs(Device->Hrtf,
+ chans[c].elevation, chans[c].angle, 1.0f, DryGain,
+ voice->Direct.Hrtf[c].Params.Coeffs,
+ voice->Direct.Hrtf[c].Params.Delay
+ );
}
}
- src->Direct.Counter = 0;
- src->Direct.Moving = AL_TRUE;
+ voice->Direct.Counter = 0;
+ voice->Direct.Moving = AL_TRUE;
+
+ voice->IsHrtf = AL_TRUE;
}
else
{
- for(i = 0;i < num_channels;i++)
+ /* Basic or no HRTF rendering. Use normal panning to the output. */
+ for(c = 0;c < num_channels;c++)
{
- ALfloat *restrict Current = src->Direct.Mix.Gains[i].Current;
- ALfloat *restrict Step = src->Direct.Mix.Gains[i].Step;
- ALfloat *restrict Target = src->Direct.Mix.Gains[i].Target;
- for(j = 0;j < MaxChannels;j++)
+ MixGains *gains = voice->Direct.Gains[c];
+ ALfloat Target[MAX_OUTPUT_CHANNELS];
+
+ /* Special-case LFE */
+ if(chans[c].channel == LFE)
{
- ALfloat trg = maxf(Target[j], FLT_EPSILON);
- ALfloat cur = maxf(Current[j], FLT_EPSILON);
- if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
- Step[j] = powf(trg/cur, 1.0f/64.0f);
- else
- Step[j] = 1.0f;
- Current[j] = cur;
+ int idx;
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ gains[i].Target = 0.0f;
+ if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
+ gains[idx].Target = DryGain;
+ continue;
}
+
+ ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target);
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ gains[i].Target = Target[i];
}
- src->Direct.Counter = 64;
- }
+ UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
+ voice->Direct.Moving = AL_TRUE;
- src->IsHrtf = AL_FALSE;
- src->Dry.Mix = SelectDirectMixer();
- }
- for(i = 0;i < NumSends;i++)
- {
- src->Send[i].Gain.Target = WetGain[i];
- if(!src->Send[i].Moving)
- {
- src->Send[i].Gain.Current = src->Send[i].Gain.Target;
- src->Send[i].Gain.Step = 1.0f;
- src->Send[i].Counter = 0;
- src->Send[i].Moving = AL_TRUE;
+ voice->IsHrtf = AL_FALSE;
}
- else
+ for(i = 0;i < NumSends;i++)
{
- ALfloat cur = maxf(src->Send[i].Gain.Current, FLT_EPSILON);
- ALfloat trg = maxf(src->Send[i].Gain.Target, FLT_EPSILON);
- if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
- src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f);
- else
- src->Send[i].Gain.Step = 1.0f;
- src->Send[i].Gain.Current = cur;
- src->Send[i].Counter = 64;
+ for(c = 0;c < num_channels;c++)
+ voice->Send[i].Gains[c].Target = WetGain[i];
+ UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0));
+ voice->Send[i].Moving = AL_TRUE;
}
}
- src->WetMix = SelectSendMixer();
{
- ALfloat gainhf = maxf(0.01f, DryGainHF);
- ALfloat gainlf = maxf(0.01f, DryGainLF);
ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
+ DryGainHF = maxf(DryGainHF, 0.0001f);
+ DryGainLF = maxf(DryGainLF, 0.0001f);
for(c = 0;c < num_channels;c++)
{
- src->Direct.Filters[c].ActiveType = AF_None;
- if(gainhf != 1.0f) src->Direct.Filters[c].ActiveType |= AF_LowPass;
- if(gainlf != 1.0f) src->Direct.Filters[c].ActiveType |= AF_HighPass;
+ voice->Direct.Filters[c].ActiveType = AF_None;
+ if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
+ if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
ALfilterState_setParams(
- &src->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
- hfscale, 0.0f
+ &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf,
+ DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
);
ALfilterState_setParams(
- &src->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
- lfscale, 0.0f
+ &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf,
+ DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
);
}
}
for(i = 0;i < NumSends;i++)
{
- ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
- ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
+ WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
+ WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
for(c = 0;c < num_channels;c++)
{
- src->Send[i].Filters[c].ActiveType = AF_None;
- if(gainhf != 1.0f) src->Send[i].Filters[c].ActiveType |= AF_LowPass;
- if(gainlf != 1.0f) src->Send[i].Filters[c].ActiveType |= AF_HighPass;
+ voice->Send[i].Filters[c].ActiveType = AF_None;
+ if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
+ if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
ALfilterState_setParams(
- &src->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
- hfscale, 0.0f
+ &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf,
+ WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
);
ALfilterState_setParams(
- &src->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
- lfscale, 0.0f
+ &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf,
+ WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
);
}
}
}
-ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
+ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
{
ALCdevice *Device = ALContext->Device;
- const ALsource *ALSource = src->Source;
- ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3];
+ aluVector Position, Velocity, Direction, SourceToListener;
ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
@@ -674,7 +850,6 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
ALfloat WetGainLF[MAX_SENDS];
ALboolean WetGainAuto;
ALboolean WetGainHFAuto;
- enum Resampler Resampler;
ALfloat Pitch;
ALuint Frequency;
ALint NumSends;
@@ -703,16 +878,9 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
MinVolume = ALSource->MinGain;
MaxVolume = ALSource->MaxGain;
Pitch = ALSource->Pitch;
- Resampler = ALSource->Resampler;
- Position[0] = ALSource->Position[0];
- Position[1] = ALSource->Position[1];
- Position[2] = ALSource->Position[2];
- Direction[0] = ALSource->Orientation[0];
- Direction[1] = ALSource->Orientation[1];
- Direction[2] = ALSource->Orientation[2];
- Velocity[0] = ALSource->Velocity[0];
- Velocity[1] = ALSource->Velocity[1];
- Velocity[2] = ALSource->Velocity[2];
+ Position = ALSource->Position;
+ Direction = ALSource->Direction;
+ Velocity = ALSource->Velocity;
MinDist = ALSource->RefDistance;
MaxDist = ALSource->MaxDistance;
Rolloff = ALSource->RollOffFactor;
@@ -724,7 +892,8 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
WetGainHFAuto = ALSource->WetGainHFAuto;
RoomRolloffBase = ALSource->RoomRolloffFactor;
- src->Direct.OutBuffer = Device->DryBuffer;
+ voice->Direct.OutBuffer = Device->DryBuffer;
+ voice->Direct.OutChannels = Device->NumChannels;
for(i = 0;i < NumSends;i++)
{
ALeffectslot *Slot = ALSource->Send[i].Slot;
@@ -764,37 +933,37 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
}
if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
- src->Send[i].OutBuffer = NULL;
+ voice->Send[i].OutBuffer = NULL;
else
- src->Send[i].OutBuffer = Slot->WetBuffer;
+ voice->Send[i].OutBuffer = Slot->WetBuffer;
}
/* Transform source to listener space (convert to head relative) */
if(ALSource->HeadRelative == AL_FALSE)
{
- ALfloat (*restrict Matrix)[4] = ALContext->Listener->Params.Matrix;
+ const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix;
/* Transform source vectors */
- aluMatrixVector(Position, 1.0f, Matrix);
- aluMatrixVector(Direction, 0.0f, Matrix);
- aluMatrixVector(Velocity, 0.0f, Matrix);
+ Position = aluMatrixdVector(Matrix, &Position);
+ Velocity = aluMatrixdVector(Matrix, &Velocity);
+ Direction = aluMatrixdVector(Matrix, &Direction);
}
else
{
- const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
+ const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
/* Offset the source velocity to be relative of the listener velocity */
- Velocity[0] += ListenerVel[0];
- Velocity[1] += ListenerVel[1];
- Velocity[2] += ListenerVel[2];
+ Velocity.v[0] += lvelocity->v[0];
+ Velocity.v[1] += lvelocity->v[1];
+ Velocity.v[2] += lvelocity->v[2];
}
- SourceToListener[0] = -Position[0];
- SourceToListener[1] = -Position[1];
- SourceToListener[2] = -Position[2];
- aluNormalize(SourceToListener);
- aluNormalize(Direction);
+ aluNormalize(Direction.v);
+ SourceToListener.v[0] = -Position.v[0];
+ SourceToListener.v[1] = -Position.v[1];
+ SourceToListener.v[2] = -Position.v[2];
+ SourceToListener.v[3] = 0.0f;
+ Distance = aluNormalize(SourceToListener.v);
/* Calculate distance attenuation */
- Distance = sqrtf(aluDotproduct(Position, Position));
ClampedDist = Distance;
Attenuation = 1.0f;
@@ -811,12 +980,12 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
case InverseDistance:
if(MinDist > 0.0f)
{
- if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
- Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
+ ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
+ if(dist > 0.0f) Attenuation = MinDist / dist;
for(i = 0;i < NumSends;i++)
{
- if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
- RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
+ dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
+ if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
}
}
break;
@@ -866,7 +1035,7 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
/* Distance-based air absorption */
if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
{
- ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
+ ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
for(i = 0;i < NumSends;i++)
WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
@@ -891,7 +1060,7 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
}
/* Calculate directional soundcones */
- Angle = RAD2DEG(acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale) * 2.0f;
+ Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
if(Angle > InnerAngle && Angle <= OuterAngle)
{
ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
@@ -942,7 +1111,7 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
/* Calculate velocity-based doppler effect */
if(DopplerFactor > 0.0f)
{
- const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
+ const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
ALfloat VSS, VLS;
if(SpeedOfSound < 1.0f)
@@ -951,14 +1120,14 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
SpeedOfSound = 1.0f;
}
- VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
- VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
+ VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
+ VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
}
- BufferListItem = ALSource->queue;
+ BufferListItem = ATOMIC_LOAD(&ALSource->queue);
while(BufferListItem != NULL)
{
ALbuffer *ALBuffer;
@@ -968,251 +1137,247 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
* frequency, and output frequency. */
Pitch = Pitch * ALBuffer->Frequency / Frequency;
if(Pitch > (ALfloat)MAX_PITCH)
- src->Step = MAX_PITCH<<FRACTIONBITS;
+ voice->Step = MAX_PITCH<<FRACTIONBITS;
else
- {
- src->Step = fastf2i(Pitch*FRACTIONONE);
- if(src->Step == 0)
- src->Step = 1;
- }
- src->Resample = SelectResampler(Resampler, src->Step);
+ voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
+ BsincPrepare(voice->Step, &voice->SincState);
break;
}
BufferListItem = BufferListItem->next;
}
- if(Device->Hrtf)
+ if(Device->Hrtf_Mode == FullHrtf)
{
- /* Use a binaural HRTF algorithm for stereo headphone playback */
- ALfloat delta, ev = 0.0f, az = 0.0f;
+ /* Full HRTF rendering. Skip the virtual channels and render to the
+ * real outputs.
+ */
+ aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
+ ALfloat ev = 0.0f, az = 0.0f;
+ ALfloat radius = ALSource->Radius;
+ ALfloat dirfact = 1.0f;
+
+ voice->Direct.OutBuffer += voice->Direct.OutChannels;
+ voice->Direct.OutChannels = 2;
if(Distance > FLT_EPSILON)
{
- ALfloat invlen = 1.0f/Distance;
- Position[0] *= invlen;
- Position[1] *= invlen;
- Position[2] *= invlen;
+ dir.v[0] = -SourceToListener.v[0];
+ dir.v[1] = -SourceToListener.v[1];
+ dir.v[2] = -SourceToListener.v[2] * ZScale;
/* Calculate elevation and azimuth only when the source is not at
* the listener. This prevents +0 and -0 Z from producing
* inconsistent panning. Also, clamp Y in case FP precision errors
* cause it to land outside of -1..+1. */
- ev = asinf(clampf(Position[1], -1.0f, 1.0f));
- az = atan2f(Position[0], -Position[2]*ZScale);
+ ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
+ az = atan2f(dir.v[0], -dir.v[2]);
+ }
+ if(radius > 0.0f)
+ {
+ if(radius >= Distance)
+ dirfact *= Distance / radius * 0.5f;
+ else
+ dirfact *= 1.0f - (asinf(radius / Distance) / F_PI);
}
/* Check to see if the HRIR is already moving. */
- if(src->Direct.Moving)
+ if(voice->Direct.Moving)
{
- /* Calculate the normalized HRTF transition factor (delta). */
- delta = CalcHrtfDelta(src->Direct.Mix.Hrtf.Gain, DryGain,
- src->Direct.Mix.Hrtf.Dir, Position);
+ ALfloat delta;
+ delta = CalcFadeTime(voice->Direct.LastGain, DryGain,
+ &voice->Direct.LastDir, &dir);
/* If the delta is large enough, get the moving HRIR target
- * coefficients, target delays, steppping values, and counter. */
- if(delta > 0.001f)
+ * coefficients, target delays, steppping values, and counter.
+ */
+ if(delta > 0.000015f)
{
ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
- ev, az, DryGain, delta,
- src->Direct.Counter,
- src->Direct.Mix.Hrtf.Params[0].Coeffs,
- src->Direct.Mix.Hrtf.Params[0].Delay,
- src->Direct.Mix.Hrtf.Params[0].CoeffStep,
- src->Direct.Mix.Hrtf.Params[0].DelayStep);
- src->Direct.Counter = counter;
- src->Direct.Mix.Hrtf.Gain = DryGain;
- src->Direct.Mix.Hrtf.Dir[0] = Position[0];
- src->Direct.Mix.Hrtf.Dir[1] = Position[1];
- src->Direct.Mix.Hrtf.Dir[2] = Position[2];
+ ev, az, dirfact, DryGain, delta, voice->Direct.Counter,
+ voice->Direct.Hrtf[0].Params.Coeffs, voice->Direct.Hrtf[0].Params.Delay,
+ voice->Direct.Hrtf[0].Params.CoeffStep, voice->Direct.Hrtf[0].Params.DelayStep
+ );
+ voice->Direct.Counter = counter;
+ voice->Direct.LastGain = DryGain;
+ voice->Direct.LastDir = dir;
}
}
else
{
/* Get the initial (static) HRIR coefficients and delays. */
- GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain,
- src->Direct.Mix.Hrtf.Params[0].Coeffs,
- src->Direct.Mix.Hrtf.Params[0].Delay);
- src->Direct.Counter = 0;
- src->Direct.Moving = AL_TRUE;
- src->Direct.Mix.Hrtf.Gain = DryGain;
- src->Direct.Mix.Hrtf.Dir[0] = Position[0];
- src->Direct.Mix.Hrtf.Dir[1] = Position[1];
- src->Direct.Mix.Hrtf.Dir[2] = Position[2];
+ GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
+ voice->Direct.Hrtf[0].Params.Coeffs,
+ voice->Direct.Hrtf[0].Params.Delay);
+ voice->Direct.Counter = 0;
+ voice->Direct.Moving = AL_TRUE;
+ voice->Direct.LastGain = DryGain;
+ voice->Direct.LastDir = dir;
}
- src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
- src->IsHrtf = AL_TRUE;
- src->Dry.HrtfMix = SelectHrtfMixer();
+ voice->IsHrtf = AL_TRUE;
}
else
{
- ALfloat *restrict Target = src->Direct.Mix.Gains[0].Target;
- ALfloat DirGain = 0.0f;
- ALfloat AmbientGain;
-
- for(j = 0;j < MaxChannels;j++)
- Target[j] = 0.0f;
+ /* Basic or no HRTF rendering. Use normal panning to the output. */
+ MixGains *gains = voice->Direct.Gains[0];
+ ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
+ ALfloat radius = ALSource->Radius;
+ ALfloat Target[MAX_OUTPUT_CHANNELS];
- /* Normalize the length, and compute panned gains. */
+ /* Get the localized direction, and compute panned gains. */
if(Distance > FLT_EPSILON)
{
- ALfloat invlen = 1.0f/Distance;
- Position[0] *= invlen;
- Position[1] *= invlen;
- Position[2] *= invlen;
-
- DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]);
- ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f,
- DryGain*DirGain, Target);
+ dir[0] = -SourceToListener.v[0];
+ dir[1] = -SourceToListener.v[1];
+ dir[2] = -SourceToListener.v[2] * ZScale;
}
-
- /* Adjustment for vertical offsets. Not the greatest, but simple
- * enough. */
- AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain);
- for(i = 0;i < (ALint)Device->NumChan;i++)
+ if(radius > 0.0f)
{
- enum Channel chan = Device->Speaker2Chan[i];
- Target[chan] = maxf(Target[chan], AmbientGain);
+ ALfloat dirfact;
+ if(radius >= Distance)
+ dirfact = Distance / radius * 0.5f;
+ else
+ dirfact = 1.0f - (asinf(radius / Distance) / F_PI);
+ dir[0] *= dirfact;
+ dir[1] *= dirfact;
+ dir[2] *= dirfact;
}
+ ComputeDirectionalGains(Device, dir, DryGain, Target);
- if(!src->Direct.Moving)
- {
- ALfloat *restrict Current = src->Direct.Mix.Gains[0].Current;
- ALfloat *restrict Step = src->Direct.Mix.Gains[0].Step;
- for(j = 0;j < MaxChannels;j++)
- {
- Current[j] = Target[j];
- Step[j] = 1.0f;
- }
- src->Direct.Counter = 0;
- src->Direct.Moving = AL_TRUE;
- }
- else
- {
- ALfloat *restrict Current = src->Direct.Mix.Gains[0].Current;
- ALfloat *restrict Step = src->Direct.Mix.Gains[0].Step;
- for(j = 0;j < MaxChannels;j++)
- {
- ALfloat cur = maxf(Current[j], FLT_EPSILON);
- ALfloat trg = maxf(Target[j], FLT_EPSILON);
- if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
- Step[j] = powf(trg/cur, 1.0f/64.0f);
- else
- Step[j] = 1.0f;
- Current[j] = cur;
- }
- src->Direct.Counter = 64;
- }
+ for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
+ gains[j].Target = Target[j];
+ UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0));
+ voice->Direct.Moving = AL_TRUE;
- src->IsHrtf = AL_FALSE;
- src->Dry.Mix = SelectDirectMixer();
+ voice->IsHrtf = AL_FALSE;
}
for(i = 0;i < NumSends;i++)
{
- src->Send[i].Gain.Target = WetGain[i];
- if(!src->Send[i].Moving)
- {
- src->Send[i].Gain.Current = src->Send[i].Gain.Target;
- src->Send[i].Gain.Step = 1.0f;
- src->Send[i].Counter = 0;
- src->Send[i].Moving = AL_TRUE;
- }
- else
- {
- ALfloat cur = maxf(src->Send[i].Gain.Current, FLT_EPSILON);
- ALfloat trg = maxf(src->Send[i].Gain.Target, FLT_EPSILON);
- if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
- src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f);
- else
- src->Send[i].Gain.Step = 1.0f;
- src->Send[i].Gain.Current = cur;
- src->Send[i].Counter = 64;
- }
+ voice->Send[i].Gains[0].Target = WetGain[i];
+ UpdateWetStepping(&voice->Send[i], 1, (voice->Send[i].Moving ? 64 : 0));
+ voice->Send[i].Moving = AL_TRUE;
}
- src->WetMix = SelectSendMixer();
{
- ALfloat gainhf = maxf(0.01f, DryGainHF);
- ALfloat gainlf = maxf(0.01f, DryGainLF);
ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
- src->Direct.Filters[0].ActiveType = AF_None;
- if(gainhf != 1.0f) src->Direct.Filters[0].ActiveType |= AF_LowPass;
- if(gainlf != 1.0f) src->Direct.Filters[0].ActiveType |= AF_HighPass;
+ DryGainHF = maxf(DryGainHF, 0.0001f);
+ DryGainLF = maxf(DryGainLF, 0.0001f);
+ voice->Direct.Filters[0].ActiveType = AF_None;
+ if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
+ if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
ALfilterState_setParams(
- &src->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
- hfscale, 0.0f
+ &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf,
+ DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
);
ALfilterState_setParams(
- &src->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
- lfscale, 0.0f
+ &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf,
+ DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
);
}
for(i = 0;i < NumSends;i++)
{
- ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
- ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
- src->Send[i].Filters[0].ActiveType = AF_None;
- if(gainhf != 1.0f) src->Send[i].Filters[0].ActiveType |= AF_LowPass;
- if(gainlf != 1.0f) src->Send[i].Filters[0].ActiveType |= AF_HighPass;
+ WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
+ WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
+ voice->Send[i].Filters[0].ActiveType = AF_None;
+ if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
+ if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
ALfilterState_setParams(
- &src->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
- hfscale, 0.0f
+ &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf,
+ WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
);
ALfilterState_setParams(
- &src->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
- lfscale, 0.0f
+ &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf,
+ WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
);
}
}
-static inline ALint aluF2I25(ALfloat val)
+void UpdateContextSources(ALCcontext *ctx)
+{
+ ALvoice *voice, *voice_end;
+ ALsource *source;
+
+ if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
+ {
+ CalcListenerParams(ctx->Listener);
+
+ voice = ctx->Voices;
+ voice_end = voice + ctx->VoiceCount;
+ for(;voice != voice_end;++voice)
+ {
+ if(!(source=voice->Source)) continue;
+ if(source->state != AL_PLAYING && source->state != AL_PAUSED)
+ voice->Source = NULL;
+ else
+ {
+ ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
+ voice->Update(voice, source, ctx);
+ }
+ }
+ }
+ else
+ {
+ voice = ctx->Voices;
+ voice_end = voice + ctx->VoiceCount;
+ for(;voice != voice_end;++voice)
+ {
+ if(!(source=voice->Source)) continue;
+ if(source->state != AL_PLAYING && source->state != AL_PAUSED)
+ voice->Source = NULL;
+ else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
+ voice->Update(voice, source, ctx);
+ }
+ }
+}
+
+
+/* Specialized function to clamp to [-1, +1] with only one branch. This also
+ * converts NaN to 0. */
+static inline ALfloat aluClampf(ALfloat val)
{
- /* Clamp the value between -1 and +1. This handles that with only a single branch. */
- if(fabsf(val) > 1.0f)
- val = (ALfloat)((0.0f < val) - (val < 0.0f));
- /* Convert to a signed integer, between -16777215 and +16777215. */
- return fastf2i(val*16777215.0f);
+ if(fabsf(val) <= 1.0f) return val;
+ return (ALfloat)((0.0f < val) - (val < 0.0f));
}
static inline ALfloat aluF2F(ALfloat val)
{ return val; }
+
static inline ALint aluF2I(ALfloat val)
-{ return aluF2I25(val)<<7; }
+{
+ /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max
+ * integer range normalized floats can be safely converted to.
+ */
+ return fastf2i(aluClampf(val)*16777215.0f)<<7;
+}
static inline ALuint aluF2UI(ALfloat val)
{ return aluF2I(val)+2147483648u; }
+
static inline ALshort aluF2S(ALfloat val)
-{ return aluF2I25(val)>>9; }
+{ return fastf2i(aluClampf(val)*32767.0f); }
static inline ALushort aluF2US(ALfloat val)
{ return aluF2S(val)+32768; }
+
static inline ALbyte aluF2B(ALfloat val)
-{ return aluF2I25(val)>>17; }
+{ return fastf2i(aluClampf(val)*127.0f); }
static inline ALubyte aluF2UB(ALfloat val)
{ return aluF2B(val)+128; }
#define DECL_TEMPLATE(T, func) \
-static void Write_##T(ALCdevice *device, ALvoid **buffer, ALuint SamplesToDo) \
+static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
+ ALuint SamplesToDo, ALuint numchans) \
{ \
- ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
- const ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
- const ALuint *offsets = device->ChannelOffsets; \
ALuint i, j; \
- \
- for(j = 0;j < MaxChannels;j++) \
+ for(j = 0;j < numchans;j++) \
{ \
- T *restrict out; \
- \
- if(offsets[j] == INVALID_OFFSET) \
- continue; \
- \
- out = (T*)(*buffer) + offsets[j]; \
+ const ALfloat *in = InBuffer[j]; \
+ T *restrict out = (T*)OutBuffer + j; \
for(i = 0;i < SamplesToDo;i++) \
- out[i*numchans] = func(DryBuffer[j][i]); \
+ out[i*numchans] = func(in[i]); \
} \
- *buffer = (char*)(*buffer) + SamplesToDo*numchans*sizeof(T); \
}
DECL_TEMPLATE(ALfloat, aluF2F)
@@ -1229,8 +1394,9 @@ DECL_TEMPLATE(ALbyte, aluF2B)
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
{
ALuint SamplesToDo;
- ALeffectslot **slot, **slot_end;
- ALactivesource **src, **src_end;
+ ALvoice *voice, *voice_end;
+ ALeffectslot *slot;
+ ALsource *source;
ALCcontext *ctx;
FPUCtl oldMode;
ALuint i, c;
@@ -1239,84 +1405,81 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
while(size > 0)
{
+ ALfloat (*OutBuffer)[BUFFERSIZE];
+ ALuint OutChannels;
+
IncrementRef(&device->MixCount);
+ OutBuffer = device->DryBuffer;
+ OutChannels = device->NumChannels;
+
SamplesToDo = minu(size, BUFFERSIZE);
- for(c = 0;c < MaxChannels;c++)
- memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
+ for(c = 0;c < OutChannels;c++)
+ memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
+ if(device->Hrtf)
+ {
+ /* Set OutBuffer/OutChannels to correspond to the actual output
+ * with HRTF. Make sure to clear them too. */
+ OutBuffer += OutChannels;
+ OutChannels = 2;
+ for(c = 0;c < OutChannels;c++)
+ memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
+ }
- ALCdevice_Lock(device);
- V(device->Synth,process)(SamplesToDo, device->DryBuffer);
+ V0(device->Backend,lock)();
- ctx = device->ContextList;
- while(ctx)
+ if((slot=device->DefaultSlot) != NULL)
{
- ALenum DeferUpdates = ctx->DeferUpdates;
- ALenum UpdateSources = AL_FALSE;
-
- if(!DeferUpdates)
- UpdateSources = ExchangeInt(&ctx->UpdateSources, AL_FALSE);
+ if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
+ V(slot->EffectState,update)(device, slot);
+ memset(slot->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat));
+ }
- if(UpdateSources)
- CalcListenerParams(ctx->Listener);
+ ctx = ATOMIC_LOAD(&device->ContextList);
+ while(ctx)
+ {
+ if(!ctx->DeferUpdates)
+ {
+ UpdateContextSources(ctx);
+#define UPDATE_SLOT(iter) do { \
+ if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
+ V((*iter)->EffectState,update)(device, *iter); \
+ memset((*iter)->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat)); \
+} while(0)
+ VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
+#undef UPDATE_SLOT
+ }
+ else
+ {
+#define CLEAR_WET_BUFFER(iter) memset((*iter)->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat))
+ VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
+#undef CLEAR_WET_BUFFER
+ }
/* source processing */
- src = ctx->ActiveSources;
- src_end = src + ctx->ActiveSourceCount;
- while(src != src_end)
+ voice = ctx->Voices;
+ voice_end = voice + ctx->VoiceCount;
+ for(;voice != voice_end;++voice)
{
- ALsource *source = (*src)->Source;
-
- if(source->state != AL_PLAYING && source->state != AL_PAUSED)
- {
- ALactivesource *temp = *(--src_end);
- *src_end = *src;
- *src = temp;
- --(ctx->ActiveSourceCount);
- continue;
- }
-
- if(!DeferUpdates && (ExchangeInt(&source->NeedsUpdate, AL_FALSE) ||
- UpdateSources))
- (*src)->Update(*src, ctx);
-
- if(source->state != AL_PAUSED)
- MixSource(*src, device, SamplesToDo);
- src++;
+ source = voice->Source;
+ if(source && source->state == AL_PLAYING)
+ MixSource(voice, source, device, SamplesToDo);
}
/* effect slot processing */
- slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
- slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
- while(slot != slot_end)
- {
- if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
- V((*slot)->EffectState,update)(device, *slot);
-
- V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
- device->DryBuffer);
-
- for(i = 0;i < SamplesToDo;i++)
- (*slot)->WetBuffer[0][i] = 0.0f;
-
- slot++;
- }
+#define PROCESS_SLOT(iter) V((*iter)->EffectState,process)( \
+ SamplesToDo, (*iter)->WetBuffer[0], device->DryBuffer, device->NumChannels \
+);
+ VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, PROCESS_SLOT);
+#undef PROCESS_SLOT
ctx = ctx->next;
}
- slot = &device->DefaultSlot;
- if(*slot != NULL)
- {
- if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
- V((*slot)->EffectState,update)(device, *slot);
-
- V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
- device->DryBuffer);
-
- for(i = 0;i < SamplesToDo;i++)
- (*slot)->WetBuffer[0][i] = 0.0f;
- }
+ if((slot=device->DefaultSlot) != NULL)
+ V(slot->EffectState,process)(
+ SamplesToDo, slot->WetBuffer[0], device->DryBuffer, device->NumChannels
+ );
/* Increment the clock time. Every second's worth of samples is
* converted and added to clock base so that large sample counts don't
@@ -1325,48 +1488,64 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
device->SamplesDone += SamplesToDo;
device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
device->SamplesDone %= device->Frequency;
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
- if(device->Bs2b)
+ if(device->Hrtf)
+ {
+ HrtfMixerFunc HrtfMix = SelectHrtfMixer();
+ ALuint irsize = GetHrtfIrSize(device->Hrtf);
+ for(c = 0;c < device->NumChannels;c++)
+ HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset,
+ 0, irsize, &device->Hrtf_Params[c], &device->Hrtf_State[c],
+ SamplesToDo
+ );
+ device->Hrtf_Offset += SamplesToDo;
+ }
+ else if(device->Bs2b)
{
/* Apply binaural/crossfeed filter */
for(i = 0;i < SamplesToDo;i++)
{
float samples[2];
- samples[0] = device->DryBuffer[FrontLeft][i];
- samples[1] = device->DryBuffer[FrontRight][i];
+ samples[0] = device->DryBuffer[0][i];
+ samples[1] = device->DryBuffer[1][i];
bs2b_cross_feed(device->Bs2b, samples);
- device->DryBuffer[FrontLeft][i] = samples[0];
- device->DryBuffer[FrontRight][i] = samples[1];
+ device->DryBuffer[0][i] = samples[0];
+ device->DryBuffer[1][i] = samples[1];
}
}
if(buffer)
{
+#define WRITE(T, a, b, c, d) do { \
+ Write_##T((a), (b), (c), (d)); \
+ buffer = (T*)buffer + (c)*(d); \
+} while(0)
switch(device->FmtType)
{
case DevFmtByte:
- Write_ALbyte(device, &buffer, SamplesToDo);
+ WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
break;
case DevFmtUByte:
- Write_ALubyte(device, &buffer, SamplesToDo);
+ WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
break;
case DevFmtShort:
- Write_ALshort(device, &buffer, SamplesToDo);
+ WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
break;
case DevFmtUShort:
- Write_ALushort(device, &buffer, SamplesToDo);
+ WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
break;
case DevFmtInt:
- Write_ALint(device, &buffer, SamplesToDo);
+ WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
break;
case DevFmtUInt:
- Write_ALuint(device, &buffer, SamplesToDo);
+ WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
break;
case DevFmtFloat:
- Write_ALfloat(device, &buffer, SamplesToDo);
+ WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
break;
}
+#undef WRITE
}
size -= SamplesToDo;
@@ -1383,26 +1562,29 @@ ALvoid aluHandleDisconnect(ALCdevice *device)
device->Connected = ALC_FALSE;
- Context = device->ContextList;
+ Context = ATOMIC_LOAD(&device->ContextList);
while(Context)
{
- ALactivesource **src, **src_end;
+ ALvoice *voice, *voice_end;
- src = Context->ActiveSources;
- src_end = src + Context->ActiveSourceCount;
- while(src != src_end)
+ voice = Context->Voices;
+ voice_end = voice + Context->VoiceCount;
+ while(voice != voice_end)
{
- ALsource *source = (*src)->Source;
- if(source->state == AL_PLAYING)
+ ALsource *source = voice->Source;
+ voice->Source = NULL;
+
+ if(source && source->state == AL_PLAYING)
{
source->state = AL_STOPPED;
- source->current_buffer = NULL;
+ ATOMIC_STORE(&source->current_buffer, NULL);
source->position = 0;
source->position_fraction = 0;
}
- src++;
+
+ voice++;
}
- Context->ActiveSourceCount = 0;
+ Context->VoiceCount = 0;
Context = Context->next;
}
diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c
index 2c9aef41..6fc9db33 100644
--- a/Alc/alcConfig.c
+++ b/Alc/alcConfig.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -33,11 +33,13 @@
#include <ctype.h>
#include <string.h>
#ifdef _WIN32_IE
+#include <windows.h>
#include <shlobj.h>
#endif
#include "alMain.h"
#include "compat.h"
+#include "bool.h"
typedef struct ConfigEntry {
@@ -137,13 +139,21 @@ static char *expdup(const char *str)
}
else
{
+ bool hasbraces;
char envname[1024];
size_t k = 0;
+ hasbraces = (*str == '{');
+ if(hasbraces) str++;
+
while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1)
envname[k++] = *(str++);
envname[k++] = '\0';
+ if(hasbraces && *str != '}')
+ continue;
+
+ if(hasbraces) str++;
if((addstr=getenv(envname)) == NULL)
continue;
addstrlen = strlen(addstr);
@@ -192,12 +202,8 @@ static void LoadConfigFromFile(FILE *f)
char key[256] = "";
char value[256] = "";
- comment = strchr(buffer, '#');
- if(comment) *(comment++) = 0;
-
line = rstrip(lstrip(buffer));
- if(!line[0])
- continue;
+ if(!line[0]) continue;
if(line[0] == '[')
{
@@ -205,10 +211,21 @@ static void LoadConfigFromFile(FILE *f)
char *endsection;
endsection = strchr(section, ']');
- if(!endsection || section == endsection || endsection[1] != 0)
+ if(!endsection || section == endsection)
{
- ERR("config parse error: bad line \"%s\"\n", line);
- continue;
+ ERR("config parse error: bad line \"%s\"\n", line);
+ continue;
+ }
+ if(endsection[1] != 0)
+ {
+ char *end = endsection+1;
+ while(isspace(*end))
+ ++end;
+ if(*end != 0 && *end != '#')
+ {
+ ERR("config parse error: bad line \"%s\"\n", line);
+ continue;
+ }
}
*endsection = 0;
@@ -223,6 +240,10 @@ static void LoadConfigFromFile(FILE *f)
continue;
}
+ comment = strchr(line, '#');
+ if(comment) *(comment++) = 0;
+ if(!line[0]) continue;
+
if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 ||
sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 ||
sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2)
@@ -296,27 +317,33 @@ void ReadALConfig(void)
if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
{
- size_t p = lstrlenW(buffer);
- _snwprintf(buffer+p, PATH_MAX-p, L"\\alsoft.ini");
+ al_string filepath = AL_STRING_INIT_STATIC();
+ al_string_copy_wcstr(&filepath, buffer);
+ al_string_append_cstr(&filepath, "\\alsoft.ini");
- TRACE("Loading config %ls...\n", buffer);
- f = _wfopen(buffer, L"rt");
+ TRACE("Loading config %s...\n", al_string_get_cstr(filepath));
+ f = al_fopen(al_string_get_cstr(filepath), "rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
+ al_string_deinit(&filepath);
}
if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str)
{
- TRACE("Loading config %ls...\n", str);
- f = _wfopen(str, L"rt");
+ al_string filepath = AL_STRING_INIT_STATIC();
+ al_string_copy_wcstr(&filepath, str);
+
+ TRACE("Loading config %s...\n", al_string_get_cstr(filepath));
+ f = al_fopen(al_string_get_cstr(filepath), "rt");
if(f)
{
LoadConfigFromFile(f);
fclose(f);
}
+ al_string_deinit(&filepath);
}
}
#else
@@ -428,7 +455,7 @@ void FreeALConfig(void)
free(cfgBlock.entries);
}
-const char *GetConfigValue(const char *blockName, const char *keyName, const char *def)
+const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def)
{
unsigned int i;
char key[256];
@@ -437,16 +464,26 @@ const char *GetConfigValue(const char *blockName, const char *keyName, const cha
return def;
if(blockName && strcasecmp(blockName, "general") != 0)
- snprintf(key, sizeof(key), "%s/%s", blockName, keyName);
+ {
+ if(devName)
+ snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName);
+ else
+ snprintf(key, sizeof(key), "%s/%s", blockName, keyName);
+ }
else
{
- strncpy(key, keyName, sizeof(key)-1);
- key[sizeof(key)-1] = 0;
+ if(devName)
+ snprintf(key, sizeof(key), "%s/%s", devName, keyName);
+ else
+ {
+ strncpy(key, keyName, sizeof(key)-1);
+ key[sizeof(key)-1] = 0;
+ }
}
for(i = 0;i < cfgBlock.entryCount;i++)
{
- if(strcasecmp(cfgBlock.entries[i].key, key) == 0)
+ if(strcmp(cfgBlock.entries[i].key, key) == 0)
{
TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value);
if(cfgBlock.entries[i].value[0])
@@ -455,46 +492,50 @@ const char *GetConfigValue(const char *blockName, const char *keyName, const cha
}
}
- TRACE("Key %s not found\n", key);
- return def;
+ if(!devName)
+ {
+ TRACE("Key %s not found\n", key);
+ return def;
+ }
+ return GetConfigValue(NULL, blockName, keyName, def);
}
-int ConfigValueExists(const char *blockName, const char *keyName)
+int ConfigValueExists(const char *devName, const char *blockName, const char *keyName)
{
- const char *val = GetConfigValue(blockName, keyName, "");
+ const char *val = GetConfigValue(devName, blockName, keyName, "");
return !!val[0];
}
-int ConfigValueStr(const char *blockName, const char *keyName, const char **ret)
+int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret)
{
- const char *val = GetConfigValue(blockName, keyName, "");
+ const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = val;
return 1;
}
-int ConfigValueInt(const char *blockName, const char *keyName, int *ret)
+int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret)
{
- const char *val = GetConfigValue(blockName, keyName, "");
+ const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = strtol(val, NULL, 0);
return 1;
}
-int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret)
+int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret)
{
- const char *val = GetConfigValue(blockName, keyName, "");
+ const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
*ret = strtoul(val, NULL, 0);
return 1;
}
-int ConfigValueFloat(const char *blockName, const char *keyName, float *ret)
+int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret)
{
- const char *val = GetConfigValue(blockName, keyName, "");
+ const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return 0;
#ifdef HAVE_STRTOF
@@ -505,9 +546,19 @@ int ConfigValueFloat(const char *blockName, const char *keyName, float *ret)
return 1;
}
-int GetConfigValueBool(const char *blockName, const char *keyName, int def)
+int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret)
+{
+ const char *val = GetConfigValue(devName, blockName, keyName, "");
+ if(!val[0]) return 0;
+
+ *ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
+ strcasecmp(val, "on") == 0 || atoi(val) != 0);
+ return 1;
+}
+
+int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def)
{
- const char *val = GetConfigValue(blockName, keyName, "");
+ const char *val = GetConfigValue(devName, blockName, keyName, "");
if(!val[0]) return !!def;
return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
diff --git a/Alc/alcRing.c b/Alc/alcRing.c
index 9b5d8214..e9a40a12 100644
--- a/Alc/alcRing.c
+++ b/Alc/alcRing.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -127,3 +127,275 @@ void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
almtx_unlock(&ring->mtx);
}
+
+
+/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended
+ * to include an element size. Consequently, parameters and return values for a
+ * size or count is in 'elements', not bytes. Additionally, it only supports
+ * single-consumer/single-provider operation. */
+struct ll_ringbuffer {
+ volatile size_t write_ptr;
+ volatile size_t read_ptr;
+ size_t size;
+ size_t size_mask;
+ size_t elem_size;
+ int mlocked;
+
+ alignas(16) char buf[];
+};
+
+/* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes.
+ * The number of elements is rounded up to the next power of two. */
+ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz)
+{
+ ll_ringbuffer_t *rb;
+ ALuint power_of_two;
+
+ power_of_two = NextPowerOf2(sz);
+ if(power_of_two < sz)
+ return NULL;
+
+ rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz);
+ if(!rb) return NULL;
+
+ rb->size = power_of_two;
+ rb->size_mask = rb->size - 1;
+ rb->elem_size = elem_sz;
+ rb->write_ptr = 0;
+ rb->read_ptr = 0;
+ rb->mlocked = 0;
+ return rb;
+}
+
+/* Free all data associated with the ringbuffer `rb'. */
+void ll_ringbuffer_free(ll_ringbuffer_t *rb)
+{
+ if(rb)
+ {
+#ifdef USE_MLOCK
+ if(rb->mlocked)
+ munlock(rb, sizeof(*rb) + rb->size*rb->elem_size);
+#endif /* USE_MLOCK */
+ al_free(rb);
+ }
+}
+
+/* Lock the data block of `rb' using the system call 'mlock'. */
+int ll_ringbuffer_mlock(ll_ringbuffer_t *rb)
+{
+#ifdef USE_MLOCK
+ if(!rb->locked && mlock(rb, sizeof(*rb) + rb->size*rb->elem_size))
+ return -1;
+#endif /* USE_MLOCK */
+ rb->mlocked = 1;
+ return 0;
+}
+
+/* Reset the read and write pointers to zero. This is not thread safe. */
+void ll_ringbuffer_reset(ll_ringbuffer_t *rb)
+{
+ rb->read_ptr = 0;
+ rb->write_ptr = 0;
+ memset(rb->buf, 0, rb->size*rb->elem_size);
+}
+
+/* Return the number of elements available for reading. This is the number of
+ * elements in front of the read pointer and behind the write pointer. */
+size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb)
+{
+ size_t w = rb->write_ptr;
+ size_t r = rb->read_ptr;
+ return (rb->size+w-r) & rb->size_mask;
+}
+/* Return the number of elements available for writing. This is the number of
+ * elements in front of the write pointer and behind the read pointer. */
+size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb)
+{
+ size_t w = rb->write_ptr;
+ size_t r = rb->read_ptr;
+ return (rb->size+r-w-1) & rb->size_mask;
+}
+
+/* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'.
+ * Returns the actual number of elements copied. */
+size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_read;
+ size_t n1, n2;
+
+ free_cnt = ll_ringbuffer_read_space(rb);
+ if(free_cnt == 0) return 0;
+
+ to_read = (cnt > free_cnt) ? free_cnt : cnt;
+ cnt2 = rb->read_ptr + to_read;
+ if(cnt2 > rb->size)
+ {
+ n1 = rb->size - rb->read_ptr;
+ n2 = cnt2 & rb->size_mask;
+ }
+ else
+ {
+ n1 = to_read;
+ n2 = 0;
+ }
+
+ memcpy(dest, &(rb->buf[rb->read_ptr*rb->elem_size]), n1*rb->elem_size);
+ rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
+ if(n2)
+ {
+ memcpy(dest + n1*rb->elem_size, &(rb->buf[rb->read_ptr*rb->elem_size]), n2*rb->elem_size);
+ rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
+ }
+ return to_read;
+}
+
+/* The copying data reader w/o read pointer advance. Copy at most `cnt'
+ * elements from `rb' to `dest'. Returns the actual number of elements copied.
+ */
+size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_read;
+ size_t n1, n2;
+ size_t tmp_read_ptr;
+
+ tmp_read_ptr = rb->read_ptr;
+ free_cnt = ll_ringbuffer_read_space(rb);
+ if(free_cnt == 0) return 0;
+
+ to_read = (cnt > free_cnt) ? free_cnt : cnt;
+ cnt2 = tmp_read_ptr + to_read;
+ if(cnt2 > rb->size)
+ {
+ n1 = rb->size - tmp_read_ptr;
+ n2 = cnt2 & rb->size_mask;
+ }
+ else
+ {
+ n1 = to_read;
+ n2 = 0;
+ }
+
+ memcpy(dest, &(rb->buf[tmp_read_ptr*rb->elem_size]), n1*rb->elem_size);
+ tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
+ if(n2)
+ memcpy(dest + n1*rb->elem_size, &(rb->buf[tmp_read_ptr*rb->elem_size]), n2*rb->elem_size);
+ return to_read;
+}
+
+/* The copying data writer. Copy at most `cnt' elements to `rb' from `src'.
+ * Returns the actual number of elements copied. */
+size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_write;
+ size_t n1, n2;
+
+ free_cnt = ll_ringbuffer_write_space(rb);
+ if(free_cnt == 0) return 0;
+
+ to_write = (cnt > free_cnt) ? free_cnt : cnt;
+ cnt2 = rb->write_ptr + to_write;
+ if(cnt2 > rb->size)
+ {
+ n1 = rb->size - rb->write_ptr;
+ n2 = cnt2 & rb->size_mask;
+ }
+ else
+ {
+ n1 = to_write;
+ n2 = 0;
+ }
+
+ memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src, n1*rb->elem_size);
+ rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
+ if(n2)
+ {
+ memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src + n1*rb->elem_size, n2*rb->elem_size);
+ rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
+ }
+ return to_write;
+}
+
+/* Advance the read pointer `cnt' places. */
+void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt)
+{
+ size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
+ rb->read_ptr = tmp;
+}
+
+/* Advance the write pointer `cnt' places. */
+void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt)
+{
+ size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
+ rb->write_ptr = tmp;
+}
+
+/* The non-copying data reader. `vec' is an array of two places. Set the values
+ * at `vec' to hold the current readable data at `rb'. If the readable data is
+ * in one segment the second segment has zero length. */
+void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t * vec)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t w, r;
+
+ w = rb->write_ptr;
+ r = rb->read_ptr;
+ free_cnt = (rb->size+w-r) & rb->size_mask;
+
+ cnt2 = r + free_cnt;
+ if(cnt2 > rb->size)
+ {
+ /* Two part vector: the rest of the buffer after the current write ptr,
+ * plus some from the start of the buffer. */
+ vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]);
+ vec[0].len = rb->size - r;
+ vec[1].buf = (char*)rb->buf;
+ vec[1].len = cnt2 & rb->size_mask;
+ }
+ else
+ {
+ /* Single part vector: just the rest of the buffer */
+ vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]);
+ vec[0].len = free_cnt;
+ vec[1].buf = NULL;
+ vec[1].len = 0;
+ }
+}
+
+/* The non-copying data writer. `vec' is an array of two places. Set the values
+ * at `vec' to hold the current writeable data at `rb'. If the writeable data
+ * is in one segment the second segment has zero length. */
+void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t w, r;
+
+ w = rb->write_ptr;
+ r = rb->read_ptr;
+ free_cnt = (rb->size+r-w-1) & rb->size_mask;
+
+ cnt2 = w + free_cnt;
+ if(cnt2 > rb->size)
+ {
+ /* Two part vector: the rest of the buffer after the current write ptr,
+ * plus some from the start of the buffer. */
+ vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]);
+ vec[0].len = rb->size - w;
+ vec[1].buf = (char*)rb->buf;
+ vec[1].len = cnt2 & rb->size_mask;
+ }
+ else
+ {
+ vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]);
+ vec[0].len = free_cnt;
+ vec[1].buf = NULL;
+ vec[1].len = 0;
+ }
+}
diff --git a/Alc/alstring.h b/Alc/alstring.h
index 5b37a483..f53d2c57 100644
--- a/Alc/alstring.h
+++ b/Alc/alstring.h
@@ -7,15 +7,16 @@
typedef char al_string_char_type;
-DECL_VECTOR(al_string_char_type)
+TYPEDEF_VECTOR(al_string_char_type, al_string)
+TYPEDEF_VECTOR(al_string, vector_al_string)
-typedef vector_al_string_char_type al_string;
-typedef const_vector_al_string_char_type const_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))
-#define AL_STRING_INIT(_x) VECTOR_INIT(_x)
-#define AL_STRING_DEINIT(_x) VECTOR_DEINIT(_x)
-
-inline ALsizei al_string_length(const_al_string str)
+inline size_t al_string_length(const_al_string str)
{ return VECTOR_SIZE(str); }
inline ALboolean al_string_empty(const_al_string str)
@@ -40,9 +41,8 @@ void al_string_append_range(al_string *str, const al_string_char_type *from, con
#include <wchar.h>
/* Windows-only methods to deal with WideChar strings. */
void al_string_copy_wcstr(al_string *str, const wchar_t *from);
+void al_string_append_wcstr(al_string *str, const wchar_t *from);
+void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to);
#endif
-
-DECL_VECTOR(al_string)
-
#endif /* ALSTRING_H */
diff --git a/Alc/backends/alsa.c b/Alc/backends/alsa.c
index 0712a412..9a443c09 100644
--- a/Alc/backends/alsa.c
+++ b/Alc/backends/alsa.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -230,7 +230,7 @@ typedef struct {
al_string name;
al_string device_name;
} DevMap;
-DECL_VECTOR(DevMap)
+TYPEDEF_VECTOR(DevMap, vector_DevMap)
static vector_DevMap PlaybackDevices;
static vector_DevMap CaptureDevices;
@@ -273,14 +273,14 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
al_string_copy_cstr(&entry.name, alsaDevice);
- al_string_copy_cstr(&entry.device_name, GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
+ al_string_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
"device" : "capture", "default"));
VECTOR_PUSH_BACK(*DeviceList, entry);
card = -1;
if((err=snd_card_next(&card)) < 0)
ERR("Failed to find a card: %s\n", snd_strerror(err));
- ConfigValueStr("alsa", prefix_name(stream), &main_prefix);
+ ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix);
while(card >= 0)
{
const char *card_prefix = main_prefix;
@@ -304,7 +304,7 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
cardid = snd_ctl_card_info_get_id(info);
snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
- ConfigValueStr("alsa", name, &card_prefix);
+ ConfigValueStr(NULL, "alsa", name, &card_prefix);
dev = -1;
while(1)
@@ -330,7 +330,7 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
devname = snd_pcm_info_get_name(pcminfo);
snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
- ConfigValueStr("alsa", name, &device_prefix);
+ ConfigValueStr(NULL, "alsa", name, &device_prefix);
snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
cardname, devname, cardid, dev);
@@ -625,28 +625,22 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
if(name)
{
- const DevMap *iter, *end;
+ const DevMap *iter;
if(VECTOR_SIZE(PlaybackDevices) == 0)
probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
- iter = VECTOR_ITER_BEGIN(PlaybackDevices);
- end = VECTOR_ITER_END(PlaybackDevices);
- for(;iter != end;iter++)
- {
- if(al_string_cmp_cstr(iter->name, name) == 0)
- {
- driver = al_string_get_cstr(iter->device_name);
- break;
- }
- }
- if(iter == end)
+#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
{
name = alsaDevice;
- driver = GetConfigValue("alsa", "device", "default");
+ driver = GetConfigValue(NULL, "alsa", "device", "default");
}
TRACE("Opening device \"%s\"\n", driver);
@@ -710,7 +704,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
break;
}
- allowmmap = GetConfigValueBool("alsa", "mmap", 1);
+ allowmmap = GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "mmap", 1);
periods = device->NumUpdates;
periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
bufferLen = periodLen * periods;
@@ -776,8 +770,11 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
}
CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
/* set rate (implicitly constrains period/buffer parameters) */
- if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
- ERR("Failed to disable ALSA resampler\n");
+ if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0))
+ {
+ if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
+ ERR("Failed to disable ALSA resampler\n");
+ }
CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL));
/* set buffer time (implicitly constrains period/buffer parameters) */
if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0)
@@ -956,28 +953,22 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
if(name)
{
- const DevMap *iter, *end;
+ const DevMap *iter;
if(VECTOR_SIZE(CaptureDevices) == 0)
probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
- iter = VECTOR_ITER_BEGIN(CaptureDevices);
- end = VECTOR_ITER_END(CaptureDevices);
- for(;iter != end;iter++)
- {
- if(al_string_cmp_cstr(iter->name, name) == 0)
- {
- driver = al_string_get_cstr(iter->device_name);
- break;
- }
- }
- if(iter == end)
+#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
{
name = alsaDevice;
- driver = GetConfigValue("alsa", "capture", "default");
+ driver = GetConfigValue(NULL, "alsa", "capture", "default");
}
TRACE("Opening device \"%s\"\n", driver);
@@ -1364,25 +1355,15 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN
if(type == ALCbackend_Playback)
{
ALCplaybackAlsa *backend;
-
- backend = ALCplaybackAlsa_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCplaybackAlsa)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCplaybackAlsa_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCcaptureAlsa *backend;
-
- backend = ALCcaptureAlsa_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCcaptureAlsa)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCcaptureAlsa_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/base.c b/Alc/backends/base.c
index 37e4ccc9..ebeb31bf 100644
--- a/Alc/backends/base.c
+++ b/Alc/backends/base.c
@@ -77,7 +77,7 @@ static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self);
static void PlaybackWrapper_stop(PlaybackWrapper *self);
static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
-static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self);
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
@@ -121,12 +121,6 @@ static void PlaybackWrapper_stop(PlaybackWrapper *self)
self->Funcs->StopPlayback(device);
}
-static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return self->Funcs->GetLatency(device);
-}
-
typedef struct CaptureWrapper {
DERIVE_FROM_TYPE(ALCbackend);
@@ -143,13 +137,12 @@ static ALCboolean CaptureWrapper_start(CaptureWrapper *self);
static void CaptureWrapper_stop(CaptureWrapper *self);
static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples);
static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
-static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALint64, getLatency)
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
-
static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
{
ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
@@ -195,12 +188,6 @@ static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
return self->Funcs->AvailableSamples(device);
}
-static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self)
-{
- ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- return self->Funcs->GetLatency(device);
-}
-
ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type)
{
@@ -208,11 +195,9 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs,
{
PlaybackWrapper *backend;
- backend = PlaybackWrapper_New(sizeof(*backend));
+ NEW_OBJ(backend, PlaybackWrapper)(device, funcs);
if(!backend) return NULL;
- PlaybackWrapper_Construct(backend, device, funcs);
-
return STATIC_CAST(ALCbackend, backend);
}
@@ -220,11 +205,9 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs,
{
CaptureWrapper *backend;
- backend = CaptureWrapper_New(sizeof(*backend));
+ NEW_OBJ(backend, CaptureWrapper)(device, funcs);
if(!backend) return NULL;
- CaptureWrapper_Construct(backend, device, funcs);
-
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/base.h b/Alc/backends/base.h
index 5573c178..f6b4b80a 100644
--- a/Alc/backends/base.h
+++ b/Alc/backends/base.h
@@ -123,9 +123,14 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \
ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
ALCbackendFactory *ALCossBackendFactory_getFactory(void);
+ALCbackendFactory *ALCjackBackendFactory_getFactory(void);
+ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
+ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void);
+ALCbackendFactory *ALCportBackendFactory_getFactory(void);
ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
+ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
ALCbackendFactory *ALCloopbackFactory_getFactory(void);
ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type);
diff --git a/Alc/backends/coreaudio.c b/Alc/backends/coreaudio.c
index b3583ffd..43e881da 100644
--- a/Alc/backends/coreaudio.c
+++ b/Alc/backends/coreaudio.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -383,6 +383,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
ca_data *data;
OSStatus err;
+ if(!deviceName)
+ deviceName = ca_device;
+ else if(strcmp(deviceName, ca_device) != 0)
+ return ALC_INVALID_VALUE;
+
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
@@ -514,9 +519,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
case DevFmtQuad:
case DevFmtX51:
- case DevFmtX51Side:
+ case DevFmtX51Rear:
case DevFmtX61:
case DevFmtX71:
+ case DevFmtBFormat3D:
ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
goto error;
}
@@ -679,8 +685,7 @@ static const BackendFuncs ca_funcs = {
ca_start_capture,
ca_stop_capture,
ca_capture_samples,
- ca_available_samples,
- ALCdevice_GetLatencyDefault
+ ca_available_samples
};
ALCboolean alc_ca_init(BackendFuncs *func_list)
diff --git a/Alc/backends/dsound.c b/Alc/backends/dsound.c
index 3ca398ed..4db4b557 100644
--- a/Alc/backends/dsound.c
+++ b/Alc/backends/dsound.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -43,6 +43,9 @@
#ifndef DSSPEAKER_5POINT1
# define DSSPEAKER_5POINT1 0x00000006
#endif
+#ifndef DSSPEAKER_5POINT1_BACK
+# define DSSPEAKER_5POINT1_BACK 0x00000006
+#endif
#ifndef DSSPEAKER_7POINT1
# define DSSPEAKER_7POINT1 0x00000007
#endif
@@ -57,6 +60,8 @@
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
+#define DEVNAME_TAIL " on OpenAL Soft"
+
#ifdef HAVE_DYNLOAD
static void *ds_handle;
@@ -109,27 +114,23 @@ typedef struct {
al_string name;
GUID guid;
} DevMap;
-DECL_VECTOR(DevMap)
+TYPEDEF_VECTOR(DevMap, vector_DevMap)
-vector_DevMap PlaybackDevices;
-vector_DevMap CaptureDevices;
+static vector_DevMap PlaybackDevices;
+static vector_DevMap CaptureDevices;
static void clear_devlist(vector_DevMap *list)
{
- DevMap *iter, *end;
-
- iter = VECTOR_ITER_BEGIN(*list);
- end = VECTOR_ITER_END(*list);
- for(;iter != end;++iter)
- AL_STRING_DEINIT(iter->name);
+#define DEINIT_STR(i) AL_STRING_DEINIT((i)->name)
+ VECTOR_FOR_EACH(DevMap, *list, DEINIT_STR);
VECTOR_RESIZE(*list, 0);
+#undef DEINIT_STR
}
static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data)
{
vector_DevMap *devices = data;
OLECHAR *guidstr = NULL;
- DevMap *iter, *end;
DevMap entry;
HRESULT hr;
int count;
@@ -140,24 +141,26 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA
AL_STRING_INIT(entry.name);
count = 0;
- do {
+ while(1)
+ {
+ const DevMap *iter;
+
al_string_copy_wcstr(&entry.name, desc);
- if(count != 0)
+ if(count == 0)
+ al_string_append_cstr(&entry.name, DEVNAME_TAIL);
+ else
{
char str[64];
- snprintf(str, sizeof(str), " #%d", count+1);
+ snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1);
al_string_append_cstr(&entry.name, str);
}
- count++;
- iter = VECTOR_ITER_BEGIN(*devices);
- end = VECTOR_ITER_END(*devices);
- for(;iter != end;++iter)
- {
- if(al_string_cmp(entry.name, iter->name) == 0)
- break;
- }
- } while(iter != end);
+#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY);
+ if(iter == VECTOR_ITER_END(*devices)) break;
+#undef MATCH_ENTRY
+ count++;
+ }
entry.guid = *guid;
hr = StringFromCLSID(guid, &guidstr);
@@ -323,7 +326,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- GUID *guid = NULL;
+ const GUID *guid = NULL;
HRESULT hr, hrcom;
if(VECTOR_SIZE(PlaybackDevices) == 0)
@@ -344,20 +347,14 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de
}
else
{
- DevMap *iter, *end;
+ const DevMap *iter;
- iter = VECTOR_ITER_BEGIN(PlaybackDevices);
- end = VECTOR_ITER_END(PlaybackDevices);
- for(;iter != end;++iter)
- {
- if(al_string_cmp_cstr(iter->name, deviceName) == 0)
- {
- guid = &iter->guid;
- break;
- }
- }
- if(iter == end)
+#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
+#undef MATCH_NAME
+ if(iter == VECTOR_ITER_END(PlaybackDevices))
return ALC_INVALID_VALUE;
+ guid = &iter->guid;
}
hr = DS_OK;
@@ -450,28 +447,35 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
hr = IDirectSound_GetSpeakerConfig(self->DS, &speakers);
if(SUCCEEDED(hr))
{
+ speakers = DSSPEAKER_CONFIG(speakers);
if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
{
- speakers = DSSPEAKER_CONFIG(speakers);
if(speakers == DSSPEAKER_MONO)
device->FmtChans = DevFmtMono;
else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
device->FmtChans = DevFmtStereo;
else if(speakers == DSSPEAKER_QUAD)
device->FmtChans = DevFmtQuad;
- else if(speakers == DSSPEAKER_5POINT1 || speakers == DSSPEAKER_5POINT1_SURROUND)
+ else if(speakers == DSSPEAKER_5POINT1_SURROUND)
device->FmtChans = DevFmtX51;
+ else if(speakers == DSSPEAKER_5POINT1_BACK)
+ device->FmtChans = DevFmtX51Rear;
else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND)
device->FmtChans = DevFmtX71;
else
ERR("Unknown system speaker config: 0x%lx\n", speakers);
}
+ device->IsHeadphones = (device->FmtChans == DevFmtStereo &&
+ speakers == DSSPEAKER_HEADPHONE);
switch(device->FmtChans)
{
case DevFmtMono:
OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
break;
+ case DevFmtBFormat3D:
+ device->FmtChans = DevFmtStereo;
+ /*fall-through*/
case DevFmtStereo:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT;
@@ -487,16 +491,16 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
- SPEAKER_BACK_LEFT |
- SPEAKER_BACK_RIGHT;
+ SPEAKER_SIDE_LEFT |
+ SPEAKER_SIDE_RIGHT;
break;
- case DevFmtX51Side:
+ case DevFmtX51Rear:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
- SPEAKER_SIDE_LEFT |
- SPEAKER_SIDE_RIGHT;
+ SPEAKER_BACK_LEFT |
+ SPEAKER_BACK_RIGHT;
break;
case DevFmtX61:
OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
@@ -681,7 +685,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
WAVEFORMATEXTENSIBLE InputType;
DSCBUFFERDESC DSCBDescription;
- GUID *guid = NULL;
+ const GUID *guid = NULL;
HRESULT hr, hrcom;
ALuint samples;
@@ -703,20 +707,14 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
}
else
{
- DevMap *iter, *end;
+ const DevMap *iter;
- iter = VECTOR_ITER_BEGIN(CaptureDevices);
- end = VECTOR_ITER_END(CaptureDevices);
- for(;iter != end;++iter)
- {
- if(al_string_cmp_cstr(iter->name, deviceName) == 0)
- {
- guid = &iter->guid;
- break;
- }
- }
- if(iter == end)
+#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
+#undef MATCH_NAME
+ if(iter == VECTOR_ITER_END(CaptureDevices))
return ALC_INVALID_VALUE;
+ guid = &iter->guid;
}
switch(device->FmtType)
@@ -760,16 +758,16 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
- SPEAKER_BACK_LEFT |
- SPEAKER_BACK_RIGHT;
+ SPEAKER_SIDE_LEFT |
+ SPEAKER_SIDE_RIGHT;
break;
- case DevFmtX51Side:
+ case DevFmtX51Rear:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
- SPEAKER_SIDE_LEFT |
- SPEAKER_SIDE_RIGHT;
+ SPEAKER_BACK_LEFT |
+ SPEAKER_BACK_RIGHT;
break;
case DevFmtX61:
InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
@@ -790,6 +788,8 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT;
break;
+ case DevFmtBFormat3D:
+ break;
}
InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
@@ -1042,26 +1042,16 @@ static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory
if(type == ALCbackend_Playback)
{
ALCdsoundPlayback *backend;
-
- backend = ALCdsoundPlayback_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCdsoundPlayback)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCdsoundPlayback_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCdsoundCapture *backend;
-
- backend = ALCdsoundCapture_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCdsoundCapture)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCdsoundCapture_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c
new file mode 100644
index 00000000..69d1277a
--- /dev/null
+++ b/Alc/backends/jack.c
@@ -0,0 +1,610 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+
+#include "alMain.h"
+#include "alu.h"
+#include "threads.h"
+#include "compat.h"
+
+#include "backends/base.h"
+
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+
+
+static const ALCchar jackDevice[] = "JACK Default";
+
+
+#ifdef HAVE_DYNLOAD
+#define JACK_FUNCS(MAGIC) \
+ MAGIC(jack_client_open); \
+ MAGIC(jack_client_close); \
+ MAGIC(jack_client_name_size); \
+ MAGIC(jack_get_client_name); \
+ MAGIC(jack_connect); \
+ MAGIC(jack_activate); \
+ MAGIC(jack_deactivate); \
+ MAGIC(jack_port_register); \
+ MAGIC(jack_port_unregister); \
+ MAGIC(jack_port_get_buffer); \
+ MAGIC(jack_port_name); \
+ MAGIC(jack_get_ports); \
+ MAGIC(jack_free); \
+ MAGIC(jack_get_sample_rate); \
+ MAGIC(jack_set_process_callback); \
+ MAGIC(jack_set_buffer_size_callback); \
+ MAGIC(jack_set_buffer_size); \
+ MAGIC(jack_get_buffer_size);
+
+static void *jack_handle;
+#define MAKE_FUNC(f) static __typeof(f) * p##f
+JACK_FUNCS(MAKE_FUNC);
+#undef MAKE_FUNC
+
+#define jack_client_open pjack_client_open
+#define jack_client_close pjack_client_close
+#define jack_client_name_size pjack_client_name_size
+#define jack_get_client_name pjack_get_client_name
+#define jack_connect pjack_connect
+#define jack_activate pjack_activate
+#define jack_deactivate pjack_deactivate
+#define jack_port_register pjack_port_register
+#define jack_port_unregister pjack_port_unregister
+#define jack_port_get_buffer pjack_port_get_buffer
+#define jack_port_name pjack_port_name
+#define jack_get_ports pjack_get_ports
+#define jack_free pjack_free
+#define jack_get_sample_rate pjack_get_sample_rate
+#define jack_set_process_callback pjack_set_process_callback
+#define jack_set_buffer_size_callback pjack_set_buffer_size_callback
+#define jack_set_buffer_size pjack_set_buffer_size
+#define jack_get_buffer_size pjack_get_buffer_size
+#endif
+
+
+static jack_options_t ClientOptions = JackNullOption;
+
+static ALCboolean jack_load(void)
+{
+ ALCboolean error = ALC_FALSE;
+
+#ifdef HAVE_DYNLOAD
+ if(!jack_handle)
+ {
+ jack_handle = LoadLib("libjack.so.0");
+ if(!jack_handle)
+ return ALC_FALSE;
+
+ error = ALC_FALSE;
+#define LOAD_FUNC(f) do { \
+ p##f = GetSymbol(jack_handle, #f); \
+ if(p##f == NULL) { \
+ error = ALC_TRUE; \
+ } \
+} while(0)
+ JACK_FUNCS(LOAD_FUNC);
+#undef LOAD_FUNC
+
+ if(error)
+ {
+ CloseLib(jack_handle);
+ jack_handle = NULL;
+ return ALC_FALSE;
+ }
+ }
+#endif
+
+ return !error;
+}
+
+
+typedef struct ALCjackPlayback {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ jack_client_t *Client;
+ jack_port_t *Port[MAX_OUTPUT_CHANNELS];
+
+ ll_ringbuffer_t *Ring;
+ alcnd_t Cond;
+
+ volatile int killNow;
+ althrd_t thread;
+} ALCjackPlayback;
+
+static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg);
+
+static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg);
+static int ALCjackPlayback_mixerProc(void *arg);
+
+static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device);
+static void ALCjackPlayback_Destruct(ALCjackPlayback *self);
+static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name);
+static void ALCjackPlayback_close(ALCjackPlayback *self);
+static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self);
+static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self);
+static void ALCjackPlayback_stop(ALCjackPlayback *self);
+static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples)
+static ALint64 ALCjackPlayback_getLatency(ALCjackPlayback *self);
+static void ALCjackPlayback_lock(ALCjackPlayback *self);
+static void ALCjackPlayback_unlock(ALCjackPlayback *self);
+DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback)
+
+DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback);
+
+
+static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device)
+{
+ ALuint i;
+
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCjackPlayback, ALCbackend, self);
+
+ alcnd_init(&self->Cond);
+
+ self->Client = NULL;
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ self->Port[i] = NULL;
+ self->Ring = NULL;
+
+ self->killNow = 1;
+}
+
+static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
+{
+ ALuint i;
+
+ if(self->Client)
+ {
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ {
+ if(self->Port[i])
+ jack_port_unregister(self->Client, self->Port[i]);
+ self->Port[i] = NULL;
+ }
+ jack_client_close(self->Client);
+ self->Client = NULL;
+ }
+
+ alcnd_destroy(&self->Cond);
+
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg)
+{
+ ALCjackPlayback *self = arg;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ ALuint bufsize;
+
+ ALCjackPlayback_lock(self);
+ device->UpdateSize = numframes;
+ device->NumUpdates = 2;
+ TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates);
+
+ bufsize = device->UpdateSize;
+ if(ConfigValueUInt(al_string_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize))
+ bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
+ bufsize += device->UpdateSize;
+
+ ll_ringbuffer_free(self->Ring);
+ self->Ring = ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType));
+ if(!self->Ring)
+ {
+ ERR("Failed to reallocate ringbuffer\n");
+ aluHandleDisconnect(device);
+ }
+ ALCjackPlayback_unlock(self);
+ return 0;
+}
+
+
+static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg)
+{
+ ALCjackPlayback *self = arg;
+ jack_default_audio_sample_t *out[MAX_OUTPUT_CHANNELS];
+ ll_ringbuffer_data_t data[2];
+ jack_nframes_t total = 0;
+ jack_nframes_t todo;
+ ALuint i, c, numchans;
+
+ ll_ringbuffer_get_read_vector(self->Ring, data);
+
+ for(c = 0;c < MAX_OUTPUT_CHANNELS && self->Port[c];c++)
+ out[c] = jack_port_get_buffer(self->Port[c], numframes);
+ numchans = c;
+
+ todo = minu(numframes, data[0].len);
+ for(c = 0;c < numchans;c++)
+ {
+ for(i = 0;i < todo;i++)
+ out[c][i] = ((ALfloat*)data[0].buf)[i*numchans + c];
+ out[c] += todo;
+ }
+ total += todo;
+
+ todo = minu(numframes-total, data[1].len);
+ if(todo > 0)
+ {
+ for(c = 0;c < numchans;c++)
+ {
+ for(i = 0;i < todo;i++)
+ out[c][i] = ((ALfloat*)data[1].buf)[i*numchans + c];
+ out[c] += todo;
+ }
+ total += todo;
+ }
+
+ ll_ringbuffer_read_advance(self->Ring, total);
+ alcnd_signal(&self->Cond);
+
+ if(numframes > total)
+ {
+ todo = numframes-total;
+ for(c = 0;c < numchans;c++)
+ {
+ for(i = 0;i < todo;i++)
+ out[c][i] = 0.0f;
+ }
+ }
+
+ return 0;
+}
+
+static int ALCjackPlayback_mixerProc(void *arg)
+{
+ ALCjackPlayback *self = arg;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ ll_ringbuffer_data_t data[2];
+
+ SetRTPriority();
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
+
+ ALCjackPlayback_lock(self);
+ while(!self->killNow && device->Connected)
+ {
+ ALuint todo, len1, len2;
+
+ /* NOTE: Unfortunately, there is an unavoidable race condition here.
+ * It's possible for the process() method to run, updating the read
+ * pointer and signaling the condition variable, in between the mixer
+ * loop checking the write size and waiting for the condition variable.
+ * This will cause the mixer loop to wait until the *next* process()
+ * invocation, most likely writing silence for it.
+ *
+ * However, this should only happen if the mixer is running behind
+ * anyway (as ideally we'll be asleep in alcnd_wait by the time the
+ * process() method is invoked), so this behavior is not unwarranted.
+ * It's unfortunate since it'll be wasting time sleeping that could be
+ * used to catch up, but there's no way around it without blocking in
+ * the process() method.
+ */
+ if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize)
+ {
+ alcnd_wait(&self->Cond, &STATIC_CAST(ALCbackend,self)->mMutex);
+ continue;
+ }
+
+ ll_ringbuffer_get_write_vector(self->Ring, data);
+ todo = data[0].len + data[1].len;
+ todo -= todo%device->UpdateSize;
+
+ len1 = minu(data[0].len, todo);
+ len2 = minu(data[1].len, todo-len1);
+
+ aluMixData(device, data[0].buf, len1);
+ if(len2 > 0)
+ aluMixData(device, data[1].buf, len2);
+ ll_ringbuffer_write_advance(self->Ring, todo);
+ }
+ ALCjackPlayback_unlock(self);
+
+ return 0;
+}
+
+
+static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ const char *client_name = "alsoft";
+ jack_status_t status;
+
+ if(!name)
+ name = jackDevice;
+ else if(strcmp(name, jackDevice) != 0)
+ return ALC_INVALID_VALUE;
+
+ self->Client = jack_client_open(client_name, ClientOptions, &status, NULL);
+ if(self->Client == NULL)
+ {
+ ERR("jack_client_open() failed, status = 0x%02x\n", status);
+ return ALC_INVALID_VALUE;
+ }
+ if((status&JackServerStarted))
+ TRACE("JACK server started\n");
+ if((status&JackNameNotUnique))
+ {
+ client_name = jack_get_client_name(self->Client);
+ TRACE("Client name not unique, got `%s' instead\n", client_name);
+ }
+
+ jack_set_process_callback(self->Client, ALCjackPlayback_process, self);
+ jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self);
+
+ al_string_copy_cstr(&device->DeviceName, name);
+
+ return ALC_NO_ERROR;
+}
+
+static void ALCjackPlayback_close(ALCjackPlayback *self)
+{
+ ALuint i;
+
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ {
+ if(self->Port[i])
+ jack_port_unregister(self->Client, self->Port[i]);
+ self->Port[i] = NULL;
+ }
+ jack_client_close(self->Client);
+ self->Client = NULL;
+}
+
+static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ ALuint numchans, i;
+ ALuint bufsize;
+
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ {
+ if(self->Port[i])
+ jack_port_unregister(self->Client, self->Port[i]);
+ self->Port[i] = NULL;
+ }
+
+ /* Ignore the requested buffer metrics and just keep one JACK-sized buffer
+ * ready for when requested. Note that one period's worth of audio in the
+ * ring buffer will always be left unfilled because one element of the ring
+ * buffer will not be writeable, and we only write in period-sized chunks.
+ */
+ device->Frequency = jack_get_sample_rate(self->Client);
+ device->UpdateSize = jack_get_buffer_size(self->Client);
+ device->NumUpdates = 2;
+
+ bufsize = device->UpdateSize;
+ if(ConfigValueUInt(al_string_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize))
+ bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
+ bufsize += device->UpdateSize;
+
+ /* Force 32-bit float output. */
+ device->FmtType = DevFmtFloat;
+
+ numchans = ChannelsFromDevFmt(device->FmtChans);
+ for(i = 0;i < numchans;i++)
+ {
+ char name[64];
+ snprintf(name, sizeof(name), "channel_%d", i+1);
+ self->Port[i] = jack_port_register(self->Client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ if(self->Port[i] == NULL)
+ {
+ ERR("Not enough JACK ports available for %s output\n", DevFmtChannelsString(device->FmtChans));
+ if(i == 0) return ALC_FALSE;
+ break;
+ }
+ }
+ if(i < numchans)
+ {
+ if(i == 1)
+ device->FmtChans = DevFmtMono;
+ else
+ {
+ for(--i;i >= 2;i--)
+ {
+ jack_port_unregister(self->Client, self->Port[i]);
+ self->Port[i] = NULL;
+ }
+ device->FmtChans = DevFmtStereo;
+ }
+ }
+
+ ll_ringbuffer_free(self->Ring);
+ self->Ring = ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType));
+ if(!self->Ring)
+ {
+ ERR("Failed to allocate ringbuffer\n");
+ return ALC_FALSE;
+ }
+
+ SetDefaultChannelOrder(device);
+
+ return ALC_TRUE;
+}
+
+static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self)
+{
+ const char **ports;
+ ALuint i;
+
+ if(jack_activate(self->Client))
+ {
+ ERR("Failed to activate client\n");
+ return ALC_FALSE;
+ }
+
+ ports = jack_get_ports(self->Client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
+ if(ports == NULL)
+ {
+ ERR("No physical playback ports found\n");
+ jack_deactivate(self->Client);
+ return ALC_FALSE;
+ }
+ for(i = 0;i < MAX_OUTPUT_CHANNELS && self->Port[i];i++)
+ {
+ if(!ports[i])
+ {
+ ERR("No physical playback port for \"%s\"\n", jack_port_name(self->Port[i]));
+ break;
+ }
+ if(jack_connect(self->Client, jack_port_name(self->Port[i]), ports[i]))
+ ERR("Failed to connect output port \"%s\" to \"%s\"\n", jack_port_name(self->Port[i]), ports[i]);
+ }
+ jack_free(ports);
+
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success)
+ {
+ jack_deactivate(self->Client);
+ return ALC_FALSE;
+ }
+
+ return ALC_TRUE;
+}
+
+static void ALCjackPlayback_stop(ALCjackPlayback *self)
+{
+ int res;
+
+ if(self->killNow)
+ return;
+
+ self->killNow = 1;
+ /* Lock the backend to ensure we don't flag the mixer to die and signal the
+ * mixer to wake up in between it checking the flag and going to sleep and
+ * wait for a wakeup (potentially leading to it never waking back up to see
+ * the flag). */
+ ALCjackPlayback_lock(self);
+ ALCjackPlayback_unlock(self);
+ alcnd_signal(&self->Cond);
+ althrd_join(self->thread, &res);
+
+ jack_deactivate(self->Client);
+}
+
+
+static ALint64 ALCjackPlayback_getLatency(ALCjackPlayback *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ ALint64 latency;
+
+ ALCjackPlayback_lock(self);
+ latency = ll_ringbuffer_read_space(self->Ring);
+ ALCjackPlayback_unlock(self);
+
+ return latency * 1000000000 / device->Frequency;
+}
+
+
+static void ALCjackPlayback_lock(ALCjackPlayback *self)
+{
+ almtx_lock(&STATIC_CAST(ALCbackend,self)->mMutex);
+}
+
+static void ALCjackPlayback_unlock(ALCjackPlayback *self)
+{
+ almtx_unlock(&STATIC_CAST(ALCbackend,self)->mMutex);
+}
+
+
+typedef struct ALCjackBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCjackBackendFactory;
+#define ALCJACKBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCjackBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self))
+{
+ jack_client_t *client;
+ jack_status_t status;
+
+ if(!jack_load())
+ return ALC_FALSE;
+
+ if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0))
+ ClientOptions |= JackNoStartServer;
+ client = jack_client_open("alsoft", ClientOptions, &status, NULL);
+ if(client == NULL)
+ {
+ WARN("jack_client_open() failed, 0x%02x\n", status);
+ if((status&JackServerFailed) && !(ClientOptions&JackNoStartServer))
+ ERR("Unable to connect to JACK server\n");
+ return ALC_FALSE;
+ }
+
+ jack_client_close(client);
+ return ALC_TRUE;
+}
+
+static void ALCjackBackendFactory_deinit(ALCjackBackendFactory* UNUSED(self))
+{
+#ifdef HAVE_DYNLOAD
+ if(jack_handle)
+ CloseLib(jack_handle);
+ jack_handle = NULL;
+#endif
+}
+
+static ALCboolean ALCjackBackendFactory_querySupport(ALCjackBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCjackBackendFactory_probe(ALCjackBackendFactory* UNUSED(self), enum DevProbe type)
+{
+ switch(type)
+ {
+ case ALL_DEVICE_PROBE:
+ AppendAllDevicesList(jackDevice);
+ break;
+
+ case CAPTURE_DEVICE_PROBE:
+ break;
+ }
+}
+
+static ALCbackend* ALCjackBackendFactory_createBackend(ALCjackBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCjackPlayback *backend;
+ NEW_OBJ(backend, ALCjackPlayback)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCjackBackendFactory);
+
+
+ALCbackendFactory *ALCjackBackendFactory_getFactory(void)
+{
+ static ALCjackBackendFactory factory = ALCJACKBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
diff --git a/Alc/backends/loopback.c b/Alc/backends/loopback.c
index 505dfacf..3e577f78 100644
--- a/Alc/backends/loopback.c
+++ b/Alc/backends/loopback.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -124,13 +124,8 @@ static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(s
if(type == ALCbackend_Loopback)
{
ALCloopback *backend;
-
- backend = ALCloopback_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCloopback)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCloopback_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c
index d732c3e1..e8563d33 100644
--- a/Alc/backends/mmdevapi.c
+++ b/Alc/backends/mmdevapi.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -51,34 +51,36 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
+DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
#define MONO SPEAKER_FRONT_CENTER
#define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
#define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
-#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
-#define X5DOT1SIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
+#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
+#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
#define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
#define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
+#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER)
+
+#define DEVNAME_TAIL " on OpenAL Soft"
typedef struct {
al_string name;
WCHAR *devid;
} DevMap;
-DECL_VECTOR(DevMap)
+TYPEDEF_VECTOR(DevMap, vector_DevMap)
static void clear_devlist(vector_DevMap *list)
{
- DevMap *iter, *end;
-
- iter = VECTOR_ITER_BEGIN(*list);
- end = VECTOR_ITER_END(*list);
- for(;iter != end;iter++)
- {
- AL_STRING_DEINIT(iter->name);
- free(iter->devid);
- }
+#define CLEAR_DEVMAP(i) do { \
+ AL_STRING_DEINIT((i)->name); \
+ free((i)->devid); \
+ (i)->devid = NULL; \
+} while(0)
+ VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP);
VECTOR_RESIZE(*list, 0);
+#undef CLEAR_DEVMAP
}
static vector_DevMap PlaybackDevices;
@@ -134,39 +136,105 @@ static void get_device_name(IMMDevice *device, al_string *name)
hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname);
if(FAILED(hr))
- WARN("GetValue failed: 0x%08lx\n", hr);
- else
+ WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr);
+ else if(pvname.vt == VT_LPWSTR)
al_string_copy_wcstr(name, pvname.pwszVal);
+ else
+ WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt);
PropVariantClear(&pvname);
IPropertyStore_Release(ps);
}
-static void add_device(IMMDevice *device, vector_DevMap *list)
+static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor)
{
- LPWSTR devid;
+ IPropertyStore *ps;
+ PROPVARIANT pvform;
HRESULT hr;
- hr = IMMDevice_GetId(device, &devid);
- if(SUCCEEDED(hr))
+ hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
+ if(FAILED(hr))
{
- DevMap entry;
- AL_STRING_INIT(entry.name);
+ WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
+ return;
+ }
+
+ PropVariantInit(&pvform);
+
+ hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_FormFactor, &pvform);
+ if(FAILED(hr))
+ WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr);
+ else if(pvform.vt == VT_UI4)
+ *formfactor = pvform.ulVal;
+ else if(pvform.vt == VT_EMPTY)
+ *formfactor = UnknownFormFactor;
+ else
+ WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt);
+
+ PropVariantClear(&pvform);
+ IPropertyStore_Release(ps);
+}
+
+
+static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list)
+{
+ int count = 0;
+ al_string tmpname;
+ DevMap entry;
+
+ AL_STRING_INIT(tmpname);
+ AL_STRING_INIT(entry.name);
+
+ entry.devid = strdupW(devid);
+ get_device_name(device, &tmpname);
+
+ while(1)
+ {
+ const DevMap *iter;
+
+ al_string_copy(&entry.name, tmpname);
+ if(count == 0)
+ al_string_append_cstr(&entry.name, DEVNAME_TAIL);
+ else
+ {
+ char str[64];
+ snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1);
+ al_string_append_cstr(&entry.name, str);
+ }
+
+#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY);
+ if(iter == VECTOR_ITER_END(*list)) break;
+#undef MATCH_ENTRY
+ count++;
+ }
- entry.devid = strdupW(devid);
- get_device_name(device, &entry.name);
+ TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
+ VECTOR_PUSH_BACK(*list, entry);
- CoTaskMemFree(devid);
+ AL_STRING_DEINIT(tmpname);
+}
+
+static LPWSTR get_device_id(IMMDevice *device)
+{
+ LPWSTR devid;
+ HRESULT hr;
- TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
- VECTOR_PUSH_BACK(*list, entry);
+ hr = IMMDevice_GetId(device, &devid);
+ if(FAILED(hr))
+ {
+ ERR("Failed to get device id: %lx\n", hr);
+ return NULL;
}
+
+ return devid;
}
static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list)
{
IMMDeviceCollection *coll;
IMMDevice *defdev = NULL;
+ LPWSTR defdevid = NULL;
HRESULT hr;
UINT count;
UINT i;
@@ -183,7 +251,7 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve
if(SUCCEEDED(hr) && count > 0)
{
clear_devlist(list);
- if(!VECTOR_RESERVE(*list, count+1))
+ if(!VECTOR_RESERVE(*list, count))
{
IMMDeviceCollection_Release(coll);
return E_OUTOFMEMORY;
@@ -193,22 +261,32 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve
eMultimedia, &defdev);
}
if(SUCCEEDED(hr) && defdev != NULL)
- add_device(defdev, list);
+ {
+ defdevid = get_device_id(defdev);
+ if(defdevid)
+ add_device(defdev, defdevid, list);
+ }
for(i = 0;i < count;++i)
{
IMMDevice *device;
+ LPWSTR devid;
- if(FAILED(IMMDeviceCollection_Item(coll, i, &device)))
- continue;
-
- if(device != defdev)
- add_device(device, list);
+ hr = IMMDeviceCollection_Item(coll, i, &device);
+ if(FAILED(hr)) continue;
+ devid = get_device_id(device);
+ if(devid)
+ {
+ if(wcscmp(devid, defdevid) != 0)
+ add_device(device, devid, list);
+ CoTaskMemFree(devid);
+ }
IMMDevice_Release(device);
}
if(defdev) IMMDevice_Release(defdev);
+ if(defdevid) CoTaskMemFree(defdevid);
IMMDeviceCollection_Release(coll);
return S_OK;
@@ -294,7 +372,7 @@ static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr)
TRACE("Starting message loop\n");
while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last))
{
- TRACE("Got message %u\n", msg.message);
+ TRACE("Got message %u (lparam=%p, wparam=%p)\n", msg.message, (void*)msg.lParam, (void*)msg.wParam);
switch(msg.message)
{
case WM_USER_OpenDevice:
@@ -483,9 +561,9 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
if(FAILED(hr))
{
ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
aluHandleDisconnect(device);
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
return 1;
}
@@ -500,9 +578,9 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
if(FAILED(hr))
{
ERR("Failed to get padding: 0x%08lx\n", hr);
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
aluHandleDisconnect(device);
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
break;
}
self->Padding = written;
@@ -521,18 +599,18 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer);
if(SUCCEEDED(hr))
{
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
aluMixData(device, buffer, len);
self->Padding = written + len;
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0);
}
if(FAILED(hr))
{
ERR("Failed to buffer data: 0x%08lx\n", hr);
- ALCdevice_Lock(device);
+ V0(device->Backend,lock)();
aluHandleDisconnect(device);
- ALCdevice_Unlock(device);
+ V0(device->Backend,unlock)();
break;
}
}
@@ -599,7 +677,7 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi
{
if(deviceName)
{
- const DevMap *iter, *end;
+ const DevMap *iter;
if(VECTOR_SIZE(PlaybackDevices) == 0)
{
@@ -609,19 +687,18 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi
}
hr = E_FAIL;
- iter = VECTOR_ITER_BEGIN(PlaybackDevices);
- end = VECTOR_ITER_END(PlaybackDevices);
- for(;iter != end;iter++)
+#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
+ if(iter == VECTOR_ITER_END(PlaybackDevices))
+ WARN("Failed to find device name matching \"%s\"\n", deviceName);
+ else
{
- if(al_string_cmp_cstr(iter->name, deviceName) == 0)
- {
- self->devid = strdupW(iter->devid);
- hr = S_OK;
- break;
- }
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ self->devid = strdupW(iter->devid);
+ al_string_copy(&device->DeviceName, iter->name);
+ hr = S_OK;
}
- if(FAILED(hr))
- WARN("Failed to find device name matching \"%s\"\n", deviceName);
+#undef MATCH_NAME
}
}
@@ -677,7 +754,11 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self)
if(SUCCEEDED(hr))
{
self->client = ptr;
- get_device_name(self->mmdev, &device->DeviceName);
+ if(al_string_empty(device->DeviceName))
+ {
+ get_device_name(self->mmdev, &device->DeviceName);
+ al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL);
+ }
}
if(FAILED(hr))
@@ -734,6 +815,7 @@ static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self)
static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
{
ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ EndpointFormFactor formfactor = UnknownFormFactor;
WAVEFORMATEXTENSIBLE OutputType;
WAVEFORMATEX *wfx = NULL;
REFERENCE_TIME min_per, buf_time;
@@ -783,11 +865,11 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
device->FmtChans = DevFmtQuad;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
device->FmtChans = DevFmtX51;
- else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
- device->FmtChans = DevFmtX51Side;
+ else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR)
+ device->FmtChans = DevFmtX51Rear;
else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
device->FmtChans = DevFmtX61;
- else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
+ else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE))
device->FmtChans = DevFmtX71;
else
ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
@@ -799,6 +881,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
OutputType.Format.nChannels = 1;
OutputType.dwChannelMask = MONO;
break;
+ case DevFmtBFormat3D:
+ device->FmtChans = DevFmtStereo;
+ /*fall-through*/
case DevFmtStereo:
OutputType.Format.nChannels = 2;
OutputType.dwChannelMask = STEREO;
@@ -811,9 +896,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
OutputType.Format.nChannels = 6;
OutputType.dwChannelMask = X5DOT1;
break;
- case DevFmtX51Side:
+ case DevFmtX51Rear:
OutputType.Format.nChannels = 6;
- OutputType.dwChannelMask = X5DOT1SIDE;
+ OutputType.dwChannelMask = X5DOT1REAR;
break;
case DevFmtX61:
OutputType.Format.nChannels = 7;
@@ -894,11 +979,11 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
device->FmtChans = DevFmtQuad;
else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
device->FmtChans = DevFmtX51;
- else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
- device->FmtChans = DevFmtX51Side;
+ else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR)
+ device->FmtChans = DevFmtX51Rear;
else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
device->FmtChans = DevFmtX61;
- else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
+ else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE))
device->FmtChans = DevFmtX71;
else
{
@@ -936,6 +1021,8 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
}
OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
}
+ get_device_formfactor(self->mmdev, &formfactor);
+ device->IsHeadphones = (device->FmtChans == DevFmtStereo && formfactor == Headphones);
SetDefaultWFXChannelOrder(device);
@@ -1055,6 +1142,575 @@ static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self)
}
+typedef struct ALCmmdevCapture {
+ DERIVE_FROM_TYPE(ALCbackend);
+ DERIVE_FROM_TYPE(ALCmmdevProxy);
+
+ WCHAR *devid;
+
+ IMMDevice *mmdev;
+ IAudioClient *client;
+ IAudioCaptureClient *capture;
+ HANDLE NotifyEvent;
+
+ HANDLE MsgEvent;
+
+ ll_ringbuffer_t *Ring;
+
+ volatile int killNow;
+ althrd_t thread;
+} ALCmmdevCapture;
+
+static int ALCmmdevCapture_recordProc(void *arg);
+
+static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device);
+static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self);
+static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *name);
+static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self);
+static void ALCmmdevCapture_close(ALCmmdevCapture *self);
+static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self);
+static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALCboolean, reset)
+static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self);
+static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self);
+static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self);
+static void ALCmmdevCapture_stop(ALCmmdevCapture *self);
+static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self);
+static ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self);
+static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCmmdevCapture)
+
+DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevCapture);
+DEFINE_ALCBACKEND_VTABLE(ALCmmdevCapture);
+
+
+static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device)
+{
+ SET_VTABLE2(ALCmmdevCapture, ALCbackend, self);
+ SET_VTABLE2(ALCmmdevCapture, ALCmmdevProxy, self);
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self));
+
+ self->devid = NULL;
+
+ self->mmdev = NULL;
+ self->client = NULL;
+ self->capture = NULL;
+ self->NotifyEvent = NULL;
+
+ self->MsgEvent = NULL;
+
+ self->Ring = NULL;
+
+ self->killNow = 0;
+}
+
+static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self)
+{
+ ll_ringbuffer_free(self->Ring);
+ self->Ring = NULL;
+
+ if(self->NotifyEvent != NULL)
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+ if(self->MsgEvent != NULL)
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+
+ ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self));
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg)
+{
+ ALCmmdevCapture *self = arg;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ HRESULT hr;
+
+ hr = CoInitialize(NULL);
+ if(FAILED(hr))
+ {
+ ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
+ V0(device->Backend,lock)();
+ aluHandleDisconnect(device);
+ V0(device->Backend,unlock)();
+ return 1;
+ }
+
+ althrd_setname(althrd_current(), RECORD_THREAD_NAME);
+
+ while(!self->killNow)
+ {
+ UINT32 avail;
+ DWORD res;
+
+ hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail);
+ if(FAILED(hr))
+ ERR("Failed to get next packet size: 0x%08lx\n", hr);
+ else while(avail > 0 && SUCCEEDED(hr))
+ {
+ UINT32 numsamples;
+ DWORD flags;
+ BYTE *data;
+
+ hr = IAudioCaptureClient_GetBuffer(self->capture,
+ &data, &numsamples, &flags, NULL, NULL
+ );
+ if(FAILED(hr))
+ {
+ ERR("Failed to get capture buffer: 0x%08lx\n", hr);
+ break;
+ }
+
+ ll_ringbuffer_write(self->Ring, (char*)data, numsamples);
+
+ hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples);
+ if(FAILED(hr))
+ {
+ ERR("Failed to release capture buffer: 0x%08lx\n", hr);
+ break;
+ }
+
+ hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail);
+ if(FAILED(hr))
+ ERR("Failed to get next packet size: 0x%08lx\n", hr);
+ }
+
+ if(FAILED(hr))
+ {
+ V0(device->Backend,lock)();
+ aluHandleDisconnect(device);
+ V0(device->Backend,unlock)();
+ break;
+ }
+
+ res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE);
+ if(res != WAIT_OBJECT_0)
+ ERR("WaitForSingleObjectEx error: 0x%lx\n", res);
+ }
+
+ CoUninitialize();
+ return 0;
+}
+
+
+static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *deviceName)
+{
+ HRESULT hr = S_OK;
+
+ self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ self->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if(self->NotifyEvent == NULL || self->MsgEvent == NULL)
+ {
+ ERR("Failed to create message events: %lu\n", GetLastError());
+ hr = E_FAIL;
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ if(deviceName)
+ {
+ const DevMap *iter;
+
+ if(VECTOR_SIZE(CaptureDevices) == 0)
+ {
+ ThreadRequest req = { self->MsgEvent, 0 };
+ if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE))
+ (void)WaitForResponse(&req);
+ }
+
+ hr = E_FAIL;
+#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
+ if(iter == VECTOR_ITER_END(CaptureDevices))
+ WARN("Failed to find device name matching \"%s\"\n", deviceName);
+ else
+ {
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ self->devid = strdupW(iter->devid);
+ al_string_copy(&device->DeviceName, iter->name);
+ hr = S_OK;
+ }
+#undef MATCH_NAME
+ }
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ ThreadRequest req = { self->MsgEvent, 0 };
+
+ hr = E_FAIL;
+ if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
+ else
+ ERR("Failed to post thread message: %lu\n", GetLastError());
+ }
+
+ if(FAILED(hr))
+ {
+ if(self->NotifyEvent != NULL)
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+ if(self->MsgEvent != NULL)
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+
+ ERR("Device init failed: 0x%08lx\n", hr);
+ return ALC_INVALID_VALUE;
+ }
+ else
+ {
+ ThreadRequest req = { self->MsgEvent, 0 };
+
+ hr = E_FAIL;
+ if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
+ else
+ ERR("Failed to post thread message: %lu\n", GetLastError());
+
+ if(FAILED(hr))
+ {
+ ALCmmdevCapture_close(self);
+ if(hr == E_OUTOFMEMORY)
+ return ALC_OUT_OF_MEMORY;
+ return ALC_INVALID_VALUE;
+ }
+ }
+
+ return ALC_NO_ERROR;
+}
+
+static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ void *ptr;
+ HRESULT hr;
+
+ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ IMMDeviceEnumerator *Enumerator = ptr;
+ if(!self->devid)
+ hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eCapture, eMultimedia, &self->mmdev);
+ else
+ hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev);
+ IMMDeviceEnumerator_Release(Enumerator);
+ Enumerator = NULL;
+ }
+ if(SUCCEEDED(hr))
+ hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ self->client = ptr;
+ if(al_string_empty(device->DeviceName))
+ {
+ get_device_name(self->mmdev, &device->DeviceName);
+ al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL);
+ }
+ }
+
+ if(FAILED(hr))
+ {
+ if(self->mmdev)
+ IMMDevice_Release(self->mmdev);
+ self->mmdev = NULL;
+ }
+
+ return hr;
+}
+
+
+static void ALCmmdevCapture_close(ALCmmdevCapture *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+
+ if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ (void)WaitForResponse(&req);
+
+ ll_ringbuffer_free(self->Ring);
+ self->Ring = NULL;
+
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+}
+
+static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self)
+{
+ if(self->client)
+ IAudioClient_Release(self->client);
+ self->client = NULL;
+
+ if(self->mmdev)
+ IMMDevice_Release(self->mmdev);
+ self->mmdev = NULL;
+}
+
+
+static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ WAVEFORMATEXTENSIBLE OutputType;
+ WAVEFORMATEX *wfx = NULL;
+ REFERENCE_TIME buf_time;
+ UINT32 buffer_len;
+ void *ptr = NULL;
+ HRESULT hr;
+
+ if(self->client)
+ IAudioClient_Release(self->client);
+ self->client = NULL;
+
+ hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
+ if(FAILED(hr))
+ {
+ ERR("Failed to reactivate audio client: 0x%08lx\n", hr);
+ return hr;
+ }
+ self->client = ptr;
+
+ buf_time = ((REFERENCE_TIME)device->UpdateSize*device->NumUpdates*10000000 +
+ device->Frequency-1) / device->Frequency;
+
+ OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ switch(device->FmtChans)
+ {
+ case DevFmtMono:
+ OutputType.Format.nChannels = 1;
+ OutputType.dwChannelMask = MONO;
+ break;
+ case DevFmtStereo:
+ OutputType.Format.nChannels = 2;
+ OutputType.dwChannelMask = STEREO;
+ break;
+ case DevFmtQuad:
+ OutputType.Format.nChannels = 4;
+ OutputType.dwChannelMask = QUAD;
+ break;
+ case DevFmtX51:
+ OutputType.Format.nChannels = 6;
+ OutputType.dwChannelMask = X5DOT1;
+ break;
+ case DevFmtX51Rear:
+ OutputType.Format.nChannels = 6;
+ OutputType.dwChannelMask = X5DOT1REAR;
+ break;
+ case DevFmtX61:
+ OutputType.Format.nChannels = 7;
+ OutputType.dwChannelMask = X6DOT1;
+ break;
+ case DevFmtX71:
+ OutputType.Format.nChannels = 8;
+ OutputType.dwChannelMask = X7DOT1;
+ break;
+
+ case DevFmtBFormat3D:
+ return E_FAIL;
+ }
+ switch(device->FmtType)
+ {
+ case DevFmtUByte:
+ OutputType.Format.wBitsPerSample = 8;
+ OutputType.Samples.wValidBitsPerSample = 8;
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ break;
+ case DevFmtShort:
+ OutputType.Format.wBitsPerSample = 16;
+ OutputType.Samples.wValidBitsPerSample = 16;
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ break;
+ case DevFmtInt:
+ OutputType.Format.wBitsPerSample = 32;
+ OutputType.Samples.wValidBitsPerSample = 32;
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ break;
+ case DevFmtFloat:
+ OutputType.Format.wBitsPerSample = 32;
+ OutputType.Samples.wValidBitsPerSample = 32;
+ OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+ break;
+
+ case DevFmtByte:
+ case DevFmtUShort:
+ case DevFmtUInt:
+ WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
+ return E_FAIL;
+ }
+ OutputType.Format.nSamplesPerSec = device->Frequency;
+
+ OutputType.Format.nBlockAlign = OutputType.Format.nChannels *
+ OutputType.Format.wBitsPerSample / 8;
+ OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
+ OutputType.Format.nBlockAlign;
+ OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format);
+
+ hr = IAudioClient_IsFormatSupported(self->client,
+ AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx
+ );
+ if(FAILED(hr))
+ {
+ ERR("Failed to check format support: 0x%08lx\n", hr);
+ return hr;
+ }
+
+ /* FIXME: We should do conversion/resampling if we didn't get a matching format. */
+ if(wfx->nSamplesPerSec != OutputType.Format.nSamplesPerSec ||
+ wfx->wBitsPerSample != OutputType.Format.wBitsPerSample ||
+ wfx->nChannels != OutputType.Format.nChannels ||
+ wfx->nBlockAlign != OutputType.Format.nBlockAlign)
+ {
+ ERR("Did not get matching format, wanted: %s %s %uhz, got: %d channel(s) %d-bit %luhz\n",
+ DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency,
+ wfx->nChannels, wfx->wBitsPerSample, wfx->nSamplesPerSec);
+ CoTaskMemFree(wfx);
+ return E_FAIL;
+ }
+
+ if(!MakeExtensible(&OutputType, wfx))
+ {
+ CoTaskMemFree(wfx);
+ return E_FAIL;
+ }
+ CoTaskMemFree(wfx);
+ wfx = NULL;
+
+ hr = IAudioClient_Initialize(self->client,
+ AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ buf_time, 0, &OutputType.Format, NULL
+ );
+ if(FAILED(hr))
+ {
+ ERR("Failed to initialize audio client: 0x%08lx\n", hr);
+ return hr;
+ }
+
+ hr = IAudioClient_GetBufferSize(self->client, &buffer_len);
+ if(FAILED(hr))
+ {
+ ERR("Failed to get buffer size: 0x%08lx\n", hr);
+ return hr;
+ }
+
+ buffer_len = maxu(device->UpdateSize*device->NumUpdates + 1, buffer_len);
+ ll_ringbuffer_free(self->Ring);
+ self->Ring = ll_ringbuffer_create(buffer_len, OutputType.Format.nBlockAlign);
+ if(!self->Ring)
+ {
+ ERR("Failed to allocate capture ring buffer\n");
+ return E_OUTOFMEMORY;
+ }
+
+ hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent);
+ if(FAILED(hr))
+ {
+ ERR("Failed to set event handle: 0x%08lx\n", hr);
+ return hr;
+ }
+
+ return hr;
+}
+
+
+static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+ HRESULT hr = E_FAIL;
+
+ if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
+
+ return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
+}
+
+static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self)
+{
+ HRESULT hr;
+ void *ptr;
+
+ ResetEvent(self->NotifyEvent);
+ hr = IAudioClient_Start(self->client);
+ if(FAILED(hr))
+ {
+ ERR("Failed to start audio client: 0x%08lx\n", hr);
+ return hr;
+ }
+
+ hr = IAudioClient_GetService(self->client, &IID_IAudioCaptureClient, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ self->capture = ptr;
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCmmdevCapture_recordProc, self) != althrd_success)
+ {
+ ERR("Failed to start thread\n");
+ IAudioCaptureClient_Release(self->capture);
+ self->capture = NULL;
+ hr = E_FAIL;
+ }
+ }
+
+ if(FAILED(hr))
+ {
+ IAudioClient_Stop(self->client);
+ IAudioClient_Reset(self->client);
+ }
+
+ return hr;
+}
+
+
+static void ALCmmdevCapture_stop(ALCmmdevCapture *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+ if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ (void)WaitForResponse(&req);
+}
+
+static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self)
+{
+ int res;
+
+ if(!self->capture)
+ return;
+
+ self->killNow = 1;
+ althrd_join(self->thread, &res);
+
+ IAudioCaptureClient_Release(self->capture);
+ self->capture = NULL;
+ IAudioClient_Stop(self->client);
+ IAudioClient_Reset(self->client);
+}
+
+
+ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self)
+{
+ return (ALuint)ll_ringbuffer_read_space(self->Ring);
+}
+
+ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples)
+{
+ if(ALCmmdevCapture_availableSamples(self) < samples)
+ return ALC_INVALID_VALUE;
+ ll_ringbuffer_read(self->Ring, buffer, samples);
+ return ALC_NO_ERROR;
+}
+
+
static inline void AppendAllDevicesList2(const DevMap *entry)
{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
static inline void AppendCaptureDeviceList2(const DevMap *entry)
@@ -1125,7 +1781,12 @@ static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory* UNUSED(self))
static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory* UNUSED(self), ALCbackend_Type type)
{
- if(type == ALCbackend_Playback)
+ /* TODO: Disable capture with mmdevapi for now, since it doesn't do any
+ * rechanneling or resampling; if the device is configured for 48000hz
+ * stereo input, for example, and the app asks for 22050hz mono,
+ * initialization will fail.
+ */
+ if(type == ALCbackend_Playback /*|| type == ALCbackend_Capture*/)
return ALC_TRUE;
return ALC_FALSE;
}
@@ -1162,13 +1823,15 @@ static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory*
if(type == ALCbackend_Playback)
{
ALCmmdevPlayback *backend;
-
- backend = ALCmmdevPlayback_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCmmdevPlayback)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+ if(type == ALCbackend_Capture)
+ {
+ ALCmmdevCapture *backend;
+ NEW_OBJ(backend, ALCmmdevCapture)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCmmdevPlayback_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/null.c b/Alc/backends/null.c
index 3f09c5d6..99729c0a 100644
--- a/Alc/backends/null.c
+++ b/Alc/backends/null.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -106,7 +106,7 @@ static int ALCnullBackend_mixerProc(void *ptr)
}
if(avail-done < device->UpdateSize)
- al_nssleep(0, restTime);
+ al_nssleep(restTime);
else while(avail-done >= device->UpdateSize)
{
aluMixData(device, NULL, device->UpdateSize);
@@ -214,13 +214,8 @@ static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UN
if(type == ALCbackend_Playback)
{
ALCnullBackend *backend;
-
- backend = ALCnullBackend_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCnullBackend)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCnullBackend_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/opensl.c b/Alc/backends/opensl.c
index 220e6e5c..7b8fdb25 100644
--- a/Alc/backends/opensl.c
+++ b/Alc/backends/opensl.c
@@ -25,7 +25,7 @@
#include "alMain.h"
#include "alu.h"
-
+#include "threads.h"
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
@@ -67,7 +67,10 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans)
SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
- SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
+ SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
+ case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
+ SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
+ SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
SL_SPEAKER_BACK_CENTER|
@@ -76,9 +79,7 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans)
SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT|
SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
- case DevFmtX51Side: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
- SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
- SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
+ case DevFmtBFormat3D: break;
}
return 0;
}
@@ -378,6 +379,15 @@ static void opensl_stop_playback(ALCdevice *Device)
result = VCALL0(bufferQueue,Clear)();
PRINTERR(result, "bufferQueue->Clear");
}
+ if(SL_RESULT_SUCCESS == result)
+ {
+ SLAndroidSimpleBufferQueueState state;
+ do {
+ althrd_yield();
+ result = VCALL(bufferQueue,GetState)(&state);
+ } while(SL_RESULT_SUCCESS == result && state.count > 0);
+ PRINTERR(result, "bufferQueue->GetState");
+ }
free(data->buffer);
data->buffer = NULL;
@@ -396,8 +406,7 @@ static const BackendFuncs opensl_funcs = {
NULL,
NULL,
NULL,
- NULL,
- ALCdevice_GetLatencyDefault
+ NULL
};
diff --git a/Alc/backends/oss.c b/Alc/backends/oss.c
index 93e026e9..dce42e21 100644
--- a/Alc/backends/oss.c
+++ b/Alc/backends/oss.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -131,7 +131,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr)
break;
}
- al_nssleep(0, 1000000);
+ al_nssleep(1000000);
continue;
}
@@ -345,7 +345,7 @@ static int ALCcaptureOSS_recordProc(void *ptr)
int amt;
SetRTPriority();
- althrd_setname(althrd_current(), "alsoft-record");
+ althrd_setname(althrd_current(), RECORD_THREAD_NAME);
frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
@@ -362,7 +362,7 @@ static int ALCcaptureOSS_recordProc(void *ptr)
}
if(amt == 0)
{
- al_nssleep(0, 1000000);
+ al_nssleep(1000000);
continue;
}
if(self->doCapture)
@@ -562,8 +562,8 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void)
ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self))
{
- ConfigValueStr("oss", "device", &oss_driver);
- ConfigValueStr("oss", "capture", &oss_capture);
+ ConfigValueStr(NULL, "oss", "device", &oss_driver);
+ ConfigValueStr(NULL, "oss", "capture", &oss_capture);
return ALC_TRUE;
}
@@ -606,25 +606,15 @@ ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self
if(type == ALCbackend_Playback)
{
ALCplaybackOSS *backend;
-
- backend = ALCplaybackOSS_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCplaybackOSS)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCplaybackOSS_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCcaptureOSS *backend;
-
- backend = ALCcaptureOSS_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCcaptureOSS)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCcaptureOSS_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/portaudio.c b/Alc/backends/portaudio.c
index 0bb6372c..f45833c6 100644
--- a/Alc/backends/portaudio.c
+++ b/Alc/backends/portaudio.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -28,6 +28,8 @@
#include "alu.h"
#include "compat.h"
+#include "backends/base.h"
+
#include <portaudio.h>
@@ -45,6 +47,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 +59,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 +101,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
@@ -119,149 +124,171 @@ static ALCboolean pa_load(void)
}
-typedef struct {
+typedef struct ALCportPlayback {
+ DERIVE_FROM_TYPE(ALCbackend);
+
PaStream *stream;
PaStreamParameters params;
ALuint update_size;
+} ALCportPlayback;
+
+static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData);
+
+static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device);
+static void ALCportPlayback_Destruct(ALCportPlayback *self);
+static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name);
+static void ALCportPlayback_close(ALCportPlayback *self);
+static ALCboolean ALCportPlayback_reset(ALCportPlayback *self);
+static ALCboolean ALCportPlayback_start(ALCportPlayback *self);
+static void ALCportPlayback_stop(ALCportPlayback *self);
+static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
+static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback)
+
+DEFINE_ALCBACKEND_VTABLE(ALCportPlayback);
+
+
+static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCportPlayback, ALCbackend, self);
- RingBuffer *ring;
-} pa_data;
-
+ self->stream = NULL;
+}
-static int pa_callback(const void *UNUSED(inputBuffer), void *outputBuffer,
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
- const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
+static void ALCportPlayback_Destruct(ALCportPlayback *self)
{
- ALCdevice *device = (ALCdevice*)userData;
+ if(self->stream)
+ Pa_CloseStream(self->stream);
+ self->stream = NULL;
- aluMixData(device, outputBuffer, framesPerBuffer);
- return 0;
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
}
-static int pa_capture_cb(const void *inputBuffer, void *UNUSED(outputBuffer),
- unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
- const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
+
+static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
+ const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
{
- ALCdevice *device = (ALCdevice*)userData;
- pa_data *data = (pa_data*)device->ExtraData;
+ ALCportPlayback *self = userData;
- WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer);
+ aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer);
return 0;
}
-static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
+static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name)
{
- pa_data *data;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
PaError err;
- if(!deviceName)
- deviceName = pa_device;
- else if(strcmp(deviceName, pa_device) != 0)
+ if(!name)
+ name = pa_device;
+ else if(strcmp(name, pa_device) != 0)
return ALC_INVALID_VALUE;
- data = (pa_data*)calloc(1, sizeof(pa_data));
- data->update_size = device->UpdateSize;
+ self->update_size = device->UpdateSize;
- data->params.device = -1;
- if(!ConfigValueInt("port", "device", &data->params.device) ||
- data->params.device < 0)
- data->params.device = Pa_GetDefaultOutputDevice();
- data->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
+ self->params.device = -1;
+ if(!ConfigValueInt(NULL, "port", "device", &self->params.device) ||
+ self->params.device < 0)
+ self->params.device = Pa_GetDefaultOutputDevice();
+ self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
(float)device->Frequency;
- data->params.hostApiSpecificStreamInfo = NULL;
+ self->params.hostApiSpecificStreamInfo = NULL;
- data->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
+ self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
switch(device->FmtType)
{
case DevFmtByte:
- data->params.sampleFormat = paInt8;
+ self->params.sampleFormat = paInt8;
break;
case DevFmtUByte:
- data->params.sampleFormat = paUInt8;
+ self->params.sampleFormat = paUInt8;
break;
case DevFmtUShort:
/* fall-through */
case DevFmtShort:
- data->params.sampleFormat = paInt16;
+ self->params.sampleFormat = paInt16;
break;
case DevFmtUInt:
/* fall-through */
case DevFmtInt:
- data->params.sampleFormat = paInt32;
+ self->params.sampleFormat = paInt32;
break;
case DevFmtFloat:
- data->params.sampleFormat = paFloat32;
+ self->params.sampleFormat = paFloat32;
break;
}
retry_open:
- err = Pa_OpenStream(&data->stream, NULL, &data->params, device->Frequency,
- device->UpdateSize, paNoFlag, pa_callback, device);
+ err = Pa_OpenStream(&self->stream, NULL, &self->params,
+ device->Frequency, device->UpdateSize, paNoFlag,
+ ALCportPlayback_WriteCallback, self
+ );
if(err != paNoError)
{
- if(data->params.sampleFormat == paFloat32)
+ if(self->params.sampleFormat == paFloat32)
{
- data->params.sampleFormat = paInt16;
+ self->params.sampleFormat = paInt16;
goto retry_open;
}
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
- free(data);
return ALC_INVALID_VALUE;
}
- device->ExtraData = data;
- al_string_copy_cstr(&device->DeviceName, deviceName);
+ al_string_copy_cstr(&device->DeviceName, name);
return ALC_NO_ERROR;
+
}
-static void pa_close_playback(ALCdevice *device)
+static void ALCportPlayback_close(ALCportPlayback *self)
{
- pa_data *data = (pa_data*)device->ExtraData;
- PaError err;
-
- err = Pa_CloseStream(data->stream);
+ PaError err = Pa_CloseStream(self->stream);
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
-
- free(data);
- device->ExtraData = NULL;
+ self->stream = NULL;
}
-static ALCboolean pa_reset_playback(ALCdevice *device)
+static ALCboolean ALCportPlayback_reset(ALCportPlayback *self)
{
- pa_data *data = (pa_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
const PaStreamInfo *streamInfo;
- streamInfo = Pa_GetStreamInfo(data->stream);
+ streamInfo = Pa_GetStreamInfo(self->stream);
device->Frequency = streamInfo->sampleRate;
- device->UpdateSize = data->update_size;
+ device->UpdateSize = self->update_size;
- if(data->params.sampleFormat == paInt8)
+ if(self->params.sampleFormat == paInt8)
device->FmtType = DevFmtByte;
- else if(data->params.sampleFormat == paUInt8)
+ else if(self->params.sampleFormat == paUInt8)
device->FmtType = DevFmtUByte;
- else if(data->params.sampleFormat == paInt16)
+ else if(self->params.sampleFormat == paInt16)
device->FmtType = DevFmtShort;
- else if(data->params.sampleFormat == paInt32)
+ else if(self->params.sampleFormat == paInt32)
device->FmtType = DevFmtInt;
- else if(data->params.sampleFormat == paFloat32)
+ else if(self->params.sampleFormat == paFloat32)
device->FmtType = DevFmtFloat;
else
{
- ERR("Unexpected sample format: 0x%lx\n", data->params.sampleFormat);
+ ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat);
return ALC_FALSE;
}
- if(data->params.channelCount == 2)
+ if(self->params.channelCount == 2)
device->FmtChans = DevFmtStereo;
- else if(data->params.channelCount == 1)
+ else if(self->params.channelCount == 1)
device->FmtChans = DevFmtMono;
else
{
- ERR("Unexpected channel count: %u\n", data->params.channelCount);
+ ERR("Unexpected channel count: %u\n", self->params.channelCount);
return ALC_FALSE;
}
SetDefaultChannelOrder(device);
@@ -269,12 +296,11 @@ static ALCboolean pa_reset_playback(ALCdevice *device)
return ALC_TRUE;
}
-static ALCboolean pa_start_playback(ALCdevice *device)
+static ALCboolean ALCportPlayback_start(ALCportPlayback *self)
{
- pa_data *data = (pa_data*)device->ExtraData;
PaError err;
- err = Pa_StartStream(data->stream);
+ err = Pa_StartStream(self->stream);
if(err != paNoError)
{
ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err));
@@ -284,161 +310,209 @@ static ALCboolean pa_start_playback(ALCdevice *device)
return ALC_TRUE;
}
-static void pa_stop_playback(ALCdevice *device)
+static void ALCportPlayback_stop(ALCportPlayback *self)
{
- pa_data *data = (pa_data*)device->ExtraData;
- PaError err;
-
- err = Pa_StopStream(data->stream);
+ PaError err = Pa_StopStream(self->stream);
if(err != paNoError)
ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
}
-static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
+typedef struct ALCportCapture {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ PaStream *stream;
+ PaStreamParameters params;
+
+ ll_ringbuffer_t *ring;
+} ALCportCapture;
+
+static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+ const PaStreamCallbackFlags statusFlags, void *userData);
+
+static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device);
+static void ALCportCapture_Destruct(ALCportCapture *self);
+static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name);
+static void ALCportCapture_close(ALCportCapture *self);
+static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCportCapture_start(ALCportCapture *self);
+static void ALCportCapture_stop(ALCportCapture *self);
+static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCportCapture_availableSamples(ALCportCapture *self);
+static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCportCapture)
+
+DEFINE_ALCBACKEND_VTABLE(ALCportCapture);
+
+
+static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCportCapture, ALCbackend, self);
+
+ self->stream = NULL;
+}
+
+static void ALCportCapture_Destruct(ALCportCapture *self)
+{
+ if(self->stream)
+ Pa_CloseStream(self->stream);
+ self->stream = NULL;
+
+ if(self->ring)
+ ll_ringbuffer_free(self->ring);
+ self->ring = NULL;
+
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer),
+ unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
+ const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
+{
+ ALCportCapture *self = userData;
+ size_t writable = ll_ringbuffer_write_space(self->ring);
+
+ if(framesPerBuffer > writable)
+ framesPerBuffer = writable;
+ ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer);
+ return 0;
+}
+
+
+static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
{
- ALuint frame_size;
- pa_data *data;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ ALuint samples, frame_size;
PaError err;
- if(!deviceName)
- deviceName = pa_device;
- else if(strcmp(deviceName, pa_device) != 0)
+ if(!name)
+ name = pa_device;
+ else if(strcmp(name, pa_device) != 0)
return ALC_INVALID_VALUE;
- data = (pa_data*)calloc(1, sizeof(pa_data));
- if(data == NULL)
- return ALC_OUT_OF_MEMORY;
-
+ samples = device->UpdateSize * device->NumUpdates;
+ samples = maxu(samples, 100 * device->Frequency / 1000);
frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
- data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates);
- if(data->ring == NULL)
- goto error;
- data->params.device = -1;
- if(!ConfigValueInt("port", "capture", &data->params.device) ||
- data->params.device < 0)
- data->params.device = Pa_GetDefaultOutputDevice();
- data->params.suggestedLatency = 0.0f;
- data->params.hostApiSpecificStreamInfo = NULL;
+ self->ring = ll_ringbuffer_create(samples, frame_size);
+ if(self->ring == NULL) return ALC_INVALID_VALUE;
+
+ self->params.device = -1;
+ if(!ConfigValueInt(NULL, "port", "capture", &self->params.device) ||
+ self->params.device < 0)
+ self->params.device = Pa_GetDefaultInputDevice();
+ self->params.suggestedLatency = 0.0f;
+ self->params.hostApiSpecificStreamInfo = NULL;
switch(device->FmtType)
{
case DevFmtByte:
- data->params.sampleFormat = paInt8;
+ self->params.sampleFormat = paInt8;
break;
case DevFmtUByte:
- data->params.sampleFormat = paUInt8;
+ self->params.sampleFormat = paUInt8;
break;
case DevFmtShort:
- data->params.sampleFormat = paInt16;
+ self->params.sampleFormat = paInt16;
break;
case DevFmtInt:
- data->params.sampleFormat = paInt32;
+ self->params.sampleFormat = paInt32;
break;
case DevFmtFloat:
- data->params.sampleFormat = paFloat32;
+ self->params.sampleFormat = paFloat32;
break;
case DevFmtUInt:
case DevFmtUShort:
ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
- goto error;
+ return ALC_INVALID_VALUE;
}
- data->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
+ self->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
- err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency,
- paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device);
+ err = Pa_OpenStream(&self->stream, &self->params, NULL,
+ device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
+ ALCportCapture_ReadCallback, self
+ );
if(err != paNoError)
{
ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
- goto error;
+ return ALC_INVALID_VALUE;
}
- al_string_copy_cstr(&device->DeviceName, deviceName);
+ al_string_copy_cstr(&device->DeviceName, name);
- device->ExtraData = data;
return ALC_NO_ERROR;
-
-error:
- DestroyRingBuffer(data->ring);
- free(data);
- return ALC_INVALID_VALUE;
}
-static void pa_close_capture(ALCdevice *device)
+static void ALCportCapture_close(ALCportCapture *self)
{
- pa_data *data = (pa_data*)device->ExtraData;
- PaError err;
-
- err = Pa_CloseStream(data->stream);
+ PaError err = Pa_CloseStream(self->stream);
if(err != paNoError)
ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
+ self->stream = NULL;
- DestroyRingBuffer(data->ring);
- data->ring = NULL;
-
- free(data);
- device->ExtraData = NULL;
+ ll_ringbuffer_free(self->ring);
+ self->ring = NULL;
}
-static void pa_start_capture(ALCdevice *device)
-{
- pa_data *data = device->ExtraData;
- PaError err;
- err = Pa_StartStream(data->stream);
+static ALCboolean ALCportCapture_start(ALCportCapture *self)
+{
+ PaError err = Pa_StartStream(self->stream);
if(err != paNoError)
+ {
ERR("Error starting stream: %s\n", Pa_GetErrorText(err));
+ return ALC_FALSE;
+ }
+ return ALC_TRUE;
}
-static void pa_stop_capture(ALCdevice *device)
+static void ALCportCapture_stop(ALCportCapture *self)
{
- pa_data *data = (pa_data*)device->ExtraData;
- PaError err;
-
- err = Pa_StopStream(data->stream);
+ PaError err = Pa_StopStream(self->stream);
if(err != paNoError)
ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
}
-static ALCenum pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+
+static ALCuint ALCportCapture_availableSamples(ALCportCapture *self)
{
- pa_data *data = device->ExtraData;
- ReadRingBuffer(data->ring, buffer, samples);
- return ALC_NO_ERROR;
+ return ll_ringbuffer_read_space(self->ring);
}
-static ALCuint pa_available_samples(ALCdevice *device)
+static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples)
{
- pa_data *data = device->ExtraData;
- return RingBufferSize(data->ring);
+ ll_ringbuffer_read(self->ring, buffer, samples);
+ return ALC_NO_ERROR;
}
-static const BackendFuncs pa_funcs = {
- pa_open_playback,
- pa_close_playback,
- pa_reset_playback,
- pa_start_playback,
- pa_stop_playback,
- pa_open_capture,
- pa_close_capture,
- pa_start_capture,
- pa_stop_capture,
- pa_capture_samples,
- pa_available_samples,
- ALCdevice_GetLatencyDefault
-};
-
-ALCboolean alc_pa_init(BackendFuncs *func_list)
+typedef struct ALCportBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCportBackendFactory;
+#define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self);
+static void ALCportBackendFactory_deinit(ALCportBackendFactory *self);
+static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type);
+static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory);
+
+
+static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self))
{
if(!pa_load())
return ALC_FALSE;
- *func_list = pa_funcs;
return ALC_TRUE;
}
-void alc_pa_deinit(void)
+static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self))
{
#ifdef HAVE_DYNLOAD
if(pa_handle)
@@ -452,7 +526,14 @@ void alc_pa_deinit(void)
#endif
}
-void alc_pa_probe(enum DevProbe type)
+static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
@@ -464,3 +545,29 @@ void alc_pa_probe(enum DevProbe type)
break;
}
}
+
+static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCportPlayback *backend;
+ NEW_OBJ(backend, ALCportPlayback)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+ if(type == ALCbackend_Capture)
+ {
+ ALCportCapture *backend;
+ NEW_OBJ(backend, ALCportCapture)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+ALCbackendFactory *ALCportBackendFactory_getFactory(void)
+{
+ static ALCportBackendFactory factory = ALCPORTBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.c
index 58252240..9ad04a71 100644
--- a/Alc/backends/pulseaudio.c
+++ b/Alc/backends/pulseaudio.c
@@ -14,8 +14,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -34,13 +34,6 @@
#if PA_API_VERSION == 12
-#ifndef PA_CHECK_VERSION
-#define PA_CHECK_VERSION(major,minor,micro) \
- ((PA_MAJOR > (major)) || \
- (PA_MAJOR == (major) && PA_MINOR > (minor)) || \
- (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
-#endif
-
#ifdef HAVE_DYNLOAD
static void *pa_handle;
#define MAKE_FUNC(x) static __typeof(x) * p##x
@@ -108,13 +101,9 @@ MAKE_FUNC(pa_operation_unref);
MAKE_FUNC(pa_proplist_new);
MAKE_FUNC(pa_proplist_free);
MAKE_FUNC(pa_proplist_set);
-#if PA_CHECK_VERSION(0,9,15)
MAKE_FUNC(pa_channel_map_superset);
MAKE_FUNC(pa_stream_set_buffer_attr_callback);
-#endif
-#if PA_CHECK_VERSION(0,9,16)
MAKE_FUNC(pa_stream_begin_write);
-#endif
#undef MAKE_FUNC
#define pa_context_unref ppa_context_unref
@@ -181,13 +170,9 @@ MAKE_FUNC(pa_stream_begin_write);
#define pa_proplist_new ppa_proplist_new
#define pa_proplist_free ppa_proplist_free
#define pa_proplist_set ppa_proplist_set
-#if PA_CHECK_VERSION(0,9,15)
#define pa_channel_map_superset ppa_channel_map_superset
#define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback
-#endif
-#if PA_CHECK_VERSION(0,9,16)
#define pa_stream_begin_write ppa_stream_begin_write
-#endif
#endif
@@ -278,18 +263,10 @@ static ALCboolean pulse_load(void)
LOAD_FUNC(pa_proplist_new);
LOAD_FUNC(pa_proplist_free);
LOAD_FUNC(pa_proplist_set);
+ LOAD_FUNC(pa_channel_map_superset);
+ LOAD_FUNC(pa_stream_set_buffer_attr_callback);
+ LOAD_FUNC(pa_stream_begin_write);
#undef LOAD_FUNC
-#define LOAD_OPTIONAL_FUNC(x) do { \
- p##x = GetSymbol(pa_handle, #x); \
-} while(0)
-#if PA_CHECK_VERSION(0,9,15)
- LOAD_OPTIONAL_FUNC(pa_channel_map_superset);
- LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback);
-#endif
-#if PA_CHECK_VERSION(0,9,16)
- LOAD_OPTIONAL_FUNC(pa_stream_begin_write);
-#endif
-#undef LOAD_OPTIONAL_FUNC
if(ret == ALC_FALSE)
{
@@ -428,18 +405,16 @@ error:
return ALC_FALSE;
}
-static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
- pa_stream *stream)
+static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream)
{
pa_threaded_mainloop_lock(loop);
if(stream)
{
+ pa_stream_set_state_callback(stream, NULL, NULL);
pa_stream_set_moved_callback(stream, NULL, NULL);
-#if PA_CHECK_VERSION(0,9,15)
- if(pa_stream_set_buffer_attr_callback)
- pa_stream_set_buffer_attr_callback(stream, NULL, NULL);
-#endif
+ pa_stream_set_write_callback(stream, NULL, NULL);
+ pa_stream_set_buffer_attr_callback(stream, NULL, NULL);
pa_stream_disconnect(stream);
pa_stream_unref(stream);
}
@@ -458,22 +433,16 @@ typedef struct {
al_string name;
al_string device_name;
} DevMap;
-DECL_VECTOR(DevMap)
+TYPEDEF_VECTOR(DevMap, vector_DevMap)
static vector_DevMap PlaybackDevices;
static vector_DevMap CaptureDevices;
static void clear_devlist(vector_DevMap *list)
{
- DevMap *iter, *end;
-
- iter = VECTOR_ITER_BEGIN(*list);
- end = VECTOR_ITER_END(*list);
- for(;iter != end;iter++)
- {
- AL_STRING_DEINIT(iter->name);
- AL_STRING_DEINIT(iter->device_name);
- }
+#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);
}
@@ -501,6 +470,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);
@@ -545,8 +515,9 @@ static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self)
static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
{
pa_threaded_mainloop *loop = pdata;
- const DevMap *iter, *end;
+ const DevMap *iter;
DevMap entry;
+ int count;
if(eol)
{
@@ -554,22 +525,36 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
return;
}
- iter = VECTOR_ITER_BEGIN(PlaybackDevices);
- end = VECTOR_ITER_END(PlaybackDevices);
- for(;iter != end;iter++)
- {
- if(al_string_cmp_cstr(iter->device_name, info->name) == 0)
- return;
- }
-
- TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
+#define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME);
+ if(iter != VECTOR_ITER_END(PlaybackDevices)) return;
+#undef MATCH_INFO_NAME
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
- al_string_copy_cstr(&entry.name, info->description);
al_string_copy_cstr(&entry.device_name, info->name);
+ count = 0;
+ while(1)
+ {
+ al_string_copy_cstr(&entry.name, info->description);
+ if(count != 0)
+ {
+ char str[64];
+ snprintf(str, sizeof(str), " #%d", count+1);
+ al_string_append_cstr(&entry.name, str);
+ }
+
+#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY);
+ if(iter == VECTOR_ITER_END(PlaybackDevices)) break;
+#undef MATCH_ENTRY
+ count++;
+ }
+
+ TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name));
+
VECTOR_PUSH_BACK(PlaybackDevices, entry);
}
@@ -657,29 +642,52 @@ static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *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)
+static void ALCpulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata)
{
ALCpulsePlayback *self = pdata;
- ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
- char chanmap_str[256] = "";
- const struct {
- const char *str;
+ pa_threaded_mainloop_signal(self->loop, 0);
+}
+
+static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
+{
+ static const struct {
enum DevFmtChannels chans;
+ pa_channel_map map;
} chanmaps[] = {
- { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
- DevFmtX71 },
- { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
- DevFmtX61 },
- { "front-left,front-right,front-center,lfe,rear-left,rear-right",
- DevFmtX51 },
- { "front-left,front-right,front-center,lfe,side-left,side-right",
- DevFmtX51Side },
- { "front-left,front-right,rear-left,rear-right", DevFmtQuad },
- { "front-left,front-right", DevFmtStereo },
- { "mono", DevFmtMono },
- { NULL, 0 }
+ { DevFmtX71, { 8, {
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+ PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
+ } } },
+ { DevFmtX61, { 7, {
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+ PA_CHANNEL_POSITION_REAR_CENTER,
+ PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
+ } } },
+ { DevFmtX51, { 6, {
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+ PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
+ } } },
+ { DevFmtX51Rear, { 6, {
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT
+ } } },
+ { DevFmtQuad, { 4, {
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+ PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT
+ } } },
+ { DevFmtStereo, { 2, {
+ PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT
+ } } },
+ { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } }
};
- int i;
+ ALCpulsePlayback *self = pdata;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ size_t i;
if(eol)
{
@@ -687,26 +695,27 @@ static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const
return;
}
- for(i = 0;chanmaps[i].str;i++)
+ for(i = 0;i < COUNTOF(chanmaps);i++)
{
- pa_channel_map map;
- if(!pa_channel_map_parse(&map, chanmaps[i].str))
- continue;
-
- if(pa_channel_map_equal(&info->channel_map, &map)
-#if PA_CHECK_VERSION(0,9,15)
- || (pa_channel_map_superset &&
- pa_channel_map_superset(&info->channel_map, &map))
-#endif
- )
+ if(pa_channel_map_superset(&info->channel_map, &chanmaps[i].map))
{
- device->FmtChans = chanmaps[i].chans;
- return;
+ if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
+ device->FmtChans = chanmaps[i].chans;
+ break;
}
}
+ if(i == COUNTOF(chanmaps))
+ {
+ char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX] = "";
+ pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
+ WARN("Failed to find format for channel map:\n %s\n", chanmap_str);
+ }
- pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
- ERR("Failed to find format for channel map:\n %s\n", chanmap_str);
+ if(info->active_port)
+ TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description);
+ device->IsHeadphones = (info->active_port &&
+ strcmp(info->active_port->name, "analog-output-headphones") == 0 &&
+ device->FmtChans == DevFmtStereo);
}
static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
@@ -806,9 +815,7 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
o = pa_stream_cork(self->stream, 0, NULL, NULL);
if(o) pa_operation_unref(o);
}
- pa_threaded_mainloop_unlock(self->loop);
- al_nssleep(0, 1000000);
- pa_threaded_mainloop_lock(self->loop);
+ pa_threaded_mainloop_wait(self->loop);
continue;
}
len -= len%update_size;
@@ -819,10 +826,7 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
void *buf;
pa_free_cb_t free_func = NULL;
-#if PA_CHECK_VERSION(0,9,16)
- if(!pa_stream_begin_write ||
- pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
-#endif
+ if(pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
{
buf = pa_xmalloc(newlen);
free_func = pa_xfree;
@@ -842,30 +846,25 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name)
{
+ const_al_string dev_name = AL_STRING_INIT_STATIC();
const char *pulse_name = NULL;
pa_stream_flags_t flags;
pa_sample_spec spec;
- pa_operation *o;
if(name)
{
- const DevMap *iter, *end;
+ const DevMap *iter;
if(VECTOR_SIZE(PlaybackDevices) == 0)
ALCpulsePlayback_probeDevices();
- iter = VECTOR_ITER_BEGIN(PlaybackDevices);
- end = VECTOR_ITER_END(PlaybackDevices);
- for(;iter != end;iter++)
- {
- if(al_string_cmp_cstr(iter->name, name) == 0)
- {
- pulse_name = al_string_get_cstr(iter->device_name);
- break;
- }
- }
- if(iter == end)
+#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);
+ dev_name = iter->name;
}
if(!pulse_open(&self->loop, &self->context, ALCpulsePlayback_contextStateCallback, self))
@@ -875,7 +874,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
PA_STREAM_FIX_CHANNELS;
- if(!GetConfigValueBool("pulse", "allow-moves", 0))
+ if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
spec.format = PA_SAMPLE_S16NE;
@@ -896,10 +895,19 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
- o = pa_context_get_sink_info_by_name(self->context,
- al_string_get_cstr(self->device_name),
- ALCpulsePlayback_sinkNameCallback, self);
- wait_for_operation(o, self->loop);
+ if(al_string_empty(dev_name))
+ {
+ pa_operation *o = pa_context_get_sink_info_by_name(
+ self->context, al_string_get_cstr(self->device_name),
+ ALCpulsePlayback_sinkNameCallback, self
+ );
+ wait_for_operation(o, self->loop);
+ }
+ else
+ {
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+ al_string_copy(&device->DeviceName, dev_name);
+ }
pa_threaded_mainloop_unlock(self->loop);
@@ -922,37 +930,33 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
pa_stream_flags_t flags = 0;
const char *mapname = NULL;
pa_channel_map chanmap;
+ pa_operation *o;
ALuint len;
pa_threaded_mainloop_lock(self->loop);
if(self->stream)
{
+ pa_stream_set_state_callback(self->stream, NULL, NULL);
pa_stream_set_moved_callback(self->stream, NULL, NULL);
-#if PA_CHECK_VERSION(0,9,15)
- if(pa_stream_set_buffer_attr_callback)
- pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL);
-#endif
+ pa_stream_set_write_callback(self->stream, NULL, NULL);
+ pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL);
pa_stream_disconnect(self->stream);
pa_stream_unref(self->stream);
self->stream = NULL;
}
- if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
- {
- pa_operation *o;
- o = pa_context_get_sink_info_by_name(self->context,
- al_string_get_cstr(self->device_name),
- ALCpulsePlayback_sinkInfoCallback, self);
- wait_for_operation(o, self->loop);
- }
- if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
- flags |= PA_STREAM_FIX_RATE;
+ o = pa_context_get_sink_info_by_name(self->context, al_string_get_cstr(self->device_name),
+ ALCpulsePlayback_sinkInfoCallback, self);
+ wait_for_operation(o, self->loop);
+ if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) ||
+ !(device->Flags&DEVICE_FREQUENCY_REQUEST))
+ flags |= PA_STREAM_FIX_RATE;
flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
flags |= PA_STREAM_ADJUST_LATENCY;
flags |= PA_STREAM_START_CORKED;
- if(!GetConfigValueBool("pulse", "allow-moves", 0))
+ if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
switch(device->FmtType)
@@ -994,6 +998,9 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
case DevFmtMono:
mapname = "mono";
break;
+ case DevFmtBFormat3D:
+ device->FmtChans = DevFmtStereo;
+ /*fall-through*/
case DevFmtStereo:
mapname = "front-left,front-right";
break;
@@ -1001,11 +1008,11 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
mapname = "front-left,front-right,rear-left,rear-right";
break;
case DevFmtX51:
- mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right";
- break;
- case DevFmtX51Side:
mapname = "front-left,front-right,front-center,lfe,side-left,side-right";
break;
+ case DevFmtX51Rear:
+ mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right";
+ break;
case DevFmtX61:
mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right";
break;
@@ -1037,12 +1044,11 @@ 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)
{
- pa_operation *o;
-
/* Server updated our playback rate, so modify the buffer attribs
* accordingly. */
device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency *
@@ -1059,15 +1065,10 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
device->Frequency = self->spec.rate;
}
-#if PA_CHECK_VERSION(0,9,15)
- if(pa_stream_set_buffer_attr_callback)
- pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
-#endif
+ pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
ALCpulsePlayback_bufferAttrCallback(self->stream, self);
len = self->attr.minreq / pa_frame_size(&self->spec);
- if((CPUCapFlags&CPU_CAP_SSE))
- len = (len+3)&~3;
device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5);
device->NumUpdates = clampu(device->NumUpdates, 2, 16);
device->UpdateSize = len;
@@ -1089,10 +1090,18 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
pa_operation *o;
int res;
- if(!self->stream)
+ if(!self->stream || self->killNow)
return;
self->killNow = AL_TRUE;
+ /* Signal the main loop in case PulseAudio isn't sending us audio requests
+ * (e.g. if the device is suspended). We need to lock the mainloop in case
+ * the mixer is between checking the killNow flag but before waiting for
+ * the signal.
+ */
+ pa_threaded_mainloop_lock(self->loop);
+ pa_threaded_mainloop_unlock(self->loop);
+ pa_threaded_mainloop_signal(self->loop, 0);
althrd_join(self->thread, &res);
pa_threaded_mainloop_lock(self->loop);
@@ -1203,8 +1212,9 @@ static void ALCpulseCapture_Destruct(ALCpulseCapture *self)
static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata)
{
pa_threaded_mainloop *loop = pdata;
- const DevMap *iter, *end;
+ const DevMap *iter;
DevMap entry;
+ int count;
if(eol)
{
@@ -1212,22 +1222,36 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
return;
}
- iter = VECTOR_ITER_BEGIN(CaptureDevices);
- end = VECTOR_ITER_END(CaptureDevices);
- for(;iter != end;iter++)
- {
- if(al_string_cmp_cstr(iter->device_name, info->name) == 0)
- return;
- }
-
- TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
+#define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME);
+ if(iter != VECTOR_ITER_END(CaptureDevices)) return;
+#undef MATCH_INFO_NAME
AL_STRING_INIT(entry.name);
AL_STRING_INIT(entry.device_name);
- al_string_copy_cstr(&entry.name, info->description);
al_string_copy_cstr(&entry.device_name, info->name);
+ count = 0;
+ while(1)
+ {
+ al_string_copy_cstr(&entry.name, info->description);
+ if(count != 0)
+ {
+ char str[64];
+ snprintf(str, sizeof(str), " #%d", count+1);
+ al_string_append_cstr(&entry.name, str);
+ }
+
+#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+ VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY);
+ if(iter == VECTOR_ITER_END(CaptureDevices)) break;
+#undef MATCH_ENTRY
+ count++;
+ }
+
+ TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name));
+
VECTOR_PUSH_BACK(CaptureDevices, entry);
}
@@ -1380,28 +1404,22 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
const char *pulse_name = NULL;
pa_stream_flags_t flags = 0;
pa_channel_map chanmap;
- pa_operation *o;
ALuint samples;
if(name)
{
- const DevMap *iter, *end;
+ const DevMap *iter;
if(VECTOR_SIZE(CaptureDevices) == 0)
ALCpulseCapture_probeDevices();
- iter = VECTOR_ITER_BEGIN(CaptureDevices);
- end = VECTOR_ITER_END(CaptureDevices);
- for(;iter != end;iter++)
- {
- if(al_string_cmp_cstr(iter->name, name) == 0)
- {
- pulse_name = al_string_get_cstr(iter->device_name);
- break;
- }
- }
- if(iter == end)
+#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);
+ al_string_copy(&device->DeviceName, iter->name);
}
if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self))
@@ -1459,7 +1477,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
pa_frame_size(&self->spec);
flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
- if(!GetConfigValueBool("pulse", "allow-moves", 0))
+ if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
flags |= PA_STREAM_DONT_MOVE;
TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
@@ -1475,10 +1493,14 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self);
al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
- o = pa_context_get_source_info_by_name(self->context,
- al_string_get_cstr(self->device_name),
- ALCpulseCapture_sourceNameCallback, self);
- wait_for_operation(o, self->loop);
+ if(al_string_empty(device->DeviceName))
+ {
+ pa_operation *o = pa_context_get_source_info_by_name(
+ self->context, al_string_get_cstr(self->device_name),
+ ALCpulseCapture_sourceNameCallback, self
+ );
+ wait_for_operation(o, self->loop);
+ }
pa_threaded_mainloop_unlock(self->loop);
return ALC_NO_ERROR;
@@ -1621,11 +1643,6 @@ static void ALCpulseCapture_unlock(ALCpulseCapture *self)
}
-static inline void AppendAllDevicesList2(const DevMap *entry)
-{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
-static inline void AppendCaptureDeviceList2(const DevMap *entry)
-{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
-
typedef struct ALCpulseBackendFactory {
DERIVE_FROM_TYPE(ALCbackendFactory);
} ALCpulseBackendFactory;
@@ -1652,7 +1669,7 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel
pa_threaded_mainloop *loop;
pulse_ctx_flags = 0;
- if(!GetConfigValueBool("pulse", "spawn-server", 1))
+ if(!GetConfigValueBool(NULL, "pulse", "spawn-server", 1))
pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
if((loop=pa_threaded_mainloop_new()) &&
@@ -1715,12 +1732,16 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e
{
case ALL_DEVICE_PROBE:
ALCpulsePlayback_probeDevices();
- VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
+#define APPEND_ALL_DEVICES_LIST(e) AppendAllDevicesList(al_string_get_cstr((e)->name))
+ VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_ALL_DEVICES_LIST);
+#undef APPEND_ALL_DEVICES_LIST
break;
case CAPTURE_DEVICE_PROBE:
ALCpulseCapture_probeDevices();
- VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
+#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(al_string_get_cstr((e)->name))
+ VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_CAPTURE_DEVICE_LIST);
+#undef APPEND_CAPTURE_DEVICE_LIST
break;
}
}
@@ -1730,25 +1751,15 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
if(type == ALCbackend_Playback)
{
ALCpulsePlayback *backend;
-
- backend = ALCpulsePlayback_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCpulsePlayback)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCpulsePlayback_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
if(type == ALCbackend_Capture)
{
ALCpulseCapture *backend;
-
- backend = ALCpulseCapture_New(sizeof(*backend));
+ NEW_OBJ(backend, ALCpulseCapture)(device);
if(!backend) return NULL;
- memset(backend, 0, sizeof(*backend));
-
- ALCpulseCapture_Construct(backend, device);
-
return STATIC_CAST(ALCbackend, backend);
}
diff --git a/Alc/backends/qsa.c b/Alc/backends/qsa.c
index 9258e4e5..291e49fc 100644
--- a/Alc/backends/qsa.c
+++ b/Alc/backends/qsa.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -53,12 +53,12 @@ typedef struct {
int card;
int dev;
} DevMap;
+TYPEDEF_VECTOR(DevMap, vector_DevMap)
+
+static vector_DevMap DeviceNameMap;
+static vector_DevMap CaptureNameMap;
static const ALCchar qsaDevice[] = "QSA Default";
-static DevMap* allDevNameMap;
-static ALuint numDevNames;
-static DevMap* allCaptureDevNameMap;
-static ALuint numCaptureDevNames;
static const struct {
int32_t format;
@@ -104,69 +104,57 @@ static const struct {
{0},
};
-static DevMap *deviceList(int type, ALuint *count)
+static void deviceList(int type, vector_DevMap *devmap)
{
snd_ctl_t* handle;
snd_pcm_info_t pcminfo;
- int max_cards, card, err, dev, num_devices, idx;
- DevMap* dev_list;
+ int max_cards, card, err, dev;
+ DevMap entry;
char name[1024];
struct snd_ctl_hw_info info;
- void* temp;
- idx=0;
- num_devices=0;
- max_cards=snd_cards();
+ max_cards = snd_cards();
+ if(max_cards < 0)
+ return;
- if (max_cards<=0)
- {
- return 0;
- }
+ VECTOR_RESERVE(*devmap, max_cards+1);
+ VECTOR_RESIZE(*devmap, 0);
- dev_list=malloc(sizeof(DevMap)*1);
- dev_list[0].name=strdup(qsaDevice);
- num_devices=1;
+ entry.name = strdup(qsaDevice);
+ entry.card = 0;
+ entry.dev = 0;
+ VECTOR_PUSH_BACK(*devmap, entry);
- for (card=0; card<max_cards; card++)
+ for(card = 0;card < max_cards;card++)
{
- if ((err=snd_ctl_open(&handle, card))<0)
- {
+ if((err=snd_ctl_open(&handle, card)) < 0)
continue;
- }
- if ((err=snd_ctl_hw_info(handle, &info))<0)
+
+ if((err=snd_ctl_hw_info(handle, &info)) < 0)
{
snd_ctl_close(handle);
continue;
}
- for (dev=0; dev<(int)info.pcmdevs; dev++)
+ for(dev = 0;dev < (int)info.pcmdevs;dev++)
{
- if ((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
- {
+ if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
continue;
- }
- if ((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
- (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
+ if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
+ (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
{
- temp=realloc(dev_list, sizeof(DevMap)*(num_devices+1));
- if (temp)
- {
- dev_list=temp;
- snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
- dev_list[num_devices].name=strdup(name);
- dev_list[num_devices].card=card;
- dev_list[num_devices].dev=dev;
- num_devices++;
- }
+ snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
+ entry.name = strdup(name);
+ entry.card = card;
+ entry.dev = dev;
+
+ VECTOR_PUSH_BACK(*devmap, entry);
+ TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev);
}
}
- snd_ctl_close (handle);
+ snd_ctl_close(handle);
}
-
- *count=num_devices;
-
- return dev_list;
}
@@ -266,71 +254,48 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr)
static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
{
- qsa_data* data;
- char driver[64];
- int status;
+ qsa_data *data;
int card, dev;
+ int status;
- strncpy(driver, GetConfigValue("qsa", "device", qsaDevice), sizeof(driver)-1);
- driver[sizeof(driver)-1]=0;
-
- data=(qsa_data*)calloc(1, sizeof(qsa_data));
- if (data==NULL)
- {
+ data = (qsa_data*)calloc(1, sizeof(qsa_data));
+ if(data == NULL)
return ALC_OUT_OF_MEMORY;
- }
- if (!deviceName)
- {
- deviceName=driver;
- }
+ if(!deviceName)
+ deviceName = qsaDevice;
- if (strcmp(deviceName, qsaDevice)==0)
- {
- if (!deviceName)
- {
- deviceName=qsaDevice;
- }
-
- status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
- }
+ if(strcmp(deviceName, qsaDevice) == 0)
+ status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
else
{
- size_t idx;
+ const DevMap *iter;
- if (!allDevNameMap)
- {
- allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames);
- }
+ if(VECTOR_SIZE(DeviceNameMap) == 0)
+ deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
- for (idx=0; idx<numDevNames; idx++)
- {
- if (allDevNameMap[idx].name && strcmp(deviceName, allDevNameMap[idx].name)==0)
- {
- if (idx>0)
- {
- break;
- }
- }
- }
- if (idx==numDevNames)
+#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
+ VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME);
+#undef MATCH_DEVNAME
+ if(iter == VECTOR_ITER_END(DeviceNameMap))
{
free(data);
return ALC_INVALID_DEVICE;
}
- status=snd_pcm_open(&data->pcmHandle, allDevNameMap[idx].card, allDevNameMap[idx].dev, SND_PCM_OPEN_PLAYBACK);
+ status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK);
}
- if (status<0)
+ if(status < 0)
{
free(data);
return ALC_INVALID_DEVICE;
}
- data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
- if (data->audio_fd<0)
+ data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
+ if(data->audio_fd < 0)
{
+ snd_pcm_close(data->pcmHandle);
free(data);
return ALC_INVALID_DEVICE;
}
@@ -633,72 +598,51 @@ static void qsa_stop_playback(ALCdevice* device)
static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
{
- qsa_data* data;
- int format=-1;
- char driver[64];
+ qsa_data *data;
int card, dev;
+ int format=-1;
int status;
- strncpy(driver, GetConfigValue("qsa", "capture", qsaDevice), sizeof(driver)-1);
- driver[sizeof(driver)-1]=0;
-
data=(qsa_data*)calloc(1, sizeof(qsa_data));
if (data==NULL)
{
return ALC_OUT_OF_MEMORY;
}
- if (!deviceName)
- {
- deviceName=driver;
- }
+ if(!deviceName)
+ deviceName = qsaDevice;
- if (strcmp(deviceName, qsaDevice)==0)
- {
- if (!deviceName)
- {
- deviceName=qsaDevice;
- }
-
- status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
- }
+ if(strcmp(deviceName, qsaDevice) == 0)
+ status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
else
{
- size_t idx;
+ const DevMap *iter;
- if (!allCaptureDevNameMap)
- {
- allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numDevNames);
- }
+ if(VECTOR_SIZE(CaptureNameMap) == 0)
+ deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
- for (idx=0; idx<numDevNames; idx++)
- {
- if (allCaptureDevNameMap[idx].name && strcmp(deviceName, allCaptureDevNameMap[idx].name)==0)
- {
- if (idx>0)
- {
- break;
- }
- }
- }
- if (idx==numDevNames)
+#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
+ VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME);
+#undef MATCH_DEVNAME
+ if(iter == VECTOR_ITER_END(CaptureNameMap))
{
free(data);
return ALC_INVALID_DEVICE;
}
- status=snd_pcm_open(&data->pcmHandle, allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev, SND_PCM_OPEN_CAPTURE);
+ status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE);
}
- if (status<0)
+ if(status < 0)
{
free(data);
return ALC_INVALID_DEVICE;
}
- data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
- if (data->audio_fd<0)
+ data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
+ if(data->audio_fd < 0)
{
+ snd_pcm_close(data->pcmHandle);
free(data);
return ALC_INVALID_DEVICE;
}
@@ -753,170 +697,13 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
data->cparams.format.format=format;
- if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
- {
- int original_rate=data->cparams.format.rate;
- int original_voices=data->cparams.format.voices;
- int original_format=data->cparams.format.format;
- int it;
- int jt;
-
- for (it=0; it<1; it++)
- {
- /* Check for second pass */
- if (it==1)
- {
- original_rate=ratelist[0].rate;
- original_voices=channellist[0].channels;
- original_format=formatlist[0].format;
- }
-
- do {
- /* At first downgrade sample format */
- jt=0;
- do {
- if (formatlist[jt].format==data->cparams.format.format)
- {
- data->cparams.format.format=formatlist[jt+1].format;
- break;
- }
- if (formatlist[jt].format==0)
- {
- data->cparams.format.format=0;
- break;
- }
- jt++;
- } while(1);
-
- if (data->cparams.format.format==0)
- {
- data->cparams.format.format=original_format;
-
- /* At secod downgrade sample rate */
- jt=0;
- do {
- if (ratelist[jt].rate==data->cparams.format.rate)
- {
- data->cparams.format.rate=ratelist[jt+1].rate;
- break;
- }
- if (ratelist[jt].rate==0)
- {
- data->cparams.format.rate=0;
- break;
- }
- jt++;
- } while(1);
-
- if (data->cparams.format.rate==0)
- {
- data->cparams.format.rate=original_rate;
- data->cparams.format.format=original_format;
-
- /* At third downgrade channels number */
- jt=0;
- do {
- if(channellist[jt].channels==data->cparams.format.voices)
- {
- data->cparams.format.voices=channellist[jt+1].channels;
- break;
- }
- if (channellist[jt].channels==0)
- {
- data->cparams.format.voices=0;
- break;
- }
- jt++;
- } while(1);
- }
-
- if (data->cparams.format.voices==0)
- {
- break;
- }
- }
-
- data->cparams.buf.block.frag_size=device->UpdateSize*
- data->cparams.format.voices*
- snd_pcm_format_width(data->cparams.format.format)/8;
- data->cparams.buf.block.frags_max=device->NumUpdates;
- data->cparams.buf.block.frags_min=device->NumUpdates;
- if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
- {
- continue;
- }
- else
- {
- break;
- }
- } while(1);
-
- if (data->cparams.format.voices!=0)
- {
- break;
- }
- }
-
- if (data->cparams.format.voices==0)
- {
- return ALC_INVALID_VALUE;
- }
- }
-
- /* now fill back to the our AL device */
- device->Frequency=data->cparams.format.rate;
-
- switch (data->cparams.format.voices)
+ if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0)
{
- case 1:
- device->FmtChans=DevFmtMono;
- break;
- case 2:
- device->FmtChans=DevFmtStereo;
- break;
- case 4:
- device->FmtChans=DevFmtQuad;
- break;
- case 6:
- device->FmtChans=DevFmtX51;
- break;
- case 7:
- device->FmtChans=DevFmtX61;
- break;
- case 8:
- device->FmtChans=DevFmtX71;
- break;
- default:
- device->FmtChans=DevFmtMono;
- break;
- }
+ snd_pcm_close(data->pcmHandle);
+ free(data);
+ device->ExtraData=NULL;
- switch (data->cparams.format.format)
- {
- case SND_PCM_SFMT_S8:
- device->FmtType=DevFmtByte;
- break;
- case SND_PCM_SFMT_U8:
- device->FmtType=DevFmtUByte;
- break;
- case SND_PCM_SFMT_S16_LE:
- device->FmtType=DevFmtShort;
- break;
- case SND_PCM_SFMT_U16_LE:
- device->FmtType=DevFmtUShort;
- break;
- case SND_PCM_SFMT_S32_LE:
- device->FmtType=DevFmtInt;
- break;
- case SND_PCM_SFMT_U32_LE:
- device->FmtType=DevFmtUInt;
- break;
- case SND_PCM_SFMT_FLOAT_LE:
- device->FmtType=DevFmtFloat;
- break;
- default:
- device->FmtType=DevFmtShort;
- break;
+ return ALC_INVALID_VALUE;
}
return ALC_NO_ERROR;
@@ -927,9 +714,8 @@ static void qsa_close_capture(ALCdevice* device)
qsa_data* data=(qsa_data*)device->ExtraData;
if (data->pcmHandle!=NULL)
- {
snd_pcm_close(data->pcmHandle);
- }
+
free(data);
device->ExtraData=NULL;
}
@@ -954,10 +740,6 @@ static void qsa_start_capture(ALCdevice* device)
}
snd_pcm_capture_go(data->pcmHandle);
-
- device->UpdateSize=data->csetup.buf.block.frag_size/
- (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType));
- device->NumUpdates=data->csetup.buf.block.frags;
}
static void qsa_stop_capture(ALCdevice* device)
@@ -1073,16 +855,7 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
return ALC_NO_ERROR;
}
-static ALint64 qsa_get_latency(ALCdevice* device)
-{
- ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
-
- return (ALint64)(device->UpdateSize*device->NumUpdates/frame_size)*
- 1000000000/device->Frequency;
-}
-
-BackendFuncs qsa_funcs=
-{
+static const BackendFuncs qsa_funcs= {
qsa_open_playback,
qsa_close_playback,
qsa_reset_playback,
@@ -1093,69 +866,52 @@ BackendFuncs qsa_funcs=
qsa_start_capture,
qsa_stop_capture,
qsa_capture_samples,
- qsa_available_samples,
- qsa_get_latency,
+ qsa_available_samples
};
ALCboolean alc_qsa_init(BackendFuncs* func_list)
{
- *func_list=qsa_funcs;
-
+ *func_list = qsa_funcs;
return ALC_TRUE;
}
void alc_qsa_deinit(void)
{
- ALuint i;
-
- for (i=0; i<numDevNames; ++i)
- {
- free(allDevNameMap[i].name);
- }
- free(allDevNameMap);
- allDevNameMap=NULL;
- numDevNames=0;
+#define FREE_NAME(iter) free((iter)->name)
+ VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
+ VECTOR_DEINIT(DeviceNameMap);
- for (i=0; i<numCaptureDevNames; ++i)
- {
- free(allCaptureDevNameMap[i].name);
- }
- free(allCaptureDevNameMap);
- allCaptureDevNameMap=NULL;
- numCaptureDevNames=0;
+ VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
+ VECTOR_DEINIT(CaptureNameMap);
+#undef FREE_NAME
}
void alc_qsa_probe(enum DevProbe type)
{
- ALuint i;
-
switch (type)
{
case ALL_DEVICE_PROBE:
- for (i=0; i<numDevNames; ++i)
- {
- free(allDevNameMap[i].name);
- }
- free(allDevNameMap);
-
- allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames);
- for (i=0; i<numDevNames; ++i)
- {
- AppendAllDevicesList(allDevNameMap[i].name);
- }
- break;
+#define FREE_NAME(iter) free((iter)->name)
+ VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
+#undef FREE_NAME
+ VECTOR_RESIZE(DeviceNameMap, 0);
+
+ deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
+#define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name)
+ VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_DEVICE);
+#undef APPEND_DEVICE
+ break;
+
case CAPTURE_DEVICE_PROBE:
- for (i=0; i<numCaptureDevNames; ++i)
- {
- free(allCaptureDevNameMap[i].name);
- }
- free(allCaptureDevNameMap);
-
- allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numCaptureDevNames);
- for (i=0; i<numCaptureDevNames; ++i)
- {
- AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
- }
- break;
+#define FREE_NAME(iter) free((iter)->name)
+ VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
+#undef FREE_NAME
+ VECTOR_RESIZE(CaptureNameMap, 0);
+
+ deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
+#define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name)
+ VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_DEVICE);
+#undef APPEND_DEVICE
+ break;
}
}
diff --git a/Alc/backends/sndio.c b/Alc/backends/sndio.c
index 7152b2d6..52bff13a 100644
--- a/Alc/backends/sndio.c
+++ b/Alc/backends/sndio.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -266,8 +266,7 @@ static const BackendFuncs sndio_funcs = {
NULL,
NULL,
NULL,
- NULL,
- ALCdevice_GetLatencyDefault
+ NULL
};
ALCboolean alc_sndio_init(BackendFuncs *func_list)
diff --git a/Alc/backends/solaris.c b/Alc/backends/solaris.c
index 20d861d2..52ca9090 100644
--- a/Alc/backends/solaris.c
+++ b/Alc/backends/solaris.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -36,14 +36,14 @@
#include "threads.h"
#include "compat.h"
-#include <sys/audioio.h>
+#include "backends/base.h"
+#include <sys/audioio.h>
-static const ALCchar solaris_device[] = "Solaris Default";
-static const char *solaris_driver = "/dev/audio";
+typedef struct ALCsolarisBackend {
+ DERIVE_FROM_TYPE(ALCbackend);
-typedef struct {
int fd;
ALubyte *mix_data;
@@ -51,13 +51,58 @@ typedef struct {
volatile int killNow;
althrd_t thread;
-} solaris_data;
+} ALCsolarisBackend;
+
+static int ALCsolarisBackend_mixerProc(void *ptr);
+
+static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device);
+static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self);
+static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name);
+static void ALCsolarisBackend_close(ALCsolarisBackend *self);
+static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self);
+static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self);
+static void ALCsolarisBackend_stop(ALCsolarisBackend *self);
+static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend)
+
+DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend);
+
+
+static const ALCchar solaris_device[] = "Solaris Default";
+
+static const char *solaris_driver = "/dev/audio";
-static int SolarisProc(void *ptr)
+static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device)
{
- ALCdevice *Device = (ALCdevice*)ptr;
- solaris_data *data = (solaris_data*)Device->ExtraData;
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCsolarisBackend, ALCbackend, self);
+
+ self->fd = -1;
+}
+
+static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self)
+{
+ if(self->fd != -1)
+ close(self->fd);
+ self->fd = -1;
+
+ free(self->mix_data);
+ self->mix_data = NULL;
+ self->data_size = 0;
+
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+static int ALCsolarisBackend_mixerProc(void *ptr)
+{
+ ALCsolarisBackend *self = ptr;
+ ALCdevice *Device = STATIC_CAST(ALCbackend,self)->mDevice;
ALint frameSize;
int wrote;
@@ -66,27 +111,27 @@ static int SolarisProc(void *ptr)
frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
- while(!data->killNow && Device->Connected)
+ while(!self->killNow && Device->Connected)
{
- ALint len = data->data_size;
- ALubyte *WritePtr = data->mix_data;
+ ALint len = self->data_size;
+ ALubyte *WritePtr = self->mix_data;
aluMixData(Device, WritePtr, len/frameSize);
- while(len > 0 && !data->killNow)
+ while(len > 0 && !self->killNow)
{
- wrote = write(data->fd, WritePtr, len);
+ wrote = write(self->fd, WritePtr, len);
if(wrote < 0)
{
if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
{
ERR("write failed: %s\n", strerror(errno));
- ALCdevice_Lock(Device);
+ ALCsolarisBackend_lock(self);
aluHandleDisconnect(Device);
- ALCdevice_Unlock(Device);
+ ALCsolarisBackend_unlock(self);
break;
}
- al_nssleep(0, 1000000);
+ al_nssleep(1000000);
continue;
}
@@ -99,43 +144,37 @@ static int SolarisProc(void *ptr)
}
-static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
+static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name)
{
- solaris_data *data;
+ ALCdevice *device;
- if(!deviceName)
- deviceName = solaris_device;
- else if(strcmp(deviceName, solaris_device) != 0)
+ if(!name)
+ name = solaris_device;
+ else if(strcmp(name, solaris_device) != 0)
return ALC_INVALID_VALUE;
- data = (solaris_data*)calloc(1, sizeof(solaris_data));
- data->killNow = 0;
-
- data->fd = open(solaris_driver, O_WRONLY);
- if(data->fd == -1)
+ self->fd = open(solaris_driver, O_WRONLY);
+ if(self->fd == -1)
{
- free(data);
ERR("Could not open %s: %s\n", solaris_driver, strerror(errno));
return ALC_INVALID_VALUE;
}
- al_string_copy_cstr(&device->DeviceName, deviceName);
- device->ExtraData = data;
+ device = STATIC_CAST(ALCbackend,self)->mDevice;
+ al_string_copy_cstr(&device->DeviceName, name);
+
return ALC_NO_ERROR;
}
-static void solaris_close_playback(ALCdevice *device)
+static void ALCsolarisBackend_close(ALCsolarisBackend *self)
{
- solaris_data *data = (solaris_data*)device->ExtraData;
-
- close(data->fd);
- free(data);
- device->ExtraData = NULL;
+ close(self->fd);
+ self->fd = -1;
}
-static ALCboolean solaris_reset_playback(ALCdevice *device)
+static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
{
- solaris_data *data = (solaris_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
audio_info_t info;
ALuint frameSize;
int numChannels;
@@ -174,7 +213,7 @@ static ALCboolean solaris_reset_playback(ALCdevice *device)
frameSize = numChannels * BytesFromDevFmt(device->FmtType);
info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize;
- if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0)
+ if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0)
{
ERR("ioctl failed: %s\n", strerror(errno));
return ALC_FALSE;
@@ -201,74 +240,72 @@ static ALCboolean solaris_reset_playback(ALCdevice *device)
SetDefaultChannelOrder(device);
+ free(self->mix_data);
+ self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ self->mix_data = calloc(1, self->data_size);
+
return ALC_TRUE;
}
-static ALCboolean solaris_start_playback(ALCdevice *device)
+static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self)
{
- solaris_data *data = (solaris_data*)device->ExtraData;
-
- data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
- data->mix_data = calloc(1, data->data_size);
-
- data->killNow = 0;
- if(althrd_create(&data->thread, SolarisProc, device) != althrd_success)
- {
- free(data->mix_data);
- data->mix_data = NULL;
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success)
return ALC_FALSE;
- }
-
return ALC_TRUE;
}
-static void solaris_stop_playback(ALCdevice *device)
+static void ALCsolarisBackend_stop(ALCsolarisBackend *self)
{
- solaris_data *data = (solaris_data*)device->ExtraData;
int res;
- if(data->killNow)
+ if(self->killNow)
return;
- data->killNow = 1;
- althrd_join(data->thread, &res);
+ self->killNow = 1;
+ althrd_join(self->thread, &res);
- if(ioctl(data->fd, AUDIO_DRAIN) < 0)
+ if(ioctl(self->fd, AUDIO_DRAIN) < 0)
ERR("Error draining device: %s\n", strerror(errno));
-
- free(data->mix_data);
- data->mix_data = NULL;
}
-static const BackendFuncs solaris_funcs = {
- solaris_open_playback,
- solaris_close_playback,
- solaris_reset_playback,
- solaris_start_playback,
- solaris_stop_playback,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- ALCdevice_GetLatencyDefault
-};
-
-ALCboolean alc_solaris_init(BackendFuncs *func_list)
+typedef struct ALCsolarisBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCsolarisBackendFactory;
+#define ALCSOLARISBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
+
+static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self);
+static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type);
+static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory);
+
+
+ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void)
{
- ConfigValueStr("solaris", "device", &solaris_driver);
+ static ALCsolarisBackendFactory factory = ALCSOLARISBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
- *func_list = solaris_funcs;
+
+static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory* UNUSED(self))
+{
+ ConfigValueStr(NULL, "solaris", "device", &solaris_driver);
return ALC_TRUE;
}
-void alc_solaris_deinit(void)
+static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory* UNUSED(self), ALCbackend_Type type)
{
+ if(type == ALCbackend_Playback)
+ return ALC_TRUE;
+ return ALC_FALSE;
}
-void alc_solaris_probe(enum DevProbe type)
+static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
@@ -286,3 +323,16 @@ void alc_solaris_probe(enum DevProbe type)
break;
}
}
+
+ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCsolarisBackend *backend;
+ NEW_OBJ(backend, ALCsolarisBackend)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
diff --git a/Alc/backends/wave.c b/Alc/backends/wave.c
index 421ca5d7..6b47c611 100644
--- a/Alc/backends/wave.c
+++ b/Alc/backends/wave.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -24,26 +24,13 @@
#include <stdio.h>
#include <memory.h>
#include <errno.h>
-#ifdef HAVE_WINDOWS_H
-#include <windows.h>
-#endif
#include "alMain.h"
#include "alu.h"
#include "threads.h"
#include "compat.h"
-
-typedef struct {
- FILE *f;
- long DataStart;
-
- ALvoid *buffer;
- ALuint size;
-
- volatile int killNow;
- althrd_t thread;
-} wave_data;
+#include "backends/base.h"
static const ALCchar waveDevice[] = "Wave File Writer";
@@ -57,18 +44,15 @@ static const ALubyte SUBTYPE_FLOAT[] = {
0x00, 0x38, 0x9b, 0x71
};
-static const ALuint channel_masks[] = {
- 0, /* invalid */
- 0x4, /* Mono */
- 0x1 | 0x2, /* Stereo */
- 0, /* 3 channel */
- 0x1 | 0x2 | 0x10 | 0x20, /* Quad */
- 0, /* 5 channel */
- 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */
- 0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */
- 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */
+static const ALubyte SUBTYPE_BFORMAT_PCM[] = {
+ 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
+ 0xca, 0x00, 0x00, 0x00
};
+static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
+ 0xca, 0x00, 0x00, 0x00
+};
static void fwrite16le(ALushort val, FILE *f)
{
@@ -85,10 +69,57 @@ static void fwrite32le(ALuint val, FILE *f)
}
-static int WaveProc(void *ptr)
+typedef struct ALCwaveBackend {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ FILE *mFile;
+ long mDataStart;
+
+ ALvoid *mBuffer;
+ ALuint mSize;
+
+ volatile int killNow;
+ althrd_t thread;
+} ALCwaveBackend;
+
+static int ALCwaveBackend_mixerProc(void *ptr);
+
+static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, Destruct)
+static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name);
+static void ALCwaveBackend_close(ALCwaveBackend *self);
+static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self);
+static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self);
+static void ALCwaveBackend_stop(ALCwaveBackend *self);
+static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend)
+
+DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend);
+
+
+static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCwaveBackend, ALCbackend, self);
+
+ self->mFile = NULL;
+ self->mDataStart = -1;
+
+ self->mBuffer = NULL;
+ self->mSize = 0;
+
+ self->killNow = 1;
+}
+
+
+static int ALCwaveBackend_mixerProc(void *ptr)
{
- ALCdevice *device = (ALCdevice*)ptr;
- wave_data *data = (wave_data*)device->ExtraData;
+ ALCwaveBackend *self = (ALCwaveBackend*)ptr;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
struct timespec now, start;
ALint64 avail, done;
ALuint frameSize;
@@ -106,7 +137,7 @@ static int WaveProc(void *ptr)
ERR("Failed to get starting time\n");
return 1;
}
- while(!data->killNow && device->Connected)
+ while(!self->killNow && device->Connected)
{
if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
{
@@ -125,41 +156,41 @@ static int WaveProc(void *ptr)
}
if(avail-done < device->UpdateSize)
- al_nssleep(0, restTime);
+ al_nssleep(restTime);
else while(avail-done >= device->UpdateSize)
{
- aluMixData(device, data->buffer, device->UpdateSize);
+ aluMixData(device, self->mBuffer, device->UpdateSize);
done += device->UpdateSize;
if(!IS_LITTLE_ENDIAN)
{
ALuint bytesize = BytesFromDevFmt(device->FmtType);
- ALubyte *bytes = data->buffer;
+ ALubyte *bytes = self->mBuffer;
ALuint i;
if(bytesize == 1)
{
- for(i = 0;i < data->size;i++)
- fputc(bytes[i], data->f);
+ for(i = 0;i < self->mSize;i++)
+ fputc(bytes[i], self->mFile);
}
else if(bytesize == 2)
{
- for(i = 0;i < data->size;i++)
- fputc(bytes[i^1], data->f);
+ for(i = 0;i < self->mSize;i++)
+ fputc(bytes[i^1], self->mFile);
}
else if(bytesize == 4)
{
- for(i = 0;i < data->size;i++)
- fputc(bytes[i^3], data->f);
+ for(i = 0;i < self->mSize;i++)
+ fputc(bytes[i^3], self->mFile);
}
}
else
{
- fs = fwrite(data->buffer, frameSize, device->UpdateSize,
- data->f);
+ fs = fwrite(self->mBuffer, frameSize, device->UpdateSize,
+ self->mFile);
(void)fs;
}
- if(ferror(data->f))
+ if(ferror(self->mFile))
{
ERR("Error writing to file\n");
ALCdevice_Lock(device);
@@ -173,52 +204,52 @@ static int WaveProc(void *ptr)
return 0;
}
-static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
+
+static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name)
{
- wave_data *data;
+ ALCdevice *device;
const char *fname;
- fname = GetConfigValue("wave", "file", "");
- if(!fname[0])
- return ALC_INVALID_VALUE;
+ fname = GetConfigValue(NULL, "wave", "file", "");
+ if(!fname[0]) return ALC_INVALID_VALUE;
- if(!deviceName)
- deviceName = waveDevice;
- else if(strcmp(deviceName, waveDevice) != 0)
+ if(!name)
+ name = waveDevice;
+ else if(strcmp(name, waveDevice) != 0)
return ALC_INVALID_VALUE;
- data = (wave_data*)calloc(1, sizeof(wave_data));
-
- data->f = al_fopen(fname, "wb");
- if(!data->f)
+ self->mFile = al_fopen(fname, "wb");
+ if(!self->mFile)
{
- free(data);
ERR("Could not open file '%s': %s\n", fname, strerror(errno));
return ALC_INVALID_VALUE;
}
- al_string_copy_cstr(&device->DeviceName, deviceName);
- device->ExtraData = data;
+ device = STATIC_CAST(ALCbackend, self)->mDevice;
+ al_string_copy_cstr(&device->DeviceName, name);
+
return ALC_NO_ERROR;
}
-static void wave_close_playback(ALCdevice *device)
+static void ALCwaveBackend_close(ALCwaveBackend *self)
{
- wave_data *data = (wave_data*)device->ExtraData;
-
- fclose(data->f);
- free(data);
- device->ExtraData = NULL;
+ if(self->mFile)
+ fclose(self->mFile);
+ self->mFile = NULL;
}
-static ALCboolean wave_reset_playback(ALCdevice *device)
+static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
{
- wave_data *data = (wave_data*)device->ExtraData;
- ALuint channels=0, bits=0;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ ALuint channels=0, bits=0, chanmask=0;
+ int isbformat = 0;
size_t val;
- fseek(data->f, 0, SEEK_SET);
- clearerr(data->f);
+ fseek(self->mFile, 0, SEEK_SET);
+ clearerr(self->mFile);
+
+ if(GetConfigValueBool(NULL, "wave", "bformat", 0))
+ device->FmtChans = DevFmtBFormat3D;
switch(device->FmtType)
{
@@ -237,135 +268,156 @@ static ALCboolean wave_reset_playback(ALCdevice *device)
case DevFmtFloat:
break;
}
+ switch(device->FmtChans)
+ {
+ case DevFmtMono: chanmask = 0x04; break;
+ case DevFmtStereo: chanmask = 0x01 | 0x02; break;
+ case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break;
+ case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
+ case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
+ case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
+ case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
+ case DevFmtBFormat3D:
+ isbformat = 1;
+ chanmask = 0;
+ break;
+ }
bits = BytesFromDevFmt(device->FmtType) * 8;
channels = ChannelsFromDevFmt(device->FmtChans);
- fprintf(data->f, "RIFF");
- fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close
+ fprintf(self->mFile, "RIFF");
+ fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close
- fprintf(data->f, "WAVE");
+ fprintf(self->mFile, "WAVE");
- fprintf(data->f, "fmt ");
- fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE
+ fprintf(self->mFile, "fmt ");
+ fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
// 16-bit val, format type id (extensible: 0xFFFE)
- fwrite16le(0xFFFE, data->f);
+ fwrite16le(0xFFFE, self->mFile);
// 16-bit val, channel count
- fwrite16le(channels, data->f);
+ fwrite16le(channels, self->mFile);
// 32-bit val, frequency
- fwrite32le(device->Frequency, data->f);
+ fwrite32le(device->Frequency, self->mFile);
// 32-bit val, bytes per second
- fwrite32le(device->Frequency * channels * bits / 8, data->f);
+ fwrite32le(device->Frequency * channels * bits / 8, self->mFile);
// 16-bit val, frame size
- fwrite16le(channels * bits / 8, data->f);
+ fwrite16le(channels * bits / 8, self->mFile);
// 16-bit val, bits per sample
- fwrite16le(bits, data->f);
+ fwrite16le(bits, self->mFile);
// 16-bit val, extra byte count
- fwrite16le(22, data->f);
+ fwrite16le(22, self->mFile);
// 16-bit val, valid bits per sample
- fwrite16le(bits, data->f);
+ fwrite16le(bits, self->mFile);
// 32-bit val, channel mask
- fwrite32le(channel_masks[channels], data->f);
+ fwrite32le(chanmask, self->mFile);
// 16 byte GUID, sub-type format
- val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f);
+ val = fwrite(((bits==32) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
+ (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM)), 1, 16, self->mFile);
(void)val;
- fprintf(data->f, "data");
- fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close
+ fprintf(self->mFile, "data");
+ fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close
- if(ferror(data->f))
+ if(ferror(self->mFile))
{
ERR("Error writing header: %s\n", strerror(errno));
return ALC_FALSE;
}
- data->DataStart = ftell(data->f);
+ self->mDataStart = ftell(self->mFile);
SetDefaultWFXChannelOrder(device);
return ALC_TRUE;
}
-static ALCboolean wave_start_playback(ALCdevice *device)
+static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self)
{
- wave_data *data = (wave_data*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
- data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
- data->buffer = malloc(data->size);
- if(!data->buffer)
+ self->mSize = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+ self->mBuffer = malloc(self->mSize);
+ if(!self->mBuffer)
{
ERR("Buffer malloc failed\n");
return ALC_FALSE;
}
- data->killNow = 0;
- if(althrd_create(&data->thread, WaveProc, device) != althrd_success)
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success)
{
- free(data->buffer);
- data->buffer = NULL;
+ free(self->mBuffer);
+ self->mBuffer = NULL;
+ self->mSize = 0;
return ALC_FALSE;
}
return ALC_TRUE;
}
-static void wave_stop_playback(ALCdevice *device)
+static void ALCwaveBackend_stop(ALCwaveBackend *self)
{
- wave_data *data = (wave_data*)device->ExtraData;
ALuint dataLen;
long size;
int res;
- if(data->killNow)
+ if(self->killNow)
return;
- data->killNow = 1;
- althrd_join(data->thread, &res);
+ self->killNow = 1;
+ althrd_join(self->thread, &res);
- free(data->buffer);
- data->buffer = NULL;
+ free(self->mBuffer);
+ self->mBuffer = NULL;
- size = ftell(data->f);
+ size = ftell(self->mFile);
if(size > 0)
{
- dataLen = size - data->DataStart;
- if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0)
- fwrite32le(dataLen, data->f); // 'data' header len
- if(fseek(data->f, 4, SEEK_SET) == 0)
- fwrite32le(size-8, data->f); // 'WAVE' header len
+ dataLen = size - self->mDataStart;
+ if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0)
+ fwrite32le(dataLen, self->mFile); // 'data' header len
+ if(fseek(self->mFile, 4, SEEK_SET) == 0)
+ fwrite32le(size-8, self->mFile); // 'WAVE' header len
}
}
-static const BackendFuncs wave_funcs = {
- wave_open_playback,
- wave_close_playback,
- wave_reset_playback,
- wave_start_playback,
- wave_stop_playback,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- ALCdevice_GetLatencyDefault
-};
+typedef struct ALCwaveBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCwaveBackendFactory;
+#define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
+
+static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self);
+static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type);
+static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory);
+
-ALCboolean alc_wave_init(BackendFuncs *func_list)
+ALCbackendFactory *ALCwaveBackendFactory_getFactory(void)
{
- *func_list = wave_funcs;
- return ALC_TRUE;
+ static ALCwaveBackendFactory factory = ALCWAVEBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
}
-void alc_wave_deinit(void)
+
+static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self))
{
+ return ALC_TRUE;
}
-void alc_wave_probe(enum DevProbe type)
+static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type)
{
- if(!ConfigValueExists("wave", "file"))
- return;
+ if(type == ALCbackend_Playback)
+ return !!ConfigValueExists(NULL, "wave", "file");
+ return ALC_FALSE;
+}
+static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type)
+{
switch(type)
{
case ALL_DEVICE_PROBE:
@@ -375,3 +427,16 @@ void alc_wave_probe(enum DevProbe type)
break;
}
}
+
+static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCwaveBackend *backend;
+ NEW_OBJ(backend, ALCwaveBackend)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
diff --git a/Alc/backends/winmm.c b/Alc/backends/winmm.c
index 624af37a..bf97ef2e 100644
--- a/Alc/backends/winmm.c
+++ b/Alc/backends/winmm.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -31,28 +31,13 @@
#include "alu.h"
#include "threads.h"
+#include "backends/base.h"
+
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
-
-typedef struct {
- // MMSYSTEM Device
- volatile ALboolean killNow;
- althrd_t thread;
-
- RefCount WaveBuffersCommitted;
- WAVEHDR WaveBuffer[4];
-
- union {
- HWAVEIN In;
- HWAVEOUT Out;
- } WaveHandle;
-
- WAVEFORMATEX Format;
-
- RingBuffer *Ring;
-} WinMMData;
+#define DEVNAME_TAIL " on OpenAL Soft"
static vector_al_string PlaybackDevices;
@@ -60,19 +45,13 @@ static vector_al_string CaptureDevices;
static void clear_devlist(vector_al_string *list)
{
- al_string *iter, *end;
-
- iter = VECTOR_ITER_BEGIN(*list);
- end = VECTOR_ITER_END(*list);
- for(;iter != end;iter++)
- AL_STRING_DEINIT(*iter);
+ 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;
@@ -83,30 +62,31 @@ static void ProbePlaybackDevices(void)
for(i = 0;i < numdevs;i++)
{
WAVEOUTCAPSW WaveCaps;
+ const al_string *iter;
al_string dname;
AL_STRING_INIT(dname);
if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
{
ALuint count = 0;
- do {
+ while(1)
+ {
al_string_copy_wcstr(&dname, WaveCaps.szPname);
- if(count != 0)
+ if(count == 0)
+ al_string_append_cstr(&dname, DEVNAME_TAIL);
+ else
{
char str[64];
- snprintf(str, sizeof(str), " #%d", count+1);
+ snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1);
al_string_append_cstr(&dname, str);
}
count++;
- iter = VECTOR_ITER_BEGIN(PlaybackDevices);
- end = VECTOR_ITER_END(PlaybackDevices);
- for(;iter != end;iter++)
- {
- if(al_string_cmp(*iter, dname) == 0)
- break;
- }
- } while(iter != end);
+#define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0)
+ VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY);
+ if(iter == VECTOR_ITER_END(PlaybackDevices)) break;
+#undef MATCH_ENTRY
+ }
TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
}
@@ -116,7 +96,6 @@ static void ProbePlaybackDevices(void)
static void ProbeCaptureDevices(void)
{
- al_string *iter, *end;
ALuint numdevs;
ALuint i;
@@ -127,30 +106,31 @@ static void ProbeCaptureDevices(void)
for(i = 0;i < numdevs;i++)
{
WAVEINCAPSW WaveCaps;
+ const al_string *iter;
al_string dname;
AL_STRING_INIT(dname);
if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
{
ALuint count = 0;
- do {
+ while(1)
+ {
al_string_copy_wcstr(&dname, WaveCaps.szPname);
- if(count != 0)
+ if(count == 0)
+ al_string_append_cstr(&dname, DEVNAME_TAIL);
+ else
{
char str[64];
- snprintf(str, sizeof(str), " #%d", count+1);
+ snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1);
al_string_append_cstr(&dname, str);
}
count++;
- iter = VECTOR_ITER_BEGIN(CaptureDevices);
- end = VECTOR_ITER_END(CaptureDevices);
- for(;iter != end;iter++)
- {
- if(al_string_cmp(*iter, dname) == 0)
- break;
- }
- } while(iter != end);
+#define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0)
+ VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY);
+ if(iter == VECTOR_ITER_END(CaptureDevices)) break;
+#undef MATCH_ENTRY
+ }
TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
}
@@ -159,111 +139,117 @@ static void ProbeCaptureDevices(void)
}
-/*
- WaveOutProc
+typedef struct ALCwinmmPlayback {
+ DERIVE_FROM_TYPE(ALCbackend);
- Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and
- returns to the application (for more data)
-*/
-static void CALLBACK WaveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
-{
- ALCdevice *Device = (ALCdevice*)instance;
- WinMMData *data = Device->ExtraData;
+ RefCount WaveBuffersCommitted;
+ WAVEHDR WaveBuffer[4];
- if(msg != WOM_DONE)
- return;
+ HWAVEOUT OutHdl;
- DecrementRef(&data->WaveBuffersCommitted);
- PostThreadMessage(data->thread, msg, 0, param1);
-}
+ WAVEFORMATEX Format;
-FORCE_ALIGN static int PlaybackThreadProc(void *arg)
-{
- ALCdevice *Device = (ALCdevice*)arg;
- WinMMData *data = Device->ExtraData;
- WAVEHDR *WaveHdr;
- MSG msg;
+ volatile ALboolean killNow;
+ althrd_t thread;
+} ALCwinmmPlayback;
- SetRTPriority();
- althrd_setname(althrd_current(), MIXER_THREAD_NAME);
+static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device);
+static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self);
- while(GetMessage(&msg, NULL, 0, 0))
- {
- if(msg.message != WOM_DONE)
- continue;
+static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2);
+static int ALCwinmmPlayback_mixerProc(void *arg);
- if(data->killNow)
- {
- if(ReadRef(&data->WaveBuffersCommitted) == 0)
- break;
- continue;
- }
+static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name);
+static void ALCwinmmPlayback_close(ALCwinmmPlayback *self);
+static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self);
+static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self);
+static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self);
+static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
+static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback)
- WaveHdr = ((WAVEHDR*)msg.lParam);
- aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength /
- data->Format.nBlockAlign);
+DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback);
- // Send buffer back to play more data
- waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR));
- IncrementRef(&data->WaveBuffersCommitted);
- }
- return 0;
+static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self);
+
+ InitRef(&self->WaveBuffersCommitted, 0);
+ self->OutHdl = NULL;
+
+ self->killNow = AL_TRUE;
}
-/*
- WaveInProc
+static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self)
+{
+ if(self->OutHdl)
+ waveOutClose(self->OutHdl);
+ self->OutHdl = 0;
- Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
- returns to the application (with more data)
-*/
-static void CALLBACK WaveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+/* ALCwinmmPlayback_waveOutProc
+ *
+ * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer
+ * is completed and returns to the application (for more data)
+ */
+static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
{
- ALCdevice *Device = (ALCdevice*)instance;
- WinMMData *data = Device->ExtraData;
+ ALCwinmmPlayback *self = (ALCwinmmPlayback*)instance;
- if(msg != WIM_DATA)
+ if(msg != WOM_DONE)
return;
- DecrementRef(&data->WaveBuffersCommitted);
- PostThreadMessage(data->thread, msg, 0, param1);
+ DecrementRef(&self->WaveBuffersCommitted);
+ PostThreadMessage(self->thread, msg, 0, param1);
}
-static int CaptureThreadProc(void *arg)
+FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg)
{
- ALCdevice *Device = (ALCdevice*)arg;
- WinMMData *data = Device->ExtraData;
+ ALCwinmmPlayback *self = arg;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
WAVEHDR *WaveHdr;
MSG msg;
- althrd_setname(althrd_current(), "alsoft-record");
+ SetRTPriority();
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
while(GetMessage(&msg, NULL, 0, 0))
{
- if(msg.message != WIM_DATA)
+ if(msg.message != WOM_DONE)
continue;
- /* Don't wait for other buffers to finish before quitting. We're
- * closing so we don't need them. */
- if(data->killNow)
- break;
+
+ if(self->killNow)
+ {
+ if(ReadRef(&self->WaveBuffersCommitted) == 0)
+ break;
+ continue;
+ }
WaveHdr = ((WAVEHDR*)msg.lParam);
- WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData,
- WaveHdr->dwBytesRecorded/data->Format.nBlockAlign);
+ aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength /
+ self->Format.nBlockAlign);
- // Send buffer back to capture more data
- waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR));
- IncrementRef(&data->WaveBuffersCommitted);
+ // Send buffer back to play more data
+ waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR));
+ IncrementRef(&self->WaveBuffersCommitted);
}
return 0;
}
-static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName)
+static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName)
{
- WinMMData *data = NULL;
- const al_string *iter, *end;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ const al_string *iter;
UINT DeviceID;
MMRESULT res;
@@ -271,129 +257,109 @@ static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName)
ProbePlaybackDevices();
// Find the Device ID matching the deviceName if valid
- iter = VECTOR_ITER_BEGIN(PlaybackDevices);
- end = VECTOR_ITER_END(PlaybackDevices);
- for(;iter != end;iter++)
- {
- if(!al_string_empty(*iter) &&
- (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
- {
- DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices));
- break;
- }
- }
- if(iter == end)
+#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && \
+ (!deviceName || al_string_cmp_cstr(*(iter), deviceName) == 0))
+ VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME);
+ if(iter == VECTOR_ITER_END(PlaybackDevices))
return ALC_INVALID_VALUE;
+#undef MATCH_DEVNAME
- data = calloc(1, sizeof(*data));
- if(!data)
- return ALC_OUT_OF_MEMORY;
- Device->ExtraData = data;
+ DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices));
retry_open:
- memset(&data->Format, 0, sizeof(WAVEFORMATEX));
- if(Device->FmtType == DevFmtFloat)
+ memset(&self->Format, 0, sizeof(WAVEFORMATEX));
+ if(device->FmtType == DevFmtFloat)
{
- data->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- data->Format.wBitsPerSample = 32;
+ self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ self->Format.wBitsPerSample = 32;
}
else
{
- data->Format.wFormatTag = WAVE_FORMAT_PCM;
- if(Device->FmtType == DevFmtUByte || Device->FmtType == DevFmtByte)
- data->Format.wBitsPerSample = 8;
+ self->Format.wFormatTag = WAVE_FORMAT_PCM;
+ if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte)
+ self->Format.wBitsPerSample = 8;
else
- data->Format.wBitsPerSample = 16;
+ self->Format.wBitsPerSample = 16;
}
- data->Format.nChannels = ((Device->FmtChans == DevFmtMono) ? 1 : 2);
- data->Format.nBlockAlign = data->Format.wBitsPerSample *
- data->Format.nChannels / 8;
- data->Format.nSamplesPerSec = Device->Frequency;
- data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec *
- data->Format.nBlockAlign;
- data->Format.cbSize = 0;
-
- if((res=waveOutOpen(&data->WaveHandle.Out, DeviceID, &data->Format, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
+ self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2);
+ self->Format.nBlockAlign = self->Format.wBitsPerSample *
+ self->Format.nChannels / 8;
+ self->Format.nSamplesPerSec = device->Frequency;
+ self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec *
+ self->Format.nBlockAlign;
+ self->Format.cbSize = 0;
+
+ if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
{
- if(Device->FmtType == DevFmtFloat)
+ if(device->FmtType == DevFmtFloat)
{
- Device->FmtType = DevFmtShort;
+ device->FmtType = DevFmtShort;
goto retry_open;
}
ERR("waveOutOpen failed: %u\n", res);
goto failure;
}
- al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
+ al_string_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
return ALC_NO_ERROR;
failure:
- if(data->WaveHandle.Out)
- waveOutClose(data->WaveHandle.Out);
+ if(self->OutHdl)
+ waveOutClose(self->OutHdl);
+ self->OutHdl = NULL;
- free(data);
- Device->ExtraData = NULL;
return ALC_INVALID_VALUE;
}
-static void WinMMClosePlayback(ALCdevice *device)
-{
- WinMMData *data = (WinMMData*)device->ExtraData;
-
- // Close the Wave device
- waveOutClose(data->WaveHandle.Out);
- data->WaveHandle.Out = 0;
-
- free(data);
- device->ExtraData = NULL;
-}
+static void ALCwinmmPlayback_close(ALCwinmmPlayback* UNUSED(self))
+{ }
-static ALCboolean WinMMResetPlayback(ALCdevice *device)
+static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self)
{
- WinMMData *data = (WinMMData*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
- data->Format.nSamplesPerSec /
+ self->Format.nSamplesPerSec /
device->Frequency);
device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4;
device->NumUpdates = 4;
- device->Frequency = data->Format.nSamplesPerSec;
+ device->Frequency = self->Format.nSamplesPerSec;
- if(data->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
+ if(self->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
{
- if(data->Format.wBitsPerSample == 32)
+ if(self->Format.wBitsPerSample == 32)
device->FmtType = DevFmtFloat;
else
{
- ERR("Unhandled IEEE float sample depth: %d\n", data->Format.wBitsPerSample);
+ ERR("Unhandled IEEE float sample depth: %d\n", self->Format.wBitsPerSample);
return ALC_FALSE;
}
}
- else if(data->Format.wFormatTag == WAVE_FORMAT_PCM)
+ else if(self->Format.wFormatTag == WAVE_FORMAT_PCM)
{
- if(data->Format.wBitsPerSample == 16)
+ if(self->Format.wBitsPerSample == 16)
device->FmtType = DevFmtShort;
- else if(data->Format.wBitsPerSample == 8)
+ else if(self->Format.wBitsPerSample == 8)
device->FmtType = DevFmtUByte;
else
{
- ERR("Unhandled PCM sample depth: %d\n", data->Format.wBitsPerSample);
+ ERR("Unhandled PCM sample depth: %d\n", self->Format.wBitsPerSample);
return ALC_FALSE;
}
}
else
{
- ERR("Unhandled format tag: 0x%04x\n", data->Format.wFormatTag);
+ ERR("Unhandled format tag: 0x%04x\n", self->Format.wFormatTag);
return ALC_FALSE;
}
- if(data->Format.nChannels == 2)
+ if(self->Format.nChannels == 2)
device->FmtChans = DevFmtStereo;
- else if(data->Format.nChannels == 1)
+ else if(self->Format.nChannels == 1)
device->FmtChans = DevFmtMono;
else
{
- ERR("Unhandled channel count: %d\n", data->Format.nChannels);
+ ERR("Unhandled channel count: %d\n", self->Format.nChannels);
return ALC_FALSE;
}
SetDefaultWFXChannelOrder(device);
@@ -401,18 +367,18 @@ static ALCboolean WinMMResetPlayback(ALCdevice *device)
return ALC_TRUE;
}
-static ALCboolean WinMMStartPlayback(ALCdevice *device)
+static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self)
{
- WinMMData *data = (WinMMData*)device->ExtraData;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
ALbyte *BufferData;
ALint BufferSize;
ALuint i;
- data->killNow = AL_FALSE;
- if(althrd_create(&data->thread, PlaybackThreadProc, device) != althrd_success)
+ self->killNow = AL_FALSE;
+ if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success)
return ALC_FALSE;
- InitRef(&data->WaveBuffersCommitted, 0);
+ InitRef(&self->WaveBuffersCommitted, 0);
// Create 4 Buffers
BufferSize = device->UpdateSize*device->NumUpdates / 4;
@@ -421,49 +387,153 @@ static ALCboolean WinMMStartPlayback(ALCdevice *device)
BufferData = calloc(4, BufferSize);
for(i = 0;i < 4;i++)
{
- memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
- data->WaveBuffer[i].dwBufferLength = BufferSize;
- 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));
- IncrementRef(&data->WaveBuffersCommitted);
+ memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR));
+ self->WaveBuffer[i].dwBufferLength = BufferSize;
+ self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
+ (self->WaveBuffer[i-1].lpData +
+ self->WaveBuffer[i-1].dwBufferLength));
+ waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
+ waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
+ IncrementRef(&self->WaveBuffersCommitted);
}
return ALC_TRUE;
}
-static void WinMMStopPlayback(ALCdevice *device)
+static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self)
{
- WinMMData *data = (WinMMData*)device->ExtraData;
void *buffer = NULL;
int i;
- if(data->killNow)
+ if(self->killNow)
return;
// Set flag to stop processing headers
- data->killNow = AL_TRUE;
- althrd_join(data->thread, &i);
+ self->killNow = AL_TRUE;
+ althrd_join(self->thread, &i);
// Release the wave buffers
for(i = 0;i < 4;i++)
{
- waveOutUnprepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR));
- if(i == 0) buffer = data->WaveBuffer[i].lpData;
- data->WaveBuffer[i].lpData = NULL;
+ waveOutUnprepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
+ if(i == 0) buffer = self->WaveBuffer[i].lpData;
+ self->WaveBuffer[i].lpData = NULL;
}
free(buffer);
}
-static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
+
+typedef struct ALCwinmmCapture {
+ DERIVE_FROM_TYPE(ALCbackend);
+
+ RefCount WaveBuffersCommitted;
+ WAVEHDR WaveBuffer[4];
+
+ HWAVEIN InHdl;
+
+ RingBuffer *Ring;
+
+ WAVEFORMATEX Format;
+
+ volatile ALboolean killNow;
+ althrd_t thread;
+} ALCwinmmCapture;
+
+static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device);
+static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self);
+
+static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2);
+static int ALCwinmmCapture_captureProc(void *arg);
+
+static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name);
+static void ALCwinmmCapture_close(ALCwinmmCapture *self);
+static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self);
+static void ALCwinmmCapture_stop(ALCwinmmCapture *self);
+static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self);
+static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture)
+
+DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture);
+
+
+static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device)
+{
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ SET_VTABLE2(ALCwinmmCapture, ALCbackend, self);
+
+ InitRef(&self->WaveBuffersCommitted, 0);
+ self->InHdl = NULL;
+
+ self->killNow = AL_TRUE;
+}
+
+static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self)
+{
+ if(self->InHdl)
+ waveInClose(self->InHdl);
+ self->InHdl = 0;
+
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+/* ALCwinmmCapture_waveInProc
+ *
+ * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer
+ * is completed and returns to the application (with more data).
+ */
+static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2))
+{
+ ALCwinmmCapture *self = (ALCwinmmCapture*)instance;
+
+ if(msg != WIM_DATA)
+ return;
+
+ DecrementRef(&self->WaveBuffersCommitted);
+ PostThreadMessage(self->thread, msg, 0, param1);
+}
+
+static int ALCwinmmCapture_captureProc(void *arg)
{
- const al_string *iter, *end;
+ ALCwinmmCapture *self = arg;
+ WAVEHDR *WaveHdr;
+ MSG msg;
+
+ althrd_setname(althrd_current(), RECORD_THREAD_NAME);
+
+ while(GetMessage(&msg, NULL, 0, 0))
+ {
+ if(msg.message != WIM_DATA)
+ continue;
+ /* Don't wait for other buffers to finish before quitting. We're
+ * closing so we don't need them. */
+ if(self->killNow)
+ break;
+
+ WaveHdr = ((WAVEHDR*)msg.lParam);
+ WriteRingBuffer(self->Ring, (ALubyte*)WaveHdr->lpData,
+ WaveHdr->dwBytesRecorded/self->Format.nBlockAlign);
+
+ // Send buffer back to capture more data
+ waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR));
+ IncrementRef(&self->WaveBuffersCommitted);
+ }
+
+ return 0;
+}
+
+
+static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ const al_string *iter;
ALbyte *BufferData = NULL;
DWORD CapturedDataSize;
- WinMMData *data = NULL;
ALint BufferSize;
UINT DeviceID;
MMRESULT res;
@@ -473,21 +543,15 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
ProbeCaptureDevices();
// Find the Device ID matching the deviceName if valid
- iter = VECTOR_ITER_BEGIN(CaptureDevices);
- end = VECTOR_ITER_END(CaptureDevices);
- for(;iter != end;iter++)
- {
- if(!al_string_empty(*iter) &&
- (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0))
- {
- DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices));
- break;
- }
- }
- if(iter == end)
+#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && (!name || al_string_cmp_cstr(*iter, name) == 0))
+ VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME);
+ if(iter == VECTOR_ITER_END(CaptureDevices))
return ALC_INVALID_VALUE;
+#undef MATCH_DEVNAME
+
+ DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices));
- switch(Device->FmtChans)
+ switch(device->FmtChans)
{
case DevFmtMono:
case DevFmtStereo:
@@ -495,13 +559,14 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
case DevFmtQuad:
case DevFmtX51:
- case DevFmtX51Side:
+ case DevFmtX51Rear:
case DevFmtX61:
case DevFmtX71:
+ case DevFmtBFormat3D:
return ALC_INVALID_ENUM;
}
- switch(Device->FmtType)
+ switch(device->FmtType)
{
case DevFmtUByte:
case DevFmtShort:
@@ -515,147 +580,134 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName)
return ALC_INVALID_ENUM;
}
- data = calloc(1, sizeof(*data));
- if(!data)
- return ALC_OUT_OF_MEMORY;
- Device->ExtraData = data;
-
- memset(&data->Format, 0, sizeof(WAVEFORMATEX));
- data->Format.wFormatTag = ((Device->FmtType == DevFmtFloat) ?
+ memset(&self->Format, 0, sizeof(WAVEFORMATEX));
+ self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ?
WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
- data->Format.nChannels = ChannelsFromDevFmt(Device->FmtChans);
- data->Format.wBitsPerSample = BytesFromDevFmt(Device->FmtType) * 8;
- data->Format.nBlockAlign = data->Format.wBitsPerSample *
- data->Format.nChannels / 8;
- data->Format.nSamplesPerSec = Device->Frequency;
- data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec *
- data->Format.nBlockAlign;
- data->Format.cbSize = 0;
-
- if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
+ self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
+ self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
+ self->Format.nBlockAlign = self->Format.wBitsPerSample *
+ self->Format.nChannels / 8;
+ self->Format.nSamplesPerSec = device->Frequency;
+ self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec *
+ self->Format.nBlockAlign;
+ self->Format.cbSize = 0;
+
+ if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
{
ERR("waveInOpen failed: %u\n", res);
goto failure;
}
// Allocate circular memory buffer for the captured audio
- CapturedDataSize = Device->UpdateSize*Device->NumUpdates;
+ CapturedDataSize = device->UpdateSize*device->NumUpdates;
// Make sure circular buffer is at least 100ms in size
- if(CapturedDataSize < (data->Format.nSamplesPerSec / 10))
- CapturedDataSize = data->Format.nSamplesPerSec / 10;
+ if(CapturedDataSize < (self->Format.nSamplesPerSec / 10))
+ CapturedDataSize = self->Format.nSamplesPerSec / 10;
- data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize);
- if(!data->Ring)
- goto failure;
+ self->Ring = CreateRingBuffer(self->Format.nBlockAlign, CapturedDataSize);
+ if(!self->Ring) goto failure;
- InitRef(&data->WaveBuffersCommitted, 0);
+ InitRef(&self->WaveBuffersCommitted, 0);
// Create 4 Buffers of 50ms each
- BufferSize = data->Format.nAvgBytesPerSec / 20;
- BufferSize -= (BufferSize % data->Format.nBlockAlign);
+ BufferSize = self->Format.nAvgBytesPerSec / 20;
+ BufferSize -= (BufferSize % self->Format.nBlockAlign);
BufferData = calloc(4, BufferSize);
- if(!BufferData)
- goto failure;
+ if(!BufferData) goto failure;
for(i = 0;i < 4;i++)
{
- memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR));
- data->WaveBuffer[i].dwBufferLength = BufferSize;
- 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));
- IncrementRef(&data->WaveBuffersCommitted);
+ memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR));
+ self->WaveBuffer[i].dwBufferLength = BufferSize;
+ self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData :
+ (self->WaveBuffer[i-1].lpData +
+ self->WaveBuffer[i-1].dwBufferLength));
+ self->WaveBuffer[i].dwFlags = 0;
+ self->WaveBuffer[i].dwLoops = 0;
+ waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
+ waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
+ IncrementRef(&self->WaveBuffersCommitted);
}
- if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success)
+ self->killNow = AL_FALSE;
+ if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success)
goto failure;
- al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
+ al_string_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
return ALC_NO_ERROR;
failure:
if(BufferData)
{
for(i = 0;i < 4;i++)
- waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
+ waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
free(BufferData);
}
- if(data->Ring)
- DestroyRingBuffer(data->Ring);
+ if(self->Ring)
+ DestroyRingBuffer(self->Ring);
+ self->Ring = NULL;
- if(data->WaveHandle.In)
- waveInClose(data->WaveHandle.In);
+ if(self->InHdl)
+ waveInClose(self->InHdl);
+ self->InHdl = NULL;
- free(data);
- Device->ExtraData = NULL;
return ALC_INVALID_VALUE;
}
-static void WinMMCloseCapture(ALCdevice *Device)
+static void ALCwinmmCapture_close(ALCwinmmCapture *self)
{
- WinMMData *data = (WinMMData*)Device->ExtraData;
void *buffer = NULL;
int i;
/* Tell the processing thread to quit and wait for it to do so. */
- data->killNow = AL_TRUE;
- PostThreadMessage(data->thread, WM_QUIT, 0, 0);
+ self->killNow = AL_TRUE;
+ PostThreadMessage(self->thread, WM_QUIT, 0, 0);
- althrd_join(data->thread, &i);
+ althrd_join(self->thread, &i);
/* Make sure capture is stopped and all pending buffers are flushed. */
- waveInReset(data->WaveHandle.In);
+ waveInReset(self->InHdl);
// Release the wave buffers
for(i = 0;i < 4;i++)
{
- waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR));
- if(i == 0) buffer = data->WaveBuffer[i].lpData;
- data->WaveBuffer[i].lpData = NULL;
+ waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
+ if(i == 0) buffer = self->WaveBuffer[i].lpData;
+ self->WaveBuffer[i].lpData = NULL;
}
free(buffer);
- DestroyRingBuffer(data->Ring);
- data->Ring = NULL;
+ DestroyRingBuffer(self->Ring);
+ self->Ring = NULL;
// Close the Wave device
- waveInClose(data->WaveHandle.In);
- data->WaveHandle.In = 0;
-
- free(data);
- Device->ExtraData = NULL;
+ waveInClose(self->InHdl);
+ self->InHdl = NULL;
}
-static void WinMMStartCapture(ALCdevice *Device)
+static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self)
{
- WinMMData *data = (WinMMData*)Device->ExtraData;
- waveInStart(data->WaveHandle.In);
+ waveInStart(self->InHdl);
+ return ALC_TRUE;
}
-static void WinMMStopCapture(ALCdevice *Device)
+static void ALCwinmmCapture_stop(ALCwinmmCapture *self)
{
- WinMMData *data = (WinMMData*)Device->ExtraData;
- waveInStop(data->WaveHandle.In);
+ waveInStop(self->InHdl);
}
-static ALCenum WinMMCaptureSamples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
+static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples)
{
- WinMMData *data = (WinMMData*)Device->ExtraData;
- ReadRingBuffer(data->Ring, Buffer, Samples);
+ ReadRingBuffer(self->Ring, buffer, samples);
return ALC_NO_ERROR;
}
-static ALCuint WinMMAvailableSamples(ALCdevice *Device)
+static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self)
{
- WinMMData *data = (WinMMData*)Device->ExtraData;
- return RingBufferSize(data->Ring);
+ return RingBufferSize(self->Ring);
}
@@ -670,31 +722,29 @@ static inline void AppendCaptureDeviceList2(const al_string *name)
AppendCaptureDeviceList(al_string_get_cstr(*name));
}
-static const BackendFuncs WinMMFuncs = {
- WinMMOpenPlayback,
- WinMMClosePlayback,
- WinMMResetPlayback,
- WinMMStartPlayback,
- WinMMStopPlayback,
- WinMMOpenCapture,
- WinMMCloseCapture,
- WinMMStartCapture,
- WinMMStopCapture,
- WinMMCaptureSamples,
- WinMMAvailableSamples,
- ALCdevice_GetLatencyDefault
-};
-
-ALCboolean alcWinMMInit(BackendFuncs *FuncList)
+typedef struct ALCwinmmBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCwinmmBackendFactory;
+#define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self);
+static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self);
+static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type);
+static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory);
+
+
+static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self))
{
VECTOR_INIT(PlaybackDevices);
VECTOR_INIT(CaptureDevices);
- *FuncList = WinMMFuncs;
return ALC_TRUE;
}
-void alcWinMMDeinit()
+static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self))
{
clear_devlist(&PlaybackDevices);
VECTOR_DEINIT(PlaybackDevices);
@@ -703,7 +753,14 @@ void alcWinMMDeinit()
VECTOR_DEINIT(CaptureDevices);
}
-void alcWinMMProbe(enum DevProbe type)
+static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type)
{
switch(type)
{
@@ -718,3 +775,29 @@ void alcWinMMProbe(enum DevProbe type)
break;
}
}
+
+static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCwinmmPlayback *backend;
+ NEW_OBJ(backend, ALCwinmmPlayback)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+ if(type == ALCbackend_Capture)
+ {
+ ALCwinmmCapture *backend;
+ NEW_OBJ(backend, ALCwinmmCapture)(device);
+ if(!backend) return NULL;
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void)
+{
+ static ALCwinmmBackendFactory factory = ALCWINMMBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
+}
diff --git a/Alc/bs2b.c b/Alc/bs2b.c
index 0319f948..6c3f052b 100644
--- a/Alc/bs2b.c
+++ b/Alc/bs2b.c
@@ -27,120 +27,98 @@
#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;
-
- if ((bs2b->srate > 192000) || (bs2b->srate < 2000))
- bs2b->srate = BS2B_DEFAULT_SRATE;
+ float Fc_lo, Fc_hi;
+ float G_lo, G_hi;
+ float x, g;
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.
* See descriptions in "bs2b.h"
*/
-void bs2b_set_level(struct bs2b *bs2b, int level)
+void bs2b_set_params(struct bs2b *bs2b, int level, int srate)
{
- if(level == bs2b->level)
- return;
+ if(srate <= 0) srate = 1;
+
bs2b->level = level;
+ bs2b->srate = srate;
init(bs2b);
-} /* bs2b_set_level */
+} /* bs2b_set_params */
int bs2b_get_level(struct bs2b *bs2b)
{
return bs2b->level;
} /* bs2b_get_level */
-void bs2b_set_srate(struct bs2b *bs2b, int srate)
-{
- if (srate == bs2b->srate)
- return;
- bs2b->srate = srate;
- init(bs2b);
-} /* bs2b_set_srate */
-
int bs2b_get_srate(struct bs2b *bs2b)
{
return bs2b->srate;
@@ -151,35 +129,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);
diff --git a/Alc/bsinc.c b/Alc/bsinc.c
new file mode 100644
index 00000000..f795120f
--- /dev/null
+++ b/Alc/bsinc.c
@@ -0,0 +1,981 @@
+
+#include "config.h"
+
+#include "AL/al.h"
+#include "align.h"
+
+/* Table of windowed sinc coefficients and deltas. This 11th order filter
+ * has a rejection of -60 dB, yielding a transition width of ~0.302
+ * (normalized frequency). Order increases when downsampling to a limit of
+ * one octave, after which the quality of the filter (transition width)
+ * suffers to reduce the CPU cost. The bandlimiting will cut all sound after
+ * downsampling by ~2.73 octaves.
+ */
+alignas(16) const ALfloat bsincTab[18840] =
+{
+ /* 24, 0 */ +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f, +0.000000000e+00f,
+
+ /* 24, 0 */ +1.501390780e-03f, +3.431804419e-03f, +6.512803185e-03f, +1.091425387e-02f, +1.664594540e-02f, +2.351091132e-02f, +3.109255671e-02f, +3.878419288e-02f, +4.586050701e-02f, +5.158058002e-02f, +5.530384985e-02f, +5.659614054e-02f, +5.530384985e-02f, +5.158058002e-02f, +4.586050701e-02f, +3.878419288e-02f, +3.109255671e-02f, +2.351091132e-02f, +1.664594540e-02f, +1.091425387e-02f, +6.512803185e-03f, +3.431804419e-03f, +1.501390780e-03f, +4.573885647e-04f,
+ /* 24, 1 */ +1.413186400e-03f, +3.279858311e-03f, +6.282638036e-03f, +1.059932179e-02f, +1.625135142e-02f, +2.305547031e-02f, +3.060840342e-02f, +3.831365198e-02f, +4.545054680e-02f, +5.127577001e-02f, +5.513916011e-02f, +5.659104154e-02f, +5.545895049e-02f, +5.187752167e-02f, +4.626513642e-02f, +3.925233583e-02f, +3.157717954e-02f, +2.396921539e-02f, +1.704503934e-02f, +1.123445076e-02f, +6.748179094e-03f, +3.588275667e-03f, +1.593065611e-03f, +5.022154476e-04f,
+ /* 24, 2 */ +1.328380648e-03f, +3.132379333e-03f, +6.057656813e-03f, +1.028967374e-02f, +1.586133102e-02f, +2.260301890e-02f, +3.012488684e-02f, +3.784089895e-02f, +4.503543229e-02f, +5.096323022e-02f, +5.496495842e-02f, +5.657574693e-02f, +5.560438923e-02f, +5.216645963e-02f, +4.666426010e-02f, +3.971789474e-02f, +3.206210284e-02f, +2.443025293e-02f, +1.744855617e-02f, +1.155988996e-02f, +6.988790100e-03f, +3.749328623e-03f, +1.688282347e-03f, +5.494305796e-04f,
+ /* 24, 3 */ +1.246901403e-03f, +2.989308098e-03f, +5.837830254e-03f, +9.985325752e-03f, +1.547595434e-02f, +2.215368059e-02f, +2.964217216e-02f, +3.736611920e-02f, +4.461534144e-02f, +5.064310236e-02f, +5.478132634e-02f, +5.655026396e-02f, +5.574009777e-02f, +5.244726189e-02f, +4.705770477e-02f, +4.018068337e-02f, +3.254715574e-02f, +2.489389144e-02f, +1.785641537e-02f, +1.189054572e-02f, +7.234657995e-03f, +3.915018340e-03f, +1.787112015e-03f, +5.991047395e-04f,
+ /* 24, 4 */ +1.168676301e-03f, +2.850583915e-03f, +5.623126723e-03f, +9.686290690e-03f, +1.509528803e-02f, +2.170757578e-02f, +2.916042250e-02f, +3.688949768e-02f, +4.419045351e-02f, +5.031553118e-02f, +5.458834968e-02f, +5.651460469e-02f, +5.586601230e-02f, +5.271979985e-02f, +4.744529894e-02f, +4.064051541e-02f, +3.303216567e-02f, +2.535999546e-02f, +1.826853297e-02f, +1.222638897e-02f, +7.485801959e-03f, +4.085398290e-03f, +1.889625146e-03f, +6.513091287e-04f,
+ /* 24, 5 */ +1.093632798e-03f, +2.716144855e-03f, +5.413512274e-03f, +9.392578266e-03f, +1.471939531e-02f, +2.126482169e-02f, +2.867979883e-02f, +3.641121873e-02f, +4.376094899e-02f, +4.998066438e-02f, +5.438611851e-02f, +5.646878599e-02f, +5.598207354e-02f, +5.298394839e-02f, +4.782687301e-02f, +4.109720465e-02f, +3.351695842e-02f, +2.582842673e-02f, +1.868482156e-02f, +1.256738733e-02f, +7.742238512e-03f, +4.260520294e-03f, +1.995891717e-03f, +7.061153220e-04f,
+ /* 24, 6 */ +1.021698233e-03f, +2.585927824e-03f, +5.208950715e-03f, +9.104195104e-03f, +1.434833590e-02f, +2.082553239e-02f, +2.820045990e-02f, +3.593146595e-02f, +4.332700946e-02f, +4.963865252e-02f, +5.417472708e-02f, +5.641282954e-02f, +5.608822683e-02f, +5.323958602e-02f, +4.820225940e-02f, +4.155056502e-02f, +3.400135826e-02f, +2.629904416e-02f, +1.910519032e-02f, +1.291350505e-02f, +8.003981455e-03f, +4.440434453e-03f, +2.105981077e-03f, +7.635952183e-04f,
+ /* 24, 7 */ +9.527998831e-04f, +2.459868628e-03f, +5.009403670e-03f, +8.821144768e-03f, +1.398216608e-02f, +2.038981869e-02f, +2.772256216e-02f, +3.545042216e-02f, +4.288881749e-02f, +4.928964888e-02f, +5.395427373e-02f, +5.634676181e-02f, +5.618442211e-02f, +5.348659488e-02f, +4.857129262e-02f, +4.200041076e-02f, +3.448518802e-02f, +2.677170395e-02f, +1.952954505e-02f, +1.326470299e-02f, +8.271041819e-03f, +4.625189083e-03f, +2.219961884e-03f, +8.238209888e-04f,
+ /* 24, 8 */ +8.868650246e-04f, +2.337902042e-03f, +4.814830642e-03f, +8.543427812e-03f, +1.362093865e-02f, +1.995778816e-02f, +2.724625964e-02f, +3.496826923e-02f, +4.244655653e-02f, +4.893380942e-02f, +5.372486088e-02f, +5.627061400e-02f, +5.627061400e-02f, +5.372486088e-02f, +4.893380942e-02f, +4.244655653e-02f, +3.496826923e-02f, +2.724625964e-02f, +1.995778816e-02f, +1.362093865e-02f, +8.543427812e-03f, +4.814830642e-03f, +2.337902042e-03f, +8.868650246e-04f,
+ /* 24, 9 */ +8.238209888e-04f, +2.219961884e-03f, +4.625189083e-03f, +8.271041819e-03f, +1.326470299e-02f, +1.952954505e-02f, +2.677170395e-02f, +3.448518802e-02f, +4.200041076e-02f, +4.857129262e-02f, +5.348659488e-02f, +5.618442211e-02f, +5.634676181e-02f, +5.395427373e-02f, +4.928964888e-02f, +4.288881749e-02f, +3.545042216e-02f, +2.772256216e-02f, +2.038981869e-02f, +1.398216608e-02f, +8.821144768e-03f, +5.009403670e-03f, +2.459868628e-03f, +9.527998831e-04f,
+ /* 24,10 */ +7.635952183e-04f, +2.105981077e-03f, +4.440434453e-03f, +8.003981455e-03f, +1.291350505e-02f, +1.910519032e-02f, +2.629904416e-02f, +3.400135826e-02f, +4.155056502e-02f, +4.820225940e-02f, +5.323958602e-02f, +5.608822683e-02f, +5.641282954e-02f, +5.417472708e-02f, +4.963865252e-02f, +4.332700946e-02f, +3.593146595e-02f, +2.820045990e-02f, +2.082553239e-02f, +1.434833590e-02f, +9.104195104e-03f, +5.208950715e-03f, +2.585927824e-03f, +1.021698233e-03f,
+ /* 24,11 */ +7.061153220e-04f, +1.995891717e-03f, +4.260520294e-03f, +7.742238512e-03f, +1.256738733e-02f, +1.868482156e-02f, +2.582842673e-02f, +3.351695842e-02f, +4.109720465e-02f, +4.782687301e-02f, +5.298394839e-02f, +5.598207354e-02f, +5.646878599e-02f, +5.438611851e-02f, +4.998066438e-02f, +4.376094899e-02f, +3.641121873e-02f, +2.867979883e-02f, +2.126482169e-02f, +1.471939531e-02f, +9.392578266e-03f, +5.413512274e-03f, +2.716144855e-03f, +1.093632798e-03f,
+ /* 24,12 */ +6.513091287e-04f, +1.889625146e-03f, +4.085398290e-03f, +7.485801959e-03f, +1.222638897e-02f, +1.826853297e-02f, +2.535999546e-02f, +3.303216567e-02f, +4.064051541e-02f, +4.744529894e-02f, +5.271979985e-02f, +5.586601230e-02f, +5.651460469e-02f, +5.458834968e-02f, +5.031553118e-02f, +4.419045351e-02f, +3.688949768e-02f, +2.916042250e-02f, +2.170757578e-02f, +1.509528803e-02f, +9.686290690e-03f, +5.623126723e-03f, +2.850583915e-03f, +1.168676301e-03f,
+ /* 24,13 */ +5.991047395e-04f, +1.787112015e-03f, +3.915018340e-03f, +7.234657995e-03f, +1.189054572e-02f, +1.785641537e-02f, +2.489389144e-02f, +3.254715574e-02f, +4.018068337e-02f, +4.705770477e-02f, +5.244726189e-02f, +5.574009777e-02f, +5.655026396e-02f, +5.478132634e-02f, +5.064310236e-02f, +4.461534144e-02f, +3.736611920e-02f, +2.964217216e-02f, +2.215368059e-02f, +1.547595434e-02f, +9.985325752e-03f, +5.837830254e-03f, +2.989308098e-03f, +1.246901403e-03f,
+ /* 24,14 */ +5.494305796e-04f, +1.688282347e-03f, +3.749328623e-03f, +6.988790100e-03f, +1.155988996e-02f, +1.744855617e-02f, +2.443025293e-02f, +3.206210284e-02f, +3.971789474e-02f, +4.666426010e-02f, +5.216645963e-02f, +5.560438923e-02f, +5.657574693e-02f, +5.496495842e-02f, +5.096323022e-02f, +4.503543229e-02f, +3.784089895e-02f, +3.012488684e-02f, +2.260301890e-02f, +1.586133102e-02f, +1.028967374e-02f, +6.057656813e-03f, +3.132379333e-03f, +1.328380648e-03f,
+ /* 24,15 */ +5.022154476e-04f, +1.593065611e-03f, +3.588275667e-03f, +6.748179094e-03f, +1.123445076e-02f, +1.704503934e-02f, +2.396921539e-02f, +3.157717954e-02f, +3.925233583e-02f, +4.626513642e-02f, +5.187752167e-02f, +5.545895049e-02f, +5.659104154e-02f, +5.513916011e-02f, +5.127577001e-02f, +4.545054680e-02f, +3.831365198e-02f, +3.060840342e-02f, +2.305547031e-02f, +1.625135142e-02f, +1.059932179e-02f, +6.282638036e-03f, +3.279858311e-03f, +1.413186400e-03f,
+ /* 24, 0 */ -1.127794091e-03f, -1.412146034e-03f, -3.831821143e-04f, +3.227045776e-03f, +1.066768284e-02f, +2.270769386e-02f, +3.918787347e-02f, +5.876378120e-02f, +7.897914846e-02f, +9.670702233e-02f, +1.088639494e-01f, +1.131922811e-01f, +1.088639494e-01f, +9.670702233e-02f, +7.897914846e-02f, +5.876378120e-02f, +3.918787347e-02f, +2.270769386e-02f, +1.066768284e-02f, +3.227045776e-03f, -3.831821143e-04f, -1.412146034e-03f, -1.127794091e-03f, -4.881068065e-04f,
+ /* 24, 1 */ -1.090580766e-03f, -1.420873386e-03f, -5.091873886e-04f, +2.900756187e-03f, +1.007202248e-02f, +2.181774373e-02f, +3.804709217e-02f, +5.749143322e-02f, +7.775467878e-02f, +9.573284944e-02f, +1.083163184e-01f, +1.131750947e-01f, +1.093805191e-01f, +9.765915788e-02f, +8.019389052e-02f, +6.003885715e-02f, +4.034112484e-02f, +2.361538773e-02f, +1.128161899e-02f, +3.568453927e-03f, -2.470940015e-04f, -1.398398357e-03f, -1.163769773e-03f, -5.264712252e-04f,
+ /* 24, 2 */ -1.052308046e-03f, -1.424863695e-03f, -6.254426725e-04f, +2.589304991e-03f, +9.494532203e-03f, +2.094570441e-02f, +3.691925193e-02f, +5.622252667e-02f, +7.652128881e-02f, +9.473734332e-02f, +1.077380418e-01f, +1.131235487e-01f, +1.098656350e-01f, +9.858856505e-02f, +8.139809812e-02f, +6.131593665e-02f, +4.150635732e-02f, +2.454063933e-02f, +1.191392194e-02f, +3.925253463e-03f, -1.005901154e-04f, -1.379341793e-03f, -1.198322390e-03f, -5.655319713e-04f,
+ /* 24, 3 */ -1.013146991e-03f, -1.424394748e-03f, -7.322803183e-04f, +2.292405169e-03f, +8.935092066e-03f, +2.009172411e-02f, +3.580480556e-02f, +5.495776346e-02f, +7.527978553e-02f, +9.372122042e-02f, +1.071295572e-01f, +1.130376830e-01f, +1.103189277e-01f, +9.949456662e-02f, +8.259096568e-02f, +6.259428489e-02f, +4.268306423e-02f, +2.548324354e-02f, +1.256466766e-02f, +4.297709369e-03f, +5.666214823e-05f, -1.354682733e-03f, -1.231259367e-03f, -6.052075404e-04f,
+ /* 24, 4 */ -9.732614753e-04f, -1.419738627e-03f, -8.300317840e-04f, +2.009763334e-03f, +8.393568260e-03f, +1.925593236e-02f, +3.470418745e-02f, +5.369783330e-02f, +7.403097485e-02f, +9.268520876e-02f, +1.064913245e-01f, +1.129175635e-01f, +1.107400515e-01f, +1.003764999e-01f, +8.377168968e-02f, +6.387315732e-02f, +4.387072153e-02f, +2.644297610e-02f, +1.323391671e-02f, +4.686078310e-03f, +2.249946366e-04f, -1.324122762e-03f, -1.262381011e-03f, -6.454100415e-04f,
+ /* 24, 5 */ -9.328082015e-04f, -1.411161525e-03f, -9.190272443e-04f, +1.741080225e-03f, +7.869813543e-03f, +1.843844016e-02f, +3.361781336e-02f, +5.244341325e-02f, +7.277566076e-02f, +9.163004717e-02f, +1.058238246e-01f, +1.127632829e-01f, +1.111286847e-01f, +1.012337173e-01f, +8.493946948e-02f, +6.515180031e-02f, +4.506878807e-02f, +2.741959349e-02f, +1.392171386e-02f, +5.090608136e-03f, +4.047380047e-04f, -1.287358924e-03f, -1.291480556e-03f, -6.860450823e-04f,
+ /* 24, 6 */ -8.919367204e-04f, -1.398923562e-03f, -9.995952120e-04f, +1.486051192e-03f, +7.363667669e-03f, +1.763934022e-02f, +3.254608027e-02f, +5.119516710e-02f, +7.151464464e-02f, +9.055648452e-02f, +1.051275597e-01f, +1.125749599e-01f, +1.114845301e-01f, +1.020655875e-01f, +8.609350809e-02f, +6.642945179e-02f, +4.627670593e-02f, +2.841283293e-02f, +1.462808772e-02f, +5.511537402e-03f, +5.962212734e-04f, -1.244083985e-03f, -1.318344226e-03f, -7.270116618e-04f,
+ /* 24, 7 */ -8.507894667e-04f, -1.383278624e-03f, -1.072062171e-03f, +1.244366682e-03f, +6.874957829e-03f, +1.685870710e-02f, +3.148936626e-02f, +4.995374490e-02f, +7.024872443e-02f, +8.946527894e-02f, +1.044030520e-01f, +1.123527394e-01f, +1.118073151e-01f, +1.028714955e-01f, +8.723301301e-02f, +6.770534195e-02f, +4.749390083e-02f, +2.942241233e-02f, +1.535305047e-02f, +5.949094883e-03f, +7.997713791e-04f, -1.193986722e-03f, -1.342751302e-03f, -7.682020711e-04f,
+ /* 24, 8 */ -8.095018024e-04f, -1.364474212e-03f, -1.136752219e-03f, +1.015712718e-03f, +6.403499096e-03f, +1.609659749e-02f, +3.044803032e-02f, +4.871978245e-02f, +6.897869391e-02f, +8.835719701e-02f, +1.036508436e-01f, +1.120967923e-01f, +1.120967923e-01f, +1.036508436e-01f, +8.835719701e-02f, +6.897869391e-02f, +4.871978245e-02f, +3.044803032e-02f, +1.609659749e-02f, +6.403499096e-03f, +1.015712718e-03f, -1.136752219e-03f, -1.364474212e-03f, -8.095018024e-04f,
+ /* 24, 9 */ -7.682020711e-04f, -1.342751302e-03f, -1.193986722e-03f, +7.997713791e-04f, +5.949094883e-03f, +1.535305047e-02f, +2.942241233e-02f, +4.749390083e-02f, +6.770534195e-02f, +8.723301301e-02f, +1.028714955e-01f, +1.118073151e-01f, +1.123527394e-01f, +1.044030520e-01f, +8.946527894e-02f, +7.024872443e-02f, +4.995374490e-02f, +3.148936626e-02f, +1.685870710e-02f, +6.874957829e-03f, +1.244366682e-03f, -1.072062171e-03f, -1.383278624e-03f, -8.507894667e-04f,
+ /* 24,10 */ -7.270116618e-04f, -1.318344226e-03f, -1.244083985e-03f, +5.962212734e-04f, +5.511537402e-03f, +1.462808772e-02f, +2.841283293e-02f, +4.627670593e-02f, +6.642945179e-02f, +8.609350809e-02f, +1.020655875e-01f, +1.114845301e-01f, +1.125749599e-01f, +1.051275597e-01f, +9.055648452e-02f, +7.151464464e-02f, +5.119516710e-02f, +3.254608027e-02f, +1.763934022e-02f, +7.363667669e-03f, +1.486051192e-03f, -9.995952120e-04f, -1.398923562e-03f, -8.919367204e-04f,
+ /* 24,11 */ -6.860450823e-04f, -1.291480556e-03f, -1.287358924e-03f, +4.047380047e-04f, +5.090608136e-03f, +1.392171386e-02f, +2.741959349e-02f, +4.506878807e-02f, +6.515180031e-02f, +8.493946948e-02f, +1.012337173e-01f, +1.111286847e-01f, +1.127632829e-01f, +1.058238246e-01f, +9.163004717e-02f, +7.277566076e-02f, +5.244341325e-02f, +3.361781336e-02f, +1.843844016e-02f, +7.869813543e-03f, +1.741080225e-03f, -9.190272443e-04f, -1.411161525e-03f, -9.328082015e-04f,
+ /* 24,12 */ -6.454100415e-04f, -1.262381011e-03f, -1.324122762e-03f, +2.249946366e-04f, +4.686078310e-03f, +1.323391671e-02f, +2.644297610e-02f, +4.387072153e-02f, +6.387315732e-02f, +8.377168968e-02f, +1.003764999e-01f, +1.107400515e-01f, +1.129175635e-01f, +1.064913245e-01f, +9.268520876e-02f, +7.403097485e-02f, +5.369783330e-02f, +3.470418745e-02f, +1.925593236e-02f, +8.393568260e-03f, +2.009763334e-03f, -8.300317840e-04f, -1.419738627e-03f, -9.732614753e-04f,
+ /* 24,13 */ -6.052075404e-04f, -1.231259367e-03f, -1.354682733e-03f, +5.666214823e-05f, +4.297709369e-03f, +1.256466766e-02f, +2.548324354e-02f, +4.268306423e-02f, +6.259428489e-02f, +8.259096568e-02f, +9.949456662e-02f, +1.103189277e-01f, +1.130376830e-01f, +1.071295572e-01f, +9.372122042e-02f, +7.527978553e-02f, +5.495776346e-02f, +3.580480556e-02f, +2.009172411e-02f, +8.935092066e-03f, +2.292405169e-03f, -7.322803183e-04f, -1.424394748e-03f, -1.013146991e-03f,
+ /* 24,14 */ -5.655319713e-04f, -1.198322390e-03f, -1.379341793e-03f, -1.005901154e-04f, +3.925253463e-03f, +1.191392194e-02f, +2.454063933e-02f, +4.150635732e-02f, +6.131593665e-02f, +8.139809812e-02f, +9.858856505e-02f, +1.098656350e-01f, +1.131235487e-01f, +1.077380418e-01f, +9.473734332e-02f, +7.652128881e-02f, +5.622252667e-02f, +3.691925193e-02f, +2.094570441e-02f, +9.494532203e-03f, +2.589304991e-03f, -6.254426725e-04f, -1.424863695e-03f, -1.052308046e-03f,
+ /* 24,15 */ -5.264712252e-04f, -1.163769773e-03f, -1.398398357e-03f, -2.470940015e-04f, +3.568453927e-03f, +1.128161899e-02f, +2.361538773e-02f, +4.034112484e-02f, +6.003885715e-02f, +8.019389052e-02f, +9.765915788e-02f, +1.093805191e-01f, +1.131750947e-01f, +1.083163184e-01f, +9.573284944e-02f, +7.775467878e-02f, +5.749143322e-02f, +3.804709217e-02f, +2.181774373e-02f, +1.007202248e-02f, +2.900756187e-03f, -5.091873886e-04f, -1.420873386e-03f, -1.090580766e-03f,
+ /* 24, 0 */ -6.542299160e-04f, -2.850723396e-03f, -6.490258587e-03f, -9.960104872e-03f, -9.809478345e-03f, -1.578994128e-03f, +1.829834548e-02f, +5.025161588e-02f, +9.015425381e-02f, +1.297327779e-01f, +1.589915292e-01f, +1.697884216e-01f, +1.589915292e-01f, +1.297327779e-01f, +9.015425381e-02f, +5.025161588e-02f, +1.829834548e-02f, -1.578994128e-03f, -9.809478345e-03f, -9.960104872e-03f, -6.490258587e-03f, -2.850723396e-03f, -6.542299160e-04f, +6.349952235e-05f,
+ /* 24, 1 */ -5.715660670e-04f, -2.664319167e-03f, -6.241370053e-03f, -9.805460951e-03f, -1.000906214e-02f, -2.409006146e-03f, +1.668518463e-02f, +4.795494216e-02f, +8.756853655e-02f, +1.274593023e-01f, +1.576392865e-01f, +1.697451719e-01f, +1.602699418e-01f, +1.319653222e-01f, +9.273931864e-02f, +5.258078166e-02f, +1.996024013e-02f, -7.024321916e-04f, -9.578061730e-03f, -1.010098516e-02f, -6.739131402e-03f, -3.043301383e-03f, -7.429059724e-04f, +4.968305000e-05f,
+ /* 24, 2 */ -4.947700224e-04f, -2.484234158e-03f, -5.993080931e-03f, -9.638098137e-03f, -1.017794029e-02f, -3.193110201e-03f, +1.512113085e-02f, +4.569233080e-02f, +8.498458400e-02f, +1.251473534e-01f, +1.562147818e-01f, +1.696154741e-01f, +1.614730379e-01f, +1.341545065e-01f, +9.532128436e-02f, +5.494080034e-02f, +2.167042077e-02f, +2.212715669e-04f, -9.313697641e-03f, -1.022703863e-02f, -6.987342300e-03f, -3.241882098e-03f, -8.377276082e-04f, +3.267464436e-05f,
+ /* 24, 3 */ -4.236872966e-04f, -2.310589033e-03f, -5.745975157e-03f, -9.459041324e-03f, -1.031725016e-02f, -3.931996122e-03f, +1.360648366e-02f, +4.346528177e-02f, +8.240478048e-02f, +1.227994149e-01f, +1.547196623e-01f, +1.693994819e-01f, +1.625994153e-01f, +1.362979353e-01f, +9.789767810e-02f, +5.732996534e-02f, +2.342836441e-02f, +1.192656872e-03f, -9.015286272e-03f, -1.033718507e-02f, -7.234214214e-03f, -3.446268223e-03f, -9.388162067e-04f, +1.226776811e-05f,
+ /* 24, 4 */ -3.581542611e-04f, -2.143480447e-03f, -5.500605429e-03f, -9.269294257e-03f, -1.042813706e-02f, -4.626399385e-03f, +1.214146970e-02f, +4.127522351e-02f, +7.983147433e-02f, +1.204179923e-01f, +1.531556516e-01f, +1.690974512e-01f, +1.636477581e-01f, +1.383932498e-01f, +1.004660042e-01f, +5.974650439e-02f, +2.523347234e-02f, +2.212209196e-03f, -8.681745020e-03f, -1.043032883e-02f, -7.479039479e-03f, -3.656235461e-03f, -1.046280200e-03f, -1.174474466e-05f,
+ /* 24, 5 */ -2.979990698e-04f, -1.982981877e-03f, -5.257493218e-03f, -9.069838305e-03f, -1.051175200e-02f, -5.277098842e-03f, +1.072624378e-02f, +3.912351177e-02f, +7.726697481e-02f, +1.180056089e-01f, +1.515245471e-01f, +1.687097397e-01f, +1.646168392e-01f, +1.404381320e-01f, +1.030237476e-01f, +6.218858132e-02f, +2.708506973e-02f, +3.280357753e-03f, -8.312010872e-03f, -1.050536039e-02f, -7.721080180e-03f, -3.871531888e-03f, -1.160214103e-03f, -3.957001380e-05f,
+ /* 24, 6 */ -2.430425717e-04f, -1.829144469e-03f, -5.017128860e-03f, -8.861631306e-03f, -1.056924947e-02f, -5.884914422e-03f, +9.360889972e-03f, +3.701142868e-02f, +7.471354913e-02f, +1.155648023e-01f, +1.498282170e-01f, +1.682368061e-01f, +1.655055219e-01f, +1.424303080e-01f, +1.055683777e-01f, +6.465429798e-02f, +2.898240538e-02f, +4.397473555e-03f, -7.905042791e-03f, -1.056115807e-02f, -7.959568583e-03f, -4.091877352e-03f, -1.280697546e-03f, -7.141440876e-05f,
+ /* 24, 7 */ -1.930992056e-04f, -1.681997919e-03f, -4.779971710e-03f, -8.645606504e-03f, -1.060178532e-02f, -6.450704795e-03f, +8.045422842e-03f, +3.494018190e-02f, +7.217341954e-02f, +1.130981205e-01f, +1.480685972e-01f, +1.676792097e-01f, +1.663127619e-01f, +1.443675516e-01f, +1.080973515e-01f, +6.714169632e-02f, +3.092465153e-02f, +5.563867546e-03f, -7.459824124e-03f, -1.059658974e-02f, -8.193707637e-03f, -4.316962918e-03f, -1.407794310e-03f, -1.074828157e-04f,
+ /* 24, 8 */ -1.479778772e-04f, -1.541551365e-03f, -4.546450360e-03f, -8.422671559e-03f, -1.061051465e-02f, -6.975365011e-03f, +6.779788805e-03f, +3.291090392e-02f, +6.964876056e-02f, +1.106081178e-01f, +1.462476880e-01f, +1.670376092e-01f, +1.670376092e-01f, +1.462476880e-01f, +1.106081178e-01f, +6.964876056e-02f, +3.291090392e-02f, +6.779788805e-03f, -6.975365011e-03f, -1.061051465e-02f, -8.422671559e-03f, -4.546450360e-03f, -1.541551365e-03f, -1.479778772e-04f,
+ /* 24, 9 */ -1.074828157e-04f, -1.407794310e-03f, -4.316962918e-03f, -8.193707637e-03f, -1.059658974e-02f, -7.459824124e-03f, +5.563867546e-03f, +3.092465153e-02f, +6.714169632e-02f, +1.080973515e-01f, +1.443675516e-01f, +1.663127619e-01f, +1.676792097e-01f, +1.480685972e-01f, +1.130981205e-01f, +7.217341954e-02f, +3.494018190e-02f, +8.045422842e-03f, -6.450704795e-03f, -1.060178532e-02f, -8.645606504e-03f, -4.779971710e-03f, -1.681997919e-03f, -1.930992056e-04f,
+ /* 24,10 */ -7.141440876e-05f, -1.280697546e-03f, -4.091877352e-03f, -7.959568583e-03f, -1.056115807e-02f, -7.905042791e-03f, +4.397473555e-03f, +2.898240538e-02f, +6.465429798e-02f, +1.055683777e-01f, +1.424303080e-01f, +1.655055219e-01f, +1.682368061e-01f, +1.498282170e-01f, +1.155648023e-01f, +7.471354913e-02f, +3.701142868e-02f, +9.360889972e-03f, -5.884914422e-03f, -1.056924947e-02f, -8.861631306e-03f, -5.017128860e-03f, -1.829144469e-03f, -2.430425717e-04f,
+ /* 24,11 */ -3.957001380e-05f, -1.160214103e-03f, -3.871531888e-03f, -7.721080180e-03f, -1.050536039e-02f, -8.312010872e-03f, +3.280357753e-03f, +2.708506973e-02f, +6.218858132e-02f, +1.030237476e-01f, +1.404381320e-01f, +1.646168392e-01f, +1.687097397e-01f, +1.515245471e-01f, +1.180056089e-01f, +7.726697481e-02f, +3.912351177e-02f, +1.072624378e-02f, -5.277098842e-03f, -1.051175200e-02f, -9.069838305e-03f, -5.257493218e-03f, -1.982981877e-03f, -2.979990698e-04f,
+ /* 24,12 */ -1.174474466e-05f, -1.046280200e-03f, -3.656235461e-03f, -7.479039479e-03f, -1.043032883e-02f, -8.681745020e-03f, +2.212209196e-03f, +2.523347234e-02f, +5.974650439e-02f, +1.004660042e-01f, +1.383932498e-01f, +1.636477581e-01f, +1.690974512e-01f, +1.531556516e-01f, +1.204179923e-01f, +7.983147433e-02f, +4.127522351e-02f, +1.214146970e-02f, -4.626399385e-03f, -1.042813706e-02f, -9.269294257e-03f, -5.500605429e-03f, -2.143480447e-03f, -3.581542611e-04f,
+ /* 24,13 */ +1.226776811e-05f, -9.388162067e-04f, -3.446268223e-03f, -7.234214214e-03f, -1.033718507e-02f, -9.015286272e-03f, +1.192656872e-03f, +2.342836441e-02f, +5.732996534e-02f, +9.789767810e-02f, +1.362979353e-01f, +1.625994153e-01f, +1.693994819e-01f, +1.547196623e-01f, +1.227994149e-01f, +8.240478048e-02f, +4.346528177e-02f, +1.360648366e-02f, -3.931996122e-03f, -1.031725016e-02f, -9.459041324e-03f, -5.745975157e-03f, -2.310589033e-03f, -4.236872966e-04f,
+ /* 24,14 */ +3.267464436e-05f, -8.377276082e-04f, -3.241882098e-03f, -6.987342300e-03f, -1.022703863e-02f, -9.313697641e-03f, +2.212715669e-04f, +2.167042077e-02f, +5.494080034e-02f, +9.532128436e-02f, +1.341545065e-01f, +1.614730379e-01f, +1.696154741e-01f, +1.562147818e-01f, +1.251473534e-01f, +8.498458400e-02f, +4.569233080e-02f, +1.512113085e-02f, -3.193110201e-03f, -1.017794029e-02f, -9.638098137e-03f, -5.993080931e-03f, -2.484234158e-03f, -4.947700224e-04f,
+ /* 24,15 */ +4.968305000e-05f, -7.429059724e-04f, -3.043301383e-03f, -6.739131402e-03f, -1.010098516e-02f, -9.578061730e-03f, -7.024321916e-04f, +1.996024013e-02f, +5.258078166e-02f, +9.273931864e-02f, +1.319653222e-01f, +1.602699418e-01f, +1.697451719e-01f, +1.576392865e-01f, +1.274593023e-01f, +8.756853655e-02f, +4.795494216e-02f, +1.668518463e-02f, -2.409006146e-03f, -1.000906214e-02f, -9.805460951e-03f, -6.241370053e-03f, -2.664319167e-03f, -5.715660670e-04f,
+ /* 24, 0 */ +1.619229527e-03f, +2.585184252e-03f, +7.650378125e-04f, -6.171975840e-03f, -1.695416291e-02f, -2.423274385e-02f, -1.612533623e-02f, +1.737483974e-02f, +7.628093610e-02f, +1.465254238e-01f, +2.041060488e-01f, +2.263845622e-01f, +2.041060488e-01f, +1.465254238e-01f, +7.628093610e-02f, +1.737483974e-02f, -1.612533623e-02f, -2.423274385e-02f, -1.695416291e-02f, -6.171975840e-03f, +7.650378125e-04f, +2.585184252e-03f, +1.619229527e-03f, +4.203426526e-04f,
+ /* 24, 1 */ +1.531668339e-03f, +2.575087939e-03f, +1.015030141e-03f, -5.584253498e-03f, -1.627529113e-02f, -2.409742304e-02f, -1.730694612e-02f, +1.446720847e-02f, +7.205349539e-02f, +1.422361210e-01f, +2.013530187e-01f, +2.262942875e-01f, +2.067165090e-01f, +1.507648574e-01f, +8.055624103e-02f, +2.038667606e-02f, -1.484111026e-02f, -2.430745079e-02f, -1.762106127e-02f, -6.776879595e-03f, +4.938567092e-04f, +2.584413048e-03f, +1.706479068e-03f, +4.743886054e-04f,
+ /* 24, 2 */ +1.444251783e-03f, +2.554897668e-03f, +1.244217996e-03f, -5.014646771e-03f, -1.558700841e-02f, -2.390468713e-02f, -1.838770218e-02f, +1.166535016e-02f, +6.787901036e-02f, +1.379034790e-01f, +1.984620386e-01f, +2.260236194e-01f, +2.091800031e-01f, +1.549479100e-01f, +8.487414623e-02f, +2.350091114e-02f, -1.345266938e-02f, -2.431836796e-02f, -1.827334019e-02f, -7.397926552e-03f, +2.011593926e-04f, +2.571998910e-03f, +1.792931314e-03f, +5.318997770e-04f,
+ /* 24, 3 */ +1.357406375e-03f, +2.525382259e-03f, +1.453038602e-03f, -4.463987325e-03f, -1.489178967e-02f, -2.365774922e-02f, -1.936952211e-02f, +8.970595311e-03f, +6.376239146e-02f, +1.335340325e-01f, +1.954379419e-01f, +2.255730254e-01f, +2.114923689e-01f, +1.590681020e-01f, +8.922922426e-02f, +2.671549986e-02f, -1.195858585e-02f, -2.426235104e-02f, -1.890827435e-02f, -8.033973302e-03f, -1.133208208e-04f, +2.547167581e-03f, +1.878071789e-03f, +5.928148062e-04f,
+ /* 24, 4 */ +1.271528621e-03f, +2.487303056e-03f, +1.641978155e-03f, -3.933006021e-03f, -1.419201875e-02f, -2.335982837e-02f, -2.025447087e-02f, +6.384038515e-03f, +5.970836021e-02f, +1.291343068e-01f, +1.922857641e-01f, +2.249432832e-01f, +2.136496877e-01f, +1.631190001e-01f, +9.361589375e-02f, +3.002815853e-02f, -1.035761042e-02f, -2.413629608e-02f, -1.952306378e-02f, -8.683770335e-03f, -4.497860188e-04f, +2.509149105e-03f, +1.961357874e-03f, +6.570484107e-04f,
+ /* 24, 5 */ +1.186984902e-03f, +2.441411339e-03f, +1.811567846e-03f, -3.422334900e-03f, -1.348998519e-02f, -2.301414142e-02f, -2.104475231e-02f, +3.906540614e-03f, +5.572144173e-02f, +1.247108046e-01f, +1.890107314e-01f, +2.241354793e-01f, +2.156482934e-01f, +1.670942309e-01f, +9.802842938e-02f, +3.343636564e-02f, -8.648679404e-03f, -2.393714847e-02f, -2.011483893e-02f, -9.345961431e-03f, -8.083699235e-04f, +2.457181100e-03f, +2.042219659e-03f, +7.244903794e-04f,
+ /* 24, 6 */ +1.104111497e-03f, +2.388445882e-03f, +1.962379900e-03f, -2.932509404e-03f, -1.278788140e-02f, -2.262389503e-02f, -2.174270056e-02f, +1.538731332e-03f, +5.180595798e-02f, +1.202699924e-01f, +1.856182490e-01f, +2.231510062e-01f, +2.174847808e-01f, +1.709874949e-01f, +1.024609723e-01f, +3.693736330e-02f, -6.830921421e-03f, -2.366191192e-02f, -2.068066597e-02f, -1.001908338e-02f, -1.189134206e-03f, +2.390512141e-03f, +2.120060933e-03f, +7.950046334e-04f,
+ /* 24, 7 */ +1.023214729e-03f, +2.329130668e-03f, +2.095023622e-03f, -2.463970822e-03f, -1.208780014e-02f, -2.219227795e-02f, -2.235077131e-02f, -7.189875350e-04f, +4.796602143e-02f, +1.158182872e-01f, +1.821138888e-01f, +2.219915591e-01f, +2.191560137e-01f, +1.747925803e-01f, +1.069075413e-01f, +4.052815924e-02f, -4.903663772e-03f, -2.330765754e-02f, -2.121755248e-02f, -1.070156599e-02f, -1.592064902e-03f, +2.308405249e-03f, +2.194260355e-03f, +8.684283615e-04f,
+ /* 24, 8 */ +9.445712380e-04f, +2.264172764e-03f, +2.210141486e-03f, -2.017068943e-03f, -1.139173248e-02f, -2.172245353e-02f, -2.287153293e-02f, -2.866438416e-03f, +4.420552946e-02f, +1.113620436e-01f, +1.785033768e-01f, +2.206591322e-01f, +2.206591322e-01f, +1.785033768e-01f, +1.113620436e-01f, +4.420552946e-02f, -2.866438416e-03f, -2.287153293e-02f, -2.172245353e-02f, -1.139173248e-02f, -2.017068943e-03f, +2.210141486e-03f, +2.264172764e-03f, +9.445712380e-04f,
+ /* 24, 9 */ +8.684283615e-04f, +2.194260355e-03f, +2.308405249e-03f, -1.592064902e-03f, -1.070156599e-02f, -2.121755248e-02f, -2.330765754e-02f, -4.903663772e-03f, +4.052815924e-02f, +1.069075413e-01f, +1.747925803e-01f, +2.191560137e-01f, +2.219915591e-01f, +1.821138888e-01f, +1.158182872e-01f, +4.796602143e-02f, -7.189875350e-04f, -2.235077131e-02f, -2.219227795e-02f, -1.208780014e-02f, -2.463970822e-03f, +2.095023622e-03f, +2.329130668e-03f, +1.023214729e-03f,
+ /* 24,10 */ +7.950046334e-04f, +2.120060933e-03f, +2.390512141e-03f, -1.189134206e-03f, -1.001908338e-02f, -2.068066597e-02f, -2.366191192e-02f, -6.830921421e-03f, +3.693736330e-02f, +1.024609723e-01f, +1.709874949e-01f, +2.174847808e-01f, +2.231510062e-01f, +1.856182490e-01f, +1.202699924e-01f, +5.180595798e-02f, +1.538731332e-03f, -2.174270056e-02f, -2.262389503e-02f, -1.278788140e-02f, -2.932509404e-03f, +1.962379900e-03f, +2.388445882e-03f, +1.104111497e-03f,
+ /* 24,11 */ +7.244903794e-04f, +2.042219659e-03f, +2.457181100e-03f, -8.083699235e-04f, -9.345961431e-03f, -2.011483893e-02f, -2.393714847e-02f, -8.648679404e-03f, +3.343636564e-02f, +9.802842938e-02f, +1.670942309e-01f, +2.156482934e-01f, +2.241354793e-01f, +1.890107314e-01f, +1.247108046e-01f, +5.572144173e-02f, +3.906540614e-03f, -2.104475231e-02f, -2.301414142e-02f, -1.348998519e-02f, -3.422334900e-03f, +1.811567846e-03f, +2.441411339e-03f, +1.186984902e-03f,
+ /* 24,12 */ +6.570484107e-04f, +1.961357874e-03f, +2.509149105e-03f, -4.497860188e-04f, -8.683770335e-03f, -1.952306378e-02f, -2.413629608e-02f, -1.035761042e-02f, +3.002815853e-02f, +9.361589375e-02f, +1.631190001e-01f, +2.136496877e-01f, +2.249432832e-01f, +1.922857641e-01f, +1.291343068e-01f, +5.970836021e-02f, +6.384038515e-03f, -2.025447087e-02f, -2.335982837e-02f, -1.419201875e-02f, -3.933006021e-03f, +1.641978155e-03f, +2.487303056e-03f, +1.271528621e-03f,
+ /* 24,13 */ +5.928148062e-04f, +1.878071789e-03f, +2.547167581e-03f, -1.133208208e-04f, -8.033973302e-03f, -1.890827435e-02f, -2.426235104e-02f, -1.195858585e-02f, +2.671549986e-02f, +8.922922426e-02f, +1.590681020e-01f, +2.114923689e-01f, +2.255730254e-01f, +1.954379419e-01f, +1.335340325e-01f, +6.376239146e-02f, +8.970595311e-03f, -1.936952211e-02f, -2.365774922e-02f, -1.489178967e-02f, -4.463987325e-03f, +1.453038602e-03f, +2.525382259e-03f, +1.357406375e-03f,
+ /* 24,14 */ +5.318997770e-04f, +1.792931314e-03f, +2.571998910e-03f, +2.011593926e-04f, -7.397926552e-03f, -1.827334019e-02f, -2.431836796e-02f, -1.345266938e-02f, +2.350091114e-02f, +8.487414623e-02f, +1.549479100e-01f, +2.091800031e-01f, +2.260236194e-01f, +1.984620386e-01f, +1.379034790e-01f, +6.787901036e-02f, +1.166535016e-02f, -1.838770218e-02f, -2.390468713e-02f, -1.558700841e-02f, -5.014646771e-03f, +1.244217996e-03f, +2.554897668e-03f, +1.444251783e-03f,
+ /* 24,15 */ +4.743886054e-04f, +1.706479068e-03f, +2.584413048e-03f, +4.938567092e-04f, -6.776879595e-03f, -1.762106127e-02f, -2.430745079e-02f, -1.484111026e-02f, +2.038667606e-02f, +8.055624103e-02f, +1.507648574e-01f, +2.067165090e-01f, +2.262942875e-01f, +2.013530187e-01f, +1.422361210e-01f, +7.205349539e-02f, +1.446720847e-02f, -1.730694612e-02f, -2.409742304e-02f, -1.627529113e-02f, -5.584253498e-03f, +1.015030141e-03f, +2.575087939e-03f, +1.531668339e-03f,
+ /* 24, 0 */ -5.620806651e-04f, +1.786951327e-03f, +6.445247430e-03f, +8.135220753e-03f, -1.055728075e-03f, -2.182587186e-02f, -3.862210468e-02f, -2.392616717e-02f, +4.121375257e-02f, +1.449837419e-01f, +2.427850309e-01f, +2.829807027e-01f, +2.427850309e-01f, +1.449837419e-01f, +4.121375257e-02f, -2.392616717e-02f, -3.862210468e-02f, -2.182587186e-02f, -1.055728075e-03f, +8.135220753e-03f, +6.445247430e-03f, +1.786951327e-03f, -5.620806651e-04f, -5.120724112e-04f,
+ /* 24, 1 */ -6.104492932e-04f, +1.548760636e-03f, +6.159105160e-03f, +8.277197332e-03f, -7.779733613e-05f, -2.039475337e-02f, -3.819819741e-02f, -2.624621678e-02f, +3.569722776e-02f, +1.380982730e-01f, +2.379020609e-01f, +2.828154582e-01f, +2.474326717e-01f, +1.518487179e-01f, +4.689321837e-02f, -2.139810919e-02f, -3.892035913e-02f, -2.324619800e-02f, -2.084809535e-03f, +7.948411519e-03f, +6.721048149e-03f, +2.036121529e-03f, -5.037148469e-04f, -5.469834647e-04f,
+ /* 24, 2 */ -6.493280747e-04f, +1.322056610e-03f, +5.864617557e-03f, +8.376206823e-03f, +8.476165560e-04f, -1.895882060e-02f, -3.765599422e-02f, -2.836041007e-02f, +3.035103267e-02f, +1.312062799e-01f, +2.327950895e-01f, +2.823201223e-01f, +2.518341522e-01f, +1.586790922e-01f, +5.272765217e-02f, -1.866041870e-02f, -3.908572584e-02f, -2.464952038e-02f, -3.163389088e-03f, +7.715013258e-03f, +6.984447000e-03f, +2.295668536e-03f, -4.348733531e-04f, -5.801620624e-04f,
+ /* 24, 3 */ -6.792484933e-04f, +1.107253309e-03f, +5.563710253e-03f, +8.434210700e-03f, +1.719427448e-03f, -1.752380524e-02f, -3.700294628e-02f, -3.027140813e-02f, +2.518195985e-02f, +1.243215533e-01f, +2.274759065e-01f, +2.814958870e-01f, +2.559791715e-01f, +1.654606562e-01f, +5.870851072e-02f, -1.571201688e-02f, -3.911111998e-02f, -2.602940857e-02f, -4.289522020e-03f, +7.433392157e-03f, +7.233326681e-03f, +2.564892035e-03f, -3.551113499e-04f, -6.111213026e-04f,
+ /* 24, 4 */ -7.007615573e-04f, +9.046745282e-04f, +5.258232435e-03f, +8.453253159e-03f, +2.536821717e-03f, -1.609518093e-02f, -3.624657153e-02f, -3.198236083e-02f, +2.019619593e-02f, +1.174576676e-01f, +2.219567270e-01f, +2.803447347e-01f, +2.598579915e-01f, +1.721791413e-01f, +6.482669661e-02f, -1.255238605e-02f, -3.898963496e-02f, -2.737922870e-02f, -5.460966964e-03f, +7.102050305e-03f, +7.465520628e-03f, +2.842992490e-03f, -2.640225027e-04f, -6.393525967e-04f,
+ /* 24, 5 */ -7.144333056e-04f, +7.145569834e-04f, +4.949951622e-03f, +8.435448103e-03f, +3.299249997e-03f, -1.467815287e-02f, -3.539442781e-02f, -3.349688539e-02f, +1.539931407e-02f, +1.106279448e-01f, +2.162501543e-01f, +2.788694321e-01f, +2.634614666e-01f, +1.788202595e-01f, +7.107257652e-02f, -9.181583996e-03f, -3.871457066e-02f, -2.869216031e-02f, -6.675182397e-03f, +6.719638981e-03f, +7.678821339e-03f, +3.129069982e-03f, -1.612438490e-04f, -6.643278432e-04f,
+ /* 24, 6 */ -7.208404573e-04f, +5.370537968e-04f, +4.640549073e-03f, +8.382966356e-03f, +4.006418111e-03f, -1.327764882e-02f, -3.445408633e-02f, -3.481904366e-02f, +1.079626845e-02f, +1.038454185e-01f, +2.103691410e-01f, +2.770735210e-01f, +2.667810728e-01f, +1.853697450e-01f, +7.743600141e-02f, -5.600256400e-03f, -3.827946167e-02f, -2.996121443e-02f, -7.929324241e-03f, +6.284971816e-03f, +7.870989279e-03f, +3.422123547e-03f, -4.646067064e-05f, -6.855018549e-04f,
+ /* 24, 7 */ -7.205662235e-04f, +3.722382714e-04f, +4.331615834e-03f, +8.298023138e-03f, +4.658277300e-03f, -1.189831143e-02f, -3.343310598e-02f, -3.595331849e-02f, +6.391391026e-03f, +9.712280024e-02f, +2.043269499e-01f, +2.749613076e-01f, +2.698089343e-01f, +1.918133956e-01f, +8.390632879e-02f, -1.809647645e-03f, -3.767810524e-02f, -3.117925279e-02f, -9.220244622e-03f, +5.797037759e-03f, +8.039762345e-03f, +3.721051017e-03f, +8.058866307e-05f, -7.023150347e-04f,
+ /* 24, 8 */ -7.141962964e-04f, +2.201079121e-04f, +4.024649403e-03f, +8.182865872e-03f, +5.255013788e-03f, -1.054449181e-02f, -3.233900821e-02f, -3.690458903e-02f, +2.188390323e-03f, +9.047244679e-02f, +1.981371140e-01f, +2.725378483e-01f, +2.725378483e-01f, +1.981371140e-01f, +9.047244679e-02f, +2.188390323e-03f, -3.690458903e-02f, -3.233900821e-02f, -1.054449181e-02f, +5.255013788e-03f, +8.182865872e-03f, +4.024649403e-03f, +2.201079121e-04f, -7.141962964e-04f,
+ /* 24, 9 */ -7.023150347e-04f, +8.058866307e-05f, +3.721051017e-03f, +8.039762345e-03f, +5.797037759e-03f, -9.220244622e-03f, -3.117925279e-02f, -3.767810524e-02f, -1.809647645e-03f, +8.390632879e-02f, +1.918133956e-01f, +2.698089343e-01f, +2.749613076e-01f, +2.043269499e-01f, +9.712280024e-02f, +6.391391026e-03f, -3.595331849e-02f, -3.343310598e-02f, -1.189831143e-02f, +4.658277300e-03f, +8.298023138e-03f, +4.331615834e-03f, +3.722382714e-04f, -7.205662235e-04f,
+ /* 24,10 */ -6.855018549e-04f, -4.646067064e-05f, +3.422123547e-03f, +7.870989279e-03f, +6.284971816e-03f, -7.929324241e-03f, -2.996121443e-02f, -3.827946167e-02f, -5.600256400e-03f, +7.743600141e-02f, +1.853697450e-01f, +2.667810728e-01f, +2.770735210e-01f, +2.103691410e-01f, +1.038454185e-01f, +1.079626845e-02f, -3.481904366e-02f, -3.445408633e-02f, -1.327764882e-02f, +4.006418111e-03f, +8.382966356e-03f, +4.640549073e-03f, +5.370537968e-04f, -7.208404573e-04f,
+ /* 24,11 */ -6.643278432e-04f, -1.612438490e-04f, +3.129069982e-03f, +7.678821339e-03f, +6.719638981e-03f, -6.675182397e-03f, -2.869216031e-02f, -3.871457066e-02f, -9.181583996e-03f, +7.107257652e-02f, +1.788202595e-01f, +2.634614666e-01f, +2.788694321e-01f, +2.162501543e-01f, +1.106279448e-01f, +1.539931407e-02f, -3.349688539e-02f, -3.539442781e-02f, -1.467815287e-02f, +3.299249997e-03f, +8.435448103e-03f, +4.949951622e-03f, +7.145569834e-04f, -7.144333056e-04f,
+ /* 24,12 */ -6.393525967e-04f, -2.640225027e-04f, +2.842992490e-03f, +7.465520628e-03f, +7.102050305e-03f, -5.460966964e-03f, -2.737922870e-02f, -3.898963496e-02f, -1.255238605e-02f, +6.482669661e-02f, +1.721791413e-01f, +2.598579915e-01f, +2.803447347e-01f, +2.219567270e-01f, +1.174576676e-01f, +2.019619593e-02f, -3.198236083e-02f, -3.624657153e-02f, -1.609518093e-02f, +2.536821717e-03f, +8.453253159e-03f, +5.258232435e-03f, +9.046745282e-04f, -7.007615573e-04f,
+ /* 24,13 */ -6.111213026e-04f, -3.551113499e-04f, +2.564892035e-03f, +7.233326681e-03f, +7.433392157e-03f, -4.289522020e-03f, -2.602940857e-02f, -3.911111998e-02f, -1.571201688e-02f, +5.870851072e-02f, +1.654606562e-01f, +2.559791715e-01f, +2.814958870e-01f, +2.274759065e-01f, +1.243215533e-01f, +2.518195985e-02f, -3.027140813e-02f, -3.700294628e-02f, -1.752380524e-02f, +1.719427448e-03f, +8.434210700e-03f, +5.563710253e-03f, +1.107253309e-03f, -6.792484933e-04f,
+ /* 24,14 */ -5.801620624e-04f, -4.348733531e-04f, +2.295668536e-03f, +6.984447000e-03f, +7.715013258e-03f, -3.163389088e-03f, -2.464952038e-02f, -3.908572584e-02f, -1.866041870e-02f, +5.272765217e-02f, +1.586790922e-01f, +2.518341522e-01f, +2.823201223e-01f, +2.327950895e-01f, +1.312062799e-01f, +3.035103267e-02f, -2.836041007e-02f, -3.765599422e-02f, -1.895882060e-02f, +8.476165560e-04f, +8.376206823e-03f, +5.864617557e-03f, +1.322056610e-03f, -6.493280747e-04f,
+ /* 24,15 */ -5.469834647e-04f, -5.037148469e-04f, +2.036121529e-03f, +6.721048149e-03f, +7.948411519e-03f, -2.084809535e-03f, -2.324619800e-02f, -3.892035913e-02f, -2.139810919e-02f, +4.689321837e-02f, +1.518487179e-01f, +2.474326717e-01f, +2.828154582e-01f, +2.379020609e-01f, +1.380982730e-01f, +3.569722776e-02f, -2.624621678e-02f, -3.819819741e-02f, -2.039475337e-02f, -7.779733613e-05f, +8.277197332e-03f, +6.159105160e-03f, +1.548760636e-03f, -6.104492932e-04f,
+ /* 24, 0 */ -1.197013499e-03f, -3.320493122e-03f, -1.144245270e-03f, +8.577337679e-03f, +1.627759141e-02f, +3.152522439e-03f, -3.255249254e-02f, -5.362651723e-02f, -5.304244056e-03f, +1.253006387e-01f, +2.738089134e-01f, +3.395768433e-01f, +2.738089134e-01f, +1.253006387e-01f, -5.304244056e-03f, -5.362651723e-02f, -3.255249254e-02f, +3.152522439e-03f, +1.627759141e-02f, +8.577337679e-03f, -1.144245270e-03f, -3.320493122e-03f, -1.197013499e-03f, +1.261205705e-04f,
+ /* 24, 1 */ -1.060573898e-03f, -3.246029352e-03f, -1.514205592e-03f, +7.849505167e-03f, +1.622707505e-02f, +4.797556391e-03f, -3.017446993e-02f, -5.385088872e-02f, -1.098434059e-02f, +1.155960124e-01f, +2.659858985e-01f, +3.393017042e-01f, +2.812897341e-01f, +1.350895441e-01f, +7.263382766e-04f, -5.311639759e-02f, -3.488122370e-02f, +1.404407443e-03f, +1.624118609e-02f, +9.301572693e-03f, -7.399572733e-04f, -3.377916464e-03f, -1.338504197e-03f, +9.901282259e-05f,
+ /* 24, 2 */ -9.298712414e-04f, -3.156277727e-03f, -1.849729696e-03f, +7.122444811e-03f, +1.609438844e-02f, +6.335978542e-03f, -2.776122262e-02f, -5.380213751e-02f, -1.630850202e-02f, +1.060004951e-01f, +2.578448120e-01f, +3.384771755e-01f, +2.884051592e-01f, +1.449371908e-01f, +7.100538384e-03f, -5.230860749e-02f, -3.714619841e-02f, -4.425295608e-04f, +1.611336946e-02f, +1.001762126e-02f, -3.016869975e-04f, -3.416553196e-03f, -1.484263468e-03f, +6.526428163e-05f,
+ /* 24, 3 */ -8.054954021e-04f, -3.052984548e-03f, -2.150934111e-03f, +6.400291527e-03f, +1.588450664e-02f, +7.764974256e-03f, -2.532636892e-02f, -5.349351937e-02f, -2.127269005e-02f, +9.653812261e-02f, +2.494105998e-01f, +3.371059190e-01f, +2.951330020e-01f, +1.548174220e-01f, +1.381006797e-02f, -5.119199897e-02f, -3.933260713e-02f, -2.383292518e-03f, +1.588995194e-02f, +1.072069264e-02f, +1.699725421e-04f, -3.434676821e-03f, -1.633412152e-03f, +2.453170435e-05f,
+ /* 24, 4 */ -6.879416803e-04f, -2.937877889e-03f, -2.418147761e-03f, +5.686932142e-03f, +1.560259046e-02f, +9.082429619e-03f, -2.288303213e-02f, -5.293884648e-02f, -2.587426360e-02f, +8.723205545e-02f, +2.407089312e-01f, +3.351923590e-01f, +3.014521813e-01f, +1.647035561e-01f, +2.084522321e-02f, -4.975626781e-02f, -4.142535273e-02f, -4.412143180e-03f, +1.556708209e-02f, +1.140581394e-02f, +6.741710759e-04f, -3.430594409e-03f, -1.784975276e-03f, -2.348660763e-05f,
+ /* 24, 5 */ -5.776128643e-04f, -2.812656385e-03f, -2.651898517e-03f, +4.985994150e-03f, +1.525394912e-02f, +1.028691298e-02f, -2.044379769e-02f, -5.215241275e-02f, -3.011195925e-02f, +7.810450253e-02f, +2.317660961e-01f, +3.327426635e-01f, +3.073428069e-01f, +1.745684830e-01f, +2.819489579e-02f, -4.799202051e-02f, -4.340911052e-02f, -6.522599631e-03f, +1.514128438e-02f, +1.206785167e-02f, +1.209792693e-03f, -3.402660968e-03f, -1.937883690e-03f, -7.904503123e-05f,
+ /* 24, 6 */ -4.748218959e-04f, -2.678978820e-03f, -2.852899102e-03f, +4.300836533e-03f, +1.484400357e-02f, +1.137765361e-02f, -1.802067434e-02f, -5.114891871e-02f, -3.398586582e-02f, +6.917664952e-02f, +2.226089010e-01f, +3.297647184e-01f, +3.127862620e-01f, +1.843847637e-01f, +3.584659036e-02f, -4.589083871e-02f, -4.526839113e-02f, -8.707438641e-03f, +1.460949637e-02f, +1.270153536e-02f, +1.775448814e-03f, -3.349294247e-03f, -2.090976552e-03f, -1.423449116e-04f,
+ /* 24, 7 */ -3.797950945e-04f, -2.538454547e-03f, -3.022032460e-03f, +3.634542645e-03f, +1.437825069e-02f, +1.235451773e-02f, -1.562505912e-02f, -4.994339647e-02f, -3.749739364e-02f, +6.046859273e-02f, +2.132645624e-01f, +3.262680950e-01f, +3.177652787e-01f, +1.941247325e-01f, +4.378644843e-02f, -4.344534054e-02f, -4.698760595e-02f, -1.095870195e-02f, +1.396910503e-02f, +1.330148306e-02f, +2.369472628e-03f, -3.268989872e-03f, -2.243004675e-03f, -2.135289700e-04f,
+ /* 24, 8 */ -2.926758839e-04f, -2.392634763e-03f, -3.160336722e-03f, +2.989915102e-03f, +1.386222860e-02f, +1.321798203e-02f, -1.326770657e-02f, -4.855113496e-02f, -4.064923848e-02f, +5.199927852e-02f, +2.037606007e-01f, +3.222640100e-01f, +3.222640100e-01f, +2.037606007e-01f, +5.199927852e-02f, -4.064923848e-02f, -4.855113496e-02f, -1.326770657e-02f, +1.321798203e-02f, +1.386222860e-02f, +2.989915102e-03f, -3.160336722e-03f, -2.392634763e-03f, -2.926758839e-04f,
+ /* 24, 9 */ -2.135289700e-04f, -2.243004675e-03f, -3.268989872e-03f, +2.369472628e-03f, +1.330148306e-02f, +1.396910503e-02f, -1.095870195e-02f, -4.698760595e-02f, -4.344534054e-02f, +4.378644843e-02f, +1.941247325e-01f, +3.177652787e-01f, +3.262680950e-01f, +2.132645624e-01f, +6.046859273e-02f, -3.749739364e-02f, -4.994339647e-02f, -1.562505912e-02f, +1.235451773e-02f, +1.437825069e-02f, +3.634542645e-03f, -3.022032460e-03f, -2.538454547e-03f, -3.797950945e-04f,
+ /* 24,10 */ -1.423449116e-04f, -2.090976552e-03f, -3.349294247e-03f, +1.775448814e-03f, +1.270153536e-02f, +1.460949637e-02f, -8.707438641e-03f, -4.526839113e-02f, -4.589083871e-02f, +3.584659036e-02f, +1.843847637e-01f, +3.127862620e-01f, +3.297647184e-01f, +2.226089010e-01f, +6.917664952e-02f, -3.398586582e-02f, -5.114891871e-02f, -1.802067434e-02f, +1.137765361e-02f, +1.484400357e-02f, +4.300836533e-03f, -2.852899102e-03f, -2.678978820e-03f, -4.748218959e-04f,
+ /* 24,11 */ -7.904503123e-05f, -1.937883690e-03f, -3.402660968e-03f, +1.209792693e-03f, +1.206785167e-02f, +1.514128438e-02f, -6.522599631e-03f, -4.340911052e-02f, -4.799202051e-02f, +2.819489579e-02f, +1.745684830e-01f, +3.073428069e-01f, +3.327426635e-01f, +2.317660961e-01f, +7.810450253e-02f, -3.011195925e-02f, -5.215241275e-02f, -2.044379769e-02f, +1.028691298e-02f, +1.525394912e-02f, +4.985994150e-03f, -2.651898517e-03f, -2.812656385e-03f, -5.776128643e-04f,
+ /* 24,12 */ -2.348660763e-05f, -1.784975276e-03f, -3.430594409e-03f, +6.741710759e-04f, +1.140581394e-02f, +1.556708209e-02f, -4.412143180e-03f, -4.142535273e-02f, -4.975626781e-02f, +2.084522321e-02f, +1.647035561e-01f, +3.014521813e-01f, +3.351923590e-01f, +2.407089312e-01f, +8.723205545e-02f, -2.587426360e-02f, -5.293884648e-02f, -2.288303213e-02f, +9.082429619e-03f, +1.560259046e-02f, +5.686932142e-03f, -2.418147761e-03f, -2.937877889e-03f, -6.879416803e-04f,
+ /* 24,13 */ +2.453170435e-05f, -1.633412152e-03f, -3.434676821e-03f, +1.699725421e-04f, +1.072069264e-02f, +1.588995194e-02f, -2.383292518e-03f, -3.933260713e-02f, -5.119199897e-02f, +1.381006797e-02f, +1.548174220e-01f, +2.951330020e-01f, +3.371059190e-01f, +2.494105998e-01f, +9.653812261e-02f, -2.127269005e-02f, -5.349351937e-02f, -2.532636892e-02f, +7.764974256e-03f, +1.588450664e-02f, +6.400291527e-03f, -2.150934111e-03f, -3.052984548e-03f, -8.054954021e-04f,
+ /* 24,14 */ +6.526428163e-05f, -1.484263468e-03f, -3.416553196e-03f, -3.016869975e-04f, +1.001762126e-02f, +1.611336946e-02f, -4.425295608e-04f, -3.714619841e-02f, -5.230860749e-02f, +7.100538384e-03f, +1.449371908e-01f, +2.884051592e-01f, +3.384771755e-01f, +2.578448120e-01f, +1.060004951e-01f, -1.630850202e-02f, -5.380213751e-02f, -2.776122262e-02f, +6.335978542e-03f, +1.609438844e-02f, +7.122444811e-03f, -1.849729696e-03f, -3.156277727e-03f, -9.298712414e-04f,
+ /* 24,15 */ +9.901282259e-05f, -1.338504197e-03f, -3.377916464e-03f, -7.399572733e-04f, +9.301572693e-03f, +1.624118609e-02f, +1.404407443e-03f, -3.488122370e-02f, -5.311639759e-02f, +7.263382766e-04f, +1.350895441e-01f, +2.812897341e-01f, +3.393017042e-01f, +2.659858985e-01f, +1.155960124e-01f, -1.098434059e-02f, -5.385088872e-02f, -3.017446993e-02f, +4.797556391e-03f, +1.622707505e-02f, +7.849505167e-03f, -1.514205592e-03f, -3.246029352e-03f, -1.060573898e-03f,
+ /* 20, 0 */ -4.161478318e-03f, -1.410215661e-03f, +1.216462436e-02f, +1.839753508e-02f, -1.019572218e-02f, -5.576407638e-02f, -3.857794503e-02f, +9.869941459e-02f, +2.903842315e-01f, +3.819037908e-01f, +2.903842315e-01f, +9.869941459e-02f, -3.857794503e-02f, -5.576407638e-02f, -1.019572218e-02f, +1.839753508e-02f, +1.216462436e-02f, -1.410215661e-03f, -4.161478318e-03f, -1.002136091e-03f,
+ /* 20, 1 */ -4.024812873e-03f, -1.935046598e-03f, +1.120868183e-02f, +1.884704309e-02f, -7.349314558e-03f, -5.377462232e-02f, -4.306909662e-02f, +8.713841011e-02f, +2.797272456e-01f, +3.815142140e-01f, +3.006231905e-01f, +1.105090175e-01f, -3.357053763e-02f, -5.750258783e-02f, -1.313424017e-02f, +1.779561475e-02f, +1.309754391e-02f, -8.338854378e-04f, -4.274968522e-03f, -1.184613130e-03f,
+ /* 20, 2 */ -3.867923854e-03f, -2.407896178e-03f, +1.023778220e-02f, +1.914947854e-02f, -4.608279480e-03f, -5.155911253e-02f, -4.704785126e-02f, +7.585987841e-02f, +2.686929243e-01f, +3.803470604e-01f, +3.104047352e-01f, +1.225315522e-01f, -2.804532708e-02f, -5.896552129e-02f, -1.615031726e-02f, +1.703673197e-02f, +1.399907244e-02f, -2.069933478e-04f, -4.362323551e-03f, -1.376799150e-03f,
+ /* 20, 3 */ -3.693729756e-03f, -2.828715617e-03f, +9.259646102e-03f, +1.931089692e-02f, -1.984565051e-03f, -4.914254142e-02f, -5.052030051e-02f, +6.489576800e-02f, +2.573230589e-01f, +3.784070525e-01f, +3.196909791e-01f, +1.347297046e-01f, -2.200314505e-02f, -6.012863981e-02f, -1.922814732e-02f, +1.611719780e-02f, +1.486058724e-02f, +4.690483654e-04f, -4.420601658e-03f, -1.577606548e-03f,
+ /* 20, 4 */ -3.505092707e-03f, -3.197865053e-03f, +8.281610454e-03f, +1.933799402e-02f, +5.112106557e-04f, -4.654987033e-02f, -5.349467921e-02f, +5.427598051e-02f, +2.456603330e-01f, +3.757020336e-01f, +3.284457292e-01f, +1.470646693e-01f, -1.544725782e-02f, -6.096825350e-02f, -2.235071271e-02f, +1.503425320e-02f, +1.567326271e-02f, +1.192336051e-03f, -4.446907145e-03f, -1.785766437e-03f,
+ /* 20, 5 */ -3.304797071e-03f, -3.516087186e-03f, +7.310594668e-03f, +1.923802927e-02f, +2.869766685e-03f, -4.380589142e-02f, -5.598126618e-02f, +4.402826232e-02f, +2.337481127e-01f, +3.722429273e-01f, +3.366346688e-01f, +1.594963158e-01f, -8.383409345e-03f, -6.146136934e-02f, -2.549983702e-02f, +1.378613431e-02f, +1.642812632e-02f, +1.960461229e-03f, -4.438419451e-03f, -1.999828319e-03f,
+ /* 20, 6 */ -3.095529963e-03f, -3.784479230e-03f, +6.353071566e-03f, +1.901874863e-02f, +5.083157654e-03f, -4.093509653e-02f, -5.799227582e-02f, +3.417810958e-02f, +2.216302330e-01f, +3.680436800e-01f, +3.442255330e-01f, +1.719833640e-01f, -8.198514564e-04f, -6.158584092e-02f, -2.865624686e-02f, +1.237213363e-02f, +1.711611824e-02f, +2.770500592e-03f, -4.392423280e-03f, -2.218161540e-03f,
+ /* 20, 7 */ -2.879863731e-03f, -4.004463491e-03f, +5.415043050e-03f, +1.868830751e-02f, +7.144763866e-03f, -3.796155187e-02f, -5.954174144e-02f, +2.474868675e-02f, +2.093507858e-01f, +3.631211887e-01f, +3.511882735e-01f, +1.844835679e-01f, +7.232639407e-03f, -6.132051750e-02f, -3.179964276e-02f, +1.079265669e-02f, +1.772815465e-02f, +3.619009684e-03f, -4.306339536e-03f, -2.438958613e-03f,
+ /* 20, 8 */ -2.660240473e-03f, -4.177756859e-03f, +4.502020476e-03f, +1.825519424e-02f, +9.049273418e-03f, -3.490877898e-02f, -6.064539119e-02f, +1.576075912e-02f, +1.969539074e-01f, +3.574952133e-01f, +3.574952133e-01f, +1.969539074e-01f, +1.576075912e-02f, -6.064539119e-02f, -3.490877898e-02f, +9.049273418e-03f, +1.825519424e-02f, +4.502020476e-03f, -4.177756859e-03f, -2.660240473e-03f,
+ /* 20, 9 */ -2.438958613e-03f, -4.306339536e-03f, +3.619009684e-03f, +1.772815465e-02f, +1.079265669e-02f, -3.179964276e-02f, -6.132051750e-02f, +7.232639407e-03f, +1.844835679e-01f, +3.511882735e-01f, +3.631211887e-01f, +2.093507858e-01f, +2.474868675e-02f, -5.954174144e-02f, -3.796155187e-02f, +7.144763866e-03f, +1.868830751e-02f, +5.415043050e-03f, -4.004463491e-03f, -2.879863731e-03f,
+ /* 20,10 */ -2.218161540e-03f, -4.392423280e-03f, +2.770500592e-03f, +1.711611824e-02f, +1.237213363e-02f, -2.865624686e-02f, -6.158584092e-02f, -8.198514564e-04f, +1.719833640e-01f, +3.442255330e-01f, +3.680436800e-01f, +2.216302330e-01f, +3.417810958e-02f, -5.799227582e-02f, -4.093509653e-02f, +5.083157654e-03f, +1.901874863e-02f, +6.353071566e-03f, -3.784479230e-03f, -3.095529963e-03f,
+ /* 20,11 */ -1.999828319e-03f, -4.438419451e-03f, +1.960461229e-03f, +1.642812632e-02f, +1.378613431e-02f, -2.549983702e-02f, -6.146136934e-02f, -8.383409345e-03f, +1.594963158e-01f, +3.366346688e-01f, +3.722429273e-01f, +2.337481127e-01f, +4.402826232e-02f, -5.598126618e-02f, -4.380589142e-02f, +2.869766685e-03f, +1.923802927e-02f, +7.310594668e-03f, -3.516087186e-03f, -3.304797071e-03f,
+ /* 20,12 */ -1.785766437e-03f, -4.446907145e-03f, +1.192336051e-03f, +1.567326271e-02f, +1.503425320e-02f, -2.235071271e-02f, -6.096825350e-02f, -1.544725782e-02f, +1.470646693e-01f, +3.284457292e-01f, +3.757020336e-01f, +2.456603330e-01f, +5.427598051e-02f, -5.349467921e-02f, -4.654987033e-02f, +5.112106557e-04f, +1.933799402e-02f, +8.281610454e-03f, -3.197865053e-03f, -3.505092707e-03f,
+ /* 20,13 */ -1.577606548e-03f, -4.420601658e-03f, +4.690483654e-04f, +1.486058724e-02f, +1.611719780e-02f, -1.922814732e-02f, -6.012863981e-02f, -2.200314505e-02f, +1.347297046e-01f, +3.196909791e-01f, +3.784070525e-01f, +2.573230589e-01f, +6.489576800e-02f, -5.052030051e-02f, -4.914254142e-02f, -1.984565051e-03f, +1.931089692e-02f, +9.259646102e-03f, -2.828715617e-03f, -3.693729756e-03f,
+ /* 20,14 */ -1.376799150e-03f, -4.362323551e-03f, -2.069933478e-04f, +1.399907244e-02f, +1.703673197e-02f, -1.615031726e-02f, -5.896552129e-02f, -2.804532708e-02f, +1.225315522e-01f, +3.104047352e-01f, +3.803470604e-01f, +2.686929243e-01f, +7.585987841e-02f, -4.704785126e-02f, -5.155911253e-02f, -4.608279480e-03f, +1.914947854e-02f, +1.023778220e-02f, -2.407896178e-03f, -3.867923854e-03f,
+ /* 20,15 */ -1.184613130e-03f, -4.274968522e-03f, -8.338854378e-04f, +1.309754391e-02f, +1.779561475e-02f, -1.313424017e-02f, -5.750258783e-02f, -3.357053763e-02f, +1.105090175e-01f, +3.006231905e-01f, +3.815142140e-01f, +2.797272456e-01f, +8.713841011e-02f, -4.306909662e-02f, -5.377462232e-02f, -7.349314558e-03f, +1.884704309e-02f, +1.120868183e-02f, -1.935046598e-03f, -4.024812873e-03f,
+ /* 20, 0 */ -1.329352252e-03f, -4.865562069e-03f, +1.662947600e-03f, +1.893743982e-02f, +1.052975469e-02f, -4.314924294e-02f, -6.168215525e-02f, +6.793829558e-02f, +3.007295231e-01f, +4.214013440e-01f, +3.007295231e-01f, +6.793829558e-02f, -6.168215525e-02f, -4.314924294e-02f, +1.052975469e-02f, +1.893743982e-02f, +1.662947600e-03f, -4.865562069e-03f, -1.329352252e-03f, +0.000000000e+00f,
+ /* 20, 1 */ -1.106503038e-03f, -4.784011640e-03f, +7.620481209e-04f, +1.810159639e-02f, +1.258770510e-02f, -3.946126222e-02f, -6.412166469e-02f, +5.516844650e-02f, +2.870012762e-01f, +4.208780002e-01f, +3.139874692e-01f, +8.118253044e-02f, -5.860314053e-02f, -4.671882663e-02f, +8.254179692e-03f, +1.967037055e-02f, +2.622520317e-03f, -4.905078775e-03f, -1.565095816e-03f, +0.000000000e+00f,
+ /* 20, 2 */ -8.979094201e-04f, -4.664743082e-03f, -7.633034189e-05f, +1.717630323e-02f, +1.442449893e-02f, -3.568911340e-02f, -6.594250862e-02f, +4.291292121e-02f, +2.728656387e-01f, +4.193105477e-01f, +3.267137817e-01f, +9.485763802e-02f, -5.486676259e-02f, -5.013477905e-02f, +5.766539049e-03f, +2.028700325e-02f, +3.636071544e-03f, -4.898357639e-03f, -1.812078842e-03f, +3.513221827e-04f,
+ /* 20, 3 */ -7.046452899e-04f, -4.512131585e-03f, -8.491713087e-04f, +1.617498084e-02f, +1.603855621e-02f, -3.186582692e-02f, -6.716828458e-02f, +3.120792005e-02f, +2.583867198e-01f, +4.167067067e-01f, +3.388490774e-01f, +1.089167196e-01f, -5.045835457e-02f, -5.336106841e-02f, +3.074480429e-03f, +2.077415592e-02f, +4.698051453e-03f, -4.841360048e-03f, -2.068349661e-03f, +3.288882594e-04f,
+ /* 20, 4 */ -5.275063595e-04f, -4.330562617e-03f, -1.554266965e-03f, +1.511089362e-02f, +1.743016199e-02f, -2.802305698e-02f, -6.782511100e-02f, +2.008577030e-02f, +2.436294448e-01f, +4.130792899e-01f, +3.503362849e-01f, +1.233097059e-01f, -4.536663323e-02f, -5.636108634e-02f, +1.877878266e-04f, +2.111898038e-02f, +5.802054958e-03f, -4.730268616e-03f, -2.331660076e-03f, +2.941732022e-04f,
+ /* 20, 5 */ -3.670219514e-04f, -4.124385552e-03f, -2.190189120e-03f, +1.399704337e-02f, +1.860136846e-02f, -2.419092016e-02f, -6.794137953e-02f, +9.574818877e-03f, +2.286591711e-01f, +4.084461208e-01f, +3.611209950e-01f, +1.379835966e-01f, -3.958387309e-02f, -5.909788086e-02f, -2.881585959e-03f, +2.130909659e-02f, +6.940829951e-03f, -4.561544087e-03f, -2.599469210e-03f, +2.461206998e-04f,
+ /* 20, 6 */ -2.234691091e-04f, -3.897870552e-03f, -2.756254356e-03f, +1.284607053e-02f, +1.955588746e-02f, -2.039785121e-02f, -6.754749865e-02f, -3.006469464e-04f, +2.135413047e-01f, +4.028299211e-01f, +3.711517965e-01f, +1.528827232e-01f, -3.310606021e-02f, -6.153439984e-02f, -6.119502817e-03f, +2.133272965e-02f, +8.106294302e-03f, -4.331982887e-03f, -2.868951124e-03f, +1.837671888e-04f,
+ /* 20, 7 */ -9.688872179e-05f, -3.655168976e-03f, -3.252484018e-03f, +1.167016373e-02f, +2.029897446e-02f, -1.667047641e-02f, -6.667563061e-02f, -9.520450398e-03f, +1.983409219e-01f, +3.962581664e-01f, +3.803805952e-01f, +1.679490334e-01f, -2.593302438e-02f, -6.363374348e-02f, -9.509639499e-03f, +2.117884859e-02f, +9.289561904e-03f, -4.038774728e-03f, -3.137006363e-03f, +1.062635081e-04f,
+ /* 20, 8 */ +1.289664191e-05f, -3.400277535e-03f, -3.679559671e-03f, +1.048097797e-02f, +2.083730557e-02f, -1.303350512e-02f, -6.535942396e-02f, -1.806854797e-02f, +1.831223958e-01f, +3.887629129e-01f, +3.887629129e-01f, +1.831223958e-01f, -1.806854797e-02f, -6.535942396e-02f, -1.303350512e-02f, +2.083730557e-02f, +1.048097797e-02f, -3.679559671e-03f, -3.400277535e-03f, +1.289664191e-05f,
+ /* 20, 9 */ +1.062635081e-04f, -3.137006363e-03f, -4.038774728e-03f, +9.289561904e-03f, +2.117884859e-02f, -9.509639499e-03f, -6.363374348e-02f, -2.593302438e-02f, +1.679490334e-01f, +3.803805952e-01f, +3.962581664e-01f, +1.983409219e-01f, -9.520450398e-03f, -6.667563061e-02f, -1.667047641e-02f, +2.029897446e-02f, +1.167016373e-02f, -3.252484018e-03f, -3.655168976e-03f, -9.688872179e-05f,
+ /* 20,10 */ +1.837671888e-04f, -2.868951124e-03f, -4.331982887e-03f, +8.106294302e-03f, +2.133272965e-02f, -6.119502817e-03f, -6.153439984e-02f, -3.310606021e-02f, +1.528827232e-01f, +3.711517965e-01f, +4.028299211e-01f, +2.135413047e-01f, -3.006469464e-04f, -6.754749865e-02f, -2.039785121e-02f, +1.955588746e-02f, +1.284607053e-02f, -2.756254356e-03f, -3.897870552e-03f, -2.234691091e-04f,
+ /* 20,11 */ +2.461206998e-04f, -2.599469210e-03f, -4.561544087e-03f, +6.940829951e-03f, +2.130909659e-02f, -2.881585959e-03f, -5.909788086e-02f, -3.958387309e-02f, +1.379835966e-01f, +3.611209950e-01f, +4.084461208e-01f, +2.286591711e-01f, +9.574818877e-03f, -6.794137953e-02f, -2.419092016e-02f, +1.860136846e-02f, +1.399704337e-02f, -2.190189120e-03f, -4.124385552e-03f, -3.670219514e-04f,
+ /* 20,12 */ +2.941732022e-04f, -2.331660076e-03f, -4.730268616e-03f, +5.802054958e-03f, +2.111898038e-02f, +1.877878266e-04f, -5.636108634e-02f, -4.536663323e-02f, +1.233097059e-01f, +3.503362849e-01f, +4.130792899e-01f, +2.436294448e-01f, +2.008577030e-02f, -6.782511100e-02f, -2.802305698e-02f, +1.743016199e-02f, +1.511089362e-02f, -1.554266965e-03f, -4.330562617e-03f, -5.275063595e-04f,
+ /* 20,13 */ +3.288882594e-04f, -2.068349661e-03f, -4.841360048e-03f, +4.698051453e-03f, +2.077415592e-02f, +3.074480429e-03f, -5.336106841e-02f, -5.045835457e-02f, +1.089167196e-01f, +3.388490774e-01f, +4.167067067e-01f, +2.583867198e-01f, +3.120792005e-02f, -6.716828458e-02f, -3.186582692e-02f, +1.603855621e-02f, +1.617498084e-02f, -8.491713087e-04f, -4.512131585e-03f, -7.046452899e-04f,
+ /* 20,14 */ +3.513221827e-04f, -1.812078842e-03f, -4.898357639e-03f, +3.636071544e-03f, +2.028700325e-02f, +5.766539049e-03f, -5.013477905e-02f, -5.486676259e-02f, +9.485763802e-02f, +3.267137817e-01f, +4.193105477e-01f, +2.728656387e-01f, +4.291292121e-02f, -6.594250862e-02f, -3.568911340e-02f, +1.442449893e-02f, +1.717630323e-02f, -7.633034189e-05f, -4.664743082e-03f, -8.979094201e-04f,
+ /* 20,15 */ +0.000000000e+00f, -1.565095816e-03f, -4.905078775e-03f, +2.622520317e-03f, +1.967037055e-02f, +8.254179692e-03f, -4.671882663e-02f, -5.860314053e-02f, +8.118253044e-02f, +3.139874692e-01f, +4.208780002e-01f, +2.870012762e-01f, +5.516844650e-02f, -6.412166469e-02f, -3.946126222e-02f, +1.258770510e-02f, +1.810159639e-02f, +7.620481209e-04f, -4.784011640e-03f, -1.106503038e-03f,
+ /* 20, 0 */ +3.735125865e-04f, -2.550984103e-03f, -4.871486096e-03f, +1.016287769e-02f, +2.252246682e-02f, -2.231523982e-02f, -7.431762424e-02f, +3.414137659e-02f, +3.062278786e-01f, +4.608988972e-01f, +3.062278786e-01f, +3.414137659e-02f, -7.431762424e-02f, -2.231523982e-02f, +2.252246682e-02f, +1.016287769e-02f, -4.871486096e-03f, -2.550984103e-03f, +3.735125865e-04f, +0.000000000e+00f,
+ /* 20, 1 */ +3.929324583e-04f, -2.236335973e-03f, -5.106050653e-03f, +8.748210493e-03f, +2.303691111e-02f, -1.786093260e-02f, -7.411924916e-02f, +2.086992015e-02f, +2.890848421e-01f, +4.602142272e-01f, +3.228796668e-01f, +4.817530421e-02f, -7.382833631e-02f, -2.685541297e-02f, +2.174514756e-02f, +1.158816420e-02f, -4.555417854e-03f, -2.871502680e-03f, +3.387491377e-04f, +0.000000000e+00f,
+ /* 20, 2 */ +0.000000000e+00f, -1.931175707e-03f, -5.263447672e-03f, +7.357928950e-03f, +2.330080531e-02f, -1.352771902e-02f, -7.327813327e-02f, +8.401230311e-03f, +2.715429904e-01f, +4.581642525e-01f, +3.389493512e-01f, +6.292517925e-02f, -7.260941515e-02f, -3.144322519e-02f, +2.069454672e-02f, +1.300917115e-02f, -4.154170312e-03f, -3.193828376e-03f, +2.870815261e-04f, +0.000000000e+00f,
+ /* 20, 3 */ +0.000000000e+00f, -1.638662038e-03f, -5.348575554e-03f, +6.004591146e-03f, +2.332816092e-02f, -9.347674729e-03f, -7.184169597e-02f, -3.230759097e-03f, +2.536956771e-01f, +4.547610488e-01f, +3.543483057e-01f, +7.833843581e-02f, -7.062228683e-02f, -3.603763775e-02f, +1.936240016e-02f, +1.440996064e-02f, -3.664825055e-03f, -3.513472060e-03f, +2.170808154e-04f, +0.000000000e+00f,
+ /* 20, 4 */ +0.000000000e+00f, -1.361489293e-03f, -5.366796329e-03f, +4.699488665e-03f, +2.313444000e-02f, -5.349604768e-03f, -6.985939290e-02f, -1.399855627e-02f, +2.356365195e-01f, +4.500246402e-01f, +3.689907742e-01f, +9.435670405e-02f, -6.783220328e-02f, -4.059502103e-02f, +1.774280068e-02f, +1.577366666e-02f, -3.085314600e-03f, -3.825546457e-03f, +1.274866066e-04f, +0.000000000e+00f,
+ /* 20, 5 */ +0.000000000e+00f, -1.101888322e-03f, -5.323837897e-03f, +3.452605627e-03f, +2.273631696e-02f, -1.558959414e-03f, -6.738225311e-02f, -2.388113922e-02f, +2.174587480e-01f, +4.439828472e-01f, +3.827944964e-01f, +1.109160995e-01f, -6.420865295e-02f, -4.506940842e-02f, +1.583239979e-02f, +1.708262332e-02f, -2.414511840e-03f, -4.124801502e-03f, +1.724424543e-05f, +0.000000000e+00f,
+ /* 20, 6 */ +0.000000000e+00f, -8.616336525e-04f, -5.225698259e-03f, +2.272594520e-03f, +2.215144089e-02f, +2.002216238e-03f, -6.446241843e-02f, -3.286393171e-02f, +1.992545658e-01f, +4.366710759e-01f, +3.956813102e-01f, +1.279475618e-01f, -5.972574809e-02f, -4.941278189e-02f, +1.363059437e-02f, +1.831850983e-02f, -1.652313816e-03f, -4.405667401e-03f, -1.144582079e-04f, +0.000000000e+00f,
+ /* 20, 7 */ +0.000000000e+00f, -6.420563626e-04f, -5.078552799e-03f, +1.166768183e-03f, +2.139820068e-02f, +5.315299677e-03f, -6.115268907e-02f, -4.093872873e-02f, +1.811145256e-01f, +4.281320500e-01f, +4.075777294e-01f, +1.453772407e-01f, -5.436258502e-02f, -5.357538755e-02f, +1.113969540e-02f, +1.946251142e-02f, -7.997184460e-04f, -4.662305323e-03f, -2.681538305e-04f, +0.000000000e+00f,
+ /* 20, 8 */ +0.000000000e+00f, -4.440621234e-04f, -4.888665552e-03f, +1.411071672e-04f, +2.049549532e-02f, +8.365076494e-03f, -5.750607943e-02f, -4.810357305e-02f, +1.631269271e-01f, +4.184154881e-01f, +4.184154881e-01f, +1.631269271e-01f, -4.810357305e-02f, -5.750607943e-02f, +8.365076494e-03f, +2.049549532e-02f, +1.411071672e-04f, -4.888665552e-03f, -4.440621234e-04f, +0.000000000e+00f,
+ /* 20, 9 */ +0.000000000e+00f, -2.681538305e-04f, -4.662305323e-03f, -7.997184460e-04f, +1.946251142e-02f, +1.113969540e-02f, -5.357538755e-02f, -5.436258502e-02f, +1.453772407e-01f, +4.075777294e-01f, +4.281320500e-01f, +1.811145256e-01f, -4.093872873e-02f, -6.115268907e-02f, +5.315299677e-03f, +2.139820068e-02f, +1.166768183e-03f, -5.078552799e-03f, -6.420563626e-04f, +0.000000000e+00f,
+ /* 20,10 */ +0.000000000e+00f, -1.144582079e-04f, -4.405667401e-03f, -1.652313816e-03f, +1.831850983e-02f, +1.363059437e-02f, -4.941278189e-02f, -5.972574809e-02f, +1.279475618e-01f, +3.956813102e-01f, +4.366710759e-01f, +1.992545658e-01f, -3.286393171e-02f, -6.446241843e-02f, +2.002216238e-03f, +2.215144089e-02f, +2.272594520e-03f, -5.225698259e-03f, -8.616336525e-04f, +0.000000000e+00f,
+ /* 20,11 */ +0.000000000e+00f, +1.724424543e-05f, -4.124801502e-03f, -2.414511840e-03f, +1.708262332e-02f, +1.583239979e-02f, -4.506940842e-02f, -6.420865295e-02f, +1.109160995e-01f, +3.827944964e-01f, +4.439828472e-01f, +2.174587480e-01f, -2.388113922e-02f, -6.738225311e-02f, -1.558959414e-03f, +2.273631696e-02f, +3.452605627e-03f, -5.323837897e-03f, -1.101888322e-03f, +0.000000000e+00f,
+ /* 20,12 */ +0.000000000e+00f, +1.274866066e-04f, -3.825546457e-03f, -3.085314600e-03f, +1.577366666e-02f, +1.774280068e-02f, -4.059502103e-02f, -6.783220328e-02f, +9.435670405e-02f, +3.689907742e-01f, +4.500246402e-01f, +2.356365195e-01f, -1.399855627e-02f, -6.985939290e-02f, -5.349604768e-03f, +2.313444000e-02f, +4.699488665e-03f, -5.366796329e-03f, -1.361489293e-03f, +0.000000000e+00f,
+ /* 20,13 */ +0.000000000e+00f, +2.170808154e-04f, -3.513472060e-03f, -3.664825055e-03f, +1.440996064e-02f, +1.936240016e-02f, -3.603763775e-02f, -7.062228683e-02f, +7.833843581e-02f, +3.543483057e-01f, +4.547610488e-01f, +2.536956771e-01f, -3.230759097e-03f, -7.184169597e-02f, -9.347674729e-03f, +2.332816092e-02f, +6.004591146e-03f, -5.348575554e-03f, -1.638662038e-03f, +0.000000000e+00f,
+ /* 20,14 */ +0.000000000e+00f, +2.870815261e-04f, -3.193828376e-03f, -4.154170312e-03f, +1.300917115e-02f, +2.069454672e-02f, -3.144322519e-02f, -7.260941515e-02f, +6.292517925e-02f, +3.389493512e-01f, +4.581642525e-01f, +2.715429904e-01f, +8.401230311e-03f, -7.327813327e-02f, -1.352771902e-02f, +2.330080531e-02f, +7.357928950e-03f, -5.263447672e-03f, -1.931175707e-03f, +0.000000000e+00f,
+ /* 20,15 */ +0.000000000e+00f, +3.387491377e-04f, -2.871502680e-03f, -4.555417854e-03f, +1.158816420e-02f, +2.174514756e-02f, -2.685541297e-02f, -7.382833631e-02f, +4.817530421e-02f, +3.228796668e-01f, +4.602142272e-01f, +2.890848421e-01f, +2.086992015e-02f, -7.411924916e-02f, -1.786093260e-02f, +2.303691111e-02f, +8.748210493e-03f, -5.106050653e-03f, -2.236335973e-03f, +3.929324583e-04f,
+ /* 16, 0 */ -4.898743621e-03f, -8.679086087e-05f, +2.336043359e-02f, +2.135055302e-04f, -7.556698393e-02f, -3.418085064e-04f, +3.068350485e-01f, +5.003964504e-01f, +3.068350485e-01f, -3.418085064e-04f, -7.556698393e-02f, +2.135055302e-04f, +2.336043359e-02f, -8.679086087e-05f, -4.898743621e-03f, +1.466795211e-05f,
+ /* 16, 1 */ -4.577177643e-03f, -1.168030162e-03f, +2.231338881e-02f, +4.259286102e-03f, -7.256190983e-02f, -1.325523148e-02f, +2.859961851e-01f, +4.995203198e-01f, +3.272077887e-01f, +1.366916740e-02f, -7.794631959e-02f, -4.137969722e-03f, +2.421268789e-02f, +1.104119466e-03f, -5.186216174e-03f, -1.424716020e-04f,
+ /* 16, 2 */ -4.229744004e-03f, -2.135347302e-03f, +2.109817837e-02f, +7.975999347e-03f, -6.900371451e-02f, -2.503996167e-02f, +2.648211478e-01f, +4.968980143e-01f, +3.469854770e-01f, +2.873680235e-02f, -7.962890015e-02f, -8.766610174e-03f, +2.484400873e-02f, +2.398541233e-03f, -5.431090074e-03f, -3.278051009e-04f,
+ /* 16, 3 */ -3.864289504e-03f, -2.986316790e-03f, +1.974155805e-02f, +1.134537917e-02f, -6.496587406e-02f, -3.567459207e-02f, +2.434398342e-01f, +4.925477372e-01f, +3.660412816e-01f, +4.481051979e-02f, -8.054606315e-02f, -1.363873477e-02f, +2.522910176e-02f, +3.788344934e-03f, -5.624692566e-03f, -5.415628140e-04f,
+ /* 16, 4 */ -3.488195595e-03f, -3.720237037e-03f, +1.827008292e-02f, +1.435416313e-02f, -6.052200094e-02f, -4.514733704e-02f, +2.219810322e-01f, +4.864996469e-01f, +3.842515379e-01f, +6.183022559e-02f, -8.063225815e-02f, -1.871557408e-02f, +2.534390000e-02f, +5.263393235e-03f, -5.758306879e-03f, -7.834433658e-04f,
+ /* 16, 5 */ -3.108305495e-03f, -4.338012209e-03f, +1.670979794e-02f, +1.699394035e-02f, -5.574514781e-02f, -5.345583367e-02f, +2.005713869e-01f, +4.787955863e-01f, +4.014968013e-01f, +7.972656727e-02f, -7.982580067e-02f, -2.395339311e-02f, +2.516595041e-02f, +6.811528665e-03f, -5.823306183e-03f, -1.052565974e-03f,
+ /* 16, 6 */ -2.730865011e-03f, -4.842020290e-03f, +1.508595356e-02f, +1.926095418e-02f, -5.070714412e-02f, -6.060686010e-02f, +1.793344024e-01f, +4.694887096e-01f, +4.176628724e-01f, +9.842128660e-02f, -7.806961406e-02f, -2.930367505e-02f, +2.467480385e-02f, +8.418588685e-03f, -5.811296621e-03f, -1.347428958e-03f,
+ /* 16, 7 */ -2.361477017e-03f, -5.235970004e-03f, +1.342274837e-02f, +2.115586371e-02f, -4.547797122e-02f, -6.661597542e-02f, +1.583894867e-01f, +4.586430086e-01f, +4.326417845e-01f, +1.178276637e-01f, -7.531195111e-02f, -3.471336612e-02f, +2.385240383e-02f, +1.006844961e-02f, -5.714267850e-03f, -1.665875716e-03f,
+ /* 16, 8 */ -2.005069351e-03f, -5.524749278e-03f, +1.174310057e-02f, +2.268346885e-02f, -4.012518151e-02f, -7.150708699e-02f, +1.378510501e-01f, +4.463327434e-01f, +4.463327434e-01f, +1.378510501e-01f, -7.150708699e-02f, -4.012518151e-02f, +2.268346885e-02f, +1.174310057e-02f, -5.524749278e-03f, -2.005069351e-03f,
+ /* 16, 9 */ -1.665875716e-03f, -5.714267850e-03f, +1.006844961e-02f, +2.385240383e-02f, -3.471336612e-02f, -7.531195111e-02f, +1.178276637e-01f, +4.326417845e-01f, +4.586430086e-01f, +1.583894867e-01f, -6.661597542e-02f, -4.547797122e-02f, +2.115586371e-02f, +1.342274837e-02f, -5.235970004e-03f, -2.361477017e-03f,
+ /* 16,10 */ -1.347428958e-03f, -5.811296621e-03f, +8.418588685e-03f, +2.467480385e-02f, -2.930367505e-02f, -7.806961406e-02f, +9.842128660e-02f, +4.176628724e-01f, +4.694887096e-01f, +1.793344024e-01f, -6.060686010e-02f, -5.070714412e-02f, +1.926095418e-02f, +1.508595356e-02f, -4.842020290e-03f, -2.730865011e-03f,
+ /* 16,11 */ -1.052565974e-03f, -5.823306183e-03f, +6.811528665e-03f, +2.516595041e-02f, -2.395339311e-02f, -7.982580067e-02f, +7.972656727e-02f, +4.014968013e-01f, +4.787955863e-01f, +2.005713869e-01f, -5.345583367e-02f, -5.574514781e-02f, +1.699394035e-02f, +1.670979794e-02f, -4.338012209e-03f, -3.108305495e-03f,
+ /* 16,12 */ -7.834433658e-04f, -5.758306879e-03f, +5.263393235e-03f, +2.534390000e-02f, -1.871557408e-02f, -8.063225815e-02f, +6.183022559e-02f, +3.842515379e-01f, +4.864996469e-01f, +2.219810322e-01f, -4.514733704e-02f, -6.052200094e-02f, +1.435416313e-02f, +1.827008292e-02f, -3.720237037e-03f, -3.488195595e-03f,
+ /* 16,13 */ -5.415628140e-04f, -5.624692566e-03f, +3.788344934e-03f, +2.522910176e-02f, -1.363873477e-02f, -8.054606315e-02f, +4.481051979e-02f, +3.660412816e-01f, +4.925477372e-01f, +2.434398342e-01f, -3.567459207e-02f, -6.496587406e-02f, +1.134537917e-02f, +1.974155805e-02f, -2.986316790e-03f, -3.864289504e-03f,
+ /* 16,14 */ -3.278051009e-04f, -5.431090074e-03f, +2.398541233e-03f, +2.484400873e-02f, -8.766610174e-03f, -7.962890015e-02f, +2.873680235e-02f, +3.469854770e-01f, +4.968980143e-01f, +2.648211478e-01f, -2.503996167e-02f, -6.900371451e-02f, +7.975999347e-03f, +2.109817837e-02f, -2.135347302e-03f, -4.229744004e-03f,
+ /* 16,15 */ -1.424716020e-04f, -5.186216174e-03f, +1.104119466e-03f, +2.421268789e-02f, -4.137969722e-03f, -7.794631959e-02f, +1.366916740e-02f, +3.272077887e-01f, +4.995203198e-01f, +2.859961851e-01f, -1.325523148e-02f, -7.256190983e-02f, +4.259286102e-03f, +2.231338881e-02f, -1.168030162e-03f, -4.577177643e-03f,
+ /* 16, 0 */ -1.854349243e-03f, -5.842655877e-03f, +1.571555836e-02f, +1.847159410e-02f, -6.634453543e-02f, -3.320569278e-02f, +3.025932104e-01f, +5.398940036e-01f, +3.025932104e-01f, -3.320569278e-02f, -6.634453543e-02f, +1.847159410e-02f, +1.571555836e-02f, -5.842655877e-03f, -1.854349243e-03f, +0.000000000e+00f,
+ /* 16, 1 */ -1.480579358e-03f, -6.106700866e-03f, +1.376986381e-02f, +2.107103425e-02f, -6.084498265e-02f, -4.482173865e-02f, +2.778559558e-01f, +5.387937054e-01f, +3.269511876e-01f, -2.013603096e-02f, -7.140657205e-02f, +1.540395578e-02f, +1.762103499e-02f, -5.450677830e-03f, -2.253515747e-03f, +0.000000000e+00f,
+ /* 16, 2 */ -1.136163241e-03f, -6.251562574e-03f, +1.181432209e-02f, +2.320368920e-02f, -5.500558000e-02f, -5.497544958e-02f, +2.529151163e-01f, +5.355017071e-01f, +3.507537104e-01f, -5.635398845e-03f, -7.593183970e-02f, +1.187314151e-02f, +1.945395611e-02f, -4.923375547e-03f, -2.673102395e-03f, +0.000000000e+00f,
+ /* 16, 3 */ -8.240613879e-04f, -6.287094834e-03f, +9.877041313e-03f, +2.487696888e-02f, -4.892141083e-02f, -6.367164518e-02f, +2.279442418e-01f, +5.300446041e-01f, +3.738258052e-01f, +1.025938806e-02f, -7.982055919e-02f, +7.890985370e-03f, +2.118036474e-02f, -4.254967852e-03f, -3.107109230e-03f, +0.000000000e+00f,
+ /* 16, 4 */ -5.462770218e-04f, -6.224002243e-03f, +7.983624178e-03f, +2.610378910e-02f, -4.268405269e-02f, -7.092815895e-02f, +2.031131300e-01f, +5.224664143e-01f, +3.959953988e-01f, +2.749725254e-02f, -8.297353764e-02f, +3.476439880e-03f, +2.276508169e-02f, -3.441527233e-03f, -3.548528769e-03f, +4.634120047e-04f,
+ /* 16, 5 */ -3.039101756e-04f, -6.073592210e-03f, +6.156978545e-03f, +2.690203687e-02f, -3.638073666e-02f, -7.677518685e-02f, +1.785862812e-01f, +5.128281199e-01f, +4.170950072e-01f, +4.601292009e-02f, -8.529332152e-02f, -1.344195268e-03f, +2.417214928e-02f, -2.481210963e-03f, -3.989383394e-03f, +4.400286560e-04f,
+ /* 16, 6 */ -9.722433303e-05f, -5.847536081e-03f, +4.417180930e-03f, +2.729400173e-02f, -3.009359622e-02f, -8.125451993e-02f, +1.545214364e-01f, +5.012070337e-01f, +4.369633957e-01f, +6.572714234e-02f, -8.668537697e-02f, -6.537129252e-03f, +2.536531778e-02f, -1.374474827e-03f, -4.420785166e-03f, +3.921992729e-04f,
+ /* 16, 7 */ +7.427658644e-05f, -5.557642708e-03f, +2.781391675e-03f, +2.730578215e-02f, -2.389901141e-02f, -8.441867356e-02f, +1.310682124e-01f, +4.876959980e-01f, +4.554471907e-01f, +8.654708074e-02f, -8.705928349e-02f, -1.206102709e-02f, +2.630856978e-02f, -1.242645535e-04f, -4.833018707e-03f, +3.169896142e-04f,
+ /* 16, 8 */ +2.117631665e-04f, -5.215647395e-03f, +1.263819875e-03f, +2.696667686e-02f, -1.786705263e-02f, -8.632992647e-02f, +1.083668491e-01f, +4.724024249e-01f, +4.724024249e-01f, +1.083668491e-01f, -8.632992647e-02f, -1.786705263e-02f, +2.696667686e-02f, +1.263819875e-03f, -5.215647395e-03f, +2.117631665e-04f,
+ /* 16, 9 */ +3.169896142e-04f, -4.833018707e-03f, -1.242645535e-04f, +2.630856978e-02f, -1.206102709e-02f, -8.705928349e-02f, +8.654708074e-02f, +4.554471907e-01f, +4.876959980e-01f, +1.310682124e-01f, -8.441867356e-02f, -2.389901141e-02f, +2.730578215e-02f, +2.781391675e-03f, -5.557642708e-03f, +7.427658644e-05f,
+ /* 16,10 */ +3.921992729e-04f, -4.420785166e-03f, -1.374474827e-03f, +2.536531778e-02f, -6.537129252e-03f, -8.668537697e-02f, +6.572714234e-02f, +4.369633957e-01f, +5.012070337e-01f, +1.545214364e-01f, -8.125451993e-02f, -3.009359622e-02f, +2.729400173e-02f, +4.417180930e-03f, -5.847536081e-03f, -9.722433303e-05f,
+ /* 16,11 */ +4.400286560e-04f, -3.989383394e-03f, -2.481210963e-03f, +2.417214928e-02f, -1.344195268e-03f, -8.529332152e-02f, +4.601292009e-02f, +4.170950072e-01f, +5.128281199e-01f, +1.785862812e-01f, -7.677518685e-02f, -3.638073666e-02f, +2.690203687e-02f, +6.156978545e-03f, -6.073592210e-03f, -3.039101756e-04f,
+ /* 16,12 */ +4.634120047e-04f, -3.548528769e-03f, -3.441527233e-03f, +2.276508169e-02f, +3.476439880e-03f, -8.297353764e-02f, +2.749725254e-02f, +3.959953988e-01f, +5.224664143e-01f, +2.031131300e-01f, -7.092815895e-02f, -4.268405269e-02f, +2.610378910e-02f, +7.983624178e-03f, -6.224002243e-03f, -5.462770218e-04f,
+ /* 16,13 */ +0.000000000e+00f, -3.107109230e-03f, -4.254967852e-03f, +2.118036474e-02f, +7.890985370e-03f, -7.982055919e-02f, +1.025938806e-02f, +3.738258052e-01f, +5.300446041e-01f, +2.279442418e-01f, -6.367164518e-02f, -4.892141083e-02f, +2.487696888e-02f, +9.877041313e-03f, -6.287094834e-03f, -8.240613879e-04f,
+ /* 16,14 */ +0.000000000e+00f, -2.673102395e-03f, -4.923375547e-03f, +1.945395611e-02f, +1.187314151e-02f, -7.593183970e-02f, -5.635398845e-03f, +3.507537104e-01f, +5.355017071e-01f, +2.529151163e-01f, -5.497544958e-02f, -5.500558000e-02f, +2.320368920e-02f, +1.181432209e-02f, -6.251562574e-03f, -1.136163241e-03f,
+ /* 16,15 */ +0.000000000e+00f, -2.253515747e-03f, -5.450677830e-03f, +1.762103499e-02f, +1.540395578e-02f, -7.140657205e-02f, -2.013603096e-02f, +3.269511876e-01f, +5.387937054e-01f, +2.778559558e-01f, -4.482173865e-02f, -6.084498265e-02f, +2.107103425e-02f, +1.376986381e-02f, -6.106700866e-03f, -1.480579358e-03f,
+ /* 16, 0 */ +2.517634455e-04f, -5.956310854e-03f, +5.008864062e-03f, +2.864631470e-02f, -4.909056125e-02f, -6.235528720e-02f, +2.936293584e-01f, +5.793915568e-01f, +2.936293584e-01f, -6.235528720e-02f, -4.909056125e-02f, +2.864631470e-02f, +5.008864062e-03f, -5.956310854e-03f, +2.517634455e-04f, +0.000000000e+00f,
+ /* 16, 1 */ +3.647589216e-04f, -5.559366521e-03f, +3.110945653e-03f, +2.922667528e-02f, -4.185408685e-02f, -7.174125192e-02f, +2.648835910e-01f, +5.780318135e-01f, +3.221602930e-01f, -5.117389488e-02f, -5.619351824e-02f, +2.755457966e-02f, +7.032385926e-03f, -6.289189967e-03f, +9.939782505e-05f, +0.000000000e+00f,
+ /* 16, 2 */ +4.414886472e-04f, -5.113535158e-03f, +1.357910925e-03f, +2.932892142e-02f, -3.459618474e-02f, -7.936172697e-02f, +2.361522790e-01f, +5.739652427e-01f, +3.502436629e-01f, -3.818535953e-02f, -6.304412145e-02f, +2.592390265e-02f, +9.158035052e-03f, -6.542440674e-03f, -9.477253367e-05f, +0.000000000e+00f,
+ /* 16, 3 */ +4.855802427e-04f, -4.633347213e-03f, -2.351453324e-04f, +2.899108127e-02f, -2.742112952e-02f, -8.526380919e-02f, +2.076588264e-01f, +5.672296697e-01f, +3.776458156e-01f, -2.339704980e-02f, -6.951800781e-02f, +2.373330296e-02f, +1.135820669e-02f, -6.700410184e-03f, -3.323676319e-04f, +0.000000000e+00f,
+ /* 16, 4 */ +0.000000000e+00f, -4.132457962e-03f, -1.657230762e-03f, +2.825501306e-02f, -2.042447313e-02f, -8.951050933e-02f, +1.796184274e-01f, +5.578876325e-01f, +4.041347532e-01f, -6.836060229e-03f, -7.548664793e-02f, +2.096923455e-02f, +1.360131724e-02f, -6.747680557e-03f, -6.140535745e-04f, +0.000000000e+00f,
+ /* 16, 5 */ +0.000000000e+00f, -3.623457200e-03f, -2.901306411e-03f, +2.716546883e-02f, -1.369230379e-02f, -9.217934767e-02f, +1.522358833e-01f, +5.460256322e-01f, +4.294827240e-01f, +1.145038182e-02f, -8.081883229e-02f, +1.762637069e-02f, +1.585203938e-02f, -6.669417793e-03f, -9.394126333e-04f, +0.000000000e+00f,
+ /* 16, 6 */ +0.000000000e+00f, -3.117716971e-03f, -3.964078879e-03f, +2.576917487e-02f, -7.300675124e-03f, -9.336081470e-02f, +1.257035893e-01f, +5.317530991e-01f, +4.534687988e-01f, +3.139475616e-02f, -8.538226676e-02f, +1.370830904e-02f, +1.807162423e-02f, -6.451740247e-03f, -1.306826648e-03f, +0.000000000e+00f,
+ /* 16, 7 */ +0.000000000e+00f, -2.625277441e-03f, -4.845741482e-03f, +2.411394259e-02f, -1.315205805e-03f, -9.315672206e-02f, +1.001997139e-01f, +5.152010878e-01f, +4.758813956e-01f, +5.290934542e-02f, -8.904525833e-02f, +9.228181275e-03f, +2.021831098e-02f, -6.082100328e-03f, -1.713377737e-03f, +0.000000000e+00f,
+ /* 16, 8 */ +0.000000000e+00f, -2.154770219e-03f, -5.549672684e-03f, +2.224782226e-02f, +4.209152176e-03f, -9.167847004e-02f, +7.588659143e-02f, +4.965207199e-01f, +4.965207199e-01f, +7.588659143e-02f, -9.167847004e-02f, +4.209152176e-03f, +2.224782226e-02f, -5.549672684e-03f, -2.154770219e-03f, +0.000000000e+00f,
+ /* 16, 9 */ +0.000000000e+00f, -1.713377737e-03f, -6.082100328e-03f, +2.021831098e-02f, +9.228181275e-03f, -8.904525833e-02f, +5.290934542e-02f, +4.758813956e-01f, +5.152010878e-01f, +1.001997139e-01f, -9.315672206e-02f, -1.315205805e-03f, +2.411394259e-02f, -4.845741482e-03f, -2.625277441e-03f, +0.000000000e+00f,
+ /* 16,10 */ +0.000000000e+00f, -1.306826648e-03f, -6.451740247e-03f, +1.807162423e-02f, +1.370830904e-02f, -8.538226676e-02f, +3.139475616e-02f, +4.534687988e-01f, +5.317530991e-01f, +1.257035893e-01f, -9.336081470e-02f, -7.300675124e-03f, +2.576917487e-02f, -3.964078879e-03f, -3.117716971e-03f, +0.000000000e+00f,
+ /* 16,11 */ +0.000000000e+00f, -9.394126333e-04f, -6.669417793e-03f, +1.585203938e-02f, +1.762637069e-02f, -8.081883229e-02f, +1.145038182e-02f, +4.294827240e-01f, +5.460256322e-01f, +1.522358833e-01f, -9.217934767e-02f, -1.369230379e-02f, +2.716546883e-02f, -2.901306411e-03f, -3.623457200e-03f, +0.000000000e+00f,
+ /* 16,12 */ +0.000000000e+00f, -6.140535745e-04f, -6.747680557e-03f, +1.360131724e-02f, +2.096923455e-02f, -7.548664793e-02f, -6.836060229e-03f, +4.041347532e-01f, +5.578876325e-01f, +1.796184274e-01f, -8.951050933e-02f, -2.042447313e-02f, +2.825501306e-02f, -1.657230762e-03f, -4.132457962e-03f, +0.000000000e+00f,
+ /* 16,13 */ +0.000000000e+00f, -3.323676319e-04f, -6.700410184e-03f, +1.135820669e-02f, +2.373330296e-02f, -6.951800781e-02f, -2.339704980e-02f, +3.776458156e-01f, +5.672296697e-01f, +2.076588264e-01f, -8.526380919e-02f, -2.742112952e-02f, +2.899108127e-02f, -2.351453324e-04f, -4.633347213e-03f, +4.855802427e-04f,
+ /* 16,14 */ +0.000000000e+00f, -9.477253367e-05f, -6.542440674e-03f, +9.158035052e-03f, +2.592390265e-02f, -6.304412145e-02f, -3.818535953e-02f, +3.502436629e-01f, +5.739652427e-01f, +2.361522790e-01f, -7.936172697e-02f, -3.459618474e-02f, +2.932892142e-02f, +1.357910925e-03f, -5.113535158e-03f, +4.414886472e-04f,
+ /* 16,15 */ +0.000000000e+00f, +9.939782505e-05f, -6.289189967e-03f, +7.032385926e-03f, +2.755457966e-02f, -5.619351824e-02f, -5.117389488e-02f, +3.221602930e-01f, +5.780318135e-01f, +2.648835910e-01f, -7.174125192e-02f, -4.185408685e-02f, +2.922667528e-02f, +3.110945653e-03f, -5.559366521e-03f, +3.647589216e-04f,
+ /* 12, 0 */ -3.638165547e-03f, +2.979985982e-02f, -2.723323293e-02f, -8.605047059e-02f, +2.801520768e-01f, +6.188891100e-01f, +2.801520768e-01f, -8.605047059e-02f, -2.723323293e-02f, +2.979985982e-02f, -3.638165547e-03f, -3.041512814e-03f,
+ /* 12, 1 */ -4.749738186e-03f, +2.841159300e-02f, -1.933319589e-02f, -9.237133076e-02f, +2.473915856e-01f, +6.172320760e-01f, +3.129551421e-01f, -7.764805088e-02f, -3.538029377e-02f, +3.077779188e-02f, -2.305275216e-03f, -3.612081594e-03f,
+ /* 12, 2 */ -5.642312008e-03f, +2.667449885e-02f, -1.178831271e-02f, -9.669686191e-02f, +2.149632830e-01f, +6.122785731e-01f, +3.455026876e-01f, -6.709962705e-02f, -4.365285408e-02f, +3.128617370e-02f, -7.534120996e-04f, -4.192641091e-03f,
+ /* 12, 3 */ -6.322395719e-03f, +2.465107974e-02f, -4.692548813e-03f, -9.913294928e-02f, +1.831448749e-01f, +6.040811565e-01f, +3.774917553e-01f, -5.436442589e-02f, -5.191703591e-02f, +3.126943445e-02f, +1.010002855e-03f, -4.769140004e-03f,
+ /* 12, 4 */ -6.800166749e-03f, +2.240361196e-02f, +1.874795505e-03f, -9.980279721e-02f, +1.521989634e-01f, +5.927266195e-01f, +4.086182709e-01f, -3.942694703e-02f, -6.002791415e-02f, +3.067703358e-02f, +2.972136287e-03f, -5.325763732e-03f,
+ /* 12, 5 */ -7.088917510e-03f, +1.999301835e-02f, +7.849320649e-03f, -9.884443272e-02f, +1.223701278e-01f, +5.783348068e-01f, +4.385808709e-01f, -2.229824534e-02f, -6.783107929e-02f, +2.946485483e-02f, +5.114495497e-03f, -5.845139328e-03f,
+ /* 12, 6 */ -7.204483224e-03f, +1.747784955e-02f, +1.318150805e-02f, -9.640809295e-02f, +9.388232321e-02f, +5.610569814e-01f, +4.670847512e-01f, -3.016864363e-03f, -7.516444191e-02f, +2.759658236e-02f, +7.412783505e-03f, -6.308600966e-03f,
+ /* 12, 7 */ -7.164664930e-03f, +1.491338589e-02f, +1.783645872e-02f, -9.265354184e-02f, +6.693662660e-02f, +5.410737692e-01f, +4.938454794e-01f, +1.835060492e-02f, -8.186025948e-02f, +2.504503167e-02f, +9.836867291e-03f, -6.696514785e-03f,
+ /* 12, 8 */ -6.988660420e-03f, +1.235086875e-02f, +2.179340724e-02f, -8.774736114e-02f, +4.170935934e-02f, +5.185927134e-01f, +5.185927134e-01f, +4.170935934e-02f, -8.774736114e-02f, +2.179340724e-02f, +1.235086875e-02f, -6.988660420e-03f,
+ /* 12, 9 */ -6.696514785e-03f, +9.836867291e-03f, +2.504503167e-02f, -8.186025948e-02f, +1.835060492e-02f, +4.938454794e-01f, +5.410737692e-01f, +6.693662660e-02f, -9.265354184e-02f, +1.783645872e-02f, +1.491338589e-02f, -7.164664930e-03f,
+ /* 12,10 */ -6.308600966e-03f, +7.412783505e-03f, +2.759658236e-02f, -7.516444191e-02f, -3.016864363e-03f, +4.670847512e-01f, +5.610569814e-01f, +9.388232321e-02f, -9.640809295e-02f, +1.318150805e-02f, +1.747784955e-02f, -7.204483224e-03f,
+ /* 12,11 */ -5.845139328e-03f, +5.114495497e-03f, +2.946485483e-02f, -6.783107929e-02f, -2.229824534e-02f, +4.385808709e-01f, +5.783348068e-01f, +1.223701278e-01f, -9.884443272e-02f, +7.849320649e-03f, +1.999301835e-02f, -7.088917510e-03f,
+ /* 12,12 */ -5.325763732e-03f, +2.972136287e-03f, +3.067703358e-02f, -6.002791415e-02f, -3.942694703e-02f, +4.086182709e-01f, +5.927266195e-01f, +1.521989634e-01f, -9.980279721e-02f, +1.874795505e-03f, +2.240361196e-02f, -6.800166749e-03f,
+ /* 12,13 */ -4.769140004e-03f, +1.010002855e-03f, +3.126943445e-02f, -5.191703591e-02f, -5.436442589e-02f, +3.774917553e-01f, +6.040811565e-01f, +1.831448749e-01f, -9.913294928e-02f, -4.692548813e-03f, +2.465107974e-02f, -6.322395719e-03f,
+ /* 12,14 */ -4.192641091e-03f, -7.534120996e-04f, +3.128617370e-02f, -4.365285408e-02f, -6.709962705e-02f, +3.455026876e-01f, +6.122785731e-01f, +2.149632830e-01f, -9.669686191e-02f, -1.178831271e-02f, +2.667449885e-02f, -5.642312008e-03f,
+ /* 12,15 */ -3.612081594e-03f, -2.305275216e-03f, +3.077779188e-02f, -3.538029377e-02f, -7.764805088e-02f, +3.129551421e-01f, +6.172320760e-01f, +2.473915856e-01f, -9.237133076e-02f, -1.933319589e-02f, +2.841159300e-02f, -4.749738186e-03f,
+ /* 12, 0 */ -7.562702671e-03f, +2.362257603e-02f, -4.531854693e-03f, -1.030173373e-01f, +2.624467795e-01f, +6.583866631e-01f, +2.624467795e-01f, -1.030173373e-01f, -4.531854693e-03f, +2.362257603e-02f, -7.562702671e-03f, -3.516889901e-04f,
+ /* 12, 1 */ -7.668183010e-03f, +2.087771707e-02f, +2.839059860e-03f, -1.056218320e-01f, +2.257778124e-01f, +6.563919279e-01f, +2.995227467e-01f, -9.814415944e-02f, -1.254420342e-02f, +2.617709089e-02f, -7.250906804e-03f, -7.142430143e-04f,
+ /* 12, 2 */ -7.590423774e-03f, +1.801705410e-02f, +9.487879886e-03f, -1.061169074e-01f, +1.898705313e-01f, +6.504316937e-01f, +3.366347146e-01f, -9.086648783e-02f, -2.109702270e-02f, +2.846338313e-02f, -6.712315500e-03f, -1.140764971e-03f,
+ /* 12, 3 */ -7.354275530e-03f, +1.511050856e-02f, +1.535418598e-02f, -1.046816488e-01f, +1.550586973e-01f, +6.405775033e-01f, +3.734003416e-01f, -8.107535131e-02f, -3.006937567e-02f, +3.040170317e-02f, -5.929880498e-03f, -1.628307909e-03f,
+ /* 12, 4 */ -6.985575046e-03f, +1.222230420e-02f, +2.039736787e-02f, -1.015111601e-01f, +1.216509697e-01f, +6.269473635e-01f, +4.094311989e-01f, -6.869168809e-02f, -3.932109040e-02f, +3.191206547e-02f, -4.890814148e-03f, -2.171433859e-03f,
+ /* 12, 5 */ -6.510406524e-03f, +9.410098002e-03f, +2.459585213e-02f, -9.681266365e-02f, +8.992722338e-02f, +6.097039216e-01f, +4.443382217e-01f, -5.366903171e-02f, -4.869391429e-02f, +3.291602689e-02f, -3.587389454e-03f, -2.762058981e-03f,
+ /* 12, 6 */ -5.954426605e-03f, +6.724324555e-03f, +2.794602403e-02f, -9.080157573e-02f, +6.013541337e-02f, +5.890519583e-01f, +4.777372670e-01f, -3.599575069e-02f, -5.801308453e-02f, +3.333857894e-02f, -2.017687876e-03f, -3.389362400e-03f,
+ /* 12, 7 */ -5.342264546e-03f, +4.207752570e-03f, +3.046088231e-02f, -8.369763050e-02f, +3.248902822e-02f, +5.652352421e-01f, +5.092546840e-01f, -1.569678608e-02f, -6.708930595e-02f, +3.311011989e-02f, -1.862710466e-04f, -4.039767889e-03f,
+ /* 12, 8 */ -4.697006242e-03f, +1.895247343e-03f, +3.216846911e-02f, -7.572111885e-02f, +7.165160645e-03f, +5.385328020e-01f, +5.385328020e-01f, +7.165160645e-03f, -7.572111885e-02f, +3.216846911e-02f, +1.895247343e-03f, -4.697006242e-03f,
+ /* 12, 9 */ -4.039767889e-03f, -1.862710466e-04f, +3.311011989e-02f, -6.708930595e-02f, -1.569678608e-02f, +5.092546840e-01f, +5.652352421e-01f, +3.248902822e-02f, -8.369763050e-02f, +3.046088231e-02f, +4.207752570e-03f, -5.342264546e-03f,
+ /* 12,10 */ -3.389362400e-03f, -2.017687876e-03f, +3.333857894e-02f, -5.801308453e-02f, -3.599575069e-02f, +4.777372670e-01f, +5.890519583e-01f, +6.013541337e-02f, -9.080157573e-02f, +2.794602403e-02f, +6.724324555e-03f, -5.954426605e-03f,
+ /* 12,11 */ -2.762058981e-03f, -3.587389454e-03f, +3.291602689e-02f, -4.869391429e-02f, -5.366903171e-02f, +4.443382217e-01f, +6.097039216e-01f, +8.992722338e-02f, -9.681266365e-02f, +2.459585213e-02f, +9.410098002e-03f, -6.510406524e-03f,
+ /* 12,12 */ -2.171433859e-03f, -4.890814148e-03f, +3.191206547e-02f, -3.932109040e-02f, -6.869168809e-02f, +4.094311989e-01f, +6.269473635e-01f, +1.216509697e-01f, -1.015111601e-01f, +2.039736787e-02f, +1.222230420e-02f, -6.985575046e-03f,
+ /* 12,13 */ -1.628307909e-03f, -5.929880498e-03f, +3.040170317e-02f, -3.006937567e-02f, -8.107535131e-02f, +3.734003416e-01f, +6.405775033e-01f, +1.550586973e-01f, -1.046816488e-01f, +1.535418598e-02f, +1.511050856e-02f, -7.354275530e-03f,
+ /* 12,14 */ -1.140764971e-03f, -6.712315500e-03f, +2.846338313e-02f, -2.109702270e-02f, -9.086648783e-02f, +3.366347146e-01f, +6.504316937e-01f, +1.898705313e-01f, -1.061169074e-01f, +9.487879886e-03f, +1.801705410e-02f, -7.590423774e-03f,
+ /* 12,15 */ -7.142430143e-04f, -7.250906804e-03f, +2.617709089e-02f, -1.254420342e-02f, -9.814415944e-02f, +2.995227467e-01f, +6.563919279e-01f, +2.257778124e-01f, -1.056218320e-01f, +2.839059860e-03f, +2.087771707e-02f, -7.668183010e-03f,
+ /* 12, 0 */ -7.009786996e-03f, +1.344312953e-02f, +1.557210222e-02f, -1.125190619e-01f, +2.408695221e-01f, +6.978842163e-01f, +2.408695221e-01f, -1.125190619e-01f, +1.557210222e-02f, +1.344312953e-02f, -7.009786996e-03f, +6.003640016e-04f,
+ /* 12, 1 */ -6.398742119e-03f, +1.026913982e-02f, +2.132332546e-02f, -1.110115061e-01f, +2.005160832e-01f, +6.955088069e-01f, +2.821133540e-01f, -1.117099281e-01f, +8.845385329e-03f, +1.669708199e-02f, -7.518519523e-03f, +5.590854556e-04f,
+ /* 12, 2 */ -5.716737920e-03f, +7.240001966e-03f, +2.606967700e-02f, -1.074325911e-01f, +1.614746033e-01f, +6.884146462e-01f, +3.237982615e-01f, -1.083606220e-01f, +1.198165974e-03f, +1.995657080e-02f, -7.892366537e-03f, +4.637249154e-04f,
+ /* 12, 3 */ -4.993154633e-03f, +4.410399512e-03f, +2.980590100e-02f, -1.020439692e-01f, +1.241329667e-01f, +6.766973789e-01f, +3.654537522e-01f, -1.022748781e-01f, -7.287927063e-03f, +2.313861998e-02f, -8.098411048e-03f, +3.063703263e-04f,
+ /* 12, 4 */ -4.254780730e-03f, +1.824453005e-03f, +3.254896791e-02f, -9.511805181e-02f, +8.884019172e-02f, +6.605145641e-01f, +4.065952670e-01f, -9.328874484e-02f, -1.650412301e-02f, +2.615301189e-02f, -8.104377377e-03f, +8.035370630e-05f,
+ /* 12, 5 */ -3.525333045e-03f, -4.843426812e-04f, +3.433584064e-02f, -8.693252112e-02f, +5.590207404e-02f, +6.400829406e-01f, +4.467316931e-01f, -8.127529114e-02f, -2.631456917e-02f, +2.890390773e-02f, -7.879705669e-03f, -2.193022854e-04f,
+ /* 12, 6 */ -2.825116890e-03f, -2.492908449e-03f, +3.522097401e-02f, -7.776502604e-02f, +2.557772128e-02f, +6.156746770e-01f, +4.853731430e-01f, -6.614880956e-02f, -3.655698883e-02f, +3.129176395e-02f, -7.396691856e-03f, -5.954441701e-04f,
+ /* 12, 7 */ -2.170822930e-03f, -4.188126176e-03f, +3.527362061e-02f, -6.788815999e-02f, -1.922977207e-03f, +5.876126808e-01f, +5.220388545e-01f, -4.786841211e-02f, -4.704395826e-02f, +3.321551909e-02f, -6.631665064e-03f, -1.048370326e-03f,
+ /* 12, 8 */ -1.575453811e-03f, -5.566170902e-03f, +3.457501660e-02f, -5.756481055e-02f, -2.644092188e-02f, +5.562650609e-01f, +5.562650609e-01f, -2.644092188e-02f, -5.756481055e-02f, +3.457501660e-02f, -5.566170902e-03f, -1.575453811e-03f,
+ /* 12, 9 */ -1.048370326e-03f, -6.631665064e-03f, +3.321551909e-02f, -4.704395826e-02f, -4.786841211e-02f, +5.220388545e-01f, +5.876126808e-01f, -1.922977207e-03f, -6.788815999e-02f, +3.527362061e-02f, -4.188126176e-03f, -2.170822930e-03f,
+ /* 12,10 */ -5.954441701e-04f, -7.396691856e-03f, +3.129176395e-02f, -3.655698883e-02f, -6.614880956e-02f, +4.853731430e-01f, +6.156746770e-01f, +2.557772128e-02f, -7.776502604e-02f, +3.522097401e-02f, -2.492908449e-03f, -2.825116890e-03f,
+ /* 12,11 */ -2.193022854e-04f, -7.879705669e-03f, +2.890390773e-02f, -2.631456917e-02f, -8.127529114e-02f, +4.467316931e-01f, +6.400829406e-01f, +5.590207404e-02f, -8.693252112e-02f, +3.433584064e-02f, -4.843426812e-04f, -3.525333045e-03f,
+ /* 12,12 */ +8.035370630e-05f, -8.104377377e-03f, +2.615301189e-02f, -1.650412301e-02f, -9.328874484e-02f, +4.065952670e-01f, +6.605145641e-01f, +8.884019172e-02f, -9.511805181e-02f, +3.254896791e-02f, +1.824453005e-03f, -4.254780730e-03f,
+ /* 12,13 */ +3.063703263e-04f, -8.098411048e-03f, +2.313861998e-02f, -7.287927063e-03f, -1.022748781e-01f, +3.654537522e-01f, +6.766973789e-01f, +1.241329667e-01f, -1.020439692e-01f, +2.980590100e-02f, +4.410399512e-03f, -4.993154633e-03f,
+ /* 12,14 */ +4.637249154e-04f, -7.892366537e-03f, +1.995657080e-02f, +1.198165974e-03f, -1.083606220e-01f, +3.237982615e-01f, +6.884146462e-01f, +1.614746033e-01f, -1.074325911e-01f, +2.606967700e-02f, +7.240001966e-03f, -5.716737920e-03f,
+ /* 12,15 */ +5.590854556e-04f, -7.518519523e-03f, +1.669708199e-02f, +8.845385329e-03f, -1.117099281e-01f, +2.821133540e-01f, +6.955088069e-01f, +2.005160832e-01f, -1.110115061e-01f, +2.132332546e-02f, +1.026913982e-02f, -6.398742119e-03f,
+
+ /* 24, 0 */ +1.501390780e-03f, +3.431804419e-03f, +6.512803185e-03f, +1.091425387e-02f, +1.664594540e-02f, +2.351091132e-02f, +3.109255671e-02f, +3.878419288e-02f, +4.586050701e-02f, +5.158058002e-02f, +5.530384985e-02f, +5.659614054e-02f, +5.530384985e-02f, +5.158058002e-02f, +4.586050701e-02f, +3.878419288e-02f, +3.109255671e-02f, +2.351091132e-02f, +1.664594540e-02f, +1.091425387e-02f, +6.512803185e-03f, +3.431804419e-03f, +1.501390780e-03f, +4.573885647e-04f,
+ /* 24, 1 */ +1.413186400e-03f, +3.279858311e-03f, +6.282638036e-03f, +1.059932179e-02f, +1.625135142e-02f, +2.305547031e-02f, +3.060840342e-02f, +3.831365198e-02f, +4.545054680e-02f, +5.127577001e-02f, +5.513916011e-02f, +5.659104154e-02f, +5.545895049e-02f, +5.187752167e-02f, +4.626513642e-02f, +3.925233583e-02f, +3.157717954e-02f, +2.396921539e-02f, +1.704503934e-02f, +1.123445076e-02f, +6.748179094e-03f, +3.588275667e-03f, +1.593065611e-03f, +5.022154476e-04f,
+ /* 24, 2 */ +1.328380648e-03f, +3.132379333e-03f, +6.057656813e-03f, +1.028967374e-02f, +1.586133102e-02f, +2.260301890e-02f, +3.012488684e-02f, +3.784089895e-02f, +4.503543229e-02f, +5.096323022e-02f, +5.496495842e-02f, +5.657574693e-02f, +5.560438923e-02f, +5.216645963e-02f, +4.666426010e-02f, +3.971789474e-02f, +3.206210284e-02f, +2.443025293e-02f, +1.744855617e-02f, +1.155988996e-02f, +6.988790100e-03f, +3.749328623e-03f, +1.688282347e-03f, +5.494305796e-04f,
+ /* 24, 3 */ +1.246901403e-03f, +2.989308098e-03f, +5.837830254e-03f, +9.985325752e-03f, +1.547595434e-02f, +2.215368059e-02f, +2.964217216e-02f, +3.736611920e-02f, +4.461534144e-02f, +5.064310236e-02f, +5.478132634e-02f, +5.655026396e-02f, +5.574009777e-02f, +5.244726189e-02f, +4.705770477e-02f, +4.018068337e-02f, +3.254715574e-02f, +2.489389144e-02f, +1.785641537e-02f, +1.189054572e-02f, +7.234657995e-03f, +3.915018340e-03f, +1.787112015e-03f, +5.991047395e-04f,
+ /* 24, 4 */ +1.168676301e-03f, +2.850583915e-03f, +5.623126723e-03f, +9.686290690e-03f, +1.509528803e-02f, +2.170757578e-02f, +2.916042250e-02f, +3.688949768e-02f, +4.419045351e-02f, +5.031553118e-02f, +5.458834968e-02f, +5.651460469e-02f, +5.586601230e-02f, +5.271979985e-02f, +4.744529894e-02f, +4.064051541e-02f, +3.303216567e-02f, +2.535999546e-02f, +1.826853297e-02f, +1.222638897e-02f, +7.485801959e-03f, +4.085398290e-03f, +1.889625146e-03f, +6.513091287e-04f,
+ /* 24, 5 */ +1.093632798e-03f, +2.716144855e-03f, +5.413512274e-03f, +9.392578266e-03f, +1.471939531e-02f, +2.126482169e-02f, +2.867979883e-02f, +3.641121873e-02f, +4.376094899e-02f, +4.998066438e-02f, +5.438611851e-02f, +5.646878599e-02f, +5.598207354e-02f, +5.298394839e-02f, +4.782687301e-02f, +4.109720465e-02f, +3.351695842e-02f, +2.582842673e-02f, +1.868482156e-02f, +1.256738733e-02f, +7.742238512e-03f, +4.260520294e-03f, +1.995891717e-03f, +7.061153220e-04f,
+ /* 24, 6 */ +1.021698233e-03f, +2.585927824e-03f, +5.208950715e-03f, +9.104195104e-03f, +1.434833590e-02f, +2.082553239e-02f, +2.820045990e-02f, +3.593146595e-02f, +4.332700946e-02f, +4.963865252e-02f, +5.417472708e-02f, +5.641282954e-02f, +5.608822683e-02f, +5.323958602e-02f, +4.820225940e-02f, +4.155056502e-02f, +3.400135826e-02f, +2.629904416e-02f, +1.910519032e-02f, +1.291350505e-02f, +8.003981455e-03f, +4.440434453e-03f, +2.105981077e-03f, +7.635952183e-04f,
+ /* 24, 7 */ +9.527998831e-04f, +2.459868628e-03f, +5.009403670e-03f, +8.821144768e-03f, +1.398216608e-02f, +2.038981869e-02f, +2.772256216e-02f, +3.545042216e-02f, +4.288881749e-02f, +4.928964888e-02f, +5.395427373e-02f, +5.634676181e-02f, +5.618442211e-02f, +5.348659488e-02f, +4.857129262e-02f, +4.200041076e-02f, +3.448518802e-02f, +2.677170395e-02f, +1.952954505e-02f, +1.326470299e-02f, +8.271041819e-03f, +4.625189083e-03f, +2.219961884e-03f, +8.238209888e-04f,
+ /* 24, 8 */ +8.868650246e-04f, +2.337902042e-03f, +4.814830642e-03f, +8.543427812e-03f, +1.362093865e-02f, +1.995778816e-02f, +2.724625964e-02f, +3.496826923e-02f, +4.244655653e-02f, +4.893380942e-02f, +5.372486088e-02f, +5.627061400e-02f, +5.627061400e-02f, +5.372486088e-02f, +4.893380942e-02f, +4.244655653e-02f, +3.496826923e-02f, +2.724625964e-02f, +1.995778816e-02f, +1.362093865e-02f, +8.543427812e-03f, +4.814830642e-03f, +2.337902042e-03f, +8.868650246e-04f,
+ /* 24, 9 */ +8.238209888e-04f, +2.219961884e-03f, +4.625189083e-03f, +8.271041819e-03f, +1.326470299e-02f, +1.952954505e-02f, +2.677170395e-02f, +3.448518802e-02f, +4.200041076e-02f, +4.857129262e-02f, +5.348659488e-02f, +5.618442211e-02f, +5.634676181e-02f, +5.395427373e-02f, +4.928964888e-02f, +4.288881749e-02f, +3.545042216e-02f, +2.772256216e-02f, +2.038981869e-02f, +1.398216608e-02f, +8.821144768e-03f, +5.009403670e-03f, +2.459868628e-03f, +9.527998831e-04f,
+ /* 24,10 */ +7.635952183e-04f, +2.105981077e-03f, +4.440434453e-03f, +8.003981455e-03f, +1.291350505e-02f, +1.910519032e-02f, +2.629904416e-02f, +3.400135826e-02f, +4.155056502e-02f, +4.820225940e-02f, +5.323958602e-02f, +5.608822683e-02f, +5.641282954e-02f, +5.417472708e-02f, +4.963865252e-02f, +4.332700946e-02f, +3.593146595e-02f, +2.820045990e-02f, +2.082553239e-02f, +1.434833590e-02f, +9.104195104e-03f, +5.208950715e-03f, +2.585927824e-03f, +1.021698233e-03f,
+ /* 24,11 */ +7.061153220e-04f, +1.995891717e-03f, +4.260520294e-03f, +7.742238512e-03f, +1.256738733e-02f, +1.868482156e-02f, +2.582842673e-02f, +3.351695842e-02f, +4.109720465e-02f, +4.782687301e-02f, +5.298394839e-02f, +5.598207354e-02f, +5.646878599e-02f, +5.438611851e-02f, +4.998066438e-02f, +4.376094899e-02f, +3.641121873e-02f, +2.867979883e-02f, +2.126482169e-02f, +1.471939531e-02f, +9.392578266e-03f, +5.413512274e-03f, +2.716144855e-03f, +1.093632798e-03f,
+ /* 24,12 */ +6.513091287e-04f, +1.889625146e-03f, +4.085398290e-03f, +7.485801959e-03f, +1.222638897e-02f, +1.826853297e-02f, +2.535999546e-02f, +3.303216567e-02f, +4.064051541e-02f, +4.744529894e-02f, +5.271979985e-02f, +5.586601230e-02f, +5.651460469e-02f, +5.458834968e-02f, +5.031553118e-02f, +4.419045351e-02f, +3.688949768e-02f, +2.916042250e-02f, +2.170757578e-02f, +1.509528803e-02f, +9.686290690e-03f, +5.623126723e-03f, +2.850583915e-03f, +1.168676301e-03f,
+ /* 24,13 */ +5.991047395e-04f, +1.787112015e-03f, +3.915018340e-03f, +7.234657995e-03f, +1.189054572e-02f, +1.785641537e-02f, +2.489389144e-02f, +3.254715574e-02f, +4.018068337e-02f, +4.705770477e-02f, +5.244726189e-02f, +5.574009777e-02f, +5.655026396e-02f, +5.478132634e-02f, +5.064310236e-02f, +4.461534144e-02f, +3.736611920e-02f, +2.964217216e-02f, +2.215368059e-02f, +1.547595434e-02f, +9.985325752e-03f, +5.837830254e-03f, +2.989308098e-03f, +1.246901403e-03f,
+ /* 24,14 */ +5.494305796e-04f, +1.688282347e-03f, +3.749328623e-03f, +6.988790100e-03f, +1.155988996e-02f, +1.744855617e-02f, +2.443025293e-02f, +3.206210284e-02f, +3.971789474e-02f, +4.666426010e-02f, +5.216645963e-02f, +5.560438923e-02f, +5.657574693e-02f, +5.496495842e-02f, +5.096323022e-02f, +4.503543229e-02f, +3.784089895e-02f, +3.012488684e-02f, +2.260301890e-02f, +1.586133102e-02f, +1.028967374e-02f, +6.057656813e-03f, +3.132379333e-03f, +1.328380648e-03f,
+ /* 24,15 */ +5.022154476e-04f, +1.593065611e-03f, +3.588275667e-03f, +6.748179094e-03f, +1.123445076e-02f, +1.704503934e-02f, +2.396921539e-02f, +3.157717954e-02f, +3.925233583e-02f, +4.626513642e-02f, +5.187752167e-02f, +5.545895049e-02f, +5.659104154e-02f, +5.513916011e-02f, +5.127577001e-02f, +4.545054680e-02f, +3.831365198e-02f, +3.060840342e-02f, +2.305547031e-02f, +1.625135142e-02f, +1.059932179e-02f, +6.282638036e-03f, +3.279858311e-03f, +1.413186400e-03f,
+ /* 24, 0 */ -2.629184871e-03f, -4.843950453e-03f, -6.895985300e-03f, -7.687208098e-03f, -5.978262553e-03f, -8.032174656e-04f, +8.095316761e-03f, +1.997958831e-02f, +3.311864145e-02f, +4.512644231e-02f, +5.356009950e-02f, +5.659614054e-02f, +5.356009950e-02f, +4.512644231e-02f, +3.311864145e-02f, +1.997958831e-02f, +8.095316761e-03f, -8.032174656e-04f, -5.978262553e-03f, -7.687208098e-03f, -6.895985300e-03f, -4.843950453e-03f, -2.629184871e-03f, -9.454953712e-04f,
+ /* 24, 1 */ -2.503767166e-03f, -4.700731697e-03f, -6.791825424e-03f, -7.698565601e-03f, -6.179328945e-03f, -1.237726578e-03f, +7.438688744e-03f, +1.917778123e-02f, +3.230413198e-02f, +4.445707943e-02f, +5.317715832e-02f, +5.658405316e-02f, +5.392156860e-02f, +4.578163621e-02f, +3.392875410e-02f, +2.078652132e-02f, +8.763945305e-03f, -3.538276542e-04f, -5.763420347e-03f, -7.665996832e-03f, -6.995273095e-03f, -4.986674025e-03f, -2.756835384e-03f, -1.028686673e-03f,
+ /* 24, 2 */ -2.380688695e-03f, -4.557243028e-03f, -6.683099486e-03f, -7.700368745e-03f, -6.366798820e-03f, -1.657314491e-03f, +6.794365087e-03f, +1.838162773e-02f, +3.148585651e-02f, +4.377411309e-02f, +5.277308334e-02f, +5.654780182e-02f, +5.426124576e-02f, +4.642210542e-02f, +3.473383802e-02f, +2.159804191e-02f, +9.444254477e-03f, +1.103863968e-04f, -5.534634231e-03f, -7.634636496e-03f, -7.089380216e-03f, -5.128670417e-03f, -2.886604737e-03f, -1.114962551e-03f,
+ /* 24, 3 */ -2.260048394e-03f, -4.413702845e-03f, -6.570110572e-03f, -7.692920583e-03f, -6.540862270e-03f, -2.061956485e-03f, +6.162633403e-03f, +1.759164425e-02f, +3.066444409e-02f, +4.307811806e-02f, +5.234823086e-02f, +5.648741902e-02f, +5.457882991e-02f, +4.704730472e-02f, +3.553326091e-02f, +2.241360152e-02f, +1.013590849e-02f, +5.893521078e-04f, -5.291747706e-03f, -7.592836347e-03f, -7.177995846e-03f, -5.269701073e-03f, -3.018371382e-03f, -1.204312280e-03f,
+ /* 24, 4 */ -2.141937776e-03f, -4.270322542e-03f, -6.453158507e-03f, -7.676527355e-03f, -6.701719772e-03f, -2.451643421e-03f, +5.543764951e-03f, +1.680833562e-02f, +2.984052134e-02f, +4.236967758e-02f, +5.190297478e-02f, +5.640295884e-02f, +5.487403917e-02f, +4.765670002e-02f, +3.632639074e-02f, +2.323264190e-02f, +1.083855586e-02f, +1.082980638e-03f, -5.034616251e-03f, -7.540310660e-03f, -7.260807322e-03f, -5.409521052e-03f, -3.152006158e-03f, -1.296719170e-03f,
+ /* 24, 5 */ -2.026441000e-03f, -4.127306381e-03f, -6.332539518e-03f, -7.651498041e-03f, -6.849581767e-03f, -2.826381528e-03f, +4.938014526e-03f, +1.603219452e-02f, +2.901471178e-02f, +4.164938279e-02f, +5.143770614e-02f, +5.629449693e-02f, +5.514661113e-02f, +4.824976895e-02f, +3.711259647e-02f, +2.405459566e-02f, +1.155182965e-02f, +1.591166761e-03f, -4.763107701e-03f, -7.476779193e-03f, -7.337500507e-03f, -5.547879217e-03f, -3.287372274e-03f, -1.392160404e-03f,
+ /* 24, 6 */ -1.913634953e-03f, -3.984851387e-03f, -6.208545927e-03f, -7.618143912e-03f, -6.984668233e-03f, -3.186192169e-03f, +4.345620369e-03f, +1.526370115e-02f, +2.818763519e-02f, +4.091783200e-02f, +5.095283267e-02f, +5.616213037e-02f, +5.539630322e-02f, +4.882600150e-02f, +3.789124869e-02f, +2.487888677e-02f, +1.227534767e-02f, +2.113788767e-03f, -4.477102606e-03f, -7.401967644e-03f, -7.407760182e-03f, -5.684518438e-03f, -3.424325302e-03f, -1.490606880e-03f,
+ /* 24, 7 */ -1.803589350e-03f, -3.843147252e-03f, -6.081465840e-03f, -7.576778087e-03f, -7.107208249e-03f, -3.531111592e-03f, +3.766804102e-03f, +1.450332275e-02f, +2.735990694e-02f, +4.017563005e-02f, +5.044877831e-02f, +5.600597761e-02f, +5.562289296e-02f, +4.938490059e-02f, +3.866172039e-02f, +2.570493119e-02f, +1.300871280e-02f, +2.650708377e-03f, -4.176494585e-03f, -7.315608112e-03f, -7.471270440e-03f, -5.819175805e-03f, -3.562713186e-03f, -1.592023060e-03f,
+ /* 24, 8 */ -1.696366827e-03f, -3.702376254e-03f, -5.951582861e-03f, -7.527715094e-03f, -7.217439556e-03f, -3.861190662e-03f, +3.201770681e-03f, +1.375151322e-02f, +2.653213738e-02f, +3.942338759e-02f, +4.992598268e-02f, +5.582617825e-02f, +5.582617825e-02f, +4.992598268e-02f, +3.942338759e-02f, +2.653213738e-02f, +1.375151322e-02f, +3.201770681e-03f, -3.861190662e-03f, -7.217439556e-03f, -7.527715094e-03f, -5.951582861e-03f, -3.702376254e-03f, -1.696366827e-03f,
+ /* 24, 9 */ -1.592023060e-03f, -3.562713186e-03f, -5.819175805e-03f, -7.471270440e-03f, -7.315608112e-03f, -4.176494585e-03f, +2.650708377e-03f, +1.300871280e-02f, +2.570493119e-02f, +3.866172039e-02f, +4.938490059e-02f, +5.562289296e-02f, +5.600597761e-02f, +5.044877831e-02f, +4.017563005e-02f, +2.735990694e-02f, +1.450332275e-02f, +3.766804102e-03f, -3.531111592e-03f, -7.107208249e-03f, -7.576778087e-03f, -6.081465840e-03f, -3.843147252e-03f, -1.803589350e-03f,
+ /* 24,10 */ -1.490606880e-03f, -3.424325302e-03f, -5.684518438e-03f, -7.407760182e-03f, -7.401967644e-03f, -4.477102606e-03f, +2.113788767e-03f, +1.227534767e-02f, +2.487888677e-02f, +3.789124869e-02f, +4.882600150e-02f, +5.539630322e-02f, +5.616213037e-02f, +5.095283267e-02f, +4.091783200e-02f, +2.818763519e-02f, +1.526370115e-02f, +4.345620369e-03f, -3.186192169e-03f, -6.984668233e-03f, -7.618143912e-03f, -6.208545927e-03f, -3.984851387e-03f, -1.913634953e-03f,
+ /* 24,11 */ -1.392160404e-03f, -3.287372274e-03f, -5.547879217e-03f, -7.337500507e-03f, -7.476779193e-03f, -4.763107701e-03f, +1.591166761e-03f, +1.155182965e-02f, +2.405459566e-02f, +3.711259647e-02f, +4.824976895e-02f, +5.514661113e-02f, +5.629449693e-02f, +5.143770614e-02f, +4.164938279e-02f, +2.901471178e-02f, +1.603219452e-02f, +4.938014526e-03f, -2.826381528e-03f, -6.849581767e-03f, -7.651498041e-03f, -6.332539518e-03f, -4.127306381e-03f, -2.026441000e-03f,
+ /* 24,12 */ -1.296719170e-03f, -3.152006158e-03f, -5.409521052e-03f, -7.260807322e-03f, -7.540310660e-03f, -5.034616251e-03f, +1.082980638e-03f, +1.083855586e-02f, +2.323264190e-02f, +3.632639074e-02f, +4.765670002e-02f, +5.487403917e-02f, +5.640295884e-02f, +5.190297478e-02f, +4.236967758e-02f, +2.984052134e-02f, +1.680833562e-02f, +5.543764951e-03f, -2.451643421e-03f, -6.701719772e-03f, -7.676527355e-03f, -6.453158507e-03f, -4.270322542e-03f, -2.141937776e-03f,
+ /* 24,13 */ -1.204312280e-03f, -3.018371382e-03f, -5.269701073e-03f, -7.177995846e-03f, -7.592836347e-03f, -5.291747706e-03f, +5.893521078e-04f, +1.013590849e-02f, +2.241360152e-02f, +3.553326091e-02f, +4.704730472e-02f, +5.457882991e-02f, +5.648741902e-02f, +5.234823086e-02f, +4.307811806e-02f, +3.066444409e-02f, +1.759164425e-02f, +6.162633403e-03f, -2.061956485e-03f, -6.540862270e-03f, -7.692920583e-03f, -6.570110572e-03f, -4.413702845e-03f, -2.260048394e-03f,
+ /* 24,14 */ -1.114962551e-03f, -2.886604737e-03f, -5.128670417e-03f, -7.089380216e-03f, -7.634636496e-03f, -5.534634231e-03f, +1.103863968e-04f, +9.444254477e-03f, +2.159804191e-02f, +3.473383802e-02f, +4.642210542e-02f, +5.426124576e-02f, +5.654780182e-02f, +5.277308334e-02f, +4.377411309e-02f, +3.148585651e-02f, +1.838162773e-02f, +6.794365087e-03f, -1.657314491e-03f, -6.366798820e-03f, -7.700368745e-03f, -6.683099486e-03f, -4.557243028e-03f, -2.380688695e-03f,
+ /* 24,15 */ -1.028686673e-03f, -2.756835384e-03f, -4.986674025e-03f, -6.995273095e-03f, -7.665996832e-03f, -5.763420347e-03f, -3.538276542e-04f, +8.763945305e-03f, +2.078652132e-02f, +3.392875410e-02f, +4.578163621e-02f, +5.392156860e-02f, +5.658405316e-02f, +5.317715832e-02f, +4.445707943e-02f, +3.230413198e-02f, +1.917778123e-02f, +7.438688744e-03f, -1.237726578e-03f, -6.179328945e-03f, -7.698565601e-03f, -6.791825424e-03f, -4.700731697e-03f, -2.503767166e-03f,
+ /* 24, 0 */ +4.735641749e-04f, -1.438577362e-03f, -6.107076473e-03f, -1.318715065e-02f, -2.047716119e-02f, -2.428668798e-02f, -2.088952800e-02f, -8.512165320e-03f, +1.117510535e-02f, +3.302575560e-02f, +5.012757987e-02f, +5.659614054e-02f, +5.012757987e-02f, +3.302575560e-02f, +1.117510535e-02f, -8.512165320e-03f, -2.088952800e-02f, -2.428668798e-02f, -2.047716119e-02f, -1.318715065e-02f, -6.107076473e-03f, -1.438577362e-03f, +4.735641749e-04f, +5.516063288e-04f,
+ /* 24, 1 */ +5.190146993e-04f, -1.243445781e-03f, -5.732182665e-03f, -1.270621714e-02f, -2.008108462e-02f, -2.422674988e-02f, -2.136190754e-02f, -9.536491055e-03f, +9.813857768e-03f, +3.172645287e-02f, +4.932296812e-02f, +5.657007725e-02f, +5.088942272e-02f, +3.430616434e-02f, +1.254542812e-02f, -7.458075491e-03f, -2.038088472e-02f, -2.431781992e-02f, -2.085968072e-02f, -1.366943909e-02f, -6.492037400e-03f, -1.644903025e-03f, +4.208638005e-04f, +5.761542752e-04f,
+ /* 24, 2 */ +5.575380238e-04f, -1.059370463e-03f, -5.367638258e-03f, -1.222740313e-02f, -1.967247249e-02f, -2.413881461e-02f, -2.179812108e-02f, -1.053019587e-02f, +8.463295193e-03f, +3.041001010e-02f, +4.847674006e-02f, +5.649192540e-02f, +5.160740292e-02f, +3.556594146e-02f, +1.392318625e-02f, -6.375136316e-03f, -1.983593655e-02f, -2.431936776e-02f, -2.122761958e-02f, -1.415229209e-02f, -6.886752185e-03f, -1.862540304e-03f, +3.605947820e-04f, +5.982066157e-04f,
+ /* 24, 3 */ +5.894596941e-04f, -8.861942853e-04f, -5.013694839e-03f, -1.175144649e-02f, -1.925234223e-02f, -2.402372023e-02f, -2.219832191e-02f, -1.149248169e-02f, +7.124994951e-03f, +2.907819451e-02f, +4.759010507e-02f, +5.636179897e-02f, +5.228048761e-02f, +3.680336864e-02f, +1.530671242e-02f, -5.264319552e-03f, -1.925469982e-02f, -2.429058667e-02f, -2.157995394e-02f, -1.463489443e-02f, -7.290876362e-03f, -2.091585491e-03f, +2.924431607e-04f, +6.174753085e-04f,
+ /* 24, 4 */ +6.151072142e-04f, -7.237418200e-04f, -4.670573645e-03f, -1.127905759e-02f, -1.882170532e-02f, -2.388233174e-02f, -2.256271775e-02f, -1.242260980e-02f, +5.800499486e-03f, +2.773278351e-02f, +4.666432713e-02f, +5.617988770e-02f, +5.290770668e-02f, +3.801674993e-02f, +1.669431448e-02f, -4.126652928e-03f, -1.863724919e-02f, -2.423076690e-02f, -2.191566174e-02f, -1.511640714e-02f, -7.704034115e-03f, -2.332112699e-03f, +2.161008111e-04f, +6.336652968e-04f,
+ /* 24, 5 */ +6.348091316e-04f, -5.718203517e-04f, -4.338465973e-03f, -1.081091853e-02f, -1.838156554e-02f, -2.371553901e-02f, -2.289156957e-02f, -1.331990148e-02f, +4.491314051e-03f, +2.637556170e-02f, +4.570072248e-02f, +5.594645674e-02f, +5.348815454e-02f, +3.920441468e-02f, +1.808427811e-02f, -2.963218986e-03f, -1.798371833e-02f, -2.413923574e-02f, -2.223372473e-02f, -1.559596853e-02f, -8.125818185e-03f, -2.584172964e-03f, +1.312664533e-04f, +6.464750685e-04f,
+ /* 24, 6 */ +6.488941487e-04f, -4.302209069e-04f, -4.017533648e-03f, -1.034768250e-02f, -1.793291714e-02f, -2.352425464e-02f, -2.318519030e-02f, -1.418373842e-02f, +3.198904487e-03f, +2.500831779e-02f, +4.470065727e-02f, +5.566184614e-02f, +5.402099181e-02f, +4.036472049e-02f, +1.947486957e-02f, -1.775153809e-03f, -1.729430055e-02f, -2.401535937e-02f, -2.253313051e-02f, -1.607269547e-02f, -8.555789856e-03f, -2.847793367e-03f, +3.764667972e-05f, +6.555972530e-04f,
+ /* 24, 7 */ +6.576902611e-04f, -2.987192943e-04f, -3.707909539e-03f, -9.889973186e-03f, -1.747674315e-02f, -2.330941189e-02f, -2.344394342e-02f, -1.501356300e-02f, +1.924695104e-03f, +2.363284155e-02f, +4.366554511e-02f, +5.532647026e-02f, +5.450544680e-02f, +4.149605616e-02f, +2.086433852e-02f, -5.636456344e-04f, -1.656924930e-02f, -2.385854478e-02f, -2.281287459e-02f, -1.654568462e-02f, -8.993479016e-03f, -3.122976195e-03f, -6.504300803e-05f, +6.607192554e-04f,
+ /* 24, 8 */ +6.615239252e-04f, -1.770771536e-04f, -3.409698141e-03f, -9.438384277e-03f, -1.701401374e-02f, -2.307196251e-02f, -2.366824152e-02f, -1.580887853e-02f, +6.700666468e-04f, +2.225092083e-02f, +4.259684448e-02f, +5.494081698e-02f, +5.494081698e-02f, +4.259684448e-02f, +2.225092083e-02f, +6.700666468e-04f, -1.580887853e-02f, -2.366824152e-02f, -2.307196251e-02f, -1.701401374e-02f, -9.438384277e-03f, -3.409698141e-03f, -1.770771536e-04f, +6.615239252e-04f,
+ /* 24, 9 */ +6.607192554e-04f, -6.504300803e-05f, -3.122976195e-03f, -8.993479016e-03f, -1.654568462e-02f, -2.281287459e-02f, -2.385854478e-02f, -1.656924930e-02f, -5.636456344e-04f, +2.086433852e-02f, +4.149605616e-02f, +5.450544680e-02f, +5.532647026e-02f, +4.366554511e-02f, +2.363284155e-02f, +1.924695104e-03f, -1.501356300e-02f, -2.344394342e-02f, -2.330941189e-02f, -1.747674315e-02f, -9.889973186e-03f, -3.707909539e-03f, -2.987192943e-04f, +6.576902611e-04f,
+ /* 24,10 */ +6.555972530e-04f, +3.764667972e-05f, -2.847793367e-03f, -8.555789856e-03f, -1.607269547e-02f, -2.253313051e-02f, -2.401535937e-02f, -1.729430055e-02f, -1.775153809e-03f, +1.947486957e-02f, +4.036472049e-02f, +5.402099181e-02f, +5.566184614e-02f, +4.470065727e-02f, +2.500831779e-02f, +3.198904487e-03f, -1.418373842e-02f, -2.318519030e-02f, -2.352425464e-02f, -1.793291714e-02f, -1.034768250e-02f, -4.017533648e-03f, -4.302209069e-04f, +6.488941487e-04f,
+ /* 24,11 */ +6.464750685e-04f, +1.312664533e-04f, -2.584172964e-03f, -8.125818185e-03f, -1.559596853e-02f, -2.223372473e-02f, -2.413923574e-02f, -1.798371833e-02f, -2.963218986e-03f, +1.808427811e-02f, +3.920441468e-02f, +5.348815454e-02f, +5.594645674e-02f, +4.570072248e-02f, +2.637556170e-02f, +4.491314051e-03f, -1.331990148e-02f, -2.289156957e-02f, -2.371553901e-02f, -1.838156554e-02f, -1.081091853e-02f, -4.338465973e-03f, -5.718203517e-04f, +6.348091316e-04f,
+ /* 24,12 */ +6.336652968e-04f, +2.161008111e-04f, -2.332112699e-03f, -7.704034115e-03f, -1.511640714e-02f, -2.191566174e-02f, -2.423076690e-02f, -1.863724919e-02f, -4.126652928e-03f, +1.669431448e-02f, +3.801674993e-02f, +5.290770668e-02f, +5.617988770e-02f, +4.666432713e-02f, +2.773278351e-02f, +5.800499486e-03f, -1.242260980e-02f, -2.256271775e-02f, -2.388233174e-02f, -1.882170532e-02f, -1.127905759e-02f, -4.670573645e-03f, -7.237418200e-04f, +6.151072142e-04f,
+ /* 24,13 */ +6.174753085e-04f, +2.924431607e-04f, -2.091585491e-03f, -7.290876362e-03f, -1.463489443e-02f, -2.157995394e-02f, -2.429058667e-02f, -1.925469982e-02f, -5.264319552e-03f, +1.530671242e-02f, +3.680336864e-02f, +5.228048761e-02f, +5.636179897e-02f, +4.759010507e-02f, +2.907819451e-02f, +7.124994951e-03f, -1.149248169e-02f, -2.219832191e-02f, -2.402372023e-02f, -1.925234223e-02f, -1.175144649e-02f, -5.013694839e-03f, -8.861942853e-04f, +5.894596941e-04f,
+ /* 24,14 */ +5.982066157e-04f, +3.605947820e-04f, -1.862540304e-03f, -6.886752185e-03f, -1.415229209e-02f, -2.122761958e-02f, -2.431936776e-02f, -1.983593655e-02f, -6.375136316e-03f, +1.392318625e-02f, +3.556594146e-02f, +5.160740292e-02f, +5.649192540e-02f, +4.847674006e-02f, +3.041001010e-02f, +8.463295193e-03f, -1.053019587e-02f, -2.179812108e-02f, -2.413881461e-02f, -1.967247249e-02f, -1.222740313e-02f, -5.367638258e-03f, -1.059370463e-03f, +5.575380238e-04f,
+ /* 24,15 */ +5.761542752e-04f, +4.208638005e-04f, -1.644903025e-03f, -6.492037400e-03f, -1.366943909e-02f, -2.085968072e-02f, -2.431781992e-02f, -2.038088472e-02f, -7.458075491e-03f, +1.254542812e-02f, +3.430616434e-02f, +5.088942272e-02f, +5.657007725e-02f, +4.932296812e-02f, +3.172645287e-02f, +9.813857768e-03f, -9.536491055e-03f, -2.136190754e-02f, -2.422674988e-02f, -2.008108462e-02f, -1.270621714e-02f, -5.732182665e-03f, -1.243445781e-03f, +5.190146993e-04f,
+ /* 24, 0 */ +2.273459443e-03f, +5.435907648e-03f, +7.255296399e-03f, +3.788129032e-03f, -7.144684562e-03f, -2.265374973e-02f, -3.442368170e-02f, -3.287677614e-02f, -1.387331771e-02f, +1.679264590e-02f, +4.511451955e-02f, +5.659614054e-02f, +4.511451955e-02f, +1.679264590e-02f, -1.387331771e-02f, -3.287677614e-02f, -3.442368170e-02f, -2.265374973e-02f, -7.144684562e-03f, +3.788129032e-03f, +7.255296399e-03f, +5.435907648e-03f, +2.273459443e-03f, +3.568431303e-04f,
+ /* 24, 1 */ +2.103234406e-03f, +5.239407106e-03f, +7.256400195e-03f, +4.221207454e-03f, -6.266228991e-03f, -2.168841690e-02f, -3.399213075e-02f, -3.348773370e-02f, -1.551504116e-02f, +1.477681868e-02f, +4.371373211e-02f, +5.654911556e-02f, +4.644656718e-02f, +1.879953521e-02f, -1.218307761e-02f, -3.219410560e-02f, -3.480135038e-02f, -2.360501860e-02f, -8.042999544e-03f, +3.324105568e-03f, +7.232988111e-03f, +5.627714430e-03f, +2.449385040e-03f, +4.247055554e-04f,
+ /* 24, 2 */ +1.939021806e-03f, +5.039131826e-03f, +7.237298926e-03f, +4.623451366e-03f, -5.409068119e-03f, -2.071157693e-02f, -3.350883303e-02f, -3.402698064e-02f, -1.710557364e-02f, +1.275612557e-02f, +4.224725679e-02f, +5.640814528e-02f, +4.770696520e-02f, +2.079340350e-02f, -1.044713814e-02f, -3.143988919e-02f, -3.512309015e-02f, -2.453963953e-02f, -8.959642554e-03f, +2.829112073e-03f, +7.188501693e-03f, +5.813881008e-03f, +2.630658922e-03f, +4.992251326e-04f,
+ /* 24, 3 */ +1.781093672e-03f, +4.835971292e-03f, +7.199013760e-03f, +4.995053998e-03f, -4.574539506e-03f, -1.972575310e-02f, -3.297600576e-02f, -3.449468646e-02f, -1.864238902e-02f, +1.073461753e-02f, +4.071827965e-02f, +5.617354343e-02f, +4.889295364e-02f, +2.277016679e-02f, -8.668453837e-03f, -3.061446547e-02f, -3.538695026e-02f, -2.545500791e-02f, -9.892988076e-03f, +2.303211764e-03f, +7.120893393e-03f, +5.993435804e-03f, +2.816887995e-03f, +5.805470381e-04f,
+ /* 24, 4 */ +1.629682882e-03f, +4.630783503e-03f, +7.142583584e-03f, +5.336288236e-03f, -3.763881685e-03f, -1.873342898e-02f, -3.239594057e-02f, -3.489118499e-02f, -2.012311412e-02f, +8.716314532e-03f, +3.913011251e-02f, +5.584583195e-02f, +5.000192959e-02f, +2.472575033e-02f, -6.850110412e-03f, -2.971834586e-02f, -3.559108276e-02f, -2.634850527e-02f, -1.084131876e-02f, +1.746558492e-03f, +7.029253460e-03f, +6.165384566e-03f, +3.007638074e-03f, +6.687931554e-04f,
+ /* 24, 5 */ +1.484983972e-03f, +4.424393216e-03f, +7.069061064e-03f, +5.647503405e-03f, -2.978233194e-03f, -1.773704257e-02f, -3.177099609e-02f, -3.521697115e-02f, -2.154553308e-02f, +6.705195776e-03f, +3.748618427e-02f, +5.542573963e-02f, +5.103145416e-02f, +2.665609886e-02f, -4.995318215e-03f, -2.875221569e-02f, -3.573374914e-02f, -2.721750622e-02f, -1.180282806e-02f, +1.159398961e-03f, +6.912710257e-03f, +6.328712988e-03f, +3.202433762e-03f, +7.640603932e-04f,
+ /* 24, 6 */ +1.347154069e-03f, +4.217590351e-03f, +6.979508760e-03f, +5.929121902e-03f, -2.218631929e-03f, -1.673898061e-02f, -3.110359053e-02f, -3.547269735e-02f, -2.290759116e-02f, +4.705190128e-03f, +3.579003198e-02f, +5.491420012e-02f, +5.197925890e-02f, +2.855718684e-02f, -3.107405323e-03f, -2.771693469e-02f, -3.581332680e-02f, -2.805938547e-02f, -1.277562317e-02f, +5.420746921e-04f, +6.770434377e-03f, +6.482389493e-03f, +3.400758480e-03f, +8.664190421e-04f,
+ /* 24, 7 */ +1.216313935e-03f, +4.011128586e-03f, +6.874995333e-03f, +6.181635683e-03f, -1.486014823e-03f, -1.574157316e-02f, -3.039619415e-02f, -3.565916944e-02f, -2.420739811e-02f, +2.720166717e-03f, +3.404529163e-02f, +5.431234943e-02f, +5.284325182e-02f, +3.042502866e-02f, -1.189810237e-03f, -2.661353708e-02f, -3.582831530e-02f, -2.887152508e-02f, -1.375772836e-02f, -1.049762569e-04f, +6.601642735e-03f, +6.625368167e-03f, +3.602054665e-03f, +9.759111772e-04f,
+ /* 24, 8 */ +1.092549115e-03f, +3.805724130e-03f, +6.756591845e-03f, +6.405602617e-03f, -7.812178358e-04f, -1.474708852e-02f, -2.965132174e-02f, -3.577734234e-02f, -2.544323110e-02f, +7.539257812e-04f, +3.225568873e-02f, +5.362152294e-02f, +5.362152294e-02f, +3.225568873e-02f, +7.539257812e-04f, -2.544323110e-02f, -3.577734234e-02f, -2.965132174e-02f, -1.474708852e-02f, -7.812178358e-04f, +6.405602617e-03f, +6.756591845e-03f, +3.805724130e-03f, +1.092549115e-03f,
+ /* 24, 9 */ +9.759111772e-04f, +3.602054665e-03f, +6.625368167e-03f, +6.601642735e-03f, -1.049762569e-04f, -1.375772836e-02f, -2.887152508e-02f, -3.582831530e-02f, -2.661353708e-02f, -1.189810237e-03f, +3.042502866e-02f, +5.284325182e-02f, +5.431234943e-02f, +3.404529163e-02f, +2.720166717e-03f, -2.420739811e-02f, -3.565916944e-02f, -3.039619415e-02f, -1.574157316e-02f, -1.486014823e-03f, +6.181635683e-03f, +6.874995333e-03f, +4.011128586e-03f, +1.216313935e-03f,
+ /* 24,10 */ +8.664190421e-04f, +3.400758480e-03f, +6.482389493e-03f, +6.770434377e-03f, +5.420746921e-04f, -1.277562317e-02f, -2.805938547e-02f, -3.581332680e-02f, -2.771693469e-02f, -3.107405323e-03f, +2.855718684e-02f, +5.197925890e-02f, +5.491420012e-02f, +3.579003198e-02f, +4.705190128e-03f, -2.290759116e-02f, -3.547269735e-02f, -3.110359053e-02f, -1.673898061e-02f, -2.218631929e-03f, +5.929121902e-03f, +6.979508760e-03f, +4.217590351e-03f, +1.347154069e-03f,
+ /* 24,11 */ +7.640603932e-04f, +3.202433762e-03f, +6.328712988e-03f, +6.912710257e-03f, +1.159398961e-03f, -1.180282806e-02f, -2.721750622e-02f, -3.573374914e-02f, -2.875221569e-02f, -4.995318215e-03f, +2.665609886e-02f, +5.103145416e-02f, +5.542573963e-02f, +3.748618427e-02f, +6.705195776e-03f, -2.154553308e-02f, -3.521697115e-02f, -3.177099609e-02f, -1.773704257e-02f, -2.978233194e-03f, +5.647503405e-03f, +7.069061064e-03f, +4.424393216e-03f, +1.484983972e-03f,
+ /* 24,12 */ +6.687931554e-04f, +3.007638074e-03f, +6.165384566e-03f, +7.029253460e-03f, +1.746558492e-03f, -1.084131876e-02f, -2.634850527e-02f, -3.559108276e-02f, -2.971834586e-02f, -6.850110412e-03f, +2.472575033e-02f, +5.000192959e-02f, +5.584583195e-02f, +3.913011251e-02f, +8.716314532e-03f, -2.012311412e-02f, -3.489118499e-02f, -3.239594057e-02f, -1.873342898e-02f, -3.763881685e-03f, +5.336288236e-03f, +7.142583584e-03f, +4.630783503e-03f, +1.629682882e-03f,
+ /* 24,13 */ +5.805470381e-04f, +2.816887995e-03f, +5.993435804e-03f, +7.120893393e-03f, +2.303211764e-03f, -9.892988076e-03f, -2.545500791e-02f, -3.538695026e-02f, -3.061446547e-02f, -8.668453837e-03f, +2.277016679e-02f, +4.889295364e-02f, +5.617354343e-02f, +4.071827965e-02f, +1.073461753e-02f, -1.864238902e-02f, -3.449468646e-02f, -3.297600576e-02f, -1.972575310e-02f, -4.574539506e-03f, +4.995053998e-03f, +7.199013760e-03f, +4.835971292e-03f, +1.781093672e-03f,
+ /* 24,14 */ +4.992251326e-04f, +2.630658922e-03f, +5.813881008e-03f, +7.188501693e-03f, +2.829112073e-03f, -8.959642554e-03f, -2.453963953e-02f, -3.512309015e-02f, -3.143988919e-02f, -1.044713814e-02f, +2.079340350e-02f, +4.770696520e-02f, +5.640814528e-02f, +4.224725679e-02f, +1.275612557e-02f, -1.710557364e-02f, -3.402698064e-02f, -3.350883303e-02f, -2.071157693e-02f, -5.409068119e-03f, +4.623451366e-03f, +7.237298926e-03f, +5.039131826e-03f, +1.939021806e-03f,
+ /* 24,15 */ +4.247055554e-04f, +2.449385040e-03f, +5.627714430e-03f, +7.232988111e-03f, +3.324105568e-03f, -8.042999544e-03f, -2.360501860e-02f, -3.480135038e-02f, -3.219410560e-02f, -1.218307761e-02f, +1.879953521e-02f, +4.644656718e-02f, +5.654911556e-02f, +4.371373211e-02f, +1.477681868e-02f, -1.551504116e-02f, -3.348773370e-02f, -3.399213075e-02f, -2.168841690e-02f, -6.266228991e-03f, +4.221207454e-03f, +7.256400195e-03f, +5.239407106e-03f, +2.103234406e-03f,
+ /* 24, 0 */ -2.181310192e-03f, -7.982329251e-04f, +5.680209618e-03f, +1.430719659e-02f, +1.589843483e-02f, +2.406871994e-03f, -2.249676846e-02f, -4.130100690e-02f, -3.506718353e-02f, -1.541681908e-03f, +3.867898214e-02f, +5.659614054e-02f, +3.867898214e-02f, -1.541681908e-03f, -3.506718353e-02f, -4.130100690e-02f, -2.249676846e-02f, +2.406871994e-03f, +1.589843483e-02f, +1.430719659e-02f, +5.680209618e-03f, -7.982329251e-04f, -2.181310192e-03f, -9.324150638e-04f,
+ /* 24, 1 */ -2.142117633e-03f, -1.026327303e-03f, +5.144075019e-03f, +1.386145083e-02f, +1.619749380e-02f, +3.702669669e-03f, -2.089125129e-02f, -4.071342524e-02f, -3.635626763e-02f, -4.137848013e-03f, +3.654904222e-02f, +5.652117066e-02f, +4.071616274e-02f, +1.083860427e-03f, -3.366302266e-02f, -4.178478525e-02f, -2.407924887e-02f, +1.061252794e-03f, +1.553625174e-02f, +1.472529111e-02f, +6.227191439e-03f, -5.482915187e-04f, -2.210193915e-03f, -1.021372070e-03f,
+ /* 24, 2 */ -2.093579858e-03f, -1.232841058e-03f, +4.620399561e-03f, +1.339085359e-02f, +1.643462496e-02f, +4.945866528e-03f, -1.926829204e-02f, -4.002576024e-02f, -3.752797769e-02f, -6.697199080e-03f, +3.433305089e-02f, +5.629650283e-02f, +4.265414906e-02f, +3.731182183e-03f, -3.214649405e-02f, -4.216132985e-02f, -2.563305646e-02f, -3.311524193e-04f, +1.510995111e-02f, +1.511293981e-02f, +6.783287607e-03f, -2.763303743e-04f, -2.227804667e-03f, -1.112061839e-03f,
+ /* 24, 3 */ -2.036654869e-03f, -1.418128950e-03f, +4.110671651e-03f, +1.289819803e-02f, +1.661121711e-02f, +6.133943976e-03f, -1.763342417e-02f, -3.924200344e-02f, -3.858043162e-02f, -9.212479159e-03f, +3.203796457e-02f, +5.592286159e-02f, +4.448680259e-02f, +6.392554173e-03f, -3.052071354e-02f, -4.242751674e-02f, -2.715253413e-02f, -1.767057534e-03f, +1.461875233e-02f, +1.546736546e-02f, +7.346647501e-03f, +1.772445414e-05f, -2.233183138e-03f, -1.203936109e-03f,
+ /* 24, 4 */ -1.972290178e-03f, -1.582628528e-03f, +3.616254280e-03f, +1.238625918e-02f, +1.672884047e-02f, +7.264647438e-03f, -1.599210066e-02f, -3.836639935e-02f, -3.951216427e-02f, -1.167663915e-02f, +2.967096294e-02f, +5.540145153e-02f, +4.620830373e-02f, +9.060141131e-03f, -2.878919714e-02f, -4.258054458e-02f, -2.863202454e-02f, -3.242932618e-03f, +1.406209682e-02f, +1.578582064e-02f, +7.915306646e-03f, +3.338433846e-04f, -2.225380377e-03f, -1.296401007e-03f,
+ /* 24, 5 */ -1.901418208e-03f, -1.726854356e-03f, +3.138383775e-03f, +1.185778300e-02f, +1.678923519e-02f, +8.335988548e-03f, -1.434967550e-02f, -3.740342600e-02f, -4.032212766e-02f, -1.408285985e-02f, +2.723942290e-02f, +5.473395280e-02f, +4.781317317e-02f, +1.172602857e-02f, -2.695585286e-02f, -4.261794963e-02f, -3.006589126e-02f, -4.755011838e-03f, +1.343965653e-02f, +1.606560041e-02f, +8.487191262e-03f, +6.718888821e-04f, -2.203463508e-03f, -1.388818223e-03f,
+ /* 24, 6 */ -1.824951954e-03f, -1.851392085e-03f, +2.678169173e-03f, +1.131547576e-02f, +1.679429951e-02f, +9.346246206e-03f, -1.271138577e-02f, -3.635777499e-02f, -4.100968953e-02f, -1.642457396e-02f, +2.475089197e-02f, +5.392251484e-02f, +4.929629202e-02f, +1.438225015e-02f, -2.502497093e-02f, -4.253761970e-02f, -3.144854025e-02f, -6.299302508e-03f, +1.275134172e-02f, +1.630405519e-02f, +9.060123484e-03f, +1.031611407e-03f, -2.166521604e-03f, -1.480506488e-03f,
+ /* 24, 7 */ -1.743780953e-03f, -1.956892396e-03f, +2.236592212e-03f, +1.076199396e-02f, +1.674607744e-02f, +1.029396653e-02f, -1.108233467e-02f, -3.523433096e-02f, -4.157463041e-02f, -1.869548696e-02f, +2.221306113e-02f, +5.296974848e-02f, +5.065292065e-02f, +1.702081530e-02f, -2.300121251e-02f, -4.233780689e-02f, -3.277444146e-02f, -7.871595256e-03f, +1.199730786e-02f, +1.649860375e-02f, +9.631827247e-03f, +1.412645767e-03f, -2.113671692e-03f, -1.570743396e-03f,
+ /* 24, 8 */ -1.658767534e-03f, -2.044064852e-03f, +1.814507917e-03f, +1.019993481e-02f, +1.664674627e-02f, +1.117796172e-02f, -9.467475281e-03f, -3.403815061e-02f, -4.201713914e-02f, -2.088959684e-02f, +1.963373727e-02f, +5.187871616e-02f, +5.187871616e-02f, +1.963373727e-02f, -2.088959684e-02f, -4.201713914e-02f, -3.403815061e-02f, -9.467475281e-03f, +1.117796172e-02f, +1.664674627e-02f, +1.019993481e-02f, +1.814507917e-03f, -2.044064852e-03f, -1.658767534e-03f,
+ /* 24, 9 */ -1.570743396e-03f, -2.113671692e-03f, +1.412645767e-03f, +9.631827247e-03f, +1.649860375e-02f, +1.199730786e-02f, -7.871595256e-03f, -3.277444146e-02f, -4.233780689e-02f, -2.300121251e-02f, +1.702081530e-02f, +5.065292065e-02f, +5.296974848e-02f, +2.221306113e-02f, -1.869548696e-02f, -4.157463041e-02f, -3.523433096e-02f, -1.108233467e-02f, +1.029396653e-02f, +1.674607744e-02f, +1.076199396e-02f, +2.236592212e-03f, -1.956892396e-03f, -1.743780953e-03f,
+ /* 24,10 */ -1.480506488e-03f, -2.166521604e-03f, +1.031611407e-03f, +9.060123484e-03f, +1.630405519e-02f, +1.275134172e-02f, -6.299302508e-03f, -3.144854025e-02f, -4.253761970e-02f, -2.502497093e-02f, +1.438225015e-02f, +4.929629202e-02f, +5.392251484e-02f, +2.475089197e-02f, -1.642457396e-02f, -4.100968953e-02f, -3.635777499e-02f, -1.271138577e-02f, +9.346246206e-03f, +1.679429951e-02f, +1.131547576e-02f, +2.678169173e-03f, -1.851392085e-03f, -1.824951954e-03f,
+ /* 24,11 */ -1.388818223e-03f, -2.203463508e-03f, +6.718888821e-04f, +8.487191262e-03f, +1.606560041e-02f, +1.343965653e-02f, -4.755011838e-03f, -3.006589126e-02f, -4.261794963e-02f, -2.695585286e-02f, +1.172602857e-02f, +4.781317317e-02f, +5.473395280e-02f, +2.723942290e-02f, -1.408285985e-02f, -4.032212766e-02f, -3.740342600e-02f, -1.434967550e-02f, +8.335988548e-03f, +1.678923519e-02f, +1.185778300e-02f, +3.138383775e-03f, -1.726854356e-03f, -1.901418208e-03f,
+ /* 24,12 */ -1.296401007e-03f, -2.225380377e-03f, +3.338433846e-04f, +7.915306646e-03f, +1.578582064e-02f, +1.406209682e-02f, -3.242932618e-03f, -2.863202454e-02f, -4.258054458e-02f, -2.878919714e-02f, +9.060141131e-03f, +4.620830373e-02f, +5.540145153e-02f, +2.967096294e-02f, -1.167663915e-02f, -3.951216427e-02f, -3.836639935e-02f, -1.599210066e-02f, +7.264647438e-03f, +1.672884047e-02f, +1.238625918e-02f, +3.616254280e-03f, -1.582628528e-03f, -1.972290178e-03f,
+ /* 24,13 */ -1.203936109e-03f, -2.233183138e-03f, +1.772445414e-05f, +7.346647501e-03f, +1.546736546e-02f, +1.461875233e-02f, -1.767057534e-03f, -2.715253413e-02f, -4.242751674e-02f, -3.052071354e-02f, +6.392554173e-03f, +4.448680259e-02f, +5.592286159e-02f, +3.203796457e-02f, -9.212479159e-03f, -3.858043162e-02f, -3.924200344e-02f, -1.763342417e-02f, +6.133943976e-03f, +1.661121711e-02f, +1.289819803e-02f, +4.110671651e-03f, -1.418128950e-03f, -2.036654869e-03f,
+ /* 24,14 */ -1.112061839e-03f, -2.227804667e-03f, -2.763303743e-04f, +6.783287607e-03f, +1.511293981e-02f, +1.510995111e-02f, -3.311524193e-04f, -2.563305646e-02f, -4.216132985e-02f, -3.214649405e-02f, +3.731182183e-03f, +4.265414906e-02f, +5.629650283e-02f, +3.433305089e-02f, -6.697199080e-03f, -3.752797769e-02f, -4.002576024e-02f, -1.926829204e-02f, +4.945866528e-03f, +1.643462496e-02f, +1.339085359e-02f, +4.620399561e-03f, -1.232841058e-03f, -2.093579858e-03f,
+ /* 24,15 */ -1.021372070e-03f, -2.210193915e-03f, -5.482915187e-04f, +6.227191439e-03f, +1.472529111e-02f, +1.553625174e-02f, +1.061252794e-03f, -2.407924887e-02f, -4.178478525e-02f, -3.366302266e-02f, +1.083860427e-03f, +4.071616274e-02f, +5.652117066e-02f, +3.654904222e-02f, -4.137848013e-03f, -3.635626763e-02f, -4.071342524e-02f, -2.089125129e-02f, +3.702669669e-03f, +1.619749380e-02f, +1.386145083e-02f, +5.144075019e-03f, -1.026327303e-03f, -2.142117633e-03f,
+ /* 24, 0 */ -6.349328336e-04f, -5.107444449e-03f, -7.589492700e-03f, +4.421169254e-04f, +1.733331948e-02f, +2.497839430e-02f, +6.069612140e-03f, -2.970035006e-02f, -4.651799663e-02f, -1.968310326e-02f, +3.102388246e-02f, +5.659614054e-02f, +3.102388246e-02f, -1.968310326e-02f, -4.651799663e-02f, -2.970035006e-02f, +6.069612140e-03f, +2.497839430e-02f, +1.733331948e-02f, +4.421169254e-04f, -7.589492700e-03f, -5.107444449e-03f, -6.349328336e-04f, +6.381929817e-04f,
+ /* 24, 1 */ -4.501246045e-04f, -4.794789988e-03f, -7.673310752e-03f, -4.276921651e-04f, +1.630487239e-02f, +2.519230977e-02f, +8.023727481e-03f, -2.760467194e-02f, -4.668156835e-02f, -2.250226055e-02f, +2.808383767e-02f, +5.648624601e-02f, +3.385706239e-02f, -1.675917373e-02f, -4.616688010e-02f, -3.171828840e-02f, +4.039135426e-03f, +2.465060544e-02f, +1.832599562e-02f, +1.353161175e-03f, -7.461005422e-03f, -5.414037993e-03f, -8.347893499e-04f, +6.459962873e-04f,
+ /* 24, 2 */ -2.805431667e-04f, -4.478334337e-03f, -7.714347254e-03f, -1.253762011e-03f, +1.524677189e-02f, +2.529479915e-02f, +9.894771606e-03f, -2.544172743e-02f, -4.665953469e-02f, -2.520578478e-02f, +2.504972253e-02f, +5.615705320e-02f, +3.657100703e-02f, -1.374190145e-02f, -4.562711379e-02f, -3.364818878e-02f, +1.939527429e-03f, +2.420699082e-02f, +1.927675855e-02f, +2.302607998e-03f, -7.286133997e-03f, -5.712221732e-03f, -1.049390115e-03f, +6.454263440e-04f,
+ /* 24, 3 */ -1.262469087e-04f, -4.160237857e-03f, -7.714644364e-03f, -2.033919173e-03f, +1.416507919e-02f, +2.528877950e-02f, +1.167657735e-02f, -2.322211124e-02f, -4.645464989e-02f, -2.778343069e-02f, +2.193469332e-02f, +5.561003206e-02f, +3.915383052e-02f, -1.064323425e-02f, -4.489844274e-02f, -3.547998209e-02f, -2.214871506e-04f, +2.364611605e-02f, +2.017947396e-02f, +3.287300483e-03f, -7.063354139e-03f, -5.999568857e-03f, -1.278300802e-03f, +6.356530069e-04f,
+ /* 24, 4 */ +1.281987696e-05f, -3.842552418e-03f, -7.676380196e-03f, -2.766321017e-03f, +1.306576874e-02f, +2.517761055e-02f, +1.336353941e-02f, -2.095648565e-02f, -4.607045954e-02f, -3.022561220e-02f, +1.875220414e-02f, +5.484762432e-02f, +4.159418981e-02f, -7.475585158e-03f, -4.398147340e-02f, -3.720388175e-02f, -2.435717775e-03f, +2.296708552e-02f, +2.102804905e-02f, +4.303763633e-03f, -6.791349552e-03f, -6.273586899e-03f, -1.520952773e-03f, +6.158659890e-04f,
+ /* 24, 5 */ +1.368204413e-04f, -3.527213369e-03f, -7.601850138e-03f, -3.449453954e-03f, +1.195469912e-02f, +2.496506585e-02f, +1.495063011e-02f, -1.865552736e-02f, -4.551127331e-02f, -3.252344226e-02f, +1.551594186e-02f, +5.387323140e-02f, +4.388134039e-02f, -4.251776447e-03f, -4.287768073e-02f, -3.881043651e-02f, -4.694539858e-03f, +2.216956067e-02f, +2.181646678e-02f, +5.348212687e-03f, -6.469028645e-03f, -6.531730950e-03f, -1.776639841e-03f, +5.852828120e-04f,
+ /* 24, 6 */ +2.460185614e-04f, -3.216032617e-03f, -7.493448175e-03f, -4.082129823e-03f, +1.083758546e-02f, +2.465530244e-02f, +1.643341199e-02f, -1.632987505e-02f, -4.478213426e-02f, -3.466876896e-02f, +1.223976005e-02f, +5.269119738e-02f, +4.600518917e-02f, -9.849812576e-04f, -4.158941105e-02f, -4.029058231e-02f, -6.988929457e-03f, +2.125377578e-02f, +2.253882061e-02f, +6.416563547e-03f, -6.095540465e-03f, -6.771417794e-03f, -2.044515881e-03f, +5.431569434e-04f,
+ /* 24, 7 */ +3.407711290e-04f, -2.910692818e-03f, -7.353648294e-03f, -4.663480492e-03f, +9.719973395e-03f, +2.425282916e-02f, +1.780804686e-02f, -1.399007798e-02f, -4.388878466e-02f, -3.665420751e-02f, +8.937612534e-03f, +5.130678745e-02f, +4.795634432e-02f, +2.311336934e-03f, -4.011988036e-02f, -4.163569289e-02f, -9.309500719e-03f, +2.022055084e-02f, +2.318934965e-02f, +7.504445299e-03f, -5.670289717e-03f, -6.990040888e-03f, -2.323593338e-03f, +4.887860648e-04f,
+ /* 24, 8 */ +4.215204125e-04f, -2.612742676e-03f, -7.184986124e-03f, -5.192950770e-03f, +8.607214812e-03f, +2.376247385e-02f, +1.907130164e-02f, -1.164654593e-02f, -4.283762880e-02f, -3.847316827e-02f, +5.623486691e-03f, +4.972616165e-02f, +4.972616165e-02f, +5.623486691e-03f, -3.847316827e-02f, -4.283762880e-02f, -1.164654593e-02f, +1.907130164e-02f, +2.376247385e-02f, +8.607214812e-03f, -5.192950770e-03f, -7.184986124e-03f, -2.612742676e-03f, +4.215204125e-04f,
+ /* 24, 9 */ +4.887860648e-04f, -2.323593338e-03f, -6.990040888e-03f, -5.670289717e-03f, +7.504445299e-03f, +2.318934965e-02f, +2.022055084e-02f, -9.309500719e-03f, -4.163569289e-02f, -4.011988036e-02f, +2.311336934e-03f, +4.795634432e-02f, +5.130678745e-02f, +8.937612534e-03f, -3.665420751e-02f, -4.388878466e-02f, -1.399007798e-02f, +1.780804686e-02f, +2.425282916e-02f, +9.719973395e-03f, -4.663480492e-03f, -7.353648294e-03f, -2.910692818e-03f, +3.407711290e-04f,
+ /* 24,10 */ +5.431569434e-04f, -2.044515881e-03f, -6.771417794e-03f, -6.095540465e-03f, +6.416563547e-03f, +2.253882061e-02f, +2.125377578e-02f, -6.988929457e-03f, -4.029058231e-02f, -4.158941105e-02f, -9.849812576e-04f, +4.600518917e-02f, +5.269119738e-02f, +1.223976005e-02f, -3.466876896e-02f, -4.478213426e-02f, -1.632987505e-02f, +1.643341199e-02f, +2.465530244e-02f, +1.083758546e-02f, -4.082129823e-03f, -7.493448175e-03f, -3.216032617e-03f, +2.460185614e-04f,
+ /* 24,11 */ +5.852828120e-04f, -1.776639841e-03f, -6.531730950e-03f, -6.469028645e-03f, +5.348212687e-03f, +2.181646678e-02f, +2.216956067e-02f, -4.694539858e-03f, -3.881043651e-02f, -4.287768073e-02f, -4.251776447e-03f, +4.388134039e-02f, +5.387323140e-02f, +1.551594186e-02f, -3.252344226e-02f, -4.551127331e-02f, -1.865552736e-02f, +1.495063011e-02f, +2.496506585e-02f, +1.195469912e-02f, -3.449453954e-03f, -7.601850138e-03f, -3.527213369e-03f, +1.368204413e-04f,
+ /* 24,12 */ +6.158659890e-04f, -1.520952773e-03f, -6.273586899e-03f, -6.791349552e-03f, +4.303763633e-03f, +2.102804905e-02f, +2.296708552e-02f, -2.435717775e-03f, -3.720388175e-02f, -4.398147340e-02f, -7.475585158e-03f, +4.159418981e-02f, +5.484762432e-02f, +1.875220414e-02f, -3.022561220e-02f, -4.607045954e-02f, -2.095648565e-02f, +1.336353941e-02f, +2.517761055e-02f, +1.306576874e-02f, -2.766321017e-03f, -7.676380196e-03f, -3.842552418e-03f, +1.281987696e-05f,
+ /* 24,13 */ +6.356530069e-04f, -1.278300802e-03f, -5.999568857e-03f, -7.063354139e-03f, +3.287300483e-03f, +2.017947396e-02f, +2.364611605e-02f, -2.214871506e-04f, -3.547998209e-02f, -4.489844274e-02f, -1.064323425e-02f, +3.915383052e-02f, +5.561003206e-02f, +2.193469332e-02f, -2.778343069e-02f, -4.645464989e-02f, -2.322211124e-02f, +1.167657735e-02f, +2.528877950e-02f, +1.416507919e-02f, -2.033919173e-03f, -7.714644364e-03f, -4.160237857e-03f, -1.262469087e-04f,
+ /* 24,14 */ +6.454263440e-04f, -1.049390115e-03f, -5.712221732e-03f, -7.286133997e-03f, +2.302607998e-03f, +1.927675855e-02f, +2.420699082e-02f, +1.939527429e-03f, -3.364818878e-02f, -4.562711379e-02f, -1.374190145e-02f, +3.657100703e-02f, +5.615705320e-02f, +2.504972253e-02f, -2.520578478e-02f, -4.665953469e-02f, -2.544172743e-02f, +9.894771606e-03f, +2.529479915e-02f, +1.524677189e-02f, -1.253762011e-03f, -7.714347254e-03f, -4.478334337e-03f, -2.805431667e-04f,
+ /* 24,15 */ +6.459962873e-04f, -8.347893499e-04f, -5.414037993e-03f, -7.461005422e-03f, +1.353161175e-03f, +1.832599562e-02f, +2.465060544e-02f, +4.039135426e-03f, -3.171828840e-02f, -4.616688010e-02f, -1.675917373e-02f, +3.385706239e-02f, +5.648624601e-02f, +2.808383767e-02f, -2.250226055e-02f, -4.668156835e-02f, -2.760467194e-02f, +8.023727481e-03f, +2.519230977e-02f, +1.630487239e-02f, -4.276921651e-04f, -7.673310752e-03f, -4.794789988e-03f, -4.501246045e-04f,
+ /* 24, 0 */ +1.197013499e-03f, +3.320493122e-03f, -3.017233048e-03f, -9.987553340e-03f, -4.112967049e-03f, +1.524501264e-02f, +2.235677036e-02f, -2.137559158e-03f, -3.327370097e-02f, -2.660122408e-02f, +1.657531807e-02f, +4.232694754e-02f, +1.657531807e-02f, -2.660122408e-02f, -3.327370097e-02f, -2.137559158e-03f, +2.235677036e-02f, +1.524501264e-02f, -4.112967049e-03f, -9.987553340e-03f, -3.017233048e-03f, +2.318357031e-03f, +1.197013499e-03f, -1.261205705e-04f,
+ /* 24, 1 */ +1.060573898e-03f, +3.246029352e-03f, -2.510607281e-03f, -9.784551764e-03f, -5.018393221e-03f, +1.404948670e-02f, +2.282515537e-02f, +7.626640355e-05f, -3.208475603e-02f, -2.845760231e-02f, +1.374134711e-02f, +4.221250979e-02f, +1.933345641e-02f, -2.458052660e-02f, -3.429687591e-02f, -4.386190237e-03f, +2.174698353e-02f, +1.639120730e-02f, -3.143642175e-03f, -1.013545813e-02f, -3.535011248e-03f, +2.193303334e-03f, +1.338504197e-03f, -9.901282259e-05f,
+ /* 24, 2 */ +9.298712414e-04f, +3.156277727e-03f, -2.018194158e-03f, -9.530340989e-03f, -5.856606243e-03f, +1.281349999e-02f, +2.315294314e-02f, +2.243024978e-03f, -3.073934924e-02f, -3.014061672e-02f, +1.084811230e-02f, +4.186988491e-02f, +2.199957595e-02f, -2.240563854e-02f, -3.514586546e-02f, -6.656913804e-03f, +2.099588115e-02f, +1.747926153e-02f, -2.114297018e-03f, -1.022461460e-02f, -4.060636553e-03f, +2.039754046e-03f, +1.484263468e-03f, -6.526428163e-05f,
+ /* 24, 3 */ +8.054954021e-04f, +3.052984548e-03f, -1.542795645e-03f, -9.229007144e-03f, -6.624860539e-03f, +1.154592266e-02f, +2.334180387e-02f, +4.350977952e-03f, -2.924761047e-02f, -3.164235460e-02f, +7.912459038e-03f, +4.130113344e-02f, +2.455797710e-02f, -2.008771737e-02f, -3.581321303e-02f, -8.936640836e-03f, +2.010445982e-02f, +1.850049032e-02f, -1.029364704e-03f, -1.025164428e-02f, -4.590574200e-03f, +1.857070273e-03f, +1.633412152e-03f, -2.453170435e-05f,
+ /* 24, 4 */ +6.879416803e-04f, +2.937877889e-03f, -1.086944946e-03f, -8.884797195e-03f, -7.320980005e-03f, +1.025556440e-02f, +2.339424278e-02f, +6.388976156e-03f, -2.762041561e-02f, -3.295607494e-02f, +4.951401864e-03f, +4.050967459e-02f, +2.699354793e-02f, -1.763888677e-02f, -3.629248103e-02f, -1.121198570e-02f, +1.907464002e-02f, +1.944639638e-02f, +1.061806254e-04f, -1.021347789e-02f, -5.121078221e-03f, +1.644827972e-03f, +1.784975276e-03f, +2.348660763e-05f,
+ /* 24, 5 */ +5.776128643e-04f, +2.812656385e-03f, -6.528985547e-04f, -8.502081335e-03f, -7.943354450e-03f, +8.951116293e-03f, +2.331356438e-02f, +8.346521334e-03f, -2.586930694e-02f, -3.407624020e-02f, +1.982016505e-03f, +3.950026382e-02f, +2.929186185e-02f, -1.507216716e-02f, -3.657830513e-02f, -1.346934883e-02f, +1.790927350e-02f, +2.030873394e-02f, +1.286841938e-03f, -1.010739044e-02f, -5.648212144e-03f, +1.402832649e-03f, +1.937883690e-03f, +7.904503123e-05f,
+ /* 24, 6 */ +4.748218959e-04f, +2.678978820e-03f, -2.426308611e-04f, -8.085315763e-03f, -8.490932000e-03f, +7.641095022e-03f, +2.310383199e-02f, +1.021382218e-02f, -2.400641001e-02f, -3.499853994e-02f, -9.786680537e-04f, +3.827896159e-02f, +3.143927100e-02f, -1.240139974e-02f, -3.666644182e-02f, -1.569500220e-02f, +1.661214427e-02f, +2.107957227e-02f, +2.506621864e-03f, -9.931034771e-03f, -6.167872094e-03f, +1.131132707e-03f, +2.090976552e-03f, +1.423449116e-04f,
+ /* 24, 7 */ +3.797950945e-04f, +2.538454547e-03f, +1.421687298e-04f, -7.639006136e-03f, -8.963207645e-03f, +6.333789781e-03f, +2.276982298e-02f, +1.198184460e-02f, -2.204434780e-02f, -3.571990598e-02f, -3.913776625e-03f, +3.685309369e-02f, +3.342299483e-02f, -9.641164594e-03f, -3.655380902e-02f, -1.787517696e-02f, +1.518796320e-02f, +2.175135864e-02f, +3.759049618e-03f, -9.682473374e-03f, -6.675812165e-03f, +8.300312585e-04f, +2.243004675e-03f, +2.135289700e-04f,
+ /* 24, 8 */ +2.926758839e-04f, +2.392634763e-03f, +5.000962484e-04f, -7.167671961e-03f, -9.360208124e-03f, +5.037212205e-03f, +2.231697999e-02f, +1.364235598e-02f, -1.999615271e-02f, -3.623851940e-02f, -6.806693291e-03f, +3.523120326e-02f, +3.523120326e-02f, -6.806693291e-03f, -3.623851940e-02f, -1.999615271e-02f, +1.364235598e-02f, +2.231697999e-02f, +5.037212205e-03f, -9.360208124e-03f, -7.167671961e-03f, +5.000962484e-04f, +2.392634763e-03f, +2.926758839e-04f,
+ /* 24, 9 */ +2.135289700e-04f, +2.243004675e-03f, +8.300312585e-04f, -6.675812165e-03f, -9.682473374e-03f, +3.759049618e-03f, +2.175135864e-02f, +1.518796320e-02f, -1.787517696e-02f, -3.655380902e-02f, -9.641164594e-03f, +3.342299483e-02f, +3.685309369e-02f, -3.913776625e-03f, -3.571990598e-02f, -2.204434780e-02f, +1.198184460e-02f, +2.276982298e-02f, +6.333789781e-03f, -8.963207645e-03f, -7.639006136e-03f, +1.421687298e-04f, +2.538454547e-03f, +3.797950945e-04f,
+ /* 24,10 */ +1.423449116e-04f, +2.090976552e-03f, +1.131132707e-03f, -6.167872094e-03f, -9.931034771e-03f, +2.506621864e-03f, +2.107957227e-02f, +1.661214427e-02f, -1.569500220e-02f, -3.666644182e-02f, -1.240139974e-02f, +3.143927100e-02f, +3.827896159e-02f, -9.786680537e-04f, -3.499853994e-02f, -2.400641001e-02f, +1.021382218e-02f, +2.310383199e-02f, +7.641095022e-03f, -8.490932000e-03f, -8.085315763e-03f, -2.426308611e-04f, +2.678978820e-03f, +4.748218959e-04f,
+ /* 24,11 */ +7.904503123e-05f, +1.937883690e-03f, +1.402832649e-03f, -5.648212144e-03f, -1.010739044e-02f, +1.286841938e-03f, +2.030873394e-02f, +1.790927350e-02f, -1.346934883e-02f, -3.657830513e-02f, -1.507216716e-02f, +2.929186185e-02f, +3.950026382e-02f, +1.982016505e-03f, -3.407624020e-02f, -2.586930694e-02f, +8.346521334e-03f, +2.331356438e-02f, +8.951116293e-03f, -7.943354450e-03f, -8.502081335e-03f, -6.528985547e-04f, +2.812656385e-03f, +5.776128643e-04f,
+ /* 24,12 */ +2.348660763e-05f, +1.784975276e-03f, +1.644827972e-03f, -5.121078221e-03f, -1.021347789e-02f, +1.061806254e-04f, +1.944639638e-02f, +1.907464002e-02f, -1.121198570e-02f, -3.629248103e-02f, -1.763888677e-02f, +2.699354793e-02f, +4.050967459e-02f, +4.951401864e-03f, -3.295607494e-02f, -2.762041561e-02f, +6.388976156e-03f, +2.339424278e-02f, +1.025556440e-02f, -7.320980005e-03f, -8.884797195e-03f, -1.086944946e-03f, +2.937877889e-03f, +6.879416803e-04f,
+ /* 24,13 */ -2.453170435e-05f, +1.633412152e-03f, +1.857070273e-03f, -4.590574200e-03f, -1.025164428e-02f, -1.029364704e-03f, +1.850049032e-02f, +2.010445982e-02f, -8.936640836e-03f, -3.581321303e-02f, -2.008771737e-02f, +2.455797710e-02f, +4.130113344e-02f, +7.912459038e-03f, -3.164235460e-02f, -2.924761047e-02f, +4.350977952e-03f, +2.334180387e-02f, +1.154592266e-02f, -6.624860539e-03f, -9.229007144e-03f, -1.542795645e-03f, +3.052984548e-03f, +8.054954021e-04f,
+ /* 24,14 */ -6.526428163e-05f, +1.484263468e-03f, +2.039754046e-03f, -4.060636553e-03f, -1.022461460e-02f, -2.114297018e-03f, +1.747926153e-02f, +2.099588115e-02f, -6.656913804e-03f, -3.514586546e-02f, -2.240563854e-02f, +2.199957595e-02f, +4.186988491e-02f, +1.084811230e-02f, -3.014061672e-02f, -3.073934924e-02f, +2.243024978e-03f, +2.315294314e-02f, +1.281349999e-02f, -5.856606243e-03f, -9.530340989e-03f, -2.018194158e-03f, +3.156277727e-03f, +9.298712414e-04f,
+ /* 24,15 */ -9.901282259e-05f, +1.338504197e-03f, +2.193303334e-03f, -3.535011248e-03f, -1.013545813e-02f, -3.143642175e-03f, +1.639120730e-02f, +2.174698353e-02f, -4.386190237e-03f, -3.429687591e-02f, -2.458052660e-02f, +1.933345641e-02f, +4.221250979e-02f, +1.374134711e-02f, -2.845760231e-02f, -3.208475603e-02f, +7.626640355e-05f, +2.282515537e-02f, +1.404948670e-02f, -5.018393221e-03f, -9.784551764e-03f, -2.510607281e-03f, +3.246029352e-03f, +1.060573898e-03f,
+ /* 20, 0 */ +2.832126065e-03f, -3.455346407e-03f, -1.050167676e-02f, +5.399047405e-04f, +2.072547687e-02f, +1.261483344e-02f, -2.310421022e-02f, -3.076111900e-02f, +1.034529168e-02f, +3.949755319e-02f, +1.034529168e-02f, -3.076111900e-02f, -2.310421022e-02f, +1.261483344e-02f, +2.072547687e-02f, +5.399047405e-04f, -1.050167676e-02f, -3.455346407e-03f, +2.832126065e-03f, +1.002136091e-03f,
+ /* 20, 1 */ +2.918309836e-03f, -2.848965042e-03f, -1.044663371e-02f, -7.454467031e-04f, +1.993701966e-02f, +1.431336010e-02f, -2.105256806e-02f, -3.196996361e-02f, +7.274030562e-03f, +3.936378623e-02f, +1.336427867e-02f, -2.932648708e-02f, -2.503260290e-02f, +1.078376120e-02f, +2.138841986e-02f, +1.874755806e-03f, -1.047502359e-02f, -4.071193337e-03f, +2.709872705e-03f, +1.184613130e-03f,
+ /* 20, 2 */ +2.970014434e-03f, -2.256846905e-03f, -1.031411254e-02f, -1.973175306e-03f, +1.903277841e-02f, +1.586999913e-02f, -1.889465735e-02f, -3.294695719e-02f, +4.172714360e-03f, +3.896348732e-02f, +1.630904655e-02f, -2.767391419e-02f, -2.682143551e-02f, +8.830742245e-03f, +2.191685631e-02f, +3.250271284e-03f, -1.036300090e-02f, -4.691364292e-03f, +2.550244709e-03f, +1.728121332e-03f,
+ /* 20, 3 */ +2.989084466e-03f, -1.683415968e-03f, -1.010881741e-02f, -3.135916081e-03f, +1.802312126e-02f, +1.727671449e-02f, -1.664798407e-02f, -3.368784795e-02f, +1.063660935e-03f, +3.829965427e-02f, +1.915809828e-02f, -2.581298498e-02f, -2.845520951e-02f, +6.767571398e-03f, +2.230262774e-02f, +4.656958119e-03f, -1.016253578e-02f, -5.310408414e-03f, +2.352251997e-03f, +1.906494808e-03f,
+ /* 20, 4 */ +2.977586348e-03f, -1.132697564e-03f, -9.835877420e-03f, -4.227100403e-03f, +1.691895133e-02f, +1.852681335e-02f, -1.433043179e-02f, -3.419021020e-02f, -2.030888217e-03f, +3.737725626e-02f, +2.189055571e-02f, -2.375496340e-02f, -2.991937541e-02f, +4.607167163e-03f, +2.253850054e-02f, +6.084727180e-03f, -9.871207756e-03f, -5.922604667e-03f, +2.115247068e-03f, +2.079939639e-03f,
+ /* 20, 5 */ +2.937775120e-03f, -6.082983663e-04f, -9.500783787e-03f, -5.240985904e-03f, +1.573160178e-02f, +1.961497125e-02f, -1.196011335e-02f, -3.445344345e-02f, -5.088941581e-03f, +3.620319350e-02f, +2.448632622e-02f, -2.151271924e-02f, -3.120046374e-02f, +2.363488482e-03f, +2.261825107e-02f, +7.522962281e-03f, -9.487296369e-03f, -6.522005316e-03f, +1.838950241e-03f, +2.245949018e-03f,
+ /* 20, 6 */ +2.872060854e-03f, -1.133913219e-04f, -9.109325922e-03f, -6.172678101e-03f, +1.447272980e-02f, +2.053724533e-02f, -9.555222824e-03f, -3.447875653e-02f, -8.088928223e-03f, +3.478624106e-02f, +2.692626358e-02f, -1.910064083e-02f, -3.228620876e-02f, +5.144107936e-05f, +2.253674404e-02f, +8.960596019e-03f, -9.009823935e-03f, -7.102483479e-03f, +1.523472156e-03f, +2.401928729e-03f,
+ /* 20, 7 */ +2.782975009e-03f, +3.492945151e-04f, -8.667527067e-03f, -7.018143782e-03f, +1.315421060e-02f, +2.129107545e-02f, -7.133889173e-03f, -3.426913715e-02f, -1.100986395e-02f, +3.313697764e-02f, +2.919232167e-02f, -1.653453452e-02f, -3.316566379e-02f, -2.313225982e-03f, +2.229000326e-02f, +1.038619190e-02f, -8.438592747e-03f, -7.657784411e-03f, +1.169333173e-03f, +2.545222121e-03f,
+ /* 20, 8 */ +2.673137115e-03f, +7.774793244e-04f, -8.181580147e-03f, -7.774216267e-03f, +1.178803215e-02f, +2.187527386e-02f, -4.714032773e-03f, -3.382930709e-02f, -1.383151166e-02f, +3.126769968e-02f, +3.126769968e-02f, -1.383151166e-02f, -3.382930709e-02f, -4.714032773e-03f, +2.187527386e-02f, +1.178803215e-02f, -7.774216267e-03f, -8.181580147e-03f, +7.774793244e-04f, +2.673137115e-03f,
+ /* 20, 9 */ +2.545222121e-03f, +1.169333173e-03f, -7.657784411e-03f, -8.438592747e-03f, +1.038619190e-02f, +2.229000326e-02f, -2.313225982e-03f, -3.316566379e-02f, -1.653453452e-02f, +2.919232167e-02f, +3.313697764e-02f, -1.100986395e-02f, -3.426913715e-02f, -7.133889173e-03f, +2.129107545e-02f, +1.315421060e-02f, -7.018143782e-03f, -8.667527067e-03f, +3.492945151e-04f, +2.782975009e-03f,
+ /* 20,10 */ +2.401928729e-03f, +1.523472156e-03f, -7.102483479e-03f, -9.009823935e-03f, +8.960596019e-03f, +2.253674404e-02f, +5.144107936e-05f, -3.228620876e-02f, -1.910064083e-02f, +2.692626358e-02f, +3.478624106e-02f, -8.088928223e-03f, -3.447875653e-02f, -9.555222824e-03f, +2.053724533e-02f, +1.447272980e-02f, -6.172678101e-03f, -9.109325922e-03f, -1.133913219e-04f, +2.872060854e-03f,
+ /* 20,11 */ +2.245949018e-03f, +1.838950241e-03f, -6.522005316e-03f, -9.487296369e-03f, +7.522962281e-03f, +2.261825107e-02f, +2.363488482e-03f, -3.120046374e-02f, -2.151271924e-02f, +2.448632622e-02f, +3.620319350e-02f, -5.088941581e-03f, -3.445344345e-02f, -1.196011335e-02f, +1.961497125e-02f, +1.573160178e-02f, -5.240985904e-03f, -9.500783787e-03f, -6.082983663e-04f, +2.937775120e-03f,
+ /* 20,12 */ +2.079939639e-03f, +2.115247068e-03f, -5.922604667e-03f, -9.871207756e-03f, +6.084727180e-03f, +2.253850054e-02f, +4.607167163e-03f, -2.991937541e-02f, -2.375496340e-02f, +2.189055571e-02f, +3.737725626e-02f, -2.030888217e-03f, -3.419021020e-02f, -1.433043179e-02f, +1.852681335e-02f, +1.691895133e-02f, -4.227100403e-03f, -9.835877420e-03f, -1.132697564e-03f, +2.977586348e-03f,
+ /* 20,13 */ +1.906494808e-03f, +2.352251997e-03f, -5.310408414e-03f, -1.016253578e-02f, +4.656958119e-03f, +2.230262774e-02f, +6.767571398e-03f, -2.845520951e-02f, -2.581298498e-02f, +1.915809828e-02f, +3.829965427e-02f, +1.063660935e-03f, -3.368784795e-02f, -1.664798407e-02f, +1.727671449e-02f, +1.802312126e-02f, -3.135916081e-03f, -1.010881741e-02f, -1.683415968e-03f, +2.989084466e-03f,
+ /* 20,14 */ +1.728121332e-03f, +2.550244709e-03f, -4.691364292e-03f, -1.036300090e-02f, +3.250271284e-03f, +2.191685631e-02f, +8.830742245e-03f, -2.682143551e-02f, -2.767391419e-02f, +1.630904655e-02f, +3.896348732e-02f, +4.172714360e-03f, -3.294695719e-02f, -1.889465735e-02f, +1.586999913e-02f, +1.903277841e-02f, -1.973175306e-03f, -1.031411254e-02f, -2.256846905e-03f, +2.970014434e-03f,
+ /* 20,15 */ +1.184613130e-03f, +2.709872705e-03f, -4.071193337e-03f, -1.047502359e-02f, +1.874755806e-03f, +2.138841986e-02f, +1.078376120e-02f, -2.503260290e-02f, -2.932648708e-02f, +1.336427867e-02f, +3.936378623e-02f, +7.274030562e-03f, -3.196996361e-02f, -2.105256806e-02f, +1.431336010e-02f, +1.993701966e-02f, -7.454467031e-04f, -1.044663371e-02f, -2.848965042e-03f, +2.918309836e-03f,
+ /* 20, 0 */ +1.702864838e-03f, +2.314577966e-03f, -6.534433696e-03f, -8.774562126e-03f, +1.199271213e-02f, +2.083400312e-02f, -1.263546899e-02f, -3.379691899e-02f, +5.498355442e-03f, +3.949755319e-02f, +5.498355442e-03f, -3.379691899e-02f, -1.263546899e-02f, +2.083400312e-02f, +1.199271213e-02f, -8.774562126e-03f, -6.534433696e-03f, +2.314577966e-03f, +1.702864838e-03f, +0.000000000e+00f,
+ /* 20, 1 */ +1.499435496e-03f, +2.547675666e-03f, -5.868098774e-03f, -9.353385898e-03f, +1.044920601e-02f, +2.160032962e-02f, -9.997584470e-03f, -3.429852636e-02f, +2.083565903e-03f, +3.933622696e-02f, +8.892197588e-03f, -3.300722623e-02f, -1.522519578e-02f, +1.986341365e-02f, +1.349096787e-02f, -8.082206357e-03f, -7.177938171e-03f, +2.033576095e-03f, +1.903844954e-03f, +0.000000000e+00f,
+ /* 20, 2 */ +8.979094201e-04f, +2.733567376e-03f, -5.187117330e-03f, -9.818374279e-03f, +8.876306372e-03f, +2.216139438e-02f, -7.335624654e-03f, -3.451169090e-02f, -1.322648265e-03f, +3.885370480e-02f, +1.223556951e-02f, -3.193245877e-02f, -1.774265256e-02f, +1.869155385e-02f, +1.492800767e-02f, -7.277832099e-03f, -7.790241855e-03f, +1.704529263e-03f, +2.099160368e-03f, -3.513221827e-04f,
+ /* 20, 3 */ +7.046452899e-04f, +2.873469547e-03f, -4.499404245e-03f, -1.017038969e-02f, +7.289604703e-03f, +2.251815219e-02f, -4.673411391e-03f, -3.443867914e-02f, -4.691042688e-03f, +3.805434209e-02f, +1.549922824e-02f, -3.057828381e-02f, -2.016393226e-02f, +1.732343066e-02f, +1.628791973e-02f, -6.364195274e-03f, -8.362876507e-03f, +1.327887989e-03f, +2.285430476e-03f, -3.288882594e-04f,
+ /* 20, 4 */ +5.275063595e-04f, +2.969073324e-03f, -3.812529364e-03f, -1.041140495e-02f, +5.704278009e-03f, +2.267345221e-02f, -2.034281900e-03f, -3.408432658e-02f, -7.992925296e-03f, +3.694535030e-02f, +1.865448932e-02f, -2.895300188e-02f, -2.246557005e-02f, +1.576606531e-02f, +1.755501285e-02f, -5.345313722e-03f, -8.887369558e-03f, +9.047221591e-04f, +2.459146683e-03f, -2.941732022e-04f,
+ /* 20, 5 */ +3.670219514e-04f, +3.022497230e-03f, -3.133648777e-03f, -1.054443774e-02f, +4.134948499e-03f, +2.263196075e-02f, +5.591264205e-04f, -3.345595810e-02f, -1.120042307e-02f, +3.553672638e-02f, +2.167350137e-02f, -2.706749712e-02f, -2.462477986e-02f, +1.402847243e-02f, +1.871398575e-02f, -4.226473266e-03f, -9.355341791e-03f, +4.367425848e-04f, +2.616713456e-03f, -2.461206998e-04f,
+ /* 20, 6 */ +2.234691091e-04f, +3.036236900e-03f, -2.469443903e-03f, -1.057347601e-02f, +2.595553432e-03f, +2.240006745e-02f, +3.085080219e-03f, -3.256328476e-02f, -1.428673893e-02f, +3.384115481e-02f, +2.452951370e-02f, -2.493516141e-02f, -2.661968788e-02f, +1.212161795e-02f, +1.975009719e-02f, -3.014219819e-03f, -9.758608118e-03f, -7.368451392e-05f, +2.754492916e-03f, -1.837671888e-04f,
+ /* 20, 7 */ +9.688872179e-05f, +3.013112613e-03f, -1.826068782e-03f, -1.050339555e-02f, +1.099226216e-03f, +2.198577609e-02f, +5.522941542e-03f, -3.141827834e-02f, -1.722639627e-02f, +3.187388359e-02f, +2.719713425e-02f, -2.257179274e-02f, -2.842956063e-02f, +1.005835593e-02f, +2.064933490e-02f, -1.716337171e-03f, -1.008928035e-02f, -6.235305950e-04f, +2.868852533e-03f, -1.062635081e-04f,
+ /* 20, 8 */ -1.289664191e-05f, +2.956215411e-03f, -1.209105881e-03f, -1.033987080e-02f, -3.418102460e-04f, +2.139858161e-02f, +7.853344535e-03f, -3.003502508e-02f, -1.999546871e-02f, +2.965257519e-02f, +2.965257519e-02f, -1.999546871e-02f, -3.003502508e-02f, +7.853344535e-03f, +2.139858161e-02f, -3.418102460e-04f, -1.033987080e-02f, -1.209105881e-03f, +2.956215411e-03f, -1.289664191e-05f,
+ /* 20, 9 */ -1.062635081e-04f, +2.868852533e-03f, -6.235305950e-04f, -1.008928035e-02f, -1.716337171e-03f, +2.064933490e-02f, +1.005835593e-02f, -2.842956063e-02f, -2.257179274e-02f, +2.719713425e-02f, +3.187388359e-02f, -1.722639627e-02f, -3.141827834e-02f, +5.522941542e-03f, +2.198577609e-02f, +1.099226216e-03f, -1.050339555e-02f, -1.826068782e-03f, +3.013112613e-03f, +9.688872179e-05f,
+ /* 20,10 */ -1.837671888e-04f, +2.754492916e-03f, -7.368451392e-05f, -9.758608118e-03f, -3.014219819e-03f, +1.975009719e-02f, +1.212161795e-02f, -2.661968788e-02f, -2.493516141e-02f, +2.452951370e-02f, +3.384115481e-02f, -1.428673893e-02f, -3.256328476e-02f, +3.085080219e-03f, +2.240006745e-02f, +2.595553432e-03f, -1.057347601e-02f, -2.469443903e-03f, +3.036236900e-03f, +2.234691091e-04f,
+ /* 20,11 */ -2.461206998e-04f, +2.616713456e-03f, +4.367425848e-04f, -9.355341791e-03f, -4.226473266e-03f, +1.871398575e-02f, +1.402847243e-02f, -2.462477986e-02f, -2.706749712e-02f, +2.167350137e-02f, +3.553672638e-02f, -1.120042307e-02f, -3.345595810e-02f, +5.591264205e-04f, +2.263196075e-02f, +4.134948499e-03f, -1.054443774e-02f, -3.133648777e-03f, +3.022497230e-03f, +3.670219514e-04f,
+ /* 20,12 */ -2.941732022e-04f, +2.459146683e-03f, +9.047221591e-04f, -8.887369558e-03f, -5.345313722e-03f, +1.755501285e-02f, +1.576606531e-02f, -2.246557005e-02f, -2.895300188e-02f, +1.865448932e-02f, +3.694535030e-02f, -7.992925296e-03f, -3.408432658e-02f, -2.034281900e-03f, +2.267345221e-02f, +5.704278009e-03f, -1.041140495e-02f, -3.812529364e-03f, +2.969073324e-03f, +5.275063595e-04f,
+ /* 20,13 */ -3.288882594e-04f, +2.285430476e-03f, +1.327887989e-03f, -8.362876507e-03f, -6.364195274e-03f, +1.628791973e-02f, +1.732343066e-02f, -2.016393226e-02f, -3.057828381e-02f, +1.549922824e-02f, +3.805434209e-02f, -4.691042688e-03f, -3.443867914e-02f, -4.673411391e-03f, +2.251815219e-02f, +7.289604703e-03f, -1.017038969e-02f, -4.499404245e-03f, +2.873469547e-03f, +7.046452899e-04f,
+ /* 20,14 */ -3.513221827e-04f, +2.099160368e-03f, +1.704529263e-03f, -7.790241855e-03f, -7.277832099e-03f, +1.492800767e-02f, +1.869155385e-02f, -1.774265256e-02f, -3.193245877e-02f, +1.223556951e-02f, +3.885370480e-02f, -1.322648265e-03f, -3.451169090e-02f, -7.335624654e-03f, +2.216139438e-02f, +8.876306372e-03f, -9.818374279e-03f, -5.187117330e-03f, +2.733567376e-03f, +8.979094201e-04f,
+ /* 20,15 */ +0.000000000e+00f, +1.903844954e-03f, +2.033576095e-03f, -7.177938171e-03f, -8.082206357e-03f, +1.349096787e-02f, +1.986341365e-02f, -1.522519578e-02f, -3.300722623e-02f, +8.892197588e-03f, +3.933622696e-02f, +2.083565903e-03f, -3.429852636e-02f, -9.997584470e-03f, +2.160032962e-02f, +1.044920601e-02f, -9.353385898e-03f, -5.868098774e-03f, +2.547675666e-03f, +1.499435496e-03f,
+ /* 20, 0 */ -3.735125865e-04f, +2.550984103e-03f, -2.725752467e-05f, -1.024966855e-02f, +8.379667777e-04f, +2.252874535e-02f, -1.249359695e-03f, -3.448318510e-02f, +6.071698875e-04f, +3.949755319e-02f, +6.071698875e-04f, -3.448318510e-02f, -1.249359695e-03f, +2.252874535e-02f, +8.379667777e-04f, -1.024966855e-02f, -2.725752467e-05f, +2.565652055e-03f, -3.735125865e-04f, +0.000000000e+00f,
+ /* 20, 1 */ -3.929324583e-04f, +2.236335973e-03f, +5.288730096e-04f, -9.916240655e-03f, -7.235223044e-04f, +2.212021870e-02f, +1.557339330e-03f, -3.412515163e-02f, -3.088657053e-03f, +3.930609269e-02f, +4.328121901e-03f, -3.450613681e-02f, -4.117983282e-03f, +2.271744325e-02f, +2.467540325e-03f, -1.048404473e-02f, -6.307983207e-04f, +2.729031078e-03f, -3.387491377e-04f, +0.000000000e+00f,
+ /* 20, 2 */ +0.000000000e+00f, +1.931175707e-03f, +1.033703668e-03f, -9.493276252e-03f, -2.202626937e-03f, +2.150371837e-02f, +4.274418757e-03f, -3.344119198e-02f, -6.721842627e-03f, +3.873376177e-02f, +8.036125742e-03f, -3.418837690e-02f, -7.019484999e-03f, +2.267661502e-02f, +4.149462009e-03f, -1.061062992e-02f, -1.276919763e-03f, +2.866023275e-03f, -2.870815261e-04f, +0.000000000e+00f,
+ /* 20, 3 */ +0.000000000e+00f, +1.638662038e-03f, +1.484286050e-03f, -8.990907936e-03f, -3.586602863e-03f, +2.069305390e-02f, +6.875821908e-03f, -3.244383298e-02f, -1.025584288e-02f, +3.778668841e-02f, +1.169297592e-02f, -3.352791602e-02f, -9.923776326e-03f, +2.239890298e-02f, +5.866701604e-03f, -1.062161571e-02f, -1.959867511e-03f, +2.971909246e-03f, -2.170808154e-04f, +0.000000000e+00f,
+ /* 20, 4 */ +0.000000000e+00f, +1.361489293e-03f, +1.878600735e-03f, -8.419725702e-03f, -4.864357078e-03f, +1.970376789e-02f, +9.337391966e-03f, -3.114878076e-02f, -1.365548733e-02f, +3.647500669e-02f, +1.526076366e-02f, -3.252647846e-02f, -1.280005487e-02f, +2.187944695e-02f, +7.601099328e-03f, -1.051027343e-02f, -2.672992279e-03f, +3.042103091e-03f, -1.274866066e-04f, +0.000000000e+00f,
+ /* 20, 5 */ +0.000000000e+00f, +1.101888322e-03f, +2.215532402e-03f, -7.790617836e-03f, -6.026519023e-03f, +1.855289977e-02f, +1.163710530e-02f, -2.957469445e-02f, -1.688736106e-02f, +3.481273909e-02f, +1.870230489e-02f, -3.118953221e-02f, -1.561714772e-02f, +2.111601531e-02f, +9.333550613e-03f, -1.027109466e-02f, -3.408794343e-03f, +3.072235528e-03f, -1.724424543e-05f, +0.000000000e+00f,
+ /* 20, 6 */ +0.000000000e+00f, +8.616336525e-04f, +2.494833248e-03f, -7.114614810e-03f, -7.065487327e-03f, +1.725873795e-02f, +1.375527431e-02f, -2.774292839e-02f, -1.992016339e-02f, +3.281763375e-02f, +2.198156213e-02f, -2.952627516e-02f, -1.834386597e-02f, +2.010910684e-02f, +1.104420948e-02f, -9.899921148e-03f, -4.158982805e-03f, +3.058238443e-03f, +1.144582079e-04f, +0.000000000e+00f,
+ /* 20, 7 */ +0.000000000e+00f, +6.420563626e-04f, +2.717075783e-03f, -6.402738187e-03f, -7.975452307e-03f, +1.584056403e-02f, +1.567471786e-02f, -2.567724669e-02f, -2.272503888e-02f, +3.051095862e-02f, +2.506405514e-02f, -2.754957697e-02f, -2.094936609e-02f, +1.886202143e-02f, +1.271270843e-02f, -9.394061811e-03f, -4.914549404e-03f, +2.996429606e-03f, +2.681538305e-04f, +0.000000000e+00f,
+ /* 20, 8 */ +0.000000000e+00f, +4.440621234e-04f, +2.883596201e-03f, -5.665856445e-03f, -8.752394750e-03f, +1.431839236e-02f, +1.738089791e-02f, -2.340351394e-02f, -2.527587699e-02f, +2.791725525e-02f, +2.791725525e-02f, -2.527587699e-02f, -2.340351394e-02f, +1.738089791e-02f, +1.431839236e-02f, -8.752394750e-03f, -5.665856445e-03f, +2.883596201e-03f, +4.440621234e-04f, +0.000000000e+00f,
+ /* 20, 9 */ +0.000000000e+00f, +2.681538305e-04f, +2.996429606e-03f, -4.914549404e-03f, -9.394061811e-03f, +1.271270843e-02f, +1.886202143e-02f, -2.094936609e-02f, -2.754957697e-02f, +2.506405514e-02f, +3.051095862e-02f, -2.272503888e-02f, -2.567724669e-02f, +1.567471786e-02f, +1.584056403e-02f, -7.975452307e-03f, -6.402738187e-03f, +2.717075783e-03f, +6.420563626e-04f, +0.000000000e+00f,
+ /* 20,10 */ +0.000000000e+00f, +1.144582079e-04f, +3.058238443e-03f, -4.158982805e-03f, -9.899921148e-03f, +1.104420948e-02f, +2.010910684e-02f, -1.834386597e-02f, -2.952627516e-02f, +2.198156213e-02f, +3.281763375e-02f, -1.992016339e-02f, -2.774292839e-02f, +1.375527431e-02f, +1.725873795e-02f, -7.065487327e-03f, -7.114614810e-03f, +2.494833248e-03f, +8.616336525e-04f, +0.000000000e+00f,
+ /* 20,11 */ +0.000000000e+00f, -1.724424543e-05f, +3.072235528e-03f, -3.408794343e-03f, -1.027109466e-02f, +9.333550613e-03f, +2.111601531e-02f, -1.561714772e-02f, -3.118953221e-02f, +1.870230489e-02f, +3.481273909e-02f, -1.688736106e-02f, -2.957469445e-02f, +1.163710530e-02f, +1.855289977e-02f, -6.026519023e-03f, -7.790617836e-03f, +2.215532402e-03f, +1.101888322e-03f, +0.000000000e+00f,
+ /* 20,12 */ +0.000000000e+00f, -1.274866066e-04f, +3.042103091e-03f, -2.672992279e-03f, -1.051027343e-02f, +7.601099328e-03f, +2.187944695e-02f, -1.280005487e-02f, -3.252647846e-02f, +1.526076366e-02f, +3.647500669e-02f, -1.365548733e-02f, -3.114878076e-02f, +9.337391966e-03f, +1.970376789e-02f, -4.864357078e-03f, -8.419725702e-03f, +1.878600735e-03f, +1.361489293e-03f, +0.000000000e+00f,
+ /* 20,13 */ +0.000000000e+00f, -2.170808154e-04f, +2.971909246e-03f, -1.959867511e-03f, -1.062161571e-02f, +5.866701604e-03f, +2.239890298e-02f, -9.923776326e-03f, -3.352791602e-02f, +1.169297592e-02f, +3.778668841e-02f, -1.025584288e-02f, -3.244383298e-02f, +6.875821908e-03f, +2.069305390e-02f, -3.586602863e-03f, -8.990907936e-03f, +1.484286050e-03f, +1.638662038e-03f, +0.000000000e+00f,
+ /* 20,14 */ +0.000000000e+00f, -2.870815261e-04f, +2.866023275e-03f, -1.276919763e-03f, -1.061062992e-02f, +4.149462009e-03f, +2.267661502e-02f, -7.019484999e-03f, -3.418837690e-02f, +8.036125742e-03f, +3.873376177e-02f, -6.721842627e-03f, -3.344119198e-02f, +4.274418757e-03f, +2.150371837e-02f, -2.202626937e-03f, -9.493276252e-03f, +1.033703668e-03f, +1.931175707e-03f, +0.000000000e+00f,
+ /* 20,15 */ +0.000000000e+00f, -3.387491377e-04f, +2.729031078e-03f, -6.307983207e-04f, -1.048404473e-02f, +2.467540325e-03f, +2.271744325e-02f, -4.117983282e-03f, -3.450613681e-02f, +4.328121901e-03f, +3.930609269e-02f, -3.088657053e-03f, -3.412515163e-02f, +1.557339330e-03f, +2.212021870e-02f, -7.235223044e-04f, -9.916240655e-03f, +5.288730096e-04f, +2.236335973e-03f, -3.929324583e-04f,
+ /* 16, 0 */ +3.044394378e-03f, -5.755865016e-03f, -7.644875237e-03f, +1.825808857e-02f, +9.222448502e-03f, -3.286388427e-02f, -4.241838036e-03f, +3.949755319e-02f, -4.241838036e-03f, -3.286388427e-02f, +9.222448502e-03f, +1.825808857e-02f, -7.644875237e-03f, -5.755865016e-03f, +3.044394378e-03f, -1.466795211e-05f,
+ /* 16, 1 */ +3.096598285e-03f, -4.938670705e-03f, -8.543525001e-03f, +1.681174815e-02f, +1.171692718e-02f, -3.156650717e-02f, -8.140229219e-03f, +3.927338559e-02f, -2.566011090e-04f, -3.380519836e-02f, +6.539747546e-03f, +1.954192550e-02f, -6.591652894e-03f, -6.554797296e-03f, +2.932700428e-03f, +1.424716020e-04f,
+ /* 16, 2 */ +3.093580763e-03f, -4.116215273e-03f, -9.283856280e-03f, +1.522768985e-02f, +1.399813452e-02f, -2.993548791e-02f, -1.190603152e-02f, +3.860369285e-02f, +3.768233493e-03f, -3.437220120e-02f, +3.697060454e-03f, +2.063975168e-02f, -5.390052618e-03f, -7.321916780e-03f, +2.757987679e-03f, +3.278051009e-04f,
+ /* 16, 3 */ +3.040228116e-03f, -3.300778044e-03f, -9.864516741e-03f, +1.353158972e-02f, +1.604446323e-02f, -2.799705310e-02f, -1.549559239e-02f, +3.749686691e-02f, +7.784523662e-03f, -3.455113173e-02f, +7.255039591e-04f, +2.152972014e-02f, -4.048737024e-03f, -8.043312786e-03f, +2.517583336e-03f, +5.415628140e-04f,
+ /* 16, 4 */ +2.941918573e-03f, -2.503765206e-03f, -1.028645874e-02f, +1.174962597e-02f, +1.783794825e-02f, -2.578082191e-02f, -1.886790220e-02f, +3.596676747e-02f, +1.174386090e-02f, -3.433297304e-02f, -2.341279491e-03f, +2.219201396e-02f, -2.578818314e-03f, -8.704920467e-03f, +2.209778110e-03f, +1.246855370e-03f,
+ /* 16, 5 */ +2.804395319e-03f, -1.735580001e-03f, -1.055281940e-02f, +9.908096520e-03f, +1.936441115e-02f, -2.331935318e-02f, -2.198510572e-02f, +3.403253365e-02f, +1.559820593e-02f, -3.371364718e-02f, -5.467520855e-03f, +2.260919785e-02f, -9.938011251e-04f, -9.292739628e-03f, +1.833922789e-03f, +1.492594630e-03f,
+ /* 16, 6 */ +2.633640678e-03f, -1.005515791e-03f, -1.066877263e-02f, +8.033047542e-03f, +2.061354789e-02f, -2.064765983e-02f, -2.481296600e-02f, +3.171832409e-02f, +1.930052332e-02f, -3.269414425e-02f, -8.615762914e-03f, +2.276654580e-02f, +6.905139302e-04f, -9.793063512e-03f, +1.390511455e-03f, +1.739628231e-03f,
+ /* 16, 7 */ +2.435753603e-03f, -3.216727033e-04f, -1.064135670e-02f, +6.149918447e-03f, +2.157895980e-02f, -1.780269814e-02f, -2.732127429e-02f, +2.905298940e-02f, +2.280540611e-02f, -3.128058296e-02f, -1.174733238e-02f, +2.265233903e-02f, +2.456165958e-03f, -1.019271416e-02f, +8.812491435e-04f, +1.982865330e-03f,
+ /* 16, 8 */ +2.216832517e-03f, +3.091018830e-04f, -1.047928070e-02f, +4.283208005e-03f, +2.225812888e-02f, -1.482283947e-02f, -2.948420097e-02f, +2.606968157e-02f, +2.606968157e-02f, -2.948420097e-02f, -1.482283947e-02f, +2.225812888e-02f, +4.283208005e-03f, -1.047928070e-02f, +3.091018830e-04f, +2.216832517e-03f,
+ /* 16, 9 */ +1.982865330e-03f, +8.812491435e-04f, -1.019271416e-02f, +2.456165958e-03f, +2.265233903e-02f, -1.174733238e-02f, -3.128058296e-02f, +2.280540611e-02f, +2.905298940e-02f, -2.732127429e-02f, -1.780269814e-02f, +2.157895980e-02f, +6.149918447e-03f, -1.064135670e-02f, -3.216727033e-04f, +2.435753603e-03f,
+ /* 16,10 */ +1.739628231e-03f, +1.390511455e-03f, -9.793063512e-03f, +6.905139302e-04f, +2.276654580e-02f, -8.615762914e-03f, -3.269414425e-02f, +1.930052332e-02f, +3.171832409e-02f, -2.481296600e-02f, -2.064765983e-02f, +2.061354789e-02f, +8.033047542e-03f, -1.066877263e-02f, -1.005515791e-03f, +2.633640678e-03f,
+ /* 16,11 */ +1.492594630e-03f, +1.833922789e-03f, -9.292739628e-03f, -9.938011251e-04f, +2.260919785e-02f, -5.467520855e-03f, -3.371364718e-02f, +1.559820593e-02f, +3.403253365e-02f, -2.198510572e-02f, -2.331935318e-02f, +1.936441115e-02f, +9.908096520e-03f, -1.055281940e-02f, -1.735580001e-03f, +2.804395319e-03f,
+ /* 16,12 */ +1.246855370e-03f, +2.209778110e-03f, -8.704920467e-03f, -2.578818314e-03f, +2.219201396e-02f, -2.341279491e-03f, -3.433297304e-02f, +1.174386090e-02f, +3.596676747e-02f, -1.886790220e-02f, -2.578082191e-02f, +1.783794825e-02f, +1.174962597e-02f, -1.028645874e-02f, -2.503765206e-03f, +2.941918573e-03f,
+ /* 16,13 */ +5.415628140e-04f, +2.517583336e-03f, -8.043312786e-03f, -4.048737024e-03f, +2.152972014e-02f, +7.255039591e-04f, -3.455113173e-02f, +7.784523662e-03f, +3.749686691e-02f, -1.549559239e-02f, -2.799705310e-02f, +1.604446323e-02f, +1.353158972e-02f, -9.864516741e-03f, -3.300778044e-03f, +3.040228116e-03f,
+ /* 16,14 */ +3.278051009e-04f, +2.757987679e-03f, -7.321916780e-03f, -5.390052618e-03f, +2.063975168e-02f, +3.697060454e-03f, -3.437220120e-02f, +3.768233493e-03f, +3.860369285e-02f, -1.190603152e-02f, -2.993548791e-02f, +1.399813452e-02f, +1.522768985e-02f, -9.283856280e-03f, -4.116215273e-03f, +3.093580763e-03f,
+ /* 16,15 */ +1.424716020e-04f, +2.932700428e-03f, -6.554797296e-03f, -6.591652894e-03f, +1.954192550e-02f, +6.539747546e-03f, -3.380519836e-02f, -2.566011090e-04f, +3.927338559e-02f, -8.140229219e-03f, -3.156650717e-02f, +1.171692718e-02f, +1.681174815e-02f, -8.543525001e-03f, -4.938670705e-03f, +3.096598285e-03f,
+ /* 16, 0 */ +2.106112688e-03f, -1.136549770e-04f, -1.070669430e-02f, +1.017472059e-02f, +1.725397418e-02f, -2.914959442e-02f, -8.963852042e-03f, +3.949755319e-02f, -8.963852042e-03f, -2.914959442e-02f, +1.725397418e-02f, +1.017472059e-02f, -1.070669430e-02f, -1.136549770e-04f, +2.106112688e-03f, +0.000000000e+00f,
+ /* 16, 1 */ +1.845338280e-03f, +5.473343456e-04f, -1.065891816e-02f, +8.155641030e-03f, +1.899089579e-02f, -2.691951328e-02f, -1.297236480e-02f, +3.923810803e-02f, -4.790894575e-03f, -3.103786392e-02f, +1.521305380e-02f, +1.215062389e-02f, -1.058864907e-02f, -8.385121370e-04f, +2.352913572e-03f, +0.000000000e+00f,
+ /* 16, 2 */ +1.577651889e-03f, +1.138027416e-03f, -1.045641117e-02f, +6.125232216e-03f, +2.040939526e-02f, -2.438627738e-02f, -1.676283724e-02f, +3.846353557e-02f, -5.100475811e-04f, -3.254996068e-02f, +1.288771825e-02f, +1.405076114e-02f, -1.029592106e-02f, -1.619065127e-03f, +2.578329862e-03f, +0.000000000e+00f,
+ /* 16, 3 */ +1.309641631e-03f, +1.653747621e-03f, -1.011218665e-02f, +4.114112388e-03f, +2.150028131e-02f, -2.159216402e-02f, -2.028541539e-02f, +3.718506562e-02f, +3.820010384e-03f, -3.365643786e-02f, +1.030255138e-02f, +1.584231759e-02f, -9.822158049e-03f, -2.445442331e-03f, +2.774741598e-03f, +0.000000000e+00f,
+ /* 16, 4 */ +5.462770218e-04f, +2.091544281e-03f, -9.640854940e-03f, +2.151223968e-03f, +2.225957955e-02f, -1.858235038e-02f, -2.349470263e-02f, +3.542121816e-02f, +8.139354376e-03f, -3.433331277e-02f, +7.486889709e-03f, +1.749279467e-02f, -9.163764446e-03f, -3.306153325e-03f, +2.934475195e-03f, -4.634120047e-04f,
+ /* 16, 5 */ +3.039101756e-04f, +2.450135010e-03f, -9.058284956e-03f, +2.634319572e-04f, +2.268843286e-02f, -1.540416082e-02f, -2.635039795e-02f, +3.319751225e-02f, +1.238771678e-02f, -3.456253827e-02f, +4.474489227e-03f, +1.897056596e-02f, -8.320109905e-03f, -4.188206830e-03f, +3.049970761e-03f, -4.400286560e-04f,
+ /* 16, 6 */ +9.722433303e-05f, +2.729819110e-03f, -8.381259809e-03f, -1.524826854e-03f, +2.279292110e-02f, -1.210629477e-02f, -2.881784707e-02f, +3.054606534e-02f, +1.650540309e-02f, -3.433238619e-02f, +1.303110212e-03f, +2.024543829e-02f, -7.293693549e-03f, -5.077265419e-03f, +3.113958519e-03f, -3.921992729e-04f,
+ /* 16, 7 */ -7.427658644e-05f, +2.932365266e-03f, -7.627133157e-03f, -3.191839567e-03f, +2.258380561e-02f, -8.738048497e-03f, -3.086849848e-02f, +2.750508980e-02f, +2.043420490e-02f, -3.363773532e-02f, -1.985974837e-03f, +2.128920837e-02f, -6.090258802e-03f, -5.957835775e-03f, +3.119640969e-03f, -3.169896142e-04f,
+ /* 16, 8 */ -2.117631665e-04f, +3.060877176e-03f, -6.813492559e-03f, -4.718854594e-03f, +2.207620481e-02f, -5.348543574e-03f, -3.248025769e-02f, +2.411829496e-02f, +2.411829496e-02f, -3.248025769e-02f, -5.348543574e-03f, +2.207620481e-02f, -4.718854594e-03f, -6.813492559e-03f, +3.060877176e-03f, -2.117631665e-04f,
+ /* 16, 9 */ -3.169896142e-04f, +3.119640969e-03f, -5.957835775e-03f, -6.090258802e-03f, +2.128920837e-02f, -1.985974837e-03f, -3.363773532e-02f, +2.043420490e-02f, +2.750508980e-02f, -3.086849848e-02f, -8.738048497e-03f, +2.258380561e-02f, -3.191839567e-03f, -7.627133157e-03f, +2.932365266e-03f, -7.427658644e-05f,
+ /* 16,10 */ -3.921992729e-04f, +3.113958519e-03f, -5.077265419e-03f, -7.293693549e-03f, +2.024543829e-02f, +1.303110212e-03f, -3.433238619e-02f, +1.650540309e-02f, +3.054606534e-02f, -2.881784707e-02f, -1.210629477e-02f, +2.279292110e-02f, -1.524826854e-03f, -8.381259809e-03f, +2.729819110e-03f, +9.722433303e-05f,
+ /* 16,11 */ -4.400286560e-04f, +3.049970761e-03f, -4.188206830e-03f, -8.320109905e-03f, +1.897056596e-02f, +4.474489227e-03f, -3.456253827e-02f, +1.238771678e-02f, +3.319751225e-02f, -2.635039795e-02f, -1.540416082e-02f, +2.268843286e-02f, +2.634319572e-04f, -9.058284956e-03f, +2.450135010e-03f, +3.039101756e-04f,
+ /* 16,12 */ -4.634120047e-04f, +2.934475195e-03f, -3.306153325e-03f, -9.163764446e-03f, +1.749279467e-02f, +7.486889709e-03f, -3.433331277e-02f, +8.139354376e-03f, +3.542121816e-02f, -2.349470263e-02f, -1.858235038e-02f, +2.225957955e-02f, +2.151223968e-03f, -9.640854940e-03f, +2.091544281e-03f, +5.462770218e-04f,
+ /* 16,13 */ +0.000000000e+00f, +2.774741598e-03f, -2.445442331e-03f, -9.822158049e-03f, +1.584231759e-02f, +1.030255138e-02f, -3.365643786e-02f, +3.820010384e-03f, +3.718506562e-02f, -2.028541539e-02f, -2.159216402e-02f, +2.150028131e-02f, +4.114112388e-03f, -1.011218665e-02f, +1.653747621e-03f, +1.309641631e-03f,
+ /* 16,14 */ +0.000000000e+00f, +2.578329862e-03f, -1.619065127e-03f, -1.029592106e-02f, +1.405076114e-02f, +1.288771825e-02f, -3.254996068e-02f, -5.100475811e-04f, +3.846353557e-02f, -1.676283724e-02f, -2.438627738e-02f, +2.040939526e-02f, +6.125232216e-03f, -1.045641117e-02f, +1.138027416e-03f, +1.577651889e-03f,
+ /* 16,15 */ +0.000000000e+00f, +2.352913572e-03f, -8.385121370e-04f, -1.058864907e-02f, +1.215062389e-02f, +1.521305380e-02f, -3.103786392e-02f, -4.790894575e-03f, +3.923810803e-02f, -1.297236480e-02f, -2.691951328e-02f, +1.899089579e-02f, +8.155641030e-03f, -1.065891816e-02f, +5.473343456e-04f, +1.845338280e-03f,
+ /* 16, 0 */ -2.517634455e-04f, +5.956310854e-03f, -8.647029609e-03f, +1.153545125e-03f, +2.185732832e-02f, -2.369518339e-02f, -1.347728153e-02f, +3.949755319e-02f, -1.347728153e-02f, -2.369518339e-02f, +2.185732832e-02f, +1.153545125e-03f, -8.647029609e-03f, +2.914798040e-03f, -2.517634455e-04f, +0.000000000e+00f,
+ /* 16, 1 */ -3.647589216e-04f, +5.559366521e-03f, -7.860683839e-03f, -8.150822761e-04f, +2.252089097e-02f, -2.063007883e-02f, -1.749200540e-02f, +3.920026256e-02f, -9.205150933e-03f, -2.647415600e-02f, +2.081322447e-02f, +3.223212212e-03f, -9.337661142e-03f, +2.677108373e-03f, -9.939782505e-05f, +0.000000000e+00f,
+ /* 16, 2 */ -4.414886472e-04f, +5.113535158e-03f, -7.000222932e-03f, -2.654422569e-03f, +2.280787202e-02f, -1.733513495e-02f, -2.118899605e-02f, +3.831333038e-02f, -4.740975303e-03f, -2.891426752e-02f, +1.939126736e-02f, +5.362271050e-03f, -9.911447152e-03f, +2.349799583e-03f, +9.477253367e-05f, +0.000000000e+00f,
+ /* 16, 3 */ -4.855802427e-04f, +4.633347213e-03f, -6.087250386e-03f, -4.340001532e-03f, +2.272858071e-02f, -1.386914009e-02f, -2.451395150e-02f, +3.685148678e-02f, -1.540603716e-04f, -3.096737610e-02f, +1.760097190e-02f, +7.536131493e-03f, -1.034820384e-02f, +1.931270179e-03f, +3.323676319e-04f, +0.000000000e+00f,
+ /* 16, 4 */ +0.000000000e+00f, +4.132457962e-03f, -5.142935987e-03f, -5.851401101e-03f, +2.229926864e-02f, -1.029228788e-02f, -2.741946400e-02f, +3.483898696e-02f, +4.483517704e-03f, -3.259088680e-02f, +1.545873378e-02f, +9.707799030e-03f, -1.062918096e-02f, +1.421916825e-03f, +6.140535745e-04f, +0.000000000e+00f,
+ /* 16, 5 */ +0.000000000e+00f, +3.623457200e-03f, -4.187611099e-03f, -7.172450485e-03f, +2.154162444e-02f, -6.665085054e-03f, -2.986575546e-02f, +3.230917458e-02f, +9.098146940e-03f, -3.374862716e-02f, +1.298775300e-02f, +1.183848413e-02f, -1.073754388e-02f, +8.242784646e-04f, +9.394126333e-04f, +0.000000000e+00f,
+ /* 16, 6 */ +0.000000000e+00f, +3.117716971e-03f, -3.240404345e-03f, -8.291325326e-03f, +2.048218318e-02f, -3.047278250e-03f, -3.182126614e-02f, +2.930388237e-02f, +1.361595241e-02f, -3.441162052e-02f, +1.021782484e-02f, +1.388827332e-02f, -1.065884073e-02f, +1.431392807e-04f, +1.306826648e-03f, +0.000000000e+00f,
+ /* 16, 7 */ +0.000000000e+00f, +2.625277441e-03f, -2.318923448e-03f, -9.200556695e-03f, +1.915166452e-02f, +5.031802154e-04f, -3.326308735e-02f, +2.587268140e-02f, +1.796408380e-02f, -3.455874049e-02f, +7.184998851e-03f, +1.581685040e-02f, -1.038144369e-02f, -6.144144569e-04f, +1.713377737e-03f, +0.000000000e+00f,
+ /* 16, 8 */ +0.000000000e+00f, +2.154770219e-03f, -1.438987736e-03f, -9.896953513e-03f, +1.758425506e-02f, +3.931108902e-03f, -3.417723209e-02f, +2.207199352e-02f, +2.207199352e-02f, -3.417723209e-02f, +3.931108902e-03f, +1.758425506e-02f, -9.896953513e-03f, -1.438987736e-03f, +2.154770219e-03f, +0.000000000e+00f,
+ /* 16, 9 */ +0.000000000e+00f, +1.713377737e-03f, -6.144144569e-04f, -1.038144369e-02f, +1.581685040e-02f, +7.184998851e-03f, -3.455874049e-02f, +1.796408380e-02f, +2.587268140e-02f, -3.326308735e-02f, +5.031802154e-04f, +1.915166452e-02f, -9.200556695e-03f, -2.318923448e-03f, +2.625277441e-03f, +0.000000000e+00f,
+ /* 16,10 */ +0.000000000e+00f, +1.306826648e-03f, +1.431392807e-04f, -1.065884073e-02f, +1.388827332e-02f, +1.021782484e-02f, -3.441162052e-02f, +1.361595241e-02f, +2.930388237e-02f, -3.182126614e-02f, -3.047278250e-03f, +2.048218318e-02f, -8.291325326e-03f, -3.240404345e-03f, +3.117716971e-03f, +0.000000000e+00f,
+ /* 16,11 */ +0.000000000e+00f, +9.394126333e-04f, +8.242784646e-04f, -1.073754388e-02f, +1.183848413e-02f, +1.298775300e-02f, -3.374862716e-02f, +9.098146940e-03f, +3.230917458e-02f, -2.986575546e-02f, -6.665085054e-03f, +2.154162444e-02f, -7.172450485e-03f, -4.187611099e-03f, +3.623457200e-03f, +0.000000000e+00f,
+ /* 16,12 */ +0.000000000e+00f, +6.140535745e-04f, +1.421916825e-03f, -1.062918096e-02f, +9.707799030e-03f, +1.545873378e-02f, -3.259088680e-02f, +4.483517704e-03f, +3.483898696e-02f, -2.741946400e-02f, -1.029228788e-02f, +2.229926864e-02f, -5.851401101e-03f, -5.142935987e-03f, +4.132457962e-03f, +0.000000000e+00f,
+ /* 16,13 */ +0.000000000e+00f, +3.323676319e-04f, +1.931270179e-03f, -1.034820384e-02f, +7.536131493e-03f, +1.760097190e-02f, -3.096737610e-02f, -1.540603716e-04f, +3.685148678e-02f, -2.451395150e-02f, -1.386914009e-02f, +2.272858071e-02f, -4.340001532e-03f, -6.087250386e-03f, +4.633347213e-03f, -4.855802427e-04f,
+ /* 16,14 */ +0.000000000e+00f, +9.477253367e-05f, +2.349799583e-03f, -9.911447152e-03f, +5.362271050e-03f, +1.939126736e-02f, -2.891426752e-02f, -4.740975303e-03f, +3.831333038e-02f, -2.118899605e-02f, -1.733513495e-02f, +2.280787202e-02f, -2.654422569e-03f, -7.000222932e-03f, +5.113535158e-03f, -4.414886472e-04f,
+ /* 16,15 */ +0.000000000e+00f, -9.939782505e-05f, +2.677108373e-03f, -9.337661142e-03f, +3.223212212e-03f, +2.081322447e-02f, -2.647415600e-02f, -9.205150933e-03f, +3.920026256e-02f, -1.749200540e-02f, -2.063007883e-02f, +2.252089097e-02f, -8.150822761e-04f, -7.860683839e-03f, +5.559366521e-03f, -3.647589216e-04f,
+ /* 12, 0 */ -3.924537125e-03f, -6.177283790e-03f, +2.270137823e-02f, -1.696686670e-02f, -1.770529738e-02f, +3.949755319e-02f, -1.770529738e-02f, -1.696686670e-02f, +2.270137823e-02f, -6.177283790e-03f, -3.924537125e-03f, +2.689823824e-03f,
+ /* 12, 1 */ -2.918444824e-03f, -7.533875928e-03f, +2.217225575e-02f, -1.325050127e-02f, -2.161377319e-02f, +3.915985190e-02f, -1.343239533e-02f, -2.049610855e-02f, +2.283609035e-02f, -4.600700986e-03f, -4.945631587e-03f, +2.897838580e-03f,
+ /* 12, 2 */ -1.948111766e-03f, -8.657444743e-03f, +2.127619260e-02f, -9.420045488e-03f, -2.509275167e-02f, +3.815312062e-02f, -8.867972963e-03f, -2.376686078e-02f, +2.255583139e-02f, -2.822790564e-03f, -5.958903400e-03f, +3.051876120e-03f,
+ /* 12, 3 */ -1.031879811e-03f, -9.540571177e-03f, +2.004673480e-02f, -5.548699503e-03f, -2.808617760e-02f, +3.649634673e-02f, -4.091413649e-03f, -2.671092541e-02f, +2.184766025e-02f, -8.677312765e-04f, -6.939883353e-03f, +3.140832095e-03f,
+ /* 12, 4 */ -1.854082964e-04f, -1.018130776e-02f, +1.852257236e-02f, -1.708362919e-03f, -3.054799363e-02f, +3.422074403e-02f, +8.129280323e-04f, -2.926474106e-02f, +2.070682375e-02f, +1.235031889e-03f, -7.862950435e-03f, +3.154329873e-03f,
+ /* 12, 5 */ +5.785109863e-04f, -1.058292035e-02f, +1.674653148e-02f, +2.031769072e-03f, -3.244290444e-02f, +3.136911490e-02f, +5.757350815e-03f, -3.137078637e-02f, +1.913716500e-02f, +3.451172065e-03f, -8.701884951e-03f, +3.083080347e-03f,
+ /* 12, 6 */ +1.250056620e-03f, -1.075352499e-02f, +1.476451598e-02f, +5.606517218e-03f, -3.374690984e-02f, +2.799497691e-02f, +1.065251585e-02f, -3.297888633e-02f, +1.715135739e-02f, +5.741996578e-03f, -9.430471381e-03f, +2.919238566e-03f,
+ /* 12, 7 */ +1.822400383e-03f, -1.070563332e-02f, +1.262442359e-02f, +8.955911342e-03f, -3.444759838e-02f, +2.416147295e-02f, +1.540920462e-02f, -3.404739100e-02f, +1.477095353e-02f, +8.065088216e-03f, -1.002313834e-02f, +2.656746896e-03f,
+ /* 12, 8 */ +2.291654178e-03f, -1.045562141e-02f, +1.037506188e-02f, +1.202624229e-02f, -3.454419870e-02f, +1.994008861e-02f, +1.994008861e-02f, -3.454419870e-02f, +1.202624229e-02f, +1.037506188e-02f, -1.045562141e-02f, +2.291654178e-03f,
+ /* 12, 9 */ +2.656746896e-03f, -1.002313834e-02f, +8.065088216e-03f, +1.477095353e-02f, -3.404739100e-02f, +1.540920462e-02f, +2.416147295e-02f, -3.444759838e-02f, +8.955911342e-03f, +1.262442359e-02f, -1.070563332e-02f, +1.822400383e-03f,
+ /* 12,10 */ +2.919238566e-03f, -9.430471381e-03f, +5.741996578e-03f, +1.715135739e-02f, -3.297888633e-02f, +1.065251585e-02f, +2.799497691e-02f, -3.374690984e-02f, +5.606517218e-03f, +1.476451598e-02f, -1.075352499e-02f, +1.250056620e-03f,
+ /* 12,11 */ +3.083080347e-03f, -8.701884951e-03f, +3.451172065e-03f, +1.913716500e-02f, -3.137078637e-02f, +5.757350815e-03f, +3.136911490e-02f, -3.244290444e-02f, +2.031769072e-03f, +1.674653148e-02f, -1.058292035e-02f, +5.785109863e-04f,
+ /* 12,12 */ +3.154329873e-03f, -7.862950435e-03f, +1.235031889e-03f, +2.070682375e-02f, -2.926474106e-02f, +8.129280323e-04f, +3.422074403e-02f, -3.054799363e-02f, -1.708362919e-03f, +1.852257236e-02f, -1.018130776e-02f, -1.854082964e-04f,
+ /* 12,13 */ +3.140832095e-03f, -6.939883353e-03f, -8.677312765e-04f, +2.184766025e-02f, -2.671092541e-02f, -4.091413649e-03f, +3.649634673e-02f, -2.808617760e-02f, -5.548699503e-03f, +2.004673480e-02f, -9.540571177e-03f, -1.031879811e-03f,
+ /* 12,14 */ +3.051876120e-03f, -5.958903400e-03f, -2.822790564e-03f, +2.255583139e-02f, -2.376686078e-02f, -8.867972963e-03f, +3.815312062e-02f, -2.509275167e-02f, -9.420045488e-03f, +2.127619260e-02f, -8.657444743e-03f, -1.948111766e-03f,
+ /* 12,15 */ +2.897838580e-03f, -4.945631587e-03f, -4.600700986e-03f, +2.283609035e-02f, -2.049610855e-02f, -1.343239533e-02f, +3.915985190e-02f, -2.161377319e-02f, -1.325050127e-02f, +2.217225575e-02f, -7.533875928e-03f, -2.918444824e-03f,
+ /* 12, 0 */ +5.529156756e-04f, -1.017944650e-02f, +2.010395691e-02f, -9.501724583e-03f, -2.157725737e-02f, +3.949755319e-02f, -2.157725737e-02f, -9.501724583e-03f, +2.010395691e-02f, -1.017944650e-02f, +5.529156756e-04f, +9.520529918e-04f,
+ /* 12, 1 */ +1.269440891e-03f, -1.060857725e-02f, +1.848426560e-02f, -5.389674050e-03f, -2.526172923e-02f, +3.911687897e-02f, -1.740939271e-02f, -1.356576871e-02f, +2.138958875e-02f, -9.480008902e-03f, -2.676127190e-04f, +1.273328470e-03f,
+ /* 12, 2 */ +1.873685854e-03f, -1.077705214e-02f, +1.658179711e-02f, -1.315683663e-03f, -2.839592801e-02f, +3.798295250e-02f, -1.283645305e-02f, -1.749413418e-02f, +2.229518867e-02f, -8.506812328e-03f, -1.180051037e-03f, +1.604489886e-03f,
+ /* 12, 3 */ +2.361120897e-03f, -1.070010905e-02f, +1.445171501e-02f, +2.637679549e-03f, -3.092573063e-02f, +3.611987567e-02f, -7.946589383e-03f, -2.119952675e-02f, +2.278144860e-02f, -7.263083188e-03f, -2.168530550e-03f, +1.934678236e-03f,
+ /* 12, 4 */ +2.730794315e-03f, -1.039785120e-02f, +1.215160004e-02f, +6.393108320e-03f, -3.281077803e-02f, +3.356720057e-02f, -2.835931904e-03f, -2.459705675e-02f, +2.281696739e-02f, -5.759053577e-03f, -3.213563229e-03f, +2.251787566e-03f,
+ /* 12, 5 */ +2.985073479e-03f, -9.894440683e-03f, +9.739988515e-03f, +9.880142532e-03f, -3.402514934e-02f, +3.037901891e-02f, +2.393471366e-03f, -2.760625942e-02f, +2.237934513e-02f, -4.012119167e-03f, -4.292316215e-03f, +2.542756696e-03f,
+ /* 12, 6 */ +3.129309714e-03f, -9.217233004e-03f, +7.274949975e-03f, +1.303654969e-02f, -3.455769209e-02f, +2.662271867e-02f, +7.635875993e-03f, -3.015305887e-02f, +2.145609570e-02f, -2.046814992e-03f, -5.379003980e-03f, +2.793918230e-03f,
+ /* 12, 7 */ +3.171441616e-03f, -8.395878746e-03f, +4.812738303e-03f, +1.580947051e-02f, -3.441200543e-02f, +2.237743869e-02f, +1.278417054e-02f, -3.217162603e-02f, +2.004534769e-02f, +1.053992035e-04f, -6.445394017e-03f, +2.991397563e-03f,
+ /* 12, 8 */ +3.121552430e-03f, -7.461418245e-03f, +2.406547485e-03f, +1.815630830e-02f, -3.360608252e-02f, +1.773225889e-02f, +1.773225889e-02f, -3.360608252e-02f, +1.815630830e-02f, +2.406547485e-03f, -7.461418245e-03f, +3.121552430e-03f,
+ /* 12, 9 */ +2.991397563e-03f, -6.445394017e-03f, +1.053992035e-04f, +2.004534769e-02f, -3.217162603e-02f, +1.278417054e-02f, +2.237743869e-02f, -3.441200543e-02f, +1.580947051e-02f, +4.812738303e-03f, -8.395878746e-03f, +3.171441616e-03f,
+ /* 12,10 */ +2.793918230e-03f, -5.379003980e-03f, -2.046814992e-03f, +2.145609570e-02f, -3.015305887e-02f, +7.635875993e-03f, +2.662271867e-02f, -3.455769209e-02f, +1.303654969e-02f, +7.274949975e-03f, -9.217233004e-03f, +3.129309714e-03f,
+ /* 12,11 */ +2.542756696e-03f, -4.292316215e-03f, -4.012119167e-03f, +2.237934513e-02f, -2.760625942e-02f, +2.393471366e-03f, +3.037901891e-02f, -3.402514934e-02f, +9.880142532e-03f, +9.739988515e-03f, -9.894440683e-03f, +2.985073479e-03f,
+ /* 12,12 */ +2.251787566e-03f, -3.213563229e-03f, -5.759053577e-03f, +2.281696739e-02f, -2.459705675e-02f, -2.835931904e-03f, +3.356720057e-02f, -3.281077803e-02f, +6.393108320e-03f, +1.215160004e-02f, -1.039785120e-02f, +2.730794315e-03f,
+ /* 12,13 */ +1.934678236e-03f, -2.168530550e-03f, -7.263083188e-03f, +2.278144860e-02f, -2.119952675e-02f, -7.946589383e-03f, +3.611987567e-02f, -3.092573063e-02f, +2.637679549e-03f, +1.445171501e-02f, -1.070010905e-02f, +2.361120897e-03f,
+ /* 12,14 */ +1.604489886e-03f, -1.180051037e-03f, -8.506812328e-03f, +2.229518867e-02f, -1.749413418e-02f, -1.283645305e-02f, +3.798295250e-02f, -2.839592801e-02f, -1.315683663e-03f, +1.658179711e-02f, -1.077705214e-02f, +1.873685854e-03f,
+ /* 12,15 */ +1.273328470e-03f, -2.676127190e-04f, -9.480008902e-03f, +2.138958875e-02f, -1.356576871e-02f, -1.740939271e-02f, +3.911687897e-02f, -2.526172923e-02f, -5.389674050e-03f, +1.848426560e-02f, -1.060857725e-02f, +1.269440891e-03f,
+
+ /* 24, 0 */ -8.820438069e-05f, -1.519461079e-04f, -2.301651496e-04f, -3.149320871e-04f, -3.945939739e-04f, -4.554410135e-04f, -4.841532882e-04f, -4.705408991e-04f, -4.099602091e-04f, -3.048100066e-04f, -1.646897470e-04f, -5.099007530e-06f, +1.551006323e-04f, +2.969416536e-04f, +4.046294158e-04f, +4.681429482e-04f, +4.846228261e-04f, +4.583040637e-04f, +3.990939388e-04f, +3.201968846e-04f, +2.353759082e-04f, +1.564712483e-04f, +9.167483068e-05f, +4.482688286e-05f,
+ /* 24, 1 */ -8.480575132e-05f, -1.474789784e-04f, -2.249812225e-04f, -3.096480504e-04f, -3.900204007e-04f, -4.524514078e-04f, -4.835165803e-04f, -4.727530367e-04f, -4.151145025e-04f, -3.125397891e-04f, -1.742016828e-04f, -1.529460870e-05f, +1.454387449e-04f, +2.889379628e-04f, +3.991236794e-04f, +4.655589110e-04f, +4.849233000e-04f, +4.610375470e-04f, +4.035168325e-04f, +3.254391996e-04f, +2.406110065e-04f, +1.610529558e-04f, +9.521673594e-05f, +4.721513201e-05f,
+ /* 24, 2 */ -8.147924507e-05f, -1.430712350e-04f, -2.198265592e-04f, -3.043479843e-04f, -3.853766873e-04f, -4.493383067e-04f, -4.827146831e-04f, -4.747797448e-04f, -4.200908527e-04f, -3.201278616e-04f, -1.836320864e-04f, -2.548296987e-05f, +1.357085413e-04f, +2.808022583e-04f, +3.934446700e-04f, +4.627886263e-04f, +4.850529052e-04f, +4.636385032e-04f, +4.078592000e-04f, +3.306557574e-04f, +2.458678944e-04f, +1.656897170e-04f, +9.882966748e-05f, +4.967415993e-05f,
+ /* 24, 3 */ -7.822510242e-05f, -1.387241832e-04f, -2.147035314e-04f, -2.990350629e-04f, -3.806663042e-04f, -4.461048161e-04f, -4.817496625e-04f, -4.766215175e-04f, -4.248879309e-04f, -3.275711800e-04f, -1.929766610e-04f, -3.565926997e-05f, +1.259145254e-04f, +2.725379532e-04f, +3.875941701e-04f, +4.598320457e-04f, +4.850099279e-04f, +4.661040260e-04f, +4.121175966e-04f, +3.358432542e-04f, +2.511439643e-04f, +1.703799499e-04f, +1.025131319e-04f, +5.220438912e-05f,
+ /* 24, 4 */ -7.504350274e-05f, -1.344390595e-04f, -2.096144489e-04f, -2.937124231e-04f, -3.758927218e-04f, -4.427540852e-04f, -4.806236671e-04f, -4.782789577e-04f, -4.295045226e-04f, -3.348667971e-04f, -2.022311686e-04f, -4.581869630e-05f, +1.160612449e-04f, +2.641485480e-04f, +3.815740737e-04f, +4.566892339e-04f, +4.847927474e-04f, +4.684312656e-04f, +4.162885910e-04f, +3.409983591e-04f, +2.564365532e-04f, +1.751220037e-04f, +1.062665706e-04f, +5.480619333e-05f,
+ /* 24, 5 */ -7.193456522e-05f, -1.302170312e-04f, -2.045615590e-04f, -2.883831622e-04f, -3.710594077e-04f, -4.392893036e-04f, -4.793389263e-04f, -4.797527765e-04f, -4.339395286e-04f, -3.420118645e-04f, -2.113914331e-04f, -5.595644787e-05f, +1.061532886e-04f, +2.556376279e-04f, +3.753863858e-04f, +4.533603695e-04f, +4.843998374e-04f, +4.706174312e-04f, +4.203687678e-04f, +3.461177167e-04f, +2.617429433e-04f, +1.799141593e-04f, +1.100893595e-04f, +5.747989630e-05f,
+ /* 24, 6 */ -6.889834987e-05f, -1.260591965e-04f, -1.995470454e-04f, -2.830503358e-04f, -3.661698243e-04f, -4.357136989e-04f, -4.778977479e-04f, -4.810437916e-04f, -4.381919648e-04f, -3.490036345e-04f, -2.204533432e-04f, -6.606773875e-05f, +9.619528314e-05f, +2.470088608e-04f, +3.690332209e-04f, +4.498457452e-04f, +4.838297683e-04f, +4.726597937e-04f, +4.243547301e-04f, +3.511979487e-04f, +2.670603639e-04f, +1.847546294e-04f, +1.139808078e-04f, +6.022577049e-05f,
+ /* 24, 7 */ -6.593485851e-05f, -1.219665852e-04f, -1.945730275e-04f, -2.777169567e-04f, -3.612274261e-04f, -4.320305335e-04f, -4.763025159e-04f, -4.821529264e-04f, -4.422609626e-04f, -3.558394612e-04f, -2.294128549e-04f, -7.614780136e-05f, +8.619188981e-05f, +2.382659945e-04f, +3.625168024e-04f, +4.461457687e-04f, +4.830812085e-04f, +4.745556880e-04f, +4.282431024e-04f, +3.562356572e-04f, +2.723859925e-04f, +1.896415594e-04f, +1.179401580e-04f, +6.304403582e-05f,
+ /* 24, 8 */ -6.304403582e-05f, -1.179401580e-04f, -1.896415594e-04f, -2.723859925e-04f, -3.562356572e-04f, -4.282431024e-04f, -4.745556880e-04f, -4.830812085e-04f, -4.461457687e-04f, -3.625168024e-04f, -2.382659945e-04f, -8.619188981e-05f, +7.614780136e-05f, +2.294128549e-04f, +3.558394612e-04f, +4.422609626e-04f, +4.821529264e-04f, +4.763025159e-04f, +4.320305335e-04f, +3.612274261e-04f, +2.777169567e-04f, +1.945730275e-04f, +1.219665852e-04f, +6.593485851e-05f,
+ /* 24, 9 */ -6.022577049e-05f, -1.139808078e-04f, -1.847546294e-04f, -2.670603639e-04f, -3.511979487e-04f, -4.243547301e-04f, -4.726597937e-04f, -4.838297683e-04f, -4.498457452e-04f, -3.690332209e-04f, -2.470088608e-04f, -9.619528314e-05f, +6.606773875e-05f, +2.204533432e-04f, +3.490036345e-04f, +4.381919648e-04f, +4.810437916e-04f, +4.778977479e-04f, +4.357136989e-04f, +3.661698243e-04f, +2.830503358e-04f, +1.995470454e-04f, +1.260591965e-04f, +6.889834987e-05f,
+ /* 24,10 */ -5.747989630e-05f, -1.100893595e-04f, -1.799141593e-04f, -2.617429433e-04f, -3.461177167e-04f, -4.203687678e-04f, -4.706174312e-04f, -4.843998374e-04f, -4.533603695e-04f, -3.753863858e-04f, -2.556376279e-04f, -1.061532886e-04f, +5.595644787e-05f, +2.113914331e-04f, +3.420118645e-04f, +4.339395286e-04f, +4.797527765e-04f, +4.793389263e-04f, +4.392893036e-04f, +3.710594077e-04f, +2.883831622e-04f, +2.045615590e-04f, +1.302170312e-04f, +7.193456522e-05f,
+ /* 24,11 */ -5.480619333e-05f, -1.062665706e-04f, -1.751220037e-04f, -2.564365532e-04f, -3.409983591e-04f, -4.162885910e-04f, -4.684312656e-04f, -4.847927474e-04f, -4.566892339e-04f, -3.815740737e-04f, -2.641485480e-04f, -1.160612449e-04f, +4.581869630e-05f, +2.022311686e-04f, +3.348667971e-04f, +4.295045226e-04f, +4.782789577e-04f, +4.806236671e-04f, +4.427540852e-04f, +3.758927218e-04f, +2.937124231e-04f, +2.096144489e-04f, +1.344390595e-04f, +7.504350274e-05f,
+ /* 24,12 */ -5.220438912e-05f, -1.025131319e-04f, -1.703799499e-04f, -2.511439643e-04f, -3.358432542e-04f, -4.121175966e-04f, -4.661040260e-04f, -4.850099279e-04f, -4.598320457e-04f, -3.875941701e-04f, -2.725379532e-04f, -1.259145254e-04f, +3.565926997e-05f, +1.929766610e-04f, +3.275711800e-04f, +4.248879309e-04f, +4.766215175e-04f, +4.817496625e-04f, +4.461048161e-04f, +3.806663042e-04f, +2.990350629e-04f, +2.147035314e-04f, +1.387241832e-04f, +7.822510242e-05f,
+ /* 24,13 */ -4.967415993e-05f, -9.882966748e-05f, -1.656897170e-04f, -2.458678944e-04f, -3.306557574e-04f, -4.078592000e-04f, -4.636385032e-04f, -4.850529052e-04f, -4.627886263e-04f, -3.934446700e-04f, -2.808022583e-04f, -1.357085413e-04f, +2.548296987e-05f, +1.836320864e-04f, +3.201278616e-04f, +4.200908527e-04f, +4.747797448e-04f, +4.827146831e-04f, +4.493383067e-04f, +3.853766873e-04f, +3.043479843e-04f, +2.198265592e-04f, +1.430712350e-04f, +8.147924507e-05f,
+ /* 24,14 */ -4.721513201e-05f, -9.521673594e-05f, -1.610529558e-04f, -2.406110065e-04f, -3.254391996e-04f, -4.035168325e-04f, -4.610375470e-04f, -4.849233000e-04f, -4.655589110e-04f, -3.991236794e-04f, -2.889379628e-04f, -1.454387449e-04f, +1.529460870e-05f, +1.742016828e-04f, +3.125397891e-04f, +4.151145025e-04f, +4.727530367e-04f, +4.835165803e-04f, +4.524514078e-04f, +3.900204007e-04f, +3.096480504e-04f, +2.249812225e-04f, +1.474789784e-04f, +8.480575132e-05f,
+ /* 24,15 */ -4.482688286e-05f, -9.167483068e-05f, -1.564712483e-04f, -2.353759082e-04f, -3.201968846e-04f, -3.990939388e-04f, -4.583040637e-04f, -4.846228261e-04f, -4.681429482e-04f, -4.046294158e-04f, -2.969416536e-04f, -1.551006323e-04f, +5.099007530e-06f, +1.646897470e-04f, +3.048100066e-04f, +4.099602091e-04f, +4.705408991e-04f, +4.841532882e-04f, +4.554410135e-04f, +3.945939739e-04f, +3.149320871e-04f, +2.301651496e-04f, +1.519461079e-04f, +8.820438069e-05f,
+ /* 24, 0 */ +3.721332452e-05f, -8.727351622e-06f, -1.260052743e-04f, -3.262895896e-04f, -5.956603662e-04f, -8.899501259e-04f, -1.140781305e-03f, -1.272347980e-03f, -1.224469676e-03f, -9.741728935e-04f, -5.476309302e-04f, -1.718639697e-05f, +5.165697336e-04f, +9.521355524e-04f, +1.214742061e-03f, +1.275075958e-03f, +1.153251370e-03f, +9.076938752e-04f, +6.139361451e-04f, +3.414081512e-04f, +1.360881127e-04f, +1.374767685e-05f, -3.597568203e-05f, -3.836441874e-05f,
+ /* 24, 1 */ +3.827272022e-05f, -3.990309212e-06f, -1.162552839e-04f, -3.114511951e-04f, -5.774902753e-04f, -8.720393210e-04f, -1.127840237e-03f, -1.268906542e-03f, -1.233389975e-03f, -9.955061195e-04f, -5.782766642e-04f, -5.154594549e-05f, +4.851159022e-04f, +9.294071718e-04f, +1.204207601e-03f, +1.277079499e-03f, +1.165232472e-03f, +9.252515980e-04f, +6.323029482e-04f, +3.567995352e-04f, +1.465038861e-04f, +1.905656402e-05f, -3.455261727e-05f, -3.906074609e-05f,
+ /* 24, 2 */ +3.916105537e-05f, +4.689475139e-07f, -1.068376458e-04f, -2.968998221e-04f, -5.594401371e-04f, -8.539803004e-04f, -1.114446367e-03f, -1.264763218e-03f, -1.241503276e-03f, -1.016122900e-03f, -6.084845647e-04f, -8.586577249e-05f, +4.532926958e-04f, +9.060015608e-04f, +1.192867560e-03f, +1.278348235e-03f, +1.176706916e-03f, +9.426042142e-04f, +6.507457252e-04f, +3.724559064e-04f, +1.572522637e-04f, +2.465906089e-05f, -3.293697730e-05f, -3.967556907e-05f,
+ /* 24, 3 */ +3.988551544e-05f, +4.656120273e-06f, -9.775146571e-05f, -2.826418349e-04f, -5.415238064e-04f, -8.357917522e-04f, -1.100618114e-03f, -1.259930153e-03f, -1.248810685e-03f, -1.036011659e-03f, -6.382327409e-04f, -1.201194461e-04f, +4.211237814e-04f, +8.819332498e-04f, +1.180724004e-03f, +1.278872430e-03f, +1.187657300e-03f, +9.597325558e-04f, +6.692490513e-04f, +3.883689407e-04f, +1.683324883e-04f, +3.055997058e-05f, -3.112164378e-05f, -4.020250110e-05f,
+ /* 24, 4 */ +4.045327387e-05f, +8.577101915e-06f, -8.899546026e-05f, -2.686831091e-04f, -5.237547173e-04f, -8.174921923e-04f, -1.086374092e-03f, -1.254420050e-03f, -1.255314082e-03f, -1.055161588e-03f, -6.674998060e-04f, -1.542806079e-04f, +3.886332072e-04f, +8.572174771e-04f, +1.167779798e-03f, +1.278642989e-03f, +1.198066533e-03f, +9.766173891e-04f, +6.877971412e-04f, +4.045298263e-04f, +1.797433681e-04f, +3.676383839e-05f, -2.909954521e-05f, -4.063504078e-05f,
+ /* 24, 5 */ +4.087148106e-05f, +1.223796294e-05f, -8.056796775e-05f, -2.550290329e-04f, -5.061458738e-04f, -7.990999447e-04f, -1.071733083e-03f, -1.248246148e-03f, -1.261016119e-03f, -1.073562648e-03f, -6.962648992e-04f, -1.883230024e-04f, +3.558453770e-04f, +8.318701747e-04f, +1.154038613e-03f, +1.277651484e-03f, +1.207917863e-03f, +9.932394374e-04f, +7.063738625e-04f, +4.209292660e-04f, +1.914832687e-04f, +4.327493877e-05f, -2.686366939e-05f, -4.096657950e-05f,
+ /* 24, 6 */ +4.114725367e-05f, +1.564493806e-05f, -7.246695886e-05f, -2.416845105e-04f, -4.887098400e-04f, -7.806331214e-04f, -1.056714015e-03f, -1.241422199e-03f, -1.265920211e-03f, -1.091205584e-03f, -7.245077077e-04f, -2.222205061e-04f, +3.227850234e-04f, +8.059079530e-04f, +1.139504920e-03f, +1.275890161e-03f, +1.217194897e-03f, +1.009579403e-03f, +7.249627509e-04f, +4.375574807e-04f, +2.035501057e-04f, +5.009726244e-05f, -2.440707607e-05f, -4.119040933e-05f,
+ /* 24, 7 */ +4.128766430e-05f, +1.880441272e-05f, -6.469004778e-05f, -2.286539641e-04f, -4.714587328e-04f, -7.621096041e-04f, -1.041335936e-03f, -1.233962452e-03f, -1.270030522e-03f, -1.108081926e-03f, -7.522084876e-04f, -2.559471563e-04f, +2.894771803e-04f, +7.793480846e-04f, +1.124183998e-03f, +1.273351959e-03f, +1.225881627e-03f, +1.025617992e-03f, +7.435470253e-04f, +4.544042133e-04f, +2.159413387e-04f, +5.723450367e-05f, -2.172290976e-05f, -4.129973134e-05f,
+ /* 24, 8 */ +4.129973134e-05f, +2.172290976e-05f, -5.723450367e-05f, -2.159413387e-04f, -4.544042133e-04f, -7.435470253e-04f, -1.025617992e-03f, -1.225881627e-03f, -1.273351959e-03f, -1.124183998e-03f, -7.793480846e-04f, -2.894771803e-04f, +2.559471563e-04f, +7.522084876e-04f, +1.108081926e-03f, +1.270030522e-03f, +1.233962452e-03f, +1.041335936e-03f, +7.621096041e-04f, +4.714587328e-04f, +2.286539641e-04f, +6.469004778e-05f, -1.880441272e-05f, -4.128766430e-05f,
+ /* 24, 9 */ +4.119040933e-05f, +2.440707607e-05f, -5.009726244e-05f, -2.035501057e-04f, -4.375574807e-04f, -7.249627509e-04f, -1.009579403e-03f, -1.217194897e-03f, -1.275890161e-03f, -1.139504920e-03f, -8.059079530e-04f, -3.227850234e-04f, +2.222205061e-04f, +7.245077077e-04f, +1.091205584e-03f, +1.265920211e-03f, +1.241422199e-03f, +1.056714015e-03f, +7.806331214e-04f, +4.887098400e-04f, +2.416845105e-04f, +7.246695886e-05f, -1.564493806e-05f, -4.114725367e-05f,
+ /* 24,10 */ +4.096657950e-05f, +2.686366939e-05f, -4.327493877e-05f, -1.914832687e-04f, -4.209292660e-04f, -7.063738625e-04f, -9.932394374e-04f, -1.207917863e-03f, -1.277651484e-03f, -1.154038613e-03f, -8.318701747e-04f, -3.558453770e-04f, +1.883230024e-04f, +6.962648992e-04f, +1.073562648e-03f, +1.261016119e-03f, +1.248246148e-03f, +1.071733083e-03f, +7.990999447e-04f, +5.061458738e-04f, +2.550290329e-04f, +8.056796775e-05f, -1.223796294e-05f, -4.087148106e-05f,
+ /* 24,11 */ +4.063504078e-05f, +2.909954521e-05f, -3.676383839e-05f, -1.797433681e-04f, -4.045298263e-04f, -6.877971412e-04f, -9.766173891e-04f, -1.198066533e-03f, -1.278642989e-03f, -1.167779798e-03f, -8.572174771e-04f, -3.886332072e-04f, +1.542806079e-04f, +6.674998060e-04f, +1.055161588e-03f, +1.255314082e-03f, +1.254420050e-03f, +1.086374092e-03f, +8.174921923e-04f, +5.237547173e-04f, +2.686831091e-04f, +8.899546026e-05f, -8.577101915e-06f, -4.045327387e-05f,
+ /* 24,12 */ +4.020250110e-05f, +3.112164378e-05f, -3.055997058e-05f, -1.683324883e-04f, -3.883689407e-04f, -6.692490513e-04f, -9.597325558e-04f, -1.187657300e-03f, -1.278872430e-03f, -1.180724004e-03f, -8.819332498e-04f, -4.211237814e-04f, +1.201194461e-04f, +6.382327409e-04f, +1.036011659e-03f, +1.248810685e-03f, +1.259930153e-03f, +1.100618114e-03f, +8.357917522e-04f, +5.415238064e-04f, +2.826418349e-04f, +9.775146571e-05f, -4.656120273e-06f, -3.988551544e-05f,
+ /* 24,13 */ +3.967556907e-05f, +3.293697730e-05f, -2.465906089e-05f, -1.572522637e-04f, -3.724559064e-04f, -6.507457252e-04f, -9.426042142e-04f, -1.176706916e-03f, -1.278348235e-03f, -1.192867560e-03f, -9.060015608e-04f, -4.532926958e-04f, +8.586577249e-05f, +6.084845647e-04f, +1.016122900e-03f, +1.241503276e-03f, +1.264763218e-03f, +1.114446367e-03f, +8.539803004e-04f, +5.594401371e-04f, +2.968998221e-04f, +1.068376458e-04f, -4.689475139e-07f, -3.916105537e-05f,
+ /* 24,14 */ +3.906074609e-05f, +3.455261727e-05f, -1.905656402e-05f, -1.465038861e-04f, -3.567995352e-04f, -6.323029482e-04f, -9.252515980e-04f, -1.165232472e-03f, -1.277079499e-03f, -1.204207601e-03f, -9.294071718e-04f, -4.851159022e-04f, +5.154594549e-05f, +5.782766642e-04f, +9.955061195e-04f, +1.233389975e-03f, +1.268906542e-03f, +1.127840237e-03f, +8.720393210e-04f, +5.774902753e-04f, +3.114511951e-04f, +1.162552839e-04f, +3.990309212e-06f, -3.827272022e-05f,
+ /* 24,15 */ +3.836441874e-05f, +3.597568203e-05f, -1.374767685e-05f, -1.360881127e-04f, -3.414081512e-04f, -6.139361451e-04f, -9.076938752e-04f, -1.153251370e-03f, -1.275075958e-03f, -1.214742061e-03f, -9.521355524e-04f, -5.165697336e-04f, +1.718639697e-05f, +5.476309302e-04f, +9.741728935e-04f, +1.224469676e-03f, +1.272347980e-03f, +1.140781305e-03f, +8.899501259e-04f, +5.956603662e-04f, +3.262895896e-04f, +1.260052743e-04f, +8.727351622e-06f, -3.721332452e-05f,
+ /* 24, 0 */ +8.266384897e-05f, +1.864042294e-04f, +2.488885336e-04f, +1.546439211e-04f, -1.995837972e-04f, -8.300120177e-04f, -1.613160849e-03f, -2.296673715e-03f, -2.585717258e-03f, -2.273475621e-03f, -1.352242686e-03f, -4.324968723e-05f, +1.278412578e-03f, +2.232544293e-03f, +2.585064833e-03f, +2.329165788e-03f, +1.661894649e-03f, +8.765619362e-04f, +2.314166150e-04f, -1.408802900e-04f, -2.488728147e-04f, -1.925779863e-04f, -8.867605644e-05f, -1.381647235e-05f,
+ /* 24, 1 */ +7.679604466e-05f, +1.800850086e-04f, +2.482891228e-04f, +1.673628145e-04f, -1.688781476e-04f, -7.841040553e-04f, -1.564053778e-03f, -2.262611362e-03f, -2.583952550e-03f, -2.311948888e-03f, -1.424504725e-03f, -1.296977982e-04f, +1.203096102e-03f, +2.189184288e-03f, +2.581965725e-03f, +2.360018674e-03f, +1.710180642e-03f, +9.237037585e-04f, +2.643640884e-04f, -1.260534627e-04f, -2.482108983e-04f, -1.985807152e-04f, -9.482163577e-05f, -1.700840565e-05f,
+ /* 24, 2 */ +7.108272573e-05f, +1.736451253e-04f, +2.471057735e-04f, +1.790568131e-04f, -1.393098721e-04f, -7.388859215e-04f, -1.514647192e-03f, -2.227049028e-03f, -2.579803518e-03f, -2.347938498e-03f, -1.495119547e-03f, -2.159922036e-04f, +1.126377386e-03f, +2.143428746e-03f, +2.576393731e-03f, +2.389164999e-03f, +1.757943642e-03f, +9.713853048e-04f, +2.984113695e-04f, -1.101464409e-04f, -2.468719141e-04f, -2.043861254e-04f, -1.010885985e-04f, -2.040687624e-05f,
+ /* 24, 3 */ +6.553303557e-05f, +1.671085856e-04f, +2.453697283e-04f, +1.897470664e-04f, -1.108869031e-04f, -6.944032625e-04f, -1.465013955e-03f, -2.190058265e-03f, -2.573306150e-03f, -2.381422658e-03f, -1.564010684e-03f, -3.020307159e-04f, +1.048342851e-03f, +2.095314540e-03f, +2.568326065e-03f, +2.416539054e-03f, +1.805107932e-03f, +1.019552324e-03f, +3.335412514e-04f, -9.314376077e-05f, -2.448252646e-04f, -2.099672379e-04f, -1.074639934e-04f, -2.401251277e-05f,
+ /* 24, 4 */ +6.015519126e-05f, +1.604985702e-04f, +2.431122111e-04f, +1.994559526e-04f, -8.361493575e-05f, -6.506994570e-04f, -1.415225919e-03f, -2.151711738e-03f, -2.564499518e-03f, -2.412383397e-03f, -1.631104459e-03f, -3.877115714e-04f, +9.690810727e-04f, +2.044882222e-03f, +2.557743429e-03f, +2.442076932e-03f, +1.851597394e-03f, +1.068148557e-03f, +3.697341485e-04f, -7.503156587e-05f, -2.420407013e-04f, -2.152964269e-04f, -1.139339030e-04f, -2.782526914e-05f,
+ /* 24, 5 */ +5.495649810e-05f, +1.538374078e-04f, +2.403643576e-04f, +2.082069988e-04f, -5.749746926e-05f, -6.078155802e-04f, -1.365353811e-03f, -2.112083086e-03f, -2.553425683e-03f, -2.440806561e-03f, -1.696330106e-03f, -4.729335981e-04f, +8.886826408e-04f, +1.992175989e-03f, +2.544630075e-03f, +2.465716661e-03f, +1.897335642e-03f, +1.117115802e-03f, +4.069680813e-04f, -5.579767803e-05f, -2.384884029e-04f, -2.203454641e-04f, -1.204834430e-04f, -3.184439496e-05f,
+ /* 24, 6 */ +4.994336610e-05f, +1.471465506e-04f, +2.371571498e-04f, +2.160248014e-04f, -3.253585139e-05f, -5.657903730e-04f, -1.315467130e-03f, -2.071246779e-03f, -2.540129593e-03f, -2.466681818e-03f, -1.759619871e-03f, -5.575963834e-04f, +8.072400133e-04f, +1.937243618e-03f, +2.528973864e-03f, +2.487398336e-03f, +1.942246152e-03f, +1.166393990e-03f, +4.452186667e-04f, -3.543166589e-05f, -2.341390536e-04f, -2.250855657e-04f, -1.270967638e-04f, -3.606840695e-05f,
+ /* 24, 7 */ +4.512132841e-05f, +1.404465535e-04f, +2.335213506e-04f, +2.229349451e-04f, -8.729326764e-06f, -5.246602166e-04f, -1.265634037e-03f, -2.029277978e-03f, -2.524658979e-03f, -2.490002646e-03f, -1.820909115e-03f, -6.416004392e-04f, +7.248473657e-04f, +1.880136408e-03f, +2.510766314e-03f, +2.507064240e-03f, +1.986252395e-03f, +1.215921259e-03f, +4.844591124e-04f, -1.392491133e-05f, -2.289639228e-04f, -2.294874421e-04f, -1.337570553e-04f, -4.049506149e-05f,
+ /* 24, 8 */ +4.049506149e-05f, +1.337570553e-04f, +2.294874421e-04f, +2.289639228e-04f, +1.392491133e-05f, -4.844591124e-04f, -1.215921259e-03f, -1.986252395e-03f, -2.507064240e-03f, -2.510766314e-03f, -1.880136408e-03f, -7.248473657e-04f, +6.416004392e-04f, +1.820909115e-03f, +2.490002646e-03f, +2.524658979e-03f, +2.029277978e-03f, +1.265634037e-03f, +5.246602166e-04f, +8.729326764e-06f, -2.229349451e-04f, -2.335213506e-04f, -1.404465535e-04f, -4.512132841e-05f,
+ /* 24, 9 */ +3.606840695e-05f, +1.270967638e-04f, +2.250855657e-04f, +2.341390536e-04f, +3.543166589e-05f, -4.452186667e-04f, -1.166393990e-03f, -1.942246152e-03f, -2.487398336e-03f, -2.528973864e-03f, -1.937243618e-03f, -8.072400133e-04f, +5.575963834e-04f, +1.759619871e-03f, +2.466681818e-03f, +2.540129593e-03f, +2.071246779e-03f, +1.315467130e-03f, +5.657903730e-04f, +3.253585139e-05f, -2.160248014e-04f, -2.371571498e-04f, -1.471465506e-04f, -4.994336610e-05f,
+ /* 24,10 */ +3.184439496e-05f, +1.204834430e-04f, +2.203454641e-04f, +2.384884029e-04f, +5.579767803e-05f, -4.069680813e-04f, -1.117115802e-03f, -1.897335642e-03f, -2.465716661e-03f, -2.544630075e-03f, -1.992175989e-03f, -8.886826408e-04f, +4.729335981e-04f, +1.696330106e-03f, +2.440806561e-03f, +2.553425683e-03f, +2.112083086e-03f, +1.365353811e-03f, +6.078155802e-04f, +5.749746926e-05f, -2.082069988e-04f, -2.403643576e-04f, -1.538374078e-04f, -5.495649810e-05f,
+ /* 24,11 */ +2.782526914e-05f, +1.139339030e-04f, +2.152964269e-04f, +2.420407013e-04f, +7.503156587e-05f, -3.697341485e-04f, -1.068148557e-03f, -1.851597394e-03f, -2.442076932e-03f, -2.557743429e-03f, -2.044882222e-03f, -9.690810727e-04f, +3.877115714e-04f, +1.631104459e-03f, +2.412383397e-03f, +2.564499518e-03f, +2.151711738e-03f, +1.415225919e-03f, +6.506994570e-04f, +8.361493575e-05f, -1.994559526e-04f, -2.431122111e-04f, -1.604985702e-04f, -6.015519126e-05f,
+ /* 24,12 */ +2.401251277e-05f, +1.074639934e-04f, +2.099672379e-04f, +2.448252646e-04f, +9.314376077e-05f, -3.335412514e-04f, -1.019552324e-03f, -1.805107932e-03f, -2.416539054e-03f, -2.568326065e-03f, -2.095314540e-03f, -1.048342851e-03f, +3.020307159e-04f, +1.564010684e-03f, +2.381422658e-03f, +2.573306150e-03f, +2.190058265e-03f, +1.465013955e-03f, +6.944032625e-04f, +1.108869031e-04f, -1.897470664e-04f, -2.453697283e-04f, -1.671085856e-04f, -6.553303557e-05f,
+ /* 24,13 */ +2.040687624e-05f, +1.010885985e-04f, +2.043861254e-04f, +2.468719141e-04f, +1.101464409e-04f, -2.984113695e-04f, -9.713853048e-04f, -1.757943642e-03f, -2.389164999e-03f, -2.576393731e-03f, -2.143428746e-03f, -1.126377386e-03f, +2.159922036e-04f, +1.495119547e-03f, +2.347938498e-03f, +2.579803518e-03f, +2.227049028e-03f, +1.514647192e-03f, +7.388859215e-04f, +1.393098721e-04f, -1.790568131e-04f, -2.471057735e-04f, -1.736451253e-04f, -7.108272573e-05f,
+ /* 24,14 */ +1.700840565e-05f, +9.482163577e-05f, +1.985807152e-04f, +2.482108983e-04f, +1.260534627e-04f, -2.643640884e-04f, -9.237037585e-04f, -1.710180642e-03f, -2.360018674e-03f, -2.581965725e-03f, -2.189184288e-03f, -1.203096102e-03f, +1.296977982e-04f, +1.424504725e-03f, +2.311948888e-03f, +2.583952550e-03f, +2.262611362e-03f, +1.564053778e-03f, +7.841040553e-04f, +1.688781476e-04f, -1.673628145e-04f, -2.482891228e-04f, -1.800850086e-04f, -7.679604466e-05f,
+ /* 24,15 */ +1.381647235e-05f, +8.867605644e-05f, +1.925779863e-04f, +2.488728147e-04f, +1.408802900e-04f, -2.314166150e-04f, -8.765619362e-04f, -1.661894649e-03f, -2.329165788e-03f, -2.585064833e-03f, -2.232544293e-03f, -1.278412578e-03f, +4.324968723e-05f, +1.352242686e-03f, +2.273475621e-03f, +2.585717258e-03f, +2.296673715e-03f, +1.613160849e-03f, +8.300120177e-04f, +1.995837972e-04f, -1.546439211e-04f, -2.488885336e-04f, -1.864042294e-04f, -8.266384897e-05f,
+ /* 24, 0 */ -8.756118778e-05f, -1.009631262e-05f, +2.499923290e-04f, +5.877223422e-04f, +6.788717735e-04f, +1.353208099e-04f, -1.181609893e-03f, -2.907631270e-03f, -4.227440709e-03f, -4.289302846e-03f, -2.753030129e-03f, -9.027467135e-05f, +2.610460208e-03f, +4.239433597e-03f, +4.275304929e-03f, +3.011836329e-03f, +1.284225967e-03f, -7.470693818e-05f, -6.668983668e-04f, -6.049037547e-04f, -2.711811033e-04f, -7.712041122e-07f, +8.724954076e-05f, +5.404595280e-05f,
+ /* 24, 1 */ -8.741655630e-05f, -2.019027119e-05f, +2.291878545e-04f, +5.696067266e-04f, +6.882827247e-04f, +1.927359117e-04f, -1.080756061e-03f, -2.801858302e-03f, -4.174485032e-03f, -4.332641998e-03f, -2.890980043e-03f, -2.706680808e-04f, +2.463494124e-03f, +4.183052585e-03f, +4.317905196e-03f, +3.114235078e-03f, +1.388440877e-03f, -1.091717027e-05f, -6.522789212e-04f, -6.210469572e-04f, -2.926973166e-04f, -1.241413728e-05f, +8.645224618e-05f, +5.751117153e-05f,
+ /* 24, 2 */ -8.684540791e-05f, -2.951540942e-05f, +2.088206066e-04f, +5.506594457e-04f, +6.952187414e-04f, +2.469379129e-04f, -9.818199274e-04f, -2.694754852e-03f, -4.116618896e-03f, -4.369446535e-03f, -3.024096686e-03f, -4.505940556e-04f, +2.312365817e-03f, +4.120192033e-03f, +4.355078033e-03f, +3.214588722e-03f, +1.494083528e-03f, +5.601692583e-05f, -6.349341530e-04f, -6.360467505e-04f, -3.144802134e-04f, -2.483132916e-05f, +8.514047439e-05f, +6.091502927e-05f,
+ /* 24, 3 */ -8.587775422e-05f, -3.807920270e-05f, +1.889395528e-04f, +5.309813040e-04f, +6.997709178e-04f, +2.979208532e-04f, -8.849487633e-04f, -2.586556795e-03f, -4.054031257e-03f, -4.399725659e-03f, -3.152177828e-03f, -6.297421881e-04f, +2.157318805e-03f, +4.050898074e-03f, +4.386669491e-03f, +3.312658663e-03f, +1.600975431e-03f, +1.260549593e-04f, -6.147894349e-04f, -6.497970322e-04f, -3.364651980e-04f, -3.801847602e-05f, +8.328608571e-05f, +6.423360450e-05f,
+ /* 24, 4 */ -8.454371894e-05f, -4.589171696e-05f, +1.695896910e-04f, +5.106711213e-04f, +7.020335552e-04f, +3.456869501e-04f, -7.902814402e-04f, -2.477497901e-03f, -3.986918477e-03f, -4.423502152e-03f, -3.275032702e-03f, -8.078038906e-04f, +1.998605647e-03f, +3.975230752e-03f, +4.412535626e-03f, +3.408207107e-03f, +1.708931018e-03f, +1.991476106e-04f, -5.917751493e-04f, -6.621910968e-04f, -3.585839047e-04f, -5.196800512e-05f, +8.086178430e-05f, +6.744196867e-05f,
+ /* 24, 5 */ -8.287340509e-05f, -5.296545744e-05f, +1.508120534e-04f, +4.898254962e-04f, +7.021037953e-04f, +3.902463858e-04f, -6.979482496e-04f, -2.367809282e-03f, -3.915483754e-03f, -4.440812209e-03f, -3.392482395e-03f, -9.844731162e-04f, +1.836487379e-03f, +3.893263974e-03f, +4.432542967e-03f, +3.500997660e-03f, +1.817757983e-03f, +2.752365501e-04f, -5.658270331e-04f, -6.731219472e-04f, -3.807642824e-04f, -6.666895953e-05f, +7.784127492e-05f, +7.051425394e-05f,
+ /* 24, 6 */ -8.089676755e-05f, -5.931521393e-05f, +1.326437227e-04f, +4.685385820e-04f, +7.000812546e-04f, +4.316170765e-04f, -6.080707472e-04f, -2.257718867e-03f, -3.839936544e-03f, -4.451705229e-03f, -3.504360214e-03f, -1.159447072e-03f, +1.671232927e-03f, +3.805085432e-03f, +4.446568950e-03f, +3.590795947e-03f, +1.927257648e-03f, +3.542543807e-04f, -5.368865161e-04f, -6.824826149e-04f, -4.029306956e-04f, -8.210689127e-05f, +7.419942176e-05f, +7.342372810e-05f,
+ /* 24, 7 */ -7.864349144e-05f, -6.495790319e-05f, +1.151178633e-04f, +4.469018792e-04f, +6.960676605e-04f, +4.698244236e-04f, -5.207616239e-04f, -2.147450881e-03f, -3.760491970e-03f, -4.456243581e-03f, -3.610512013e-03f, -1.332426925e-03f, +1.503118492e-03f, +3.710796487e-03f, +4.454502333e-03f, +3.677370219e-03f, +2.037225356e-03f, +4.361246060e-04f, -5.049010493e-04f, -6.901664903e-04f, -4.250040411e-04f, -9.826376366e-05f, +6.991240915e-05f, +7.614287656e-05f,
+ /* 24, 8 */ -7.614287656e-05f, -6.991240915e-05f, +9.826376366e-05f, +4.250040411e-04f, +6.901664903e-04f, +5.049010493e-04f, -4.361246060e-04f, -2.037225356e-03f, -3.677370219e-03f, -4.454502333e-03f, -3.710796487e-03f, -1.503118492e-03f, +1.332426925e-03f, +3.610512013e-03f, +4.456243581e-03f, +3.760491970e-03f, +2.147450881e-03f, +5.207616239e-04f, -4.698244236e-04f, -6.960676605e-04f, -4.469018792e-04f, -1.151178633e-04f, +6.495790319e-05f, +7.864349144e-05f,
+ /* 24, 9 */ -7.342372810e-05f, -7.419942176e-05f, +8.210689127e-05f, +4.029306956e-04f, +6.824826149e-04f, +5.368865161e-04f, -3.542543807e-04f, -1.927257648e-03f, -3.590795947e-03f, -4.446568950e-03f, -3.805085432e-03f, -1.671232927e-03f, +1.159447072e-03f, +3.504360214e-03f, +4.451705229e-03f, +3.839936544e-03f, +2.257718867e-03f, +6.080707472e-04f, -4.316170765e-04f, -7.000812546e-04f, -4.685385820e-04f, -1.326437227e-04f, +5.931521393e-05f, +8.089676755e-05f,
+ /* 24,10 */ -7.051425394e-05f, -7.784127492e-05f, +6.666895953e-05f, +3.807642824e-04f, +6.731219472e-04f, +5.658270331e-04f, -2.752365501e-04f, -1.817757983e-03f, -3.500997660e-03f, -4.432542967e-03f, -3.893263974e-03f, -1.836487379e-03f, +9.844731162e-04f, +3.392482395e-03f, +4.440812209e-03f, +3.915483754e-03f, +2.367809282e-03f, +6.979482496e-04f, -3.902463858e-04f, -7.021037953e-04f, -4.898254962e-04f, -1.508120534e-04f, +5.296545744e-05f, +8.287340509e-05f,
+ /* 24,11 */ -6.744196867e-05f, -8.086178430e-05f, +5.196800512e-05f, +3.585839047e-04f, +6.621910968e-04f, +5.917751493e-04f, -1.991476106e-04f, -1.708931018e-03f, -3.408207107e-03f, -4.412535626e-03f, -3.975230752e-03f, -1.998605647e-03f, +8.078038906e-04f, +3.275032702e-03f, +4.423502152e-03f, +3.986918477e-03f, +2.477497901e-03f, +7.902814402e-04f, -3.456869501e-04f, -7.020335552e-04f, -5.106711213e-04f, -1.695896910e-04f, +4.589171696e-05f, +8.454371894e-05f,
+ /* 24,12 */ -6.423360450e-05f, -8.328608571e-05f, +3.801847602e-05f, +3.364651980e-04f, +6.497970322e-04f, +6.147894349e-04f, -1.260549593e-04f, -1.600975431e-03f, -3.312658663e-03f, -4.386669491e-03f, -4.050898074e-03f, -2.157318805e-03f, +6.297421881e-04f, +3.152177828e-03f, +4.399725659e-03f, +4.054031257e-03f, +2.586556795e-03f, +8.849487633e-04f, -2.979208532e-04f, -6.997709178e-04f, -5.309813040e-04f, -1.889395528e-04f, +3.807920270e-05f, +8.587775422e-05f,
+ /* 24,13 */ -6.091502927e-05f, -8.514047439e-05f, +2.483132916e-05f, +3.144802134e-04f, +6.360467505e-04f, +6.349341530e-04f, -5.601692583e-05f, -1.494083528e-03f, -3.214588722e-03f, -4.355078033e-03f, -4.120192033e-03f, -2.312365817e-03f, +4.505940556e-04f, +3.024096686e-03f, +4.369446535e-03f, +4.116618896e-03f, +2.694754852e-03f, +9.818199274e-04f, -2.469379129e-04f, -6.952187414e-04f, -5.506594457e-04f, -2.088206066e-04f, +2.951540942e-05f, +8.684540791e-05f,
+ /* 24,14 */ -5.751117153e-05f, -8.645224618e-05f, +1.241413728e-05f, +2.926973166e-04f, +6.210469572e-04f, +6.522789212e-04f, +1.091717027e-05f, -1.388440877e-03f, -3.114235078e-03f, -4.317905196e-03f, -4.183052585e-03f, -2.463494124e-03f, +2.706680808e-04f, +2.890980043e-03f, +4.332641998e-03f, +4.174485032e-03f, +2.801858302e-03f, +1.080756061e-03f, -1.927359117e-04f, -6.882827247e-04f, -5.696067266e-04f, -2.291878545e-04f, +2.019027119e-05f, +8.741655630e-05f,
+ /* 24,15 */ -5.404595280e-05f, -8.724954076e-05f, +7.712041122e-07f, +2.711811033e-04f, +6.049037547e-04f, +6.668983668e-04f, +7.470693818e-05f, -1.284225967e-03f, -3.011836329e-03f, -4.275304929e-03f, -4.239433597e-03f, -2.610460208e-03f, +9.027467135e-05f, +2.753030129e-03f, +4.289302846e-03f, +4.227440709e-03f, +2.907631270e-03f, +1.181609893e-03f, -1.353208099e-04f, -6.788717735e-04f, -5.877223422e-04f, -2.499923290e-04f, +1.009631262e-05f, +8.756118778e-05f,
+ /* 24, 0 */ -4.836862817e-05f, -2.381906908e-04f, -2.861422699e-04f, +1.419765781e-04f, +9.779307384e-04f, +1.431118485e-03f, +4.239072727e-04f, -2.320049614e-03f, -5.516524807e-03f, -6.885468951e-03f, -4.882970050e-03f, -1.652445539e-04f, +4.647640808e-03f, +6.864975932e-03f, +5.679465803e-03f, +2.528057977e-03f, -2.982544427e-04f, -1.420326139e-03f, -1.029081461e-03f, -1.868092348e-04f, +2.758007186e-04f, +2.491702023e-04f, +5.836581816e-05f, -3.491105347e-05f,
+ /* 24, 1 */ -3.887878147e-05f, -2.267040256e-04f, -2.944876029e-04f, +9.900949096e-05f, +9.254138922e-04f, +1.435932770e-03f, +5.422031866e-04f, -2.114193296e-03f, -5.346195092e-03f, -6.891993065e-03f, -5.106971374e-03f, -4.953359135e-04f, +4.401480442e-03f, +6.830374341e-03f, +5.834433801e-03f, +2.737690485e-03f, -1.653667139e-04f, -1.403322383e-03f, -1.078579553e-03f, -2.333982604e-04f, +2.633988510e-04f, +2.595470071e-04f, +6.884149383e-05f, -3.317859772e-05f,
+ /* 24, 2 */ -2.992041863e-05f, -2.148033017e-04f, -3.009073041e-04f, +5.800387728e-05f, +8.718108917e-04f, +1.435015360e-03f, +6.530479478e-04f, -1.910998057e-03f, -5.169072824e-03f, -6.884726614e-03f, -5.319183002e-03f, -8.242352929e-04f, +4.145019341e-03f, +6.781564023e-03f, +5.980858542e-03f, +2.948401826e-03f, -2.539414214e-05f, -1.379888189e-03f, -1.126132932e-03f, -2.816211011e-04f, +2.488796810e-04f, +2.692234993e-04f, +7.976200316e-05f, -3.095924021e-05f,
+ /* 24, 3 */ -2.151306397e-05f, -2.025787804e-04f, -3.054778181e-04f, +1.904245883e-05f, +8.173942695e-04f, +1.428624316e-03f, +7.563747429e-04f, -1.710952703e-03f, -4.985763915e-03f, -6.863885651e-03f, -5.519179462e-03f, -1.151152247e-03f, +3.878819947e-03f, +6.718485032e-03f, +6.118185890e-03f, +3.159630822e-03f, +1.214850236e-04f, -1.349820125e-03f, -1.171444944e-03f, -3.313418525e-04f, +2.321939470e-04f, +2.781004545e-04f, +9.108884721e-05f, -2.823129406e-05f,
+ /* 24, 4 */ -1.367174826e-05f, -1.901175448e-04f, -3.082808136e-04f, -1.780505549e-05f, +7.624282793e-04f, +1.417028061e-03f, +8.521437270e-04f, -1.514524553e-03f, -4.796881865e-03f, -6.829722854e-03f, -5.706572744e-03f, -1.475302628e-03f, +3.603475092e-03f, +6.641118197e-03f, +6.245879909e-03f, +3.370802059e-03f, +2.750642929e-04f, -1.312931609e-03f, -1.214215433e-03f, -3.824113238e-04f, +2.133007109e-04f, +2.860774924e-04f, +1.027786538e-04f, -2.497524656e-05f,
+ /* 24, 5 */ -6.407151783e-06f, -1.775031866e-04f, -3.094025487e-04f, -5.248174754e-05f, +7.071681142e-04f, +1.400504044e-03f, +9.403414758e-04f, -1.322158275e-03f, -4.603045619e-03f, -6.782526316e-03f, -5.881013326e-03f, -1.795911068e-03f, +3.319606230e-03f, +6.549485546e-03f, +6.363424898e-03f, +3.581327596e-03f, +4.351089927e-04f, -1.269054120e-03f, -1.254141844e-03f, -4.346671648e-04f, +1.921679399e-04f, +2.930535649e-04f, +1.147831783e-04f, -2.117401174e-05f,
+ /* 24, 6 */ +2.742338831e-07f, -1.648155254e-04f, -3.089332390e-04f, -8.494321776e-05f, +6.518591895e-04f, +1.379337399e-03f, +1.020980349e-03f, -1.134274832e-03f, -4.404877423e-03f, -6.722618231e-03f, -6.042191052e-03f, -2.112213435e-03f, +3.027861551e-03f, +6.443650588e-03f, +6.470327373e-03f, +3.790608755e-03f, +6.013564365e-04f, -1.218038367e-03f, -1.290920380e-03f, -4.879340571e-04f, +1.687730668e-04f, +2.989274696e-04f, +1.270493337e-04f, -1.681317980e-05f,
+ /* 24, 7 */ +6.369927035e-06f, -1.521303593e-04f, -3.069664313e-04f, -1.151572658e-04f, +5.967364879e-04f, +1.353819611e-03f, +1.094097769e-03f, -9.512705360e-04f, -4.203000702e-03f, -6.650353458e-03f, -6.189835876e-03f, -2.423459243e-03f, +2.728914008e-03f, +6.323718452e-03f, +6.566118000e-03f, +3.998037969e-03f, +7.735162047e-04f, -1.159755419e-03f, -1.324247193e-03f, -5.420239710e-04f, +1.431035268e-04f, +3.035983857e-04f, +1.395192491e-04f, -1.188126168e-05f,
+ /* 24, 8 */ +1.188126168e-05f, -1.395192491e-04f, -3.035983857e-04f, -1.431035268e-04f, +5.420239710e-04f, +1.324247193e-03f, +1.159755419e-03f, -7.735162047e-04f, -3.998037969e-03f, -6.566118000e-03f, -6.323718452e-03f, -2.728914008e-03f, +2.423459243e-03f, +6.189835876e-03f, +6.650353458e-03f, +4.203000702e-03f, +9.512705360e-04f, -1.094097769e-03f, -1.353819611e-03f, -5.967364879e-04f, +1.151572658e-04f, +3.069664313e-04f, +1.521303593e-04f, -6.369927035e-06f,
+ /* 24, 9 */ +1.681317980e-05f, -1.270493337e-04f, -2.989274696e-04f, -1.687730668e-04f, +4.879340571e-04f, +1.290920380e-03f, +1.218038367e-03f, -6.013564365e-04f, -3.790608755e-03f, -6.470327373e-03f, -6.443650588e-03f, -3.027861551e-03f, +2.112213435e-03f, +6.042191052e-03f, +6.722618231e-03f, +4.404877423e-03f, +1.134274832e-03f, -1.020980349e-03f, -1.379337399e-03f, -6.518591895e-04f, +8.494321776e-05f, +3.089332390e-04f, +1.648155254e-04f, -2.742338831e-07f,
+ /* 24,10 */ +2.117401174e-05f, -1.147831783e-04f, -2.930535649e-04f, -1.921679399e-04f, +4.346671648e-04f, +1.254141844e-03f, +1.269054120e-03f, -4.351089927e-04f, -3.581327596e-03f, -6.363424898e-03f, -6.549485546e-03f, -3.319606230e-03f, +1.795911068e-03f, +5.881013326e-03f, +6.782526316e-03f, +4.603045619e-03f, +1.322158275e-03f, -9.403414758e-04f, -1.400504044e-03f, -7.071681142e-04f, +5.248174754e-05f, +3.094025487e-04f, +1.775031866e-04f, +6.407151783e-06f,
+ /* 24,11 */ +2.497524656e-05f, -1.027786538e-04f, -2.860774924e-04f, -2.133007109e-04f, +3.824113238e-04f, +1.214215433e-03f, +1.312931609e-03f, -2.750642929e-04f, -3.370802059e-03f, -6.245879909e-03f, -6.641118197e-03f, -3.603475092e-03f, +1.475302628e-03f, +5.706572744e-03f, +6.829722854e-03f, +4.796881865e-03f, +1.514524553e-03f, -8.521437270e-04f, -1.417028061e-03f, -7.624282793e-04f, +1.780505549e-05f, +3.082808136e-04f, +1.901175448e-04f, +1.367174826e-05f,
+ /* 24,12 */ +2.823129406e-05f, -9.108884721e-05f, -2.781004545e-04f, -2.321939470e-04f, +3.313418525e-04f, +1.171444944e-03f, +1.349820125e-03f, -1.214850236e-04f, -3.159630822e-03f, -6.118185890e-03f, -6.718485032e-03f, -3.878819947e-03f, +1.151152247e-03f, +5.519179462e-03f, +6.863885651e-03f, +4.985763915e-03f, +1.710952703e-03f, -7.563747429e-04f, -1.428624316e-03f, -8.173942695e-04f, -1.904245883e-05f, +3.054778181e-04f, +2.025787804e-04f, +2.151306397e-05f,
+ /* 24,13 */ +3.095924021e-05f, -7.976200316e-05f, -2.692234993e-04f, -2.488796810e-04f, +2.816211011e-04f, +1.126132932e-03f, +1.379888189e-03f, +2.539414214e-05f, -2.948401826e-03f, -5.980858542e-03f, -6.781564023e-03f, -4.145019341e-03f, +8.242352929e-04f, +5.319183002e-03f, +6.884726614e-03f, +5.169072824e-03f, +1.910998057e-03f, -6.530479478e-04f, -1.435015360e-03f, -8.718108917e-04f, -5.800387728e-05f, +3.009073041e-04f, +2.148033017e-04f, +2.992041863e-05f,
+ /* 24,14 */ +3.317859772e-05f, -6.884149383e-05f, -2.595470071e-04f, -2.633988510e-04f, +2.333982604e-04f, +1.078579553e-03f, +1.403322383e-03f, +1.653667139e-04f, -2.737690485e-03f, -5.834433801e-03f, -6.830374341e-03f, -4.401480442e-03f, +4.953359135e-04f, +5.106971374e-03f, +6.891993065e-03f, +5.346195092e-03f, +2.114193296e-03f, -5.422031866e-04f, -1.435932770e-03f, -9.254138922e-04f, -9.900949096e-05f, +2.944876029e-04f, +2.267040256e-04f, +3.887878147e-05f,
+ /* 24,15 */ +3.491105347e-05f, -5.836581816e-05f, -2.491702023e-04f, -2.758007186e-04f, +1.868092348e-04f, +1.029081461e-03f, +1.420326139e-03f, +2.982544427e-04f, -2.528057977e-03f, -5.679465803e-03f, -6.864975932e-03f, -4.647640808e-03f, +1.652445539e-04f, +4.882970050e-03f, +6.885468951e-03f, +5.516524807e-03f, +2.320049614e-03f, -4.239072727e-04f, -1.431118485e-03f, -9.779307384e-04f, -1.419765781e-04f, +2.861422699e-04f, +2.381906908e-04f, +4.836862817e-05f,
+ /* 24, 0 */ +1.364396009e-04f, +7.446376994e-05f, -3.699603221e-04f, -7.278325124e-04f, -5.051635567e-05f, +1.645033952e-03f, +2.378022613e-03f, -2.243714932e-04f, -5.680096534e-03f, -9.704626250e-03f, -7.823014841e-03f, -2.751390883e-04f, +7.480820734e-03f, +9.788905453e-03f, +6.030582333e-03f, +5.101196376e-04f, -2.328731157e-03f, -1.748114996e-03f, -3.640531891e-05f, +7.242350145e-04f, +4.042879967e-04f, -5.742334247e-05f, -1.414906982e-04f, -2.710774794e-05f,
+ /* 24, 1 */ +1.307026563e-04f, +8.975162518e-05f, -3.355241044e-04f, -7.270603554e-04f, -1.326866063e-04f, +1.538422151e-03f, +2.413247311e-03f, +4.875121157e-05f, -5.324161431e-03f, -9.595517291e-03f, -8.141086512e-03f, -8.245287223e-04f, +7.115425083e-03f, +9.847646625e-03f, +6.374200107e-03f, +8.077901021e-04f, -2.264974711e-03f, -1.846937004e-03f, -1.278166248e-04f, +7.160485626e-04f, +4.382702758e-04f, -3.863673145e-05f, -1.457592711e-04f, -3.374854096e-05f,
+ /* 24, 2 */ +1.243758393e-04f, +1.032931784e-04f, -3.012044148e-04f, -7.221532843e-04f, -2.098818030e-04f, +1.428995714e-03f, +2.434853697e-03f, +3.086181402e-04f, -4.964188024e-03f, -9.462372525e-03f, -8.434212217e-03f, -1.371256439e-03f, +6.727842835e-03f, +9.880231223e-03f, +6.709529590e-03f, +1.116608515e-03f, -2.186408722e-03f, -1.940762958e-03f, -2.234175210e-04f, +7.030713845e-04f, +4.716595396e-04f, -1.812362539e-05f, -1.491486840e-04f, -4.073257728e-05f,
+ /* 24, 3 */ +1.175537217e-04f, +1.151066589e-04f, -2.672136493e-04f, -7.133593846e-04f, -2.819161814e-04f, +1.317455363e-03f, +2.443336794e-03f, +5.546728855e-04f, -4.601573558e-03f, -9.306067159e-03f, -8.701668636e-03f, -1.913559980e-03f, +6.319179241e-03f, +9.886134123e-03f, +7.035155238e-03f, +1.435731166e-03f, -2.092745601e-03f, -2.028850662e-03f, -3.228698520e-04f, +6.851212972e-04f, +5.041985339e-04f, +4.082412249e-06f, -1.515631236e-04f, -4.801831197e-05f,
+ /* 24, 4 */ +1.103288160e-04f, +1.252215041e-04f, -2.337507561e-04f, -7.009379926e-04f, -3.486413414e-04f, +1.204483360e-03f, +2.439234434e-03f, +7.864337317e-04f, -4.237695644e-03f, -9.127552920e-03f, -8.942835031e-03f, -2.449695551e-03f, +5.890625670e-03f, +9.864926907e-03f, +7.349672574e-03f, +1.764247300e-03f, -1.983757790e-03f, -2.110456450e-03f, -4.257977068e-04f, +6.620377298e-04f, +5.356216172e-04f, +2.793344097e-05f, -1.529084143e-04f, -5.555842361e-05f,
+ /* 24, 5 */ +1.027909684e-04f, +1.336775649e-04f, -2.010005851e-04f, -6.851576168e-04f, -4.099455518e-04f, +1.090740633e-03f, +2.423123355e-03f, +1.003494037e-03f, -3.873906570e-03f, -8.927853008e-03f, -9.157195135e-03f, -2.977945083e-03f, +5.443455012e-03f, +9.816280735e-03f, +7.651694576e-03f, +2.101181791e-03f, -1.859280606e-03f, -2.184839011e-03f, -5.317880090e-04f, +6.336836952e-04f, +5.656561208e-04f, +5.336672075e-05f, -1.530928622e-04f, -6.329988035e-05f,
+ /* 24, 6 */ +9.502680145e-05f, +1.405242734e-04f, -1.691333585e-04f, -6.662938873e-04f, -4.657528710e-04f, +9.768641187e-04f, +2.395615219e-03f, +1.205522243e-03f, -3.511527821e-03f, -8.708056786e-03f, -9.344338564e-03f, -3.496623369e-03f, +4.979016698e-03f, +9.739968779e-03f, +7.939858067e-03f, +2.445498177e-03f, -1.719214825e-03f, -2.251263312e-03f, -6.403913399e-04f, +5.999476948e-04f, +5.940238143e-04f, +8.030437567e-05f, -1.520281231e-04f, -7.118405837e-05f,
+ /* 24, 7 */ +8.711921055e-05f, +1.458197836e-04f, -1.383042613e-04f, -6.446275435e-04f, -5.160220948e-04f, +8.634643034e-04f, +2.357352548e-03f, +1.392261511e-03f, -3.151844842e-03f, -8.469314215e-03f, -9.503961719e-03f, -4.004085039e-03f, +4.498731341e-03f, +9.635868210e-03f, +8.212830089e-03f, +2.796102059e-03f, -1.563529005e-03f, -2.309004616e-03f, -7.511229995e-04f, +5.607455425e-04f, +6.204424737e-04f, +1.086531499e-04f, -1.496300883e-04f, -7.914691395e-05f,
+ /* 24, 8 */ +7.914691395e-05f, +1.496300883e-04f, -1.086531499e-04f, -6.204424737e-04f, -5.607455425e-04f, +7.511229995e-04f, +2.309004616e-03f, +1.563529005e-03f, -2.796102059e-03f, -8.212830089e-03f, -9.635868210e-03f, -4.498731341e-03f, +4.004085039e-03f, +9.503961719e-03f, +8.469314215e-03f, +3.151844842e-03f, -1.392261511e-03f, -2.357352548e-03f, -8.634643034e-04f, +5.160220948e-04f, +6.446275435e-04f, +1.383042613e-04f, -1.458197836e-04f, -8.711921055e-05f,
+ /* 24, 9 */ +7.118405837e-05f, +1.520281231e-04f, -8.030437567e-05f, -5.940238143e-04f, -5.999476948e-04f, +6.403913399e-04f, +2.251263312e-03f, +1.719214825e-03f, -2.445498177e-03f, -7.939858067e-03f, -9.739968779e-03f, -4.979016698e-03f, +3.496623369e-03f, +9.344338564e-03f, +8.708056786e-03f, +3.511527821e-03f, -1.205522243e-03f, -2.395615219e-03f, -9.768641187e-04f, +4.657528710e-04f, +6.662938873e-04f, +1.691333585e-04f, -1.405242734e-04f, -9.502680145e-05f,
+ /* 24,10 */ +6.329988035e-05f, +1.530928622e-04f, -5.336672075e-05f, -5.656561208e-04f, -6.336836952e-04f, +5.317880090e-04f, +2.184839011e-03f, +1.859280606e-03f, -2.101181791e-03f, -7.651694576e-03f, -9.816280735e-03f, -5.443455012e-03f, +2.977945083e-03f, +9.157195135e-03f, +8.927853008e-03f, +3.873906570e-03f, -1.003494037e-03f, -2.423123355e-03f, -1.090740633e-03f, +4.099455518e-04f, +6.851576168e-04f, +2.010005851e-04f, -1.336775649e-04f, -1.027909684e-04f,
+ /* 24,11 */ +5.555842361e-05f, +1.529084143e-04f, -2.793344097e-05f, -5.356216172e-04f, -6.620377298e-04f, +4.257977068e-04f, +2.110456450e-03f, +1.983757790e-03f, -1.764247300e-03f, -7.349672574e-03f, -9.864926907e-03f, -5.890625670e-03f, +2.449695551e-03f, +8.942835031e-03f, +9.127552920e-03f, +4.237695644e-03f, -7.864337317e-04f, -2.439234434e-03f, -1.204483360e-03f, +3.486413414e-04f, +7.009379926e-04f, +2.337507561e-04f, -1.252215041e-04f, -1.103288160e-04f,
+ /* 24,12 */ +4.801831197e-05f, +1.515631236e-04f, -4.082412249e-06f, -5.041985339e-04f, -6.851212972e-04f, +3.228698520e-04f, +2.028850662e-03f, +2.092745601e-03f, -1.435731166e-03f, -7.035155238e-03f, -9.886134123e-03f, -6.319179241e-03f, +1.913559980e-03f, +8.701668636e-03f, +9.306067159e-03f, +4.601573558e-03f, -5.546728855e-04f, -2.443336794e-03f, -1.317455363e-03f, +2.819161814e-04f, +7.133593846e-04f, +2.672136493e-04f, -1.151066589e-04f, -1.175537217e-04f,
+ /* 24,13 */ +4.073257728e-05f, +1.491486840e-04f, +1.812362539e-05f, -4.716595396e-04f, -7.030713845e-04f, +2.234175210e-04f, +1.940762958e-03f, +2.186408722e-03f, -1.116608515e-03f, -6.709529590e-03f, -9.880231223e-03f, -6.727842835e-03f, +1.371256439e-03f, +8.434212217e-03f, +9.462372525e-03f, +4.964188024e-03f, -3.086181402e-04f, -2.434853697e-03f, -1.428995714e-03f, +2.098818030e-04f, +7.221532843e-04f, +3.012044148e-04f, -1.032931784e-04f, -1.243758393e-04f,
+ /* 24,14 */ +3.374854096e-05f, +1.457592711e-04f, +3.863673145e-05f, -4.382702758e-04f, -7.160485626e-04f, +1.278166248e-04f, +1.846937004e-03f, +2.264974711e-03f, -8.077901021e-04f, -6.374200107e-03f, -9.847646625e-03f, -7.115425083e-03f, +8.245287223e-04f, +8.141086512e-03f, +9.595517291e-03f, +5.324161431e-03f, -4.875121157e-05f, -2.413247311e-03f, -1.538422151e-03f, +1.326866063e-04f, +7.270603554e-04f, +3.355241044e-04f, -8.975162518e-05f, -1.307026563e-04f,
+ /* 24,15 */ +2.710774794e-05f, +1.414906982e-04f, +5.742334247e-05f, -4.042879967e-04f, -7.242350145e-04f, +3.640531891e-05f, +1.748114996e-03f, +2.328731157e-03f, -5.101196376e-04f, -6.030582333e-03f, -9.788905453e-03f, -7.480820734e-03f, +2.751390883e-04f, +7.823014841e-03f, +9.704626250e-03f, +5.680096534e-03f, +2.243714932e-04f, -2.378022613e-03f, -1.645033952e-03f, +5.051635567e-05f, +7.278325124e-04f, +3.699603221e-04f, -7.446376994e-05f, -1.364396009e-04f,
+ /* 20, 0 */ +1.366654441e-04f, -5.248309364e-04f, -9.559425272e-04f, +4.495080153e-04f, +2.846407623e-03f, +1.989454068e-03f, -4.491151594e-03f, -1.156100448e-02f, -1.065698581e-02f, -3.895768346e-04f, +1.023895907e-02f, +1.180960294e-02f, +5.007407400e-03f, -1.738511442e-03f, -2.938517986e-03f, -6.019203323e-04f, +9.329195550e-04f, +5.763302237e-04f, -1.134902041e-04f, -1.824770389e-04f,
+ /* 20, 1 */ +1.568890194e-04f, -4.728495798e-04f, -9.708996289e-04f, +3.024354413e-04f, +2.741035078e-03f, +2.215509786e-03f, -3.978754642e-03f, -1.127853170e-02f, -1.103432131e-02f, -1.167153605e-03f, +9.781544627e-03f, +1.202253469e-02f, +5.525210549e-03f, -1.462933465e-03f, -3.016077094e-03f, -7.588827792e-04f, +9.015285321e-04f, +6.268920900e-04f, -8.735502929e-05f, -1.921860197e-04f,
+ /* 20, 2 */ +1.741940978e-04f, -4.208194393e-04f, -9.781360984e-04f, +1.614183836e-04f, +2.623714429e-03f, +2.416571115e-03f, -3.472449249e-03f, -1.096411041e-02f, -1.136986548e-02f, -1.940007910e-03f, +9.286243980e-03f, +1.219815240e-02f, +6.042182027e-03f, -1.163118517e-03f, -3.077830056e-03f, -9.195341683e-04f, +8.615147935e-04f, +6.760417132e-04f, -5.827810709e-05f, -2.008073985e-04f,
+ /* 20, 3 */ +1.886370492e-04f, -3.691494362e-04f, -9.780356474e-04f, +2.709710175e-05f, +2.495775707e-03f, +2.592671089e-03f, -2.974378699e-03f, -1.061978749e-02f, -1.166272581e-02f, -2.705018824e-03f, +8.754750074e-03f, +1.233496472e-02f, +6.555887236e-03f, -8.396136973e-04f, -3.122565398e-03f, -1.082944596e-03f, +8.126754773e-04f, +7.232876858e-04f, -2.630548656e-05f, -2.081598890e-04f,
+ /* 20, 4 */ +2.002956356e-04f, -3.182221327e-04f, -9.710157868e-04f, -9.996474913e-05f, +2.358556029e-03f, +2.743978910e-03f, -2.486586970e-03f, -1.024771819e-02f, -1.191222039e-02f, -3.459106327e-03f, +8.188939591e-03f, +1.243164652e-02f, +7.063848473e-03f, -4.931158341e-04f, -3.149124311e-03f, -1.248118895e-03f, +7.548636055e-04f, +7.681251779e-04f, +8.487693398e-06f, -2.140618814e-04f,
+ /* 20, 5 */ +2.092671085e-04f, -2.683920446e-04f, -9.575231021e-04f, -2.192806382e-04f, +2.213390969e-03f, +2.870794883e-03f, -2.011009640e-03f, -9.850152742e-03f, -1.211787969e-02f, -4.199247312e-03f, +7.590864160e-03f, +1.248704815e-02f, +7.563557889e-03f, -1.244715801e-04f, -3.156409832e-03f, -1.414000676e-03f, +6.879919170e-04f, +8.100393630e-04f, +4.599617124e-05f, -2.183332212e-04f,
+ /* 20, 6 */ +2.156662323e-04f, -2.199842607e-04f, -9.380285157e-04f, -3.304411223e-04f, +2.061606212e-03f, +2.973544666e-03f, -1.549465619e-03f, -9.429422833e-03f, -1.227944713e-02f, -4.922491262e-03f, +6.962740532e-03f, +1.250020393e-02f, +8.052490864e-03f, +2.653234199e-04f, -3.143395899e-03f, -1.579476941e-03f, +6.120364145e-04f, +8.485090918e-04f, +8.608374363e-05f, -2.207970734e-04f,
+ /* 20, 7 */ +2.196232573e-04f, -1.732933680e-04f, -9.130225739e-04f, -4.331132727e-04f, +1.904509553e-03f, +3.052772891e-03f, -1.103649750e-03f, -8.987927630e-03f, -1.239687839e-02f, -5.625975475e-03f, +6.306939763e-03f, +1.247033951e-02f, +8.528119711e-03f, +6.751263085e-04f, -3.109136222e-03f, -1.743383273e-03f, +5.270395872e-04f, +8.830107920e-04f, +1.285826773e-04f, -2.212818602e-04f,
+ /* 20, 8 */ +2.212818602e-04f, -1.285826773e-04f, -8.830107920e-04f, -5.270395872e-04f, +1.743383273e-03f, +3.109136222e-03f, -6.751263085e-04f, -8.528119711e-03f, -1.247033951e-02f, -6.306939763e-03f, +5.625975475e-03f, +1.239687839e-02f, +8.987927630e-03f, +1.103649750e-03f, -3.052772891e-03f, -1.904509553e-03f, +4.331132727e-04f, +9.130225739e-04f, +1.732933680e-04f, -2.196232573e-04f,
+ /* 20, 9 */ +2.207970734e-04f, -8.608374363e-05f, -8.485090918e-04f, -6.120364145e-04f, +1.579476941e-03f, +3.143395899e-03f, -2.653234199e-04f, -8.052490864e-03f, -1.250020393e-02f, -6.962740532e-03f, +4.922491262e-03f, +1.227944713e-02f, +9.429422833e-03f, +1.549465619e-03f, -2.973544666e-03f, -2.061606212e-03f, +3.304411223e-04f, +9.380285157e-04f, +2.199842607e-04f, -2.156662323e-04f,
+ /* 20,10 */ +2.183332212e-04f, -4.599617124e-05f, -8.100393630e-04f, -6.879919170e-04f, +1.414000676e-03f, +3.156409832e-03f, +1.244715801e-04f, -7.563557889e-03f, -1.248704815e-02f, -7.590864160e-03f, +4.199247312e-03f, +1.211787969e-02f, +9.850152742e-03f, +2.011009640e-03f, -2.870794883e-03f, -2.213390969e-03f, +2.192806382e-04f, +9.575231021e-04f, +2.683920446e-04f, -2.092671085e-04f,
+ /* 20,11 */ +2.140618814e-04f, -8.487693398e-06f, -7.681251779e-04f, -7.548636055e-04f, +1.248118895e-03f, +3.149124311e-03f, +4.931158341e-04f, -7.063848473e-03f, -1.243164652e-02f, -8.188939591e-03f, +3.459106327e-03f, +1.191222039e-02f, +1.024771819e-02f, +2.486586970e-03f, -2.743978910e-03f, -2.358556029e-03f, +9.996474913e-05f, +9.710157868e-04f, +3.182221327e-04f, -2.002956356e-04f,
+ /* 20,12 */ +2.081598890e-04f, +2.630548656e-05f, -7.232876858e-04f, -8.126754773e-04f, +1.082944596e-03f, +3.122565398e-03f, +8.396136973e-04f, -6.555887236e-03f, -1.233496472e-02f, -8.754750074e-03f, +2.705018824e-03f, +1.166272581e-02f, +1.061978749e-02f, +2.974378699e-03f, -2.592671089e-03f, -2.495775707e-03f, -2.709710175e-05f, +9.780356474e-04f, +3.691494362e-04f, -1.886370492e-04f,
+ /* 20,13 */ +2.008073985e-04f, +5.827810709e-05f, -6.760417132e-04f, -8.615147935e-04f, +9.195341683e-04f, +3.077830056e-03f, +1.163118517e-03f, -6.042182027e-03f, -1.219815240e-02f, -9.286243980e-03f, +1.940007910e-03f, +1.136986548e-02f, +1.096411041e-02f, +3.472449249e-03f, -2.416571115e-03f, -2.623714429e-03f, -1.614183836e-04f, +9.781360984e-04f, +4.208194393e-04f, -1.741940978e-04f,
+ /* 20,14 */ +1.921860197e-04f, +8.735502929e-05f, -6.268920900e-04f, -9.015285321e-04f, +7.588827792e-04f, +3.016077094e-03f, +1.462933465e-03f, -5.525210549e-03f, -1.202253469e-02f, -9.781544627e-03f, +1.167153605e-03f, +1.103432131e-02f, +1.127853170e-02f, +3.978754642e-03f, -2.215509786e-03f, -2.741035078e-03f, -3.024354413e-04f, +9.708996289e-04f, +4.728495798e-04f, -1.568890194e-04f,
+ /* 20,15 */ +1.824770389e-04f, +1.134902041e-04f, -5.763302237e-04f, -9.329195550e-04f, +6.019203323e-04f, +2.938517986e-03f, +1.738511442e-03f, -5.007407400e-03f, -1.180960294e-02f, -1.023895907e-02f, +3.895768346e-04f, +1.065698581e-02f, +1.156100448e-02f, +4.491151594e-03f, -1.989454068e-03f, -2.846407623e-03f, -4.495080153e-04f, +9.559425272e-04f, +5.248309364e-04f, -1.366654441e-04f,
+ /* 20, 0 */ +2.228492143e-04f, +8.155042897e-05f, -9.008994790e-04f, -8.358434283e-04f, +2.057950411e-03f, +3.687980724e-03f, -2.439509438e-03f, -1.276984908e-02f, -1.372824692e-02f, -5.233437973e-04f, +1.325794606e-02f, +1.324423486e-02f, +3.079014715e-03f, -3.569583683e-03f, -2.275574997e-03f, +7.329307333e-04f, +9.595727172e-04f, -3.951670647e-05f, -2.357435643e-04f, +0.000000000e+00f,
+ /* 20, 1 */ +2.085936177e-04f, +1.192685572e-04f, -8.383784628e-04f, -9.252931617e-04f, +1.836793834e-03f, +3.772148819e-03f, -1.820843931e-03f, -1.225552529e-02f, -1.413563751e-02f, -1.567452511e-03f, +1.272631251e-02f, +1.367510758e-02f, +3.736377939e-03f, -3.415952420e-03f, -2.487640644e-03f, +6.166326985e-04f, +1.013551226e-03f, +6.721135679e-06f, -2.469830254e-04f, +3.513221827e-04f,
+ /* 20, 2 */ +1.932641301e-04f, +1.526114972e-04f, -7.728409668e-04f, -1.001322392e-03f, +1.614057279e-03f, +3.823286477e-03f, -1.225775962e-03f, -1.170500117e-02f, -1.447891891e-02f, -2.603840968e-03f, +1.213529571e-02f, +1.405908160e-02f, +4.408408028e-03f, -3.226289363e-03f, -2.692058620e-03f, +4.871526668e-04f, +1.061979909e-03f, +5.699759108e-05f, -2.562708188e-04f, -2.243392330e-05f,
+ /* 20, 3 */ +1.771389305e-04f, +1.815689683e-04f, -7.050956564e-04f, -1.064087220e-03f, +1.391605775e-03f, +3.842769943e-03f, -6.568264230e-04f, -1.112214974e-02f, -1.475727496e-02f, -3.627416831e-03f, +1.148720750e-02f, +1.439298630e-02f, +5.091721334e-03f, -3.000017933e-03f, -2.886692602e-03f, +3.448244648e-04f, +1.104003505e-03f, +1.110914327e-04f, -2.633104157e-04f, -3.471505729e-05f,
+ /* 20, 4 */ +1.604844080e-04f, +2.061770649e-04f, -6.359221544e-04f, -1.113850250e-03f, +1.171206475e-03f, +3.832136817e-03f, -1.162685315e-04f, -1.051095143e-02f, -1.497027375e-02f, -4.633169088e-03f, +1.078471010e-02f, +1.467389068e-02f, +5.782760145e-03f, -2.736794515e-03f, -3.069373786e-03f, +1.901162062e-04f, +1.138774993e-03f, +1.687245284e-04f, -2.678091338e-04f, -4.805250238e-05f,
+ /* 20, 5 */ +1.435528424e-04f, +2.265149998e-04f, -5.660652366e-04f, -1.150972836e-03f, +9.545189950e-04f, +3.793068954e-03f, +3.938808876e-04f, -9.875465824e-03f, -1.511786634e-02f, -5.616199746e-03f, +1.003080152e-02f, +1.489912656e-02f, +6.477812874e-03f, -2.436518983e-03f, -3.237916857e-03f, +2.363306300e-05f, +1.165464351e-03f, +2.295611999e-04f, -2.694819135e-04f, -6.235351094e-05f,
+ /* 20, 6 */ +1.265803873e-04f, +2.427015763e-04f, -4.962296614e-04f, -1.175906803e-03f, +7.430870045e-04f, +3.727374795e-03f, +8.718680321e-04f, -9.219803451e-03f, -1.520038286e-02f, -6.571754682e-03f, +9.228798617e-03f, +1.506631023e-02f, +7.173035830e-03f, -2.099343642e-03f, -3.390136682e-03f, -1.538810619e-04f, +1.183267602e-03f, +2.932081598e-04f, -2.680552395e-04f, -7.750368078e-05f,
+ /* 20, 7 */ +1.097853637e-04f, +2.548914413e-04f, -4.270756535e-04f, -1.189185758e-03f, +5.383311068e-04f, +3.636971298e-03f, +1.316206650e-03f, -8.548097577e-03f, -1.521852609e-02f, -7.495253444e-03f, +8.382317770e-03f, +1.517336238e-02f, +7.864476409e-03f, -1.725680482e-03f, -3.523865616e-03f, -3.415430197e-04f, +1.191416067e-03f, +3.592150564e-04f, -2.632711715e-04f, -9.336686615e-05f,
+ /* 20, 8 */ +9.336686615e-05f, +2.632711715e-04f, -3.592150564e-04f, -1.191416067e-03f, +3.415430197e-04f, +3.523865616e-03f, +1.725680482e-03f, -7.864476409e-03f, -1.517336238e-02f, -8.382317770e-03f, +7.495253444e-03f, +1.521852609e-02f, +8.548097577e-03f, -1.316206650e-03f, -3.636971298e-03f, -5.383311068e-04f, +1.189185758e-03f, +4.270756535e-04f, -2.548914413e-04f, -1.097853637e-04f,
+ /* 20, 9 */ +7.750368078e-05f, +2.680552395e-04f, -2.932081598e-04f, -1.183267602e-03f, +1.538810619e-04f, +3.390136682e-03f, +2.099343642e-03f, -7.173035830e-03f, -1.506631023e-02f, -9.228798617e-03f, +6.571754682e-03f, +1.520038286e-02f, +9.219803451e-03f, -8.718680321e-04f, -3.727374795e-03f, -7.430870045e-04f, +1.175906803e-03f, +4.962296614e-04f, -2.427015763e-04f, -1.265803873e-04f,
+ /* 20,10 */ +6.235351094e-05f, +2.694819135e-04f, -2.295611999e-04f, -1.165464351e-03f, -2.363306300e-05f, +3.237916857e-03f, +2.436518983e-03f, -6.477812874e-03f, -1.489912656e-02f, -1.003080152e-02f, +5.616199746e-03f, +1.511786634e-02f, +9.875465824e-03f, -3.938808876e-04f, -3.793068954e-03f, -9.545189950e-04f, +1.150972836e-03f, +5.660652366e-04f, -2.265149998e-04f, -1.435528424e-04f,
+ /* 20,11 */ +4.805250238e-05f, +2.678091338e-04f, -1.687245284e-04f, -1.138774993e-03f, -1.901162062e-04f, +3.069373786e-03f, +2.736794515e-03f, -5.782760145e-03f, -1.467389068e-02f, -1.078471010e-02f, +4.633169088e-03f, +1.497027375e-02f, +1.051095143e-02f, +1.162685315e-04f, -3.832136817e-03f, -1.171206475e-03f, +1.113850250e-03f, +6.359221544e-04f, -2.061770649e-04f, -1.604844080e-04f,
+ /* 20,12 */ +3.471505729e-05f, +2.633104157e-04f, -1.110914327e-04f, -1.104003505e-03f, -3.448244648e-04f, +2.886692602e-03f, +3.000017933e-03f, -5.091721334e-03f, -1.439298630e-02f, -1.148720750e-02f, +3.627416831e-03f, +1.475727496e-02f, +1.112214974e-02f, +6.568264230e-04f, -3.842769943e-03f, -1.391605775e-03f, +1.064087220e-03f, +7.050956564e-04f, -1.815689683e-04f, -1.771389305e-04f,
+ /* 20,13 */ +2.243392330e-05f, +2.562708188e-04f, -5.699759108e-05f, -1.061979909e-03f, -4.871526668e-04f, +2.692058620e-03f, +3.226289363e-03f, -4.408408028e-03f, -1.405908160e-02f, -1.213529571e-02f, +2.603840968e-03f, +1.447891891e-02f, +1.170500117e-02f, +1.225775962e-03f, -3.823286477e-03f, -1.614057279e-03f, +1.001322392e-03f, +7.728409668e-04f, -1.526114972e-04f, -1.932641301e-04f,
+ /* 20,14 */ -3.513221827e-04f, +2.469830254e-04f, -6.721135679e-06f, -1.013551226e-03f, -6.166326985e-04f, +2.487640644e-03f, +3.415952420e-03f, -3.736377939e-03f, -1.367510758e-02f, -1.272631251e-02f, +1.567452511e-03f, +1.413563751e-02f, +1.225552529e-02f, +1.820843931e-03f, -3.772148819e-03f, -1.836793834e-03f, +9.252931617e-04f, +8.383784628e-04f, -1.192685572e-04f, -2.085936177e-04f,
+ /* 20,15 */ +0.000000000e+00f, +2.357435643e-04f, +3.951670647e-05f, -9.595727172e-04f, -7.329307333e-04f, +2.275574997e-03f, +3.569583683e-03f, -3.079014715e-03f, -1.324423486e-02f, -1.325794606e-02f, +5.233437973e-04f, +1.372824692e-02f, +1.276984908e-02f, +2.439509438e-03f, -3.687980724e-03f, -2.057950411e-03f, +8.358434283e-04f, +9.008994790e-04f, -8.155042897e-05f, -2.228492143e-04f,
+ /* 20, 0 */ +1.941987182e-05f, +3.146481294e-04f, -2.345645569e-04f, -1.414667200e-03f, +5.144442975e-04f, +4.454307224e-03f, +1.983750799e-04f, -1.327145644e-02f, -1.714303646e-02f, -6.846700315e-04f, +1.665178821e-02f, +1.403392762e-02f, +4.892879248e-04f, -4.540173148e-03f, -7.773192529e-04f, +1.425286503e-03f, +3.160682424e-04f, -3.205185770e-04f, -3.476344875e-05f, +0.000000000e+00f,
+ /* 20, 1 */ -3.929324583e-04f, +3.051602666e-04f, -1.573970191e-04f, -1.390281543e-03f, +2.638941923e-04f, +4.333213577e-03f, +8.411158857e-04f, -1.246868983e-02f, -1.754185168e-02f, -2.049974665e-03f, +1.606968443e-02f, +1.474987505e-02f, +1.218921159e-03f, -4.587812221e-03f, -1.050600845e-03f, +1.421006956e-03f, +4.012475422e-04f, -3.223256966e-04f, -5.166761157e-05f, +0.000000000e+00f,
+ /* 20, 2 */ +0.000000000e+00f, +2.925136688e-04f, -8.512788201e-05f, -1.353337804e-03f, +2.735561011e-05f, +4.180044295e-03f, +1.436437300e-03f, -1.163198941e-02f, -1.784731333e-02f, -3.403203680e-03f, +1.539895444e-02f, +1.541325656e-02f, +1.987128326e-03f, -4.594412557e-03f, -1.332146559e-03f, +1.400789491e-03f, +4.893452569e-04f, -3.196436833e-04f, -7.000071077e-05f, +0.000000000e+00f,
+ /* 20, 3 */ +0.000000000e+00f, +2.771727451e-04f, -1.822077520e-05f, -1.305102482e-03f, -1.937209193e-04f, +3.998069961e-03f, +1.982303068e-03f, -1.076779718e-02f, -1.805915757e-02f, -4.736408619e-03f, +1.464246859e-02f, +1.601826823e-02f, +2.790083541e-03f, -4.557383277e-03f, -1.619599483e-03f, +1.363706016e-03f, +5.795104543e-04f, -3.120743969e-04f, -8.959420873e-05f, +0.000000000e+00f,
+ /* 20, 4 */ +0.000000000e+00f, +2.596009711e-04f, +4.295843246e-05f, -1.246883037e-03f, -3.981230344e-04f, +3.790645354e-03f, +2.477139789e-03f, -9.882582946e-03f, -1.817777152e-02f, -6.041793017e-03f, +1.380372215e-02f, +1.655939544e-02f, +3.623550339e-03f, -4.474387395e-03f, -1.910400883e-03f, +1.308956662e-03f, +6.708027600e-04f, -2.992550459e-04f, -1.102423612e-04f, +0.000000000e+00f,
+ /* 20, 5 */ +0.000000000e+00f, +2.402546692e-04f, +9.813963752e-05f, -1.180011107e-03f, -5.848760724e-04f, +3.561175652e-03f, +2.919834686e-03f, -8.982792490e-03f, -1.820418220e-02f, -7.311771311e-03f, +1.288681385e-02f, +1.703146227e-02f, +4.482904855e-03f, -4.343373467e-03f, -2.201805423e-03f, +1.235886510e-03f, +7.621980241e-04f, -2.808658988e-04f, -1.317024534e-04f, +0.000000000e+00f,
+ /* 20, 6 */ +0.000000000e+00f, +2.195772899e-04f, +1.471454599e-04f, -1.105826337e-03f, -7.532402115e-04f, +3.313083439e-03f, +3.309729355e-03f, -8.074797022e-03f, -1.814004021e-02f, -8.539025902e-03f, +1.189641917e-02f, +1.742967891e-02f, +5.363163073e-03f, -4.162605659e-03f, -2.490898970e-03f, +1.144001586e-03f, +8.525953702e-04f, -2.566379213e-04f, -1.536956226e-04f, +0.000000000e+00f,
+ /* 20, 7 */ +0.000000000e+00f, +1.979942392e-04f, +1.898872476e-04f, -1.025661016e-03f, -9.027053553e-04f, +3.049776817e-03f, +3.646609643e-03f, -7.164844319e-03f, -1.798759853e-02f, -9.716561844e-03f, +1.083775871e-02f, +1.774968640e-02f, +6.259011965e-03f, -3.930691879e-03f, -2.774618906e-03f, +1.032983905e-03f, +9.408256132e-04f, -2.263602294e-04f, -1.759082929e-04f, +0.000000000e+00f,
+ /* 20, 8 */ +0.000000000e+00f, +1.759082929e-04f, +2.263602294e-04f, -9.408256132e-04f, -1.032983905e-03f, +2.774618906e-03f, +3.930691879e-03f, -6.259011965e-03f, -1.774968640e-02f, -1.083775871e-02f, +9.716561844e-03f, +1.798759853e-02f, +7.164844319e-03f, -3.646609643e-03f, -3.049776817e-03f, +9.027053553e-04f, +1.025661016e-03f, -1.898872476e-04f, -1.979942392e-04f, +0.000000000e+00f,
+ /* 20, 9 */ +0.000000000e+00f, +1.536956226e-04f, +2.566379213e-04f, -8.525953702e-04f, -1.144001586e-03f, +2.490898970e-03f, +4.162605659e-03f, -5.363163073e-03f, -1.742967891e-02f, -1.189641917e-02f, +8.539025902e-03f, +1.814004021e-02f, +8.074797022e-03f, -3.309729355e-03f, -3.313083439e-03f, +7.532402115e-04f, +1.105826337e-03f, -1.471454599e-04f, -2.195772899e-04f, +0.000000000e+00f,
+ /* 20,10 */ +0.000000000e+00f, +1.317024534e-04f, +2.808658988e-04f, -7.621980241e-04f, -1.235886510e-03f, +2.201805423e-03f, +4.343373467e-03f, -4.482904855e-03f, -1.703146227e-02f, -1.288681385e-02f, +7.311771311e-03f, +1.820418220e-02f, +8.982792490e-03f, -2.919834686e-03f, -3.561175652e-03f, +5.848760724e-04f, +1.180011107e-03f, -9.813963752e-05f, -2.402546692e-04f, +0.000000000e+00f,
+ /* 20,11 */ +0.000000000e+00f, +1.102423612e-04f, +2.992550459e-04f, -6.708027600e-04f, -1.308956662e-03f, +1.910400883e-03f, +4.474387395e-03f, -3.623550339e-03f, -1.655939544e-02f, -1.380372215e-02f, +6.041793017e-03f, +1.817777152e-02f, +9.882582946e-03f, -2.477139789e-03f, -3.790645354e-03f, +3.981230344e-04f, +1.246883037e-03f, -4.295843246e-05f, -2.596009711e-04f, +0.000000000e+00f,
+ /* 20,12 */ +0.000000000e+00f, +8.959420873e-05f, +3.120743969e-04f, -5.795104543e-04f, -1.363706016e-03f, +1.619599483e-03f, +4.557383277e-03f, -2.790083541e-03f, -1.601826823e-02f, -1.464246859e-02f, +4.736408619e-03f, +1.805915757e-02f, +1.076779718e-02f, -1.982303068e-03f, -3.998069961e-03f, +1.937209193e-04f, +1.305102482e-03f, +1.822077520e-05f, -2.771727451e-04f, +0.000000000e+00f,
+ /* 20,13 */ +0.000000000e+00f, +7.000071077e-05f, +3.196436833e-04f, -4.893452569e-04f, -1.400789491e-03f, +1.332146559e-03f, +4.594412557e-03f, -1.987128326e-03f, -1.541325656e-02f, -1.539895444e-02f, +3.403203680e-03f, +1.784731333e-02f, +1.163198941e-02f, -1.436437300e-03f, -4.180044295e-03f, -2.735561011e-05f, +1.353337804e-03f, +8.512788201e-05f, -2.925136688e-04f, +0.000000000e+00f,
+ /* 20,14 */ +0.000000000e+00f, +5.166761157e-05f, +3.223256966e-04f, -4.012475422e-04f, -1.421006956e-03f, +1.050600845e-03f, +4.587812221e-03f, -1.218921159e-03f, -1.474987505e-02f, -1.606968443e-02f, +2.049974665e-03f, +1.754185168e-02f, +1.246868983e-02f, -8.411158857e-04f, -4.333213577e-03f, -2.638941923e-04f, +1.390281543e-03f, +1.573970191e-04f, -3.051602666e-04f, +3.929324583e-04f,
+ /* 20,15 */ +0.000000000e+00f, +3.476344875e-05f, +3.205185770e-04f, -3.160682424e-04f, -1.425286503e-03f, +7.773192529e-04f, +4.540173148e-03f, -4.892879248e-04f, -1.403392762e-02f, -1.665178821e-02f, +6.846700315e-04f, +1.714303646e-02f, +1.327145644e-02f, -1.983750799e-04f, -4.454307224e-03f, -5.144442975e-04f, +1.414667200e-03f, +2.345645569e-04f, -3.146481294e-04f, -1.941987182e-05f,
+ /* 16, 0 */ +3.215659774e-04f, -1.081239301e-03f, -1.047044785e-03f, +4.045780572e-03f, +3.005074105e-03f, -1.291342297e-02f, -2.083886340e-02f, -8.761305366e-04f, +2.037274022e-02f, +1.401097590e-02f, -2.379335663e-03f, -4.351475252e-03f, +8.522542940e-04f, +1.190910327e-03f, -2.874725537e-04f, -1.571395541e-04f,
+ /* 16, 1 */ +3.474336395e-04f, -9.673171402e-04f, -1.215210440e-03f, +3.716713245e-03f, +3.558195313e-03f, -1.178473019e-02f, -2.117503726e-02f, -2.622305580e-03f, +1.977768827e-02f, +1.506763496e-02f, -1.682580557e-03f, -4.628640452e-03f, +6.313208395e-04f, +1.294421768e-03f, -2.448738999e-04f, -1.853334990e-04f,
+ /* 16, 2 */ +3.654544998e-04f, -8.509694882e-04f, -1.356620316e-03f, +3.369379821e-03f, +4.037840451e-03f, -1.063463040e-02f, -2.138131359e-02f, -4.350277043e-03f, +1.905580462e-02f, +1.607371744e-02f, -9.171630004e-04f, -4.872124601e-03f, +3.850930357e-04f, +1.389803701e-03f, -1.936024914e-04f, -2.137577131e-04f,
+ /* 16, 3 */ +3.760939096e-04f, -7.339202470e-04f, -1.471475134e-03f, +3.008783957e-03f, +4.443873126e-03f, -9.472744965e-03f, -2.145880202e-02f, -6.048090342e-03f, +1.821025632e-02f, +1.701970579e-02f, -8.619500088e-05f, -5.076839304e-03f, +1.147982409e-04f, +1.475048300e-03f, -1.336143134e-04f, -2.418805517e-04f,
+ /* 16, 4 */ +3.798900997e-04f, -6.177751723e-04f, -1.560284979e-03f, +2.639777229e-03f, +4.776853126e-03f, -8.308496634e-03f, -2.140964525e-02f, -7.704060609e-03f, +1.724526338e-02f, +1.789634168e-02f, +8.064574864e-04f, -5.237819035e-03f, -1.779495980e-04f, +1.548135431e-03f, -6.499930382e-05f, -2.691226085e-04f,
+ /* 16, 5 */ +3.774404835e-04f, -5.040080805e-04f, -1.623844377e-03f, +2.267013831e-03f, +5.038003695e-03f, -7.151026424e-03f, -2.123698452e-02f, -9.306876654e-03f, +1.616607109e-02f, +1.869471933e-02f, +1.756186609e-03f, -5.350281937e-03f, -4.911465534e-04f, +1.607060019e-03f, +1.200956190e-05f, -2.948629835e-04f,
+ /* 16, 6 */ +3.693879948e-04f, -3.939497146e-04f, -1.663205192e-03f, +1.894909522e-03f, +5.229172900e-03f, -6.009115326e-03f, -2.094491570e-02f, -1.084570103e-02f, +1.497891218e-02f, +1.940637710e-02f, +2.757662946e-03f, -5.409691072e-03f, -8.224000281e-04f, +1.649860923e-03f, +9.702877105e-05f, -3.184467584e-04f,
+ /* 16, 7 */ +3.564076658e-04f, -2.887792732e-04f, -1.679647798e-03f, +1.527605146e-03f, +5.352789702e-03f, -4.891111570e-03f, -2.053843663e-02f, -1.231026521e-02f, +1.369095882e-02f, +2.002338639e-02f, +3.804864118e-03f, -5.411815390e-03f, -1.168934972e-03f, +1.674650966e-03f, +1.895185724e-04f, -3.391936346e-04f,
+ /* 16, 8 */ +3.391936346e-04f, -1.895185724e-04f, -1.674650966e-03f, +1.168934972e-03f, +5.411815390e-03f, -3.804864118e-03f, -2.002338639e-02f, -1.369095882e-02f, +1.231026521e-02f, +2.053843663e-02f, +4.891111570e-03f, -5.352789702e-03f, -1.527605146e-03f, +1.679647798e-03f, +2.887792732e-04f, -3.564076658e-04f,
+ /* 16, 9 */ +3.184467584e-04f, -9.702877105e-05f, -1.649860923e-03f, +8.224000281e-04f, +5.409691072e-03f, -2.757662946e-03f, -1.940637710e-02f, -1.497891218e-02f, +1.084570103e-02f, +2.094491570e-02f, +6.009115326e-03f, -5.229172900e-03f, -1.894909522e-03f, +1.663205192e-03f, +3.939497146e-04f, -3.693879948e-04f,
+ /* 16,10 */ +2.948629835e-04f, -1.200956190e-05f, -1.607060019e-03f, +4.911465534e-04f, +5.350281937e-03f, -1.756186609e-03f, -1.869471933e-02f, -1.616607109e-02f, +9.306876654e-03f, +2.123698452e-02f, +7.151026424e-03f, -5.038003695e-03f, -2.267013831e-03f, +1.623844377e-03f, +5.040080805e-04f, -3.774404835e-04f,
+ /* 16,11 */ +2.691226085e-04f, +6.499930382e-05f, -1.548135431e-03f, +1.779495980e-04f, +5.237819035e-03f, -8.064574864e-04f, -1.789634168e-02f, -1.724526338e-02f, +7.704060609e-03f, +2.140964525e-02f, +8.308496634e-03f, -4.776853126e-03f, -2.639777229e-03f, +1.560284979e-03f, +6.177751723e-04f, -3.798900997e-04f,
+ /* 16,12 */ +2.418805517e-04f, +1.336143134e-04f, -1.475048300e-03f, -1.147982409e-04f, +5.076839304e-03f, +8.619500088e-05f, -1.701970579e-02f, -1.821025632e-02f, +6.048090342e-03f, +2.145880202e-02f, +9.472744965e-03f, -4.443873126e-03f, -3.008783957e-03f, +1.471475134e-03f, +7.339202470e-04f, -3.760939096e-04f,
+ /* 16,13 */ +2.137577131e-04f, +1.936024914e-04f, -1.389803701e-03f, -3.850930357e-04f, +4.872124601e-03f, +9.171630004e-04f, -1.607371744e-02f, -1.905580462e-02f, +4.350277043e-03f, +2.138131359e-02f, +1.063463040e-02f, -4.037840451e-03f, -3.369379821e-03f, +1.356620316e-03f, +8.509694882e-04f, -3.654544998e-04f,
+ /* 16,14 */ +1.853334990e-04f, +2.448738999e-04f, -1.294421768e-03f, -6.313208395e-04f, +4.628640452e-03f, +1.682580557e-03f, -1.506763496e-02f, -1.977768827e-02f, +2.622305580e-03f, +2.117503726e-02f, +1.178473019e-02f, -3.558195313e-03f, -3.716713245e-03f, +1.215210440e-03f, +9.673171402e-04f, -3.474336395e-04f,
+ /* 16,15 */ +1.571395541e-04f, +2.874725537e-04f, -1.190910327e-03f, -8.522542940e-04f, +4.351475252e-03f, +2.379335663e-03f, -1.401097590e-02f, -2.037274022e-02f, +8.761305366e-04f, +2.083886340e-02f, +1.291342297e-02f, -3.005074105e-03f, -4.045780572e-03f, +1.047044785e-03f, +1.081239301e-03f, -3.215659774e-04f,
+ /* 16, 0 */ +3.737698842e-04f, -2.640449894e-04f, -1.945694549e-03f, +2.599440145e-03f, +5.499552783e-03f, -1.161604587e-02f, -2.473725459e-02f, -1.100298137e-03f, +2.435797715e-02f, +1.306966182e-02f, -5.062036618e-03f, -3.067638325e-03f, +1.905476637e-03f, +3.919780470e-04f, -3.991665042e-04f, +0.000000000e+00f,
+ /* 16, 1 */ +3.444161169e-04f, -1.448617079e-04f, -1.955541719e-03f, +2.132654952e-03f, +5.839402648e-03f, -1.015371093e-02f, -2.494083956e-02f, -3.291998323e-03f, +2.380252288e-02f, +1.450063212e-02f, -4.525267650e-03f, -3.530814272e-03f, +1.832921116e-03f, +5.273022833e-04f, -4.195866486e-04f, +0.000000000e+00f,
+ /* 16, 2 */ +3.121018536e-04f, -3.553225965e-05f, -1.937280777e-03f, +1.673279684e-03f, +6.084169165e-03f, -8.696195593e-03f, -2.497087446e-02f, -5.457102987e-03f, +2.307209479e-02f, +1.589478690e-02f, -3.888719495e-03f, -3.982156136e-03f, +1.726408630e-03f, +6.684076945e-04f, -4.340068349e-04f, +0.000000000e+00f,
+ /* 16, 3 */ +2.777843660e-04f, +6.309259068e-05f, -1.893417136e-03f, +1.226820211e-03f, +6.237358144e-03f, -7.256513778e-03f, -2.483111182e-02f, -7.578189778e-03f, +2.216959356e-02f, +1.723786448e-02f, -3.152978451e-03f, -4.414545490e-03f, +1.584716951e-03f, +8.134406195e-04f, -4.414195390e-04f, +4.634120047e-04f,
+ /* 16, 4 */ +2.423668462e-04f, +1.504100330e-04f, -1.826645633e-03f, +7.982477790e-04f, +6.303316031e-03f, -5.847027899e-03f, -2.452684878e-02f, -9.638294429e-03f, +2.109960841e-02f, +1.851566754e-02f, -2.319783877e-03f, -4.820635148e-03f, +1.407067591e-03f, +9.603162700e-04f, -4.408546251e-04f, -2.338334874e-05f,
+ /* 16, 5 */ +2.066858426e-04f, +2.260561294e-04f, -1.739797615e-03f, +3.919648528e-04f, +6.287140435e-03f, -4.479333074e-03f, -2.406484480e-02f, -1.162108621e-02f, +1.986838848e-02f, +1.971422226e-02f, -1.392055451e-03f, -5.192933984e-03f, +1.193168502e-03f, +1.106736135e-03f, -4.314017719e-04f, -4.782938304e-05f,
+ /* 16, 6 */ +1.715009195e-04f, +2.898933732e-04f, -1.635789255e-03f, +1.178042715e-05f, +6.194584811e-03f, -3.164153635e-03f, -2.345322399e-02f, -1.351103572e-02f, +1.848379497e-02f, +2.081993840e-02f, -3.739065234e-04f, -5.523897843e-03f, +9.432519997e-04f, +1.250210274e-03f, -4.122335402e-04f, -7.520965874e-05f,
+ /* 16, 7 */ +1.374865801e-04f, +3.419953130e-04f, -1.517571800e-03f, -3.391052954e-04f, +6.031958779e-03f, -1.911252903e-03f, -2.270136331e-02f, -1.529357304e-02f, +1.695523429e-02f, +2.181976838e-02f, +7.293570292e-04f, -5.806025538e-03f, +6.581070752e-04f, +1.388084428e-03f, -3.826286881e-04f, -1.052264476e-04f,
+ /* 16, 8 */ +1.052264476e-04f, +3.826286881e-04f, -1.388084428e-03f, -6.581070752e-04f, +5.806025538e-03f, -7.293570292e-04f, -2.181976838e-02f, -1.695523429e-02f, +1.529357304e-02f, +2.270136331e-02f, +1.911252903e-03f, -6.031958779e-03f, +3.391052954e-04f, +1.517571800e-03f, -3.419953130e-04f, -1.374865801e-04f,
+ /* 16, 9 */ +7.520965874e-05f, +4.122335402e-04f, -1.250210274e-03f, -9.432519997e-04f, +5.523897843e-03f, +3.739065234e-04f, -2.081993840e-02f, -1.848379497e-02f, +1.351103572e-02f, +2.345322399e-02f, +3.164153635e-03f, -6.194584811e-03f, -1.178042715e-05f, +1.635789255e-03f, -2.898933732e-04f, -1.715009195e-04f,
+ /* 16,10 */ +4.782938304e-05f, +4.314017719e-04f, -1.106736135e-03f, -1.193168502e-03f, +5.192933984e-03f, +1.392055451e-03f, -1.971422226e-02f, -1.986838848e-02f, +1.162108621e-02f, +2.406484480e-02f, +4.479333074e-03f, -6.287140435e-03f, -3.919648528e-04f, +1.739797615e-03f, -2.260561294e-04f, -2.066858426e-04f,
+ /* 16,11 */ +2.338334874e-05f, +4.408546251e-04f, -9.603162700e-04f, -1.407067591e-03f, +4.820635148e-03f, +2.319783877e-03f, -1.851566754e-02f, -2.109960841e-02f, +9.638294429e-03f, +2.452684878e-02f, +5.847027899e-03f, -6.303316031e-03f, -7.982477790e-04f, +1.826645633e-03f, -1.504100330e-04f, -2.423668462e-04f,
+ /* 16,12 */ -4.634120047e-04f, +4.414195390e-04f, -8.134406195e-04f, -1.584716951e-03f, +4.414545490e-03f, +3.152978451e-03f, -1.723786448e-02f, -2.216959356e-02f, +7.578189778e-03f, +2.483111182e-02f, +7.256513778e-03f, -6.237358144e-03f, -1.226820211e-03f, +1.893417136e-03f, -6.309259068e-05f, -2.777843660e-04f,
+ /* 16,13 */ +0.000000000e+00f, +4.340068349e-04f, -6.684076945e-04f, -1.726408630e-03f, +3.982156136e-03f, +3.888719495e-03f, -1.589478690e-02f, -2.307209479e-02f, +5.457102987e-03f, +2.497087446e-02f, +8.696195593e-03f, -6.084169165e-03f, -1.673279684e-03f, +1.937280777e-03f, +3.553225965e-05f, -3.121018536e-04f,
+ /* 16,14 */ +0.000000000e+00f, +4.195866486e-04f, -5.273022833e-04f, -1.832921116e-03f, +3.530814272e-03f, +4.525267650e-03f, -1.450063212e-02f, -2.380252288e-02f, +3.291998323e-03f, +2.494083956e-02f, +1.015371093e-02f, -5.839402648e-03f, -2.132654952e-03f, +1.955541719e-03f, +1.448617079e-04f, -3.444161169e-04f,
+ /* 16,15 */ +0.000000000e+00f, +3.991665042e-04f, -3.919780470e-04f, -1.905476637e-03f, +3.067638325e-03f, +5.062036618e-03f, -1.306966182e-02f, -2.435797715e-02f, +1.100298137e-03f, +2.473725459e-02f, +1.161604587e-02f, -5.499552783e-03f, -2.599440145e-03f, +1.945694549e-03f, +2.640449894e-04f, -3.737698842e-04f,
+ /* 16, 0 */ +1.129954761e-04f, +3.969443331e-04f, -1.897918409e-03f, +5.803605804e-04f, +7.236474393e-03f, -9.385964725e-03f, -2.874576735e-02f, -1.359743295e-03f, +2.853093461e-02f, +1.118139232e-02f, -7.102956997e-03f, -1.091735034e-03f, +2.023521864e-03f, -3.328791130e-04f, -1.523656204e-04f, +0.000000000e+00f,
+ /* 16, 1 */ +7.672972562e-05f, +4.458313625e-04f, -1.753034729e-03f, +1.022461377e-04f, +7.257902118e-03f, -7.620475041e-03f, -2.873131200e-02f, -4.066570788e-03f, +2.808336987e-02f, +1.298853535e-02f, -6.850603202e-03f, -1.630677017e-03f, +2.125649126e-03f, -2.532507071e-04f, -1.941703587e-04f, +0.000000000e+00f,
+ /* 16, 2 */ +4.409159553e-05f, +4.801879450e-04f, -1.593056257e-03f, -3.378401438e-04f, +7.175055211e-03f, -5.902082228e-03f, -2.849345261e-02f, -6.735572940e-03f, +2.740215275e-02f, +1.478830973e-02f, -6.473886365e-03f, -2.190599691e-03f, +2.200171639e-03f, -1.579695096e-04f, -2.375950982e-04f, +0.000000000e+00f,
+ /* 16, 3 */ -4.855802427e-04f, +5.008892512e-04f, -1.422085430e-03f, -7.360682089e-04f, +6.996656391e-03f, -4.246700138e-03f, -2.804039906e-02f, -9.342037235e-03f, +2.648893755e-02f, +1.656098957e-02f, -5.968640123e-03f, -2.764068406e-03f, +2.243110553e-03f, -4.727037370e-05f, -2.816859426e-04f, +0.000000000e+00f,
+ /* 16, 4 */ +0.000000000e+00f, +5.090007623e-04f, -1.244075649e-03f, -1.089544232e-03f, +6.732169339e-03f, -2.668838337e-03f, -2.738254409e-02f, -1.186200034e-02f, +2.534797081e-02f, +1.828644204e-02f, -5.332184360e-03f, -3.342863857e-03f, +2.250722132e-03f, +7.826276448e-05f, -3.253590588e-04f, +0.000000000e+00f,
+ /* 16, 5 */ +0.000000000e+00f, +5.057402285e-04f, -1.062772468e-03f, -1.396293958e-03f, +6.391628670e-03f, -1.181467029e-03f, -2.653229393e-02f, -1.427253312e-02f, +2.398607480e-02f, +1.994437434e-02f, -4.563434465e-03f, -3.918061651e-03f, +2.219584858e-03f, +2.176775461e-04f, -3.674140144e-04f, +0.000000000e+00f,
+ /* 16, 6 */ +0.000000000e+00f, +4.924395299e-04f, -8.816626027e-04f, -1.655232286e-03f, +5.985469320e-03f, +2.040926394e-04f, -2.550387540e-02f, -1.655201127e-02f, +2.241259678e-02f, +2.151458926e-02f, -3.662991573e-03f, -4.480127768e-03f, +2.146686747e-03f, +3.696399185e-04f, -4.065510896e-04f, +0.000000000e+00f,
+ /* 16, 7 */ +0.000000000e+00f, +4.705072223e-04f, -7.039312026e-04f, -1.866120323e-03f, +5.524357980e-03f, +1.478252020e-03f, -2.431312252e-02f, -1.868036788e-02f, +2.063932435e-02f, +2.297724601e-02f, -2.633211707e-03f, -5.019029099e-03f, +2.029511283e-03f, +5.324276437e-04f, -4.413924818e-04f, +0.000000000e+00f,
+ /* 16, 8 */ +0.000000000e+00f, +4.413924818e-04f, -5.324276437e-04f, -2.029511283e-03f, +5.019029099e-03f, +2.633211707e-03f, -2.297724601e-02f, -2.063932435e-02f, +1.868036788e-02f, +2.431312252e-02f, -1.478252020e-03f, -5.524357980e-03f, +1.866120323e-03f, +7.039312026e-04f, -4.705072223e-04f, +0.000000000e+00f,
+ /* 16, 9 */ +0.000000000e+00f, +4.065510896e-04f, -3.696399185e-04f, -2.146686747e-03f, +4.480127768e-03f, +3.662991573e-03f, -2.151458926e-02f, -2.241259678e-02f, +1.655201127e-02f, +2.550387540e-02f, -2.040926394e-04f, -5.985469320e-03f, +1.655232286e-03f, +8.816626027e-04f, -4.924395299e-04f, +0.000000000e+00f,
+ /* 16,10 */ +0.000000000e+00f, +3.674140144e-04f, -2.176775461e-04f, -2.219584858e-03f, +3.918061651e-03f, +4.563434465e-03f, -1.994437434e-02f, -2.398607480e-02f, +1.427253312e-02f, +2.653229393e-02f, +1.181467029e-03f, -6.391628670e-03f, +1.396293958e-03f, +1.062772468e-03f, -5.057402285e-04f, +0.000000000e+00f,
+ /* 16,11 */ +0.000000000e+00f, +3.253590588e-04f, -7.826276448e-05f, -2.250722132e-03f, +3.342863857e-03f, +5.332184360e-03f, -1.828644204e-02f, -2.534797081e-02f, +1.186200034e-02f, +2.738254409e-02f, +2.668838337e-03f, -6.732169339e-03f, +1.089544232e-03f, +1.244075649e-03f, -5.090007623e-04f, +0.000000000e+00f,
+ /* 16,12 */ +0.000000000e+00f, +2.816859426e-04f, +4.727037370e-05f, -2.243110553e-03f, +2.764068406e-03f, +5.968640123e-03f, -1.656098957e-02f, -2.648893755e-02f, +9.342037235e-03f, +2.804039906e-02f, +4.246700138e-03f, -6.996656391e-03f, +7.360682089e-04f, +1.422085430e-03f, -5.008892512e-04f, +4.855802427e-04f,
+ /* 16,13 */ +0.000000000e+00f, +2.375950982e-04f, +1.579695096e-04f, -2.200171639e-03f, +2.190599691e-03f, +6.473886365e-03f, -1.478830973e-02f, -2.740215275e-02f, +6.735572940e-03f, +2.849345261e-02f, +5.902082228e-03f, -7.175055211e-03f, +3.378401438e-04f, +1.593056257e-03f, -4.801879450e-04f, -4.409159553e-05f,
+ /* 16,14 */ +0.000000000e+00f, +1.941703587e-04f, +2.532507071e-04f, -2.125649126e-03f, +1.630677017e-03f, +6.850603202e-03f, -1.298853535e-02f, -2.808336987e-02f, +4.066570788e-03f, +2.873131200e-02f, +7.620475041e-03f, -7.257902118e-03f, -1.022461377e-04f, +1.753034729e-03f, -4.458313625e-04f, -7.672972562e-05f,
+ /* 16,15 */ +0.000000000e+00f, +1.523656204e-04f, +3.328791130e-04f, -2.023521864e-03f, +1.091735034e-03f, +7.102956997e-03f, -1.118139232e-02f, -2.853093461e-02f, +1.359743295e-03f, +2.874576735e-02f, +9.385964725e-03f, -7.236474393e-03f, -5.803605804e-04f, +1.897918409e-03f, -3.969443331e-04f, -1.129954761e-04f,
+ /* 12, 0 */ -1.111572639e-03f, -1.388266820e-03f, +7.900037037e-03f, -6.320860170e-03f, -3.276049121e-02f, -1.657033928e-03f, +3.280306521e-02f, +8.402419704e-03f, -8.147060845e-03f, +9.779320530e-04f, +1.332890330e-03f, -5.705687800e-04f,
+ /* 12, 1 */ -8.925738220e-04f, -1.737094155e-03f, +7.544883174e-03f, -4.325531156e-03f, -3.242830266e-02f, -4.953502968e-03f, +3.254754550e-02f, +1.054842384e-02f, -8.272560314e-03f, +5.083818205e-04f, +1.551863117e-03f, -5.805594968e-04f,
+ /* 12, 2 */ -6.800837112e-04f, -2.023419107e-03f, +7.095763901e-03f, -2.436087367e-03f, -3.181840805e-02f, -8.197416535e-03f, +3.198906769e-02f, +1.273520115e-02f, -8.264181830e-03f, -1.673924732e-05f, +1.763414955e-03f, -5.764989135e-04f,
+ /* 12, 3 */ -4.777710304e-04f, -2.247467778e-03f, +6.567344318e-03f, -6.698479312e-04f, -3.094591156e-02f, -1.135453705e-02f, +3.112651563e-02f, +1.493747887e-02f, -8.110878239e-03f, -5.924008684e-04f, +1.962133432e-03f, -5.566237283e-04f,
+ /* 12, 4 */ -2.887507612e-04f, -2.410593616e-03f, +5.974525144e-03f, +9.583644900e-04f, -2.982883555e-02f, -1.439181272e-02f, +2.996260004e-02f, +1.712870168e-02f, -7.803165138e-03f, -1.212178752e-03f, +2.142359210e-03f, -5.193755958e-04f,
+ /* 12, 5 */ -1.155657138e-04f, -2.515168800e-03f, +5.332187403e-03f, +2.436339775e-03f, -2.848780461e-02f, -1.727782533e-02f, +2.850388027e-02f, +1.928138098e-02f, -7.333362623e-03f, -1.868272468e-03f, +2.298288008e-03f, -4.634616378e-04f,
+ /* 12, 6 */ +3.981829456e-05f, -2.564463655e-03f, +4.654950666e-03f, +3.754551105e-03f, -2.694569661e-02f, -1.998321224e-02f, +2.676072816e-02f, +2.136746929e-02f, -6.695817566e-03f, -2.551550686e-03f, +2.424083786e-03f, -3.879138191e-04f,
+ /* 12, 7 */ +1.760045094e-04f, -2.562517141e-03f, +3.956948521e-03f, +4.906180706e-03f, -2.522726725e-02f, -2.248105576e-02f, +2.474723407e-02f, +2.335875442e-02f, -5.887101657e-03f, -3.251624436e-03f, +2.514001460e-03f, -2.921456350e-04f,
+ /* 12, 8 */ +2.921456350e-04f, -2.514001460e-03f, +3.251624436e-03f, +5.887101657e-03f, -2.335875442e-02f, -2.474723407e-02f, +2.248105576e-02f, +2.522726725e-02f, -4.906180706e-03f, -3.956948521e-03f, +2.562517141e-03f, -1.760045094e-04f,
+ /* 12, 9 */ +3.879138191e-04f, -2.424083786e-03f, +2.551550686e-03f, +6.695817566e-03f, -2.136746929e-02f, -2.676072816e-02f, +1.998321224e-02f, +2.694569661e-02f, -3.754551105e-03f, -4.654950666e-03f, +2.564463655e-03f, -3.981829456e-05f,
+ /* 12,10 */ +4.634616378e-04f, -2.298288008e-03f, +1.868272468e-03f, +7.333362623e-03f, -1.928138098e-02f, -2.850388027e-02f, +1.727782533e-02f, +2.848780461e-02f, -2.436339775e-03f, -5.332187403e-03f, +2.515168800e-03f, +1.155657138e-04f,
+ /* 12,11 */ +5.193755958e-04f, -2.142359210e-03f, +1.212178752e-03f, +7.803165138e-03f, -1.712870168e-02f, -2.996260004e-02f, +1.439181272e-02f, +2.982883555e-02f, -9.583644900e-04f, -5.974525144e-03f, +2.410593616e-03f, +2.887507612e-04f,
+ /* 12,12 */ +5.566237283e-04f, -1.962133432e-03f, +5.924008684e-04f, +8.110878239e-03f, -1.493747887e-02f, -3.112651563e-02f, +1.135453705e-02f, +3.094591156e-02f, +6.698479312e-04f, -6.567344318e-03f, +2.247467778e-03f, +4.777710304e-04f,
+ /* 12,13 */ +5.764989135e-04f, -1.763414955e-03f, +1.673924732e-05f, +8.264181830e-03f, -1.273520115e-02f, -3.198906769e-02f, +8.197416535e-03f, +3.181840805e-02f, +2.436087367e-03f, -7.095763901e-03f, +2.023419107e-03f, +6.800837112e-04f,
+ /* 12,14 */ +5.805594968e-04f, -1.551863117e-03f, -5.083818205e-04f, +8.272560314e-03f, -1.054842384e-02f, -3.254754550e-02f, +4.953502968e-03f, +3.242830266e-02f, +4.325531156e-03f, -7.544883174e-03f, +1.737094155e-03f, +8.925738220e-04f,
+ /* 12,15 */ +5.705687800e-04f, -1.332890330e-03f, -9.779320530e-04f, +8.147060845e-03f, -8.402419704e-03f, -3.280306521e-02f, +1.657033928e-03f, +3.276049121e-02f, +6.320860170e-03f, -7.900037037e-03f, +1.388266820e-03f, +1.111572639e-03f,
+ /* 12, 0 */ -1.054803383e-04f, -2.744858958e-03f, +7.370914553e-03f, -2.604494739e-03f, -3.666896703e-02f, -1.994735221e-03f, +3.707596726e-02f, +4.873177855e-03f, -8.012348726e-03f, +2.554514858e-03f, +3.117958677e-04f, -3.625540242e-04f,
+ /* 12, 1 */ +7.775923585e-05f, -2.860662969e-03f, +6.648820026e-03f, -4.950753709e-04f, -3.590728113e-02f, -5.960234251e-03f, +3.711196787e-02f, +7.277671607e-03f, -8.552819277e-03f, +2.286292242e-03f, +5.385913036e-04f, -4.265219564e-04f,
+ /* 12, 2 */ +2.361482435e-04f, -2.906545541e-03f, +5.866306097e-03f, +1.435258618e-03f, -3.481183398e-02f, -9.854190425e-03f, +3.676562700e-02f, +9.791136525e-03f, -8.972352970e-03f, +1.938320040e-03f, +7.824350015e-04f, -4.875429386e-04f,
+ /* 12, 3 */ +3.687004846e-04f, -2.888204359e-03f, +5.043181884e-03f, +3.170488652e-03f, -3.340772759e-02f, -1.363013975e-02f, +3.603085731e-02f, +1.238366322e-02f, -9.251714734e-03f, +1.510362297e-03f, +1.039066351e-03f, -5.431259501e-04f,
+ /* 12, 4 */ +4.751685216e-04f, -2.812206203e-03f, +4.198484259e-03f, +4.698496481e-03f, -3.172374637e-02f, -1.724344185e-02f, +3.490702283e-02f, +1.502265637e-02f, -9.372823891e-03f, +1.003961424e-03f, +1.303424694e-03f, -5.906251216e-04f,
+ /* 12, 5 */ +5.559799195e-04f, -2.685773447e-03f, +3.350171906e-03f, +6.011087921e-03f, -2.979181001e-02f, -2.065196332e-02f, +3.339904530e-02f, +1.767328103e-02f, -9.319170237e-03f, +4.225520445e-04f, +1.569701578e-03f, -6.273034189e-04f,
+ /* 12, 6 */ +6.121620582e-04f, -2.516571985e-03f, +2.514858275e-03f, +7.103945228e-03f, -2.764638515e-02f, -2.381671619e-02f, +3.151741694e-02f, +2.029896461e-02f, -9.076221424e-03f, -2.284590483e-04f, +1.831416829e-03f, -6.504054889e-04f,
+ /* 12, 7 */ +6.452583046e-04f, -2.312505227e-03f, +1.707586806e-03f, +7.976511649e-03f, -2.532386758e-02f, -2.670244010e-02f, +2.927811806e-02f, +2.286194672e-02f, -8.631812899e-03f, -9.416507761e-04f, +2.081518390e-03f, -6.572383529e-04f,
+ /* 12, 8 */ +6.572383529e-04f, -2.081518390e-03f, +9.416507761e-04f, +8.631812899e-03f, -2.286194672e-02f, -2.927811806e-02f, +2.670244010e-02f, +2.532386758e-02f, -7.976511649e-03f, -1.707586806e-03f, +2.312505227e-03f, -6.452583046e-04f,
+ /* 12, 9 */ +6.504054889e-04f, -1.831416829e-03f, +2.284590483e-04f, +9.076221424e-03f, -2.029896461e-02f, -3.151741694e-02f, +2.381671619e-02f, +2.764638515e-02f, -7.103945228e-03f, -2.514858275e-03f, +2.516571985e-03f, -6.121620582e-04f,
+ /* 12,10 */ +6.273034189e-04f, -1.569701578e-03f, -4.225520445e-04f, +9.319170237e-03f, -1.767328103e-02f, -3.339904530e-02f, +2.065196332e-02f, +2.979181001e-02f, -6.011087921e-03f, -3.350171906e-03f, +2.685773447e-03f, -5.559799195e-04f,
+ /* 12,11 */ +5.906251216e-04f, -1.303424694e-03f, -1.003961424e-03f, +9.372823891e-03f, -1.502265637e-02f, -3.490702283e-02f, +1.724344185e-02f, +3.172374637e-02f, -4.698496481e-03f, -4.198484259e-03f, +2.812206203e-03f, -4.751685216e-04f,
+ /* 12,12 */ +5.431259501e-04f, -1.039066351e-03f, -1.510362297e-03f, +9.251714734e-03f, -1.238366322e-02f, -3.603085731e-02f, +1.363013975e-02f, +3.340772759e-02f, -3.170488652e-03f, -5.043181884e-03f, +2.888204359e-03f, -3.687004846e-04f,
+ /* 12,13 */ +4.875429386e-04f, -7.824350015e-04f, -1.938320040e-03f, +8.972352970e-03f, -9.791136525e-03f, -3.676562700e-02f, +9.854190425e-03f, +3.481183398e-02f, -1.435258618e-03f, -5.866306097e-03f, +2.906545541e-03f, -2.361482435e-04f,
+ /* 12,14 */ +4.265219564e-04f, -5.385913036e-04f, -2.286292242e-03f, +8.552819277e-03f, -7.277671607e-03f, -3.711196787e-02f, +5.960234251e-03f, +3.590728113e-02f, +4.950753709e-04f, -6.648820026e-03f, +2.860662969e-03f, -7.775923585e-05f,
+ /* 12,15 */ +3.625540242e-04f, -3.117958677e-04f, -2.554514858e-03f, +8.012348726e-03f, -4.873177855e-03f, -3.707596726e-02f, +1.994735221e-03f, +3.666896703e-02f, +2.604494739e-03f, -7.370914553e-03f, +2.744858958e-03f, +1.054803383e-04f,
+ /* 12, 0 */ +6.110448771e-04f, -3.173989705e-03f, +5.751223243e-03f, +1.507555794e-03f, -4.035343888e-02f, -2.375409442e-03f, +4.124383193e-02f, +8.091337269e-04f, -6.726716888e-03f, +3.253952459e-03f, -5.087325269e-04f, -4.127854608e-05f,
+ /* 12, 1 */ +6.820041984e-04f, -3.029137857e-03f, +4.746351538e-03f, +3.578915017e-03f, -3.904147991e-02f, -7.094160720e-03f, +4.168490752e-02f, +3.349306133e-03f, -7.647219355e-03f, +3.259488816e-03f, -3.738470149e-04f, -9.536054020e-05f,
+ /* 12, 2 */ +7.235832870e-04f, -2.829602454e-03f, +3.736224000e-03f, +5.388621830e-03f, -3.734163661e-02f, -1.171726725e-02f, +4.165549067e-02f, +6.085743956e-03f, -8.486093037e-03f, +3.182049180e-03f, -2.060445111e-04f, -1.573545891e-04f,
+ /* 12, 3 */ +7.383739029e-04f, -2.585946508e-03f, +2.743066911e-03f, +6.925917423e-03f, -3.529277498e-02f, -1.618281485e-02f, +4.114151479e-02f, +8.986133221e-03f, -9.216195947e-03f, +3.014391908e-03f, -5.966328360e-06f, -2.260166200e-04f,
+ /* 12, 4 */ +7.294476853e-04f, -2.308795686e-03f, +1.786872733e-03f, +8.185530694e-03f, -3.293811768e-02f, -2.043162352e-02f, +4.013642610e-02f, +1.201345370e-02f, -9.810446156e-03f, +2.750895834e-03f, +2.246717082e-04f, -2.996559917e-04f,
+ /* 12, 5 */ +7.002161546e-04f, -2.008565767e-03f, +8.851333656e-04f, +9.167495079e-03f, -3.032435275e-02f, -2.440826356e-02f, +3.864144993e-02f, +1.512648157e-02f, -1.024241966e-02f, +2.387856219e-03f, +4.830138128e-04f, -3.761418846e-04f,
+ /* 12, 6 */ +6.542939604e-04f, -1.695217727e-03f, +5.264660367e-05f, +9.876866054e-03f, -2.750069849e-02f, -2.806199617e-02f, +3.666571148e-02f, +1.828039745e-02f, -1.048696943e-02f, +1.923755148e-03f, +7.650267923e-04f, -4.529261561e-04f,
+ /* 12, 7 */ +5.953691186e-04f, -1.378044726e-03f, -6.986040124e-04f, +1.032334944e-02f, -2.451794467e-02f, -3.134761990e-02f, +3.422620641e-02f, +2.142749023e-02f, -1.052085229e-02f, +1.359497506e-03f, +1.065494162e-03f, -5.270834853e-04f,
+ /* 12, 8 */ +5.270834853e-04f, -1.065494162e-03f, -1.359497506e-03f, +1.052085229e-02f, -2.142749023e-02f, -3.422620641e-02f, +3.134761990e-02f, +2.451794467e-02f, -1.032334944e-02f, +6.986040124e-04f, +1.378044726e-03f, -5.953691186e-04f,
+ /* 12, 9 */ +4.529261561e-04f, -7.650267923e-04f, -1.923755148e-03f, +1.048696943e-02f, -1.828039745e-02f, -3.666571148e-02f, +2.806199617e-02f, +2.750069849e-02f, -9.876866054e-03f, -5.264660367e-05f, +1.695217727e-03f, -6.542939604e-04f,
+ /* 12,10 */ +3.761418846e-04f, -4.830138128e-04f, -2.387856219e-03f, +1.024241966e-02f, -1.512648157e-02f, -3.864144993e-02f, +2.440826356e-02f, +3.032435275e-02f, -9.167495079e-03f, -8.851333656e-04f, +2.008565767e-03f, -7.002161546e-04f,
+ /* 12,11 */ +2.996559917e-04f, -2.246717082e-04f, -2.750895834e-03f, +9.810446156e-03f, -1.201345370e-02f, -4.013642610e-02f, +2.043162352e-02f, +3.293811768e-02f, -8.185530694e-03f, -1.786872733e-03f, +2.308795686e-03f, -7.294476853e-04f,
+ /* 12,12 */ +2.260166200e-04f, +5.966328360e-06f, -3.014391908e-03f, +9.216195947e-03f, -8.986133221e-03f, -4.114151479e-02f, +1.618281485e-02f, +3.529277498e-02f, -6.925917423e-03f, -2.743066911e-03f, +2.585946508e-03f, -7.383739029e-04f,
+ /* 12,13 */ +1.573545891e-04f, +2.060445111e-04f, -3.182049180e-03f, +8.486093037e-03f, -6.085743956e-03f, -4.165549067e-02f, +1.171726725e-02f, +3.734163661e-02f, -5.388621830e-03f, -3.736224000e-03f, +2.829602454e-03f, -7.235832870e-04f,
+ /* 12,14 */ +9.536054020e-05f, +3.738470149e-04f, -3.259488816e-03f, +7.647219355e-03f, -3.349306133e-03f, -4.168490752e-02f, +7.094160720e-03f, +3.904147991e-02f, -3.578915017e-03f, -4.746351538e-03f, +3.029137857e-03f, -6.820041984e-04f,
+ /* 12,15 */ +4.127854608e-05f, +5.087325269e-04f, -3.253952459e-03f, +6.726716888e-03f, -8.091337269e-04f, -4.124383193e-02f, +2.375409442e-03f, +4.035343888e-02f, -1.507555794e-03f, -5.751223243e-03f, +3.173989705e-03f, -6.110448771e-04f,
+
+ /* 24, 0 */ -8.820438069e-05f, -1.519461079e-04f, -2.301651496e-04f, -3.149320871e-04f, -3.945939739e-04f, -4.554410135e-04f, -4.841532882e-04f, -4.705408991e-04f, -4.099602091e-04f, -3.048100066e-04f, -1.646897470e-04f, -5.099007530e-06f, +1.551006323e-04f, +2.969416536e-04f, +4.046294158e-04f, +4.681429482e-04f, +4.846228261e-04f, +4.583040637e-04f, +3.990939388e-04f, +3.201968846e-04f, +2.353759082e-04f, +1.564712483e-04f, +9.167483068e-05f, +4.482688286e-05f,
+ /* 24, 1 */ -8.480575132e-05f, -1.474789784e-04f, -2.249812225e-04f, -3.096480504e-04f, -3.900204007e-04f, -4.524514078e-04f, -4.835165803e-04f, -4.727530367e-04f, -4.151145025e-04f, -3.125397891e-04f, -1.742016828e-04f, -1.529460870e-05f, +1.454387449e-04f, +2.889379628e-04f, +3.991236794e-04f, +4.655589110e-04f, +4.849233000e-04f, +4.610375470e-04f, +4.035168325e-04f, +3.254391996e-04f, +2.406110065e-04f, +1.610529558e-04f, +9.521673594e-05f, +4.721513201e-05f,
+ /* 24, 2 */ -8.147924507e-05f, -1.430712350e-04f, -2.198265592e-04f, -3.043479843e-04f, -3.853766873e-04f, -4.493383067e-04f, -4.827146831e-04f, -4.747797448e-04f, -4.200908527e-04f, -3.201278616e-04f, -1.836320864e-04f, -2.548296987e-05f, +1.357085413e-04f, +2.808022583e-04f, +3.934446700e-04f, +4.627886263e-04f, +4.850529052e-04f, +4.636385032e-04f, +4.078592000e-04f, +3.306557574e-04f, +2.458678944e-04f, +1.656897170e-04f, +9.882966748e-05f, +4.967415993e-05f,
+ /* 24, 3 */ -7.822510242e-05f, -1.387241832e-04f, -2.147035314e-04f, -2.990350629e-04f, -3.806663042e-04f, -4.461048161e-04f, -4.817496625e-04f, -4.766215175e-04f, -4.248879309e-04f, -3.275711800e-04f, -1.929766610e-04f, -3.565926997e-05f, +1.259145254e-04f, +2.725379532e-04f, +3.875941701e-04f, +4.598320457e-04f, +4.850099279e-04f, +4.661040260e-04f, +4.121175966e-04f, +3.358432542e-04f, +2.511439643e-04f, +1.703799499e-04f, +1.025131319e-04f, +5.220438912e-05f,
+ /* 24, 4 */ -7.504350274e-05f, -1.344390595e-04f, -2.096144489e-04f, -2.937124231e-04f, -3.758927218e-04f, -4.427540852e-04f, -4.806236671e-04f, -4.782789577e-04f, -4.295045226e-04f, -3.348667971e-04f, -2.022311686e-04f, -4.581869630e-05f, +1.160612449e-04f, +2.641485480e-04f, +3.815740737e-04f, +4.566892339e-04f, +4.847927474e-04f, +4.684312656e-04f, +4.162885910e-04f, +3.409983591e-04f, +2.564365532e-04f, +1.751220037e-04f, +1.062665706e-04f, +5.480619333e-05f,
+ /* 24, 5 */ -7.193456522e-05f, -1.302170312e-04f, -2.045615590e-04f, -2.883831622e-04f, -3.710594077e-04f, -4.392893036e-04f, -4.793389263e-04f, -4.797527765e-04f, -4.339395286e-04f, -3.420118645e-04f, -2.113914331e-04f, -5.595644787e-05f, +1.061532886e-04f, +2.556376279e-04f, +3.753863858e-04f, +4.533603695e-04f, +4.843998374e-04f, +4.706174312e-04f, +4.203687678e-04f, +3.461177167e-04f, +2.617429433e-04f, +1.799141593e-04f, +1.100893595e-04f, +5.747989630e-05f,
+ /* 24, 6 */ -6.889834987e-05f, -1.260591965e-04f, -1.995470454e-04f, -2.830503358e-04f, -3.661698243e-04f, -4.357136989e-04f, -4.778977479e-04f, -4.810437916e-04f, -4.381919648e-04f, -3.490036345e-04f, -2.204533432e-04f, -6.606773875e-05f, +9.619528314e-05f, +2.470088608e-04f, +3.690332209e-04f, +4.498457452e-04f, +4.838297683e-04f, +4.726597937e-04f, +4.243547301e-04f, +3.511979487e-04f, +2.670603639e-04f, +1.847546294e-04f, +1.139808078e-04f, +6.022577049e-05f,
+ /* 24, 7 */ -6.593485851e-05f, -1.219665852e-04f, -1.945730275e-04f, -2.777169567e-04f, -3.612274261e-04f, -4.320305335e-04f, -4.763025159e-04f, -4.821529264e-04f, -4.422609626e-04f, -3.558394612e-04f, -2.294128549e-04f, -7.614780136e-05f, +8.619188981e-05f, +2.382659945e-04f, +3.625168024e-04f, +4.461457687e-04f, +4.830812085e-04f, +4.745556880e-04f, +4.282431024e-04f, +3.562356572e-04f, +2.723859925e-04f, +1.896415594e-04f, +1.179401580e-04f, +6.304403582e-05f,
+ /* 24, 8 */ -6.304403582e-05f, -1.179401580e-04f, -1.896415594e-04f, -2.723859925e-04f, -3.562356572e-04f, -4.282431024e-04f, -4.745556880e-04f, -4.830812085e-04f, -4.461457687e-04f, -3.625168024e-04f, -2.382659945e-04f, -8.619188981e-05f, +7.614780136e-05f, +2.294128549e-04f, +3.558394612e-04f, +4.422609626e-04f, +4.821529264e-04f, +4.763025159e-04f, +4.320305335e-04f, +3.612274261e-04f, +2.777169567e-04f, +1.945730275e-04f, +1.219665852e-04f, +6.593485851e-05f,
+ /* 24, 9 */ -6.022577049e-05f, -1.139808078e-04f, -1.847546294e-04f, -2.670603639e-04f, -3.511979487e-04f, -4.243547301e-04f, -4.726597937e-04f, -4.838297683e-04f, -4.498457452e-04f, -3.690332209e-04f, -2.470088608e-04f, -9.619528314e-05f, +6.606773875e-05f, +2.204533432e-04f, +3.490036345e-04f, +4.381919648e-04f, +4.810437916e-04f, +4.778977479e-04f, +4.357136989e-04f, +3.661698243e-04f, +2.830503358e-04f, +1.995470454e-04f, +1.260591965e-04f, +6.889834987e-05f,
+ /* 24,10 */ -5.747989630e-05f, -1.100893595e-04f, -1.799141593e-04f, -2.617429433e-04f, -3.461177167e-04f, -4.203687678e-04f, -4.706174312e-04f, -4.843998374e-04f, -4.533603695e-04f, -3.753863858e-04f, -2.556376279e-04f, -1.061532886e-04f, +5.595644787e-05f, +2.113914331e-04f, +3.420118645e-04f, +4.339395286e-04f, +4.797527765e-04f, +4.793389263e-04f, +4.392893036e-04f, +3.710594077e-04f, +2.883831622e-04f, +2.045615590e-04f, +1.302170312e-04f, +7.193456522e-05f,
+ /* 24,11 */ -5.480619333e-05f, -1.062665706e-04f, -1.751220037e-04f, -2.564365532e-04f, -3.409983591e-04f, -4.162885910e-04f, -4.684312656e-04f, -4.847927474e-04f, -4.566892339e-04f, -3.815740737e-04f, -2.641485480e-04f, -1.160612449e-04f, +4.581869630e-05f, +2.022311686e-04f, +3.348667971e-04f, +4.295045226e-04f, +4.782789577e-04f, +4.806236671e-04f, +4.427540852e-04f, +3.758927218e-04f, +2.937124231e-04f, +2.096144489e-04f, +1.344390595e-04f, +7.504350274e-05f,
+ /* 24,12 */ -5.220438912e-05f, -1.025131319e-04f, -1.703799499e-04f, -2.511439643e-04f, -3.358432542e-04f, -4.121175966e-04f, -4.661040260e-04f, -4.850099279e-04f, -4.598320457e-04f, -3.875941701e-04f, -2.725379532e-04f, -1.259145254e-04f, +3.565926997e-05f, +1.929766610e-04f, +3.275711800e-04f, +4.248879309e-04f, +4.766215175e-04f, +4.817496625e-04f, +4.461048161e-04f, +3.806663042e-04f, +2.990350629e-04f, +2.147035314e-04f, +1.387241832e-04f, +7.822510242e-05f,
+ /* 24,13 */ -4.967415993e-05f, -9.882966748e-05f, -1.656897170e-04f, -2.458678944e-04f, -3.306557574e-04f, -4.078592000e-04f, -4.636385032e-04f, -4.850529052e-04f, -4.627886263e-04f, -3.934446700e-04f, -2.808022583e-04f, -1.357085413e-04f, +2.548296987e-05f, +1.836320864e-04f, +3.201278616e-04f, +4.200908527e-04f, +4.747797448e-04f, +4.827146831e-04f, +4.493383067e-04f, +3.853766873e-04f, +3.043479843e-04f, +2.198265592e-04f, +1.430712350e-04f, +8.147924507e-05f,
+ /* 24,14 */ -4.721513201e-05f, -9.521673594e-05f, -1.610529558e-04f, -2.406110065e-04f, -3.254391996e-04f, -4.035168325e-04f, -4.610375470e-04f, -4.849233000e-04f, -4.655589110e-04f, -3.991236794e-04f, -2.889379628e-04f, -1.454387449e-04f, +1.529460870e-05f, +1.742016828e-04f, +3.125397891e-04f, +4.151145025e-04f, +4.727530367e-04f, +4.835165803e-04f, +4.524514078e-04f, +3.900204007e-04f, +3.096480504e-04f, +2.249812225e-04f, +1.474789784e-04f, +8.480575132e-05f,
+ /* 24,15 */ -4.482688286e-05f, -9.167483068e-05f, -1.564712483e-04f, -2.353759082e-04f, -3.201968846e-04f, -3.990939388e-04f, -4.583040637e-04f, -4.846228261e-04f, -4.681429482e-04f, -4.046294158e-04f, -2.969416536e-04f, -1.551006323e-04f, +5.099007530e-06f, +1.646897470e-04f, +3.048100066e-04f, +4.099602091e-04f, +4.705408991e-04f, +4.841532882e-04f, +4.554410135e-04f, +3.945939739e-04f, +3.149320871e-04f, +2.301651496e-04f, +1.519461079e-04f, +8.820438069e-05f,
+ /* 24, 0 */ +1.254177052e-04f, +1.432187562e-04f, +1.041598752e-04f, -1.135750248e-05f, -2.010663923e-04f, -4.345091125e-04f, -6.566280172e-04f, -8.018070806e-04f, -8.145094672e-04f, -6.693628869e-04f, -3.829411831e-04f, -1.208738944e-05f, +3.614691013e-04f, +6.551938988e-04f, +8.101126455e-04f, +8.069330100e-04f, +6.686285441e-04f, +4.493898115e-04f, +2.148422063e-04f, +2.121126661e-05f, -9.928779545e-05f, -1.427235715e-04f, -1.276505127e-04f, -8.319130160e-05f,
+ /* 24, 1 */ +1.230784715e-04f, +1.434886692e-04f, +1.087259386e-04f, -1.803144714e-06f, -1.874698746e-04f, -4.195879132e-04f, -6.443236569e-04f, -7.961535056e-04f, -8.182754723e-04f, -6.829663304e-04f, -4.040749814e-04f, -3.625133679e-05f, +3.396771574e-04f, +6.404692089e-04f, +8.050839212e-04f, +8.115205881e-04f, +6.803091718e-04f, +4.642140510e-04f, +2.287861157e-04f, +3.136033560e-05f, -9.410712043e-05f, -1.419963918e-04f, -1.297693532e-04f, -8.627587811e-05f,
+ /* 24, 2 */ +1.206403004e-04f, +1.435401825e-04f, +1.129889134e-04f, +7.448162127e-06f, -1.740634498e-04f, -4.046419937e-04f, -6.317316839e-04f, -7.899834729e-04f, -8.214124236e-04f, -6.959950382e-04f, -4.248524782e-04f, -6.038280262e-05f, +3.175841545e-04f, +6.251993025e-04f, +7.994228899e-04f, +8.155596091e-04f, +6.916540113e-04f, +4.789657110e-04f, +2.428865252e-04f, +4.180014906e-05f, -8.861563067e-05f, -1.410306561e-04f, -1.317666448e-04f, -8.934972901e-05f,
+ /* 24, 3 */ +1.181106179e-04f, +1.433803035e-04f, +1.169520657e-04f, +1.639322797e-05f, -1.608575022e-04f, -3.896869361e-04f, -6.188684520e-04f, -7.833086355e-04f, -8.239227539e-04f, -7.084404793e-04f, -4.452560799e-04f, -8.446017611e-05f, +2.952092559e-04f, +6.093952965e-04f, +7.931298338e-04f, +8.190403838e-04f, +7.026473724e-04f, +4.936285297e-04f, +2.571314547e-04f, +5.252568657e-05f, -8.281147599e-05f, -1.398199793e-04f, -1.336347757e-04f, -9.240689021e-05f,
+ /* 24, 4 */ +1.154967766e-04f, +1.430161614e-04f, +1.206189886e-04f, +2.502931407e-05f, -1.478619956e-04f, -3.747381071e-04f, -6.057504254e-04f, -7.761410928e-04f, -8.258095592e-04f, -7.202947906e-04f, -4.652686374e-04f, -1.084619116e-04f, +2.725719623e-04f, +5.930689291e-04f, +7.862057246e-04f, +8.219537553e-04f, +7.132737861e-04f, +5.081861235e-04f, +2.715085502e-04f, +6.353146713e-05f, -7.669318508e-05f, -1.383581653e-04f, -1.353661159e-04f, -9.544123411e-05f,
+ /* 24, 5 */ +1.128060463e-04f, +1.424549941e-04f, +1.239935912e-04f, +3.335412922e-05f, -1.350864661e-04f, -3.598106411e-04f, -5.923941571e-04f, -7.684933716e-04f, -8.270765907e-04f, -7.315507834e-04f, -4.848734661e-04f, -1.323665545e-04f, +2.496920884e-04f, +5.762325468e-04f, +7.786522269e-04f, +8.242911148e-04f, +7.235180256e-04f, +5.226220062e-04f, +2.860050947e-04f, +7.481154929e-05f, -7.025967465e-05f, -1.366392205e-04f, -1.369530289e-04f, -9.844647580e-05f,
+ /* 24, 6 */ +1.100456035e-04f, +1.417041346e-04f, +1.270800866e-04f, +4.136582536e-05f, -1.225400157e-04f, -3.449194225e-04f, -5.788162671e-04f, -7.603784078e-04f, -8.277282458e-04f, -7.422019493e-04f, -5.040543645e-04f, -1.561527673e-04f, +2.265897402e-04f, +5.588990922e-04f, +7.704716994e-04f, +8.260444163e-04f, +7.333651287e-04f, +5.369196097e-04f, +3.006080208e-04f, +8.635953200e-05f, -6.351025813e-05f, -1.346573670e-04f, -1.383878839e-04f, -1.014161798e-04f,
+ /* 24, 7 */ +1.072225228e-04f, +1.407709979e-04f, +1.298829797e-04f, +4.906299265e-05f, -1.102313067e-04f, -3.300790706e-04f, -5.650334202e-04f, -7.518095256e-04f, -8.277695590e-04f, -7.522424649e-04f, -5.227956327e-04f, -1.797993550e-04f, +2.032852905e-04f, +5.410820901e-04f, +7.616671958e-04f, +8.272061905e-04f, +7.428004186e-04f, +5.510623045e-04f, +3.153039229e-04f, +9.816855611e-05f, -5.644465382e-05f, -1.324070557e-04f, -1.396630677e-04f, -1.043437672e-04f,
+ /* 24, 8 */ +1.043437672e-04f, +1.396630677e-04f, +1.324070557e-04f, +5.644465382e-05f, -9.816855611e-05f, -3.153039229e-04f, -5.510623045e-04f, -7.428004186e-04f, -8.272061905e-04f, -7.616671958e-04f, -5.410820901e-04f, -2.032852905e-04f, +1.797993550e-04f, +5.227956327e-04f, +7.522424649e-04f, +8.277695590e-04f, +7.518095256e-04f, +5.650334202e-04f, +3.300790706e-04f, +1.102313067e-04f, -4.906299265e-05f, -1.298829797e-04f, -1.407709979e-04f, -1.072225228e-04f,
+ /* 24, 9 */ +1.014161798e-04f, +1.383878839e-04f, +1.346573670e-04f, +6.351025813e-05f, -8.635953200e-05f, -3.006080208e-04f, -5.369196097e-04f, -7.333651287e-04f, -8.260444163e-04f, -7.704716994e-04f, -5.588990922e-04f, -2.265897402e-04f, +1.561527673e-04f, +5.040543645e-04f, +7.422019493e-04f, +8.277282458e-04f, +7.603784078e-04f, +5.788162671e-04f, +3.449194225e-04f, +1.225400157e-04f, -4.136582536e-05f, -1.270800866e-04f, -1.417041346e-04f, -1.100456035e-04f,
+ /* 24,10 */ +9.844647580e-05f, +1.369530289e-04f, +1.366392205e-04f, +7.025967465e-05f, -7.481154929e-05f, -2.860050947e-04f, -5.226220062e-04f, -7.235180256e-04f, -8.242911148e-04f, -7.786522269e-04f, -5.762325468e-04f, -2.496920884e-04f, +1.323665545e-04f, +4.848734661e-04f, +7.315507834e-04f, +8.270765907e-04f, +7.684933716e-04f, +5.923941571e-04f, +3.598106411e-04f, +1.350864661e-04f, -3.335412922e-05f, -1.239935912e-04f, -1.424549941e-04f, -1.128060463e-04f,
+ /* 24,11 */ +9.544123411e-05f, +1.353661159e-04f, +1.383581653e-04f, +7.669318508e-05f, -6.353146713e-05f, -2.715085502e-04f, -5.081861235e-04f, -7.132737861e-04f, -8.219537553e-04f, -7.862057246e-04f, -5.930689291e-04f, -2.725719623e-04f, +1.084619116e-04f, +4.652686374e-04f, +7.202947906e-04f, +8.258095592e-04f, +7.761410928e-04f, +6.057504254e-04f, +3.747381071e-04f, +1.478619956e-04f, -2.502931407e-05f, -1.206189886e-04f, -1.430161614e-04f, -1.154967766e-04f,
+ /* 24,12 */ +9.240689021e-05f, +1.336347757e-04f, +1.398199793e-04f, +8.281147599e-05f, -5.252568657e-05f, -2.571314547e-04f, -4.936285297e-04f, -7.026473724e-04f, -8.190403838e-04f, -7.931298338e-04f, -6.093952965e-04f, -2.952092559e-04f, +8.446017611e-05f, +4.452560799e-04f, +7.084404793e-04f, +8.239227539e-04f, +7.833086355e-04f, +6.188684520e-04f, +3.896869361e-04f, +1.608575022e-04f, -1.639322797e-05f, -1.169520657e-04f, -1.433803035e-04f, -1.181106179e-04f,
+ /* 24,13 */ +8.934972901e-05f, +1.317666448e-04f, +1.410306561e-04f, +8.861563067e-05f, -4.180014906e-05f, -2.428865252e-04f, -4.789657110e-04f, -6.916540113e-04f, -8.155596091e-04f, -7.994228899e-04f, -6.251993025e-04f, -3.175841545e-04f, +6.038280262e-05f, +4.248524782e-04f, +6.959950382e-04f, +8.214124236e-04f, +7.899834729e-04f, +6.317316839e-04f, +4.046419937e-04f, +1.740634498e-04f, -7.448162127e-06f, -1.129889134e-04f, -1.435401825e-04f, -1.206403004e-04f,
+ /* 24,14 */ +8.627587811e-05f, +1.297693532e-04f, +1.419963918e-04f, +9.410712043e-05f, -3.136033560e-05f, -2.287861157e-04f, -4.642140510e-04f, -6.803091718e-04f, -8.115205881e-04f, -8.050839212e-04f, -6.404692089e-04f, -3.396771574e-04f, +3.625133679e-05f, +4.040749814e-04f, +6.829663304e-04f, +8.182754723e-04f, +7.961535056e-04f, +6.443236569e-04f, +4.195879132e-04f, +1.874698746e-04f, +1.803144714e-06f, -1.087259386e-04f, -1.434886692e-04f, -1.230784715e-04f,
+ /* 24,15 */ +8.319130160e-05f, +1.276505127e-04f, +1.427235715e-04f, +9.928779545e-05f, -2.121126661e-05f, -2.148422063e-04f, -4.493898115e-04f, -6.686285441e-04f, -8.069330100e-04f, -8.101126455e-04f, -6.551938988e-04f, -3.614691013e-04f, +1.208738944e-05f, +3.829411831e-04f, +6.693628869e-04f, +8.145094672e-04f, +8.018070806e-04f, +6.566280172e-04f, +4.345091125e-04f, +2.010663923e-04f, +1.135750248e-05f, -1.041598752e-04f, -1.432187562e-04f, -1.254177052e-04f,
+ /* 24, 0 */ +4.545052445e-05f, +1.951315810e-04f, +3.748938080e-04f, +4.809335107e-04f, +3.960765690e-04f, +5.993810822e-05f, -4.723795438e-04f, -1.024325735e-03f, -1.361247582e-03f, -1.299302728e-03f, -8.046117557e-04f, -2.606329026e-05f, +7.618428442e-04f, +1.280408741e-03f, +1.370322771e-03f, +1.054089829e-03f, +5.086432784e-04f, -3.113193898e-05f, -3.825195300e-04f, -4.822884412e-04f, -3.849609275e-04f, -2.063256631e-04f, -5.270037440e-05f, +2.454794639e-05f,
+ /* 24, 1 */ +3.852332445e-05f, +1.840753178e-04f, +3.645444067e-04f, +4.788140096e-04f, +4.086121277e-04f, +8.793526572e-05f, -4.362135407e-04f, -9.937048198e-04f, -1.350562575e-03f, -1.316442769e-03f, -8.462280606e-04f, -7.815185270e-05f, +7.179801999e-04f, +1.259777116e-03f, +1.377758125e-03f, +1.082939175e-03f, +5.449481703e-04f, -1.547839432e-06f, -3.679388598e-04f, -4.828529979e-04f, -3.947147844e-04f, -2.176372792e-04f, -6.026901850e-05f, +2.205234045e-05f,
+ /* 24, 2 */ +3.192167036e-05f, +1.731761778e-04f, +3.539434193e-04f, +4.759566352e-04f, +4.201302650e-04f, +1.150943789e-04f, -4.002008253e-04f, -9.622858103e-04f, -1.338300241e-03f, -1.331815598e-03f, -8.866349827e-04f, -1.301264311e-04f, +6.730846905e-04f, +1.237427186e-03f, +1.383526171e-03f, +1.110816763e-03f, +5.812367254e-04f, +2.878109064e-05f, -3.523343557e-04f, -4.826023474e-04f, -4.041241778e-04f, -2.290451863e-04f, -6.815162122e-05f, +1.926869283e-05f,
+ /* 24, 3 */ +2.564752013e-05f, +1.624524653e-04f, +3.431211940e-04f, +4.723889014e-04f, +4.306369033e-04f, +1.413884897e-04f, -3.643958409e-04f, -9.301281119e-04f, -1.324495465e-03f, -1.345410999e-03f, -9.257779427e-04f, -1.819112698e-04f, +6.272190697e-04f, +1.213381290e-03f, +1.387602061e-03f, +1.137666624e-03f, +6.174506312e-04f, +5.981976836e-05f, -3.357077999e-04f, -4.815127015e-04f, -4.131577529e-04f, -2.405272085e-04f, -7.634234963e-05f, +1.618998833e-05f,
+ /* 24, 4 */ +1.970191739e-05f, +1.519214683e-04f, +3.321076713e-04f, +4.681390617e-04f, +4.401397816e-04f, +1.667927354e-04f, -3.288518263e-04f, -8.972916878e-04f, -1.309185436e-03f, -1.357221809e-03f, -9.636046528e-04f, -2.334309635e-04f, +5.804478655e-04f, +1.187664745e-03f, +1.389963631e-03f, +1.163433942e-03f, +6.535308606e-04f, +9.153116784e-05f, -3.180629927e-04f, -4.795613921e-04f, -4.217840695e-04f, -2.520602653e-04f, -8.483435780e-05f, +1.280977164e-05f,
+ /* 24, 5 */ +1.408501704e-05f, +1.415994448e-04f, +3.209323254e-04f, +4.632360317e-04f, +4.486484045e-04f, +1.912843645e-04f, -2.936207276e-04f, -8.638369381e-04f, -1.292409564e-03f, -1.367243913e-03f, -1.000065207e-03f, -2.846105957e-04f, +5.328372638e-04f, +1.160305814e-03f, +1.390591463e-03f, +1.188065177e-03f, +6.894177793e-04f, +1.238763650e-04f, -2.994057812e-04f, -4.767269440e-04f, -4.299716716e-04f, -2.636204028e-04f, -9.361977359e-05f, +9.122184539e-06f,
+ /* 24, 6 */ +8.796112429e-06f, +1.315016126e-04f, +3.096241086e-04f, +4.577093118e-04f, +4.561739887e-04f, +2.148427485e-04f, -2.587531149e-04f, -8.298245798e-04f, -1.274209383e-03f, -1.375476234e-03f, -1.035112163e-03f, -3.353758773e-04f, +4.844549899e-04f, +1.131335665e-03f, +1.389468944e-03f, +1.211508174e-03f, +7.250512548e-04f, +1.568145870e-04f, -2.797440842e-04f, -4.729891466e-04f, -4.376891593e-04f, -2.751828281e-04f, -1.026896878e-04f, +5.122002376e-06f,
+ /* 24, 7 */ +3.833664119e-06f, +1.216421408e-04f, +2.982113984e-04f, +4.515889092e-04f, +4.627294060e-04f, +2.374493875e-04f, -2.242981012e-04f, -7.953155261e-04f, -1.254628457e-03f, -1.381920720e-03f, -1.068700627e-03f, -3.856532828e-04f, +4.353701854e-04f, +1.100788324e-03f, +1.386582316e-03f, +1.233712281e-03f, +7.603707678e-04f, +1.903032668e-04f, -2.590879129e-04f, -4.683291247e-04f, -4.449052614e-04f, -2.867219458e-04f, -1.120341455e-04f, +8.046698450e-07f,
+ /* 24, 8 */ -8.046698450e-07f, +1.120341455e-04f, +2.867219458e-04f, +4.449052614e-04f, +4.683291247e-04f, +2.590879129e-04f, -1.903032668e-04f, -7.603707678e-04f, -1.233712281e-03f, -1.386582316e-03f, -1.100788324e-03f, -4.353701854e-04f, +3.856532828e-04f, +1.068700627e-03f, +1.381920720e-03f, +1.254628457e-03f, +7.953155261e-04f, +2.242981012e-04f, -2.374493875e-04f, -4.627294060e-04f, -4.515889092e-04f, -2.982113984e-04f, -1.216421408e-04f, -3.833664119e-06f,
+ /* 24, 9 */ -5.122002376e-06f, +1.026896878e-04f, +2.751828281e-04f, +4.376891593e-04f, +4.729891466e-04f, +2.797440842e-04f, -1.568145870e-04f, -7.250512548e-04f, -1.211508174e-03f, -1.389468944e-03f, -1.131335665e-03f, -4.844549899e-04f, +3.353758773e-04f, +1.035112163e-03f, +1.375476234e-03f, +1.274209383e-03f, +8.298245798e-04f, +2.587531149e-04f, -2.148427485e-04f, -4.561739887e-04f, -4.577093118e-04f, -3.096241086e-04f, -1.315016126e-04f, -8.796112429e-06f,
+ /* 24,10 */ -9.122184539e-06f, +9.361977359e-05f, +2.636204028e-04f, +4.299716716e-04f, +4.767269440e-04f, +2.994057812e-04f, -1.238763650e-04f, -6.894177793e-04f, -1.188065177e-03f, -1.390591463e-03f, -1.160305814e-03f, -5.328372638e-04f, +2.846105957e-04f, +1.000065207e-03f, +1.367243913e-03f, +1.292409564e-03f, +8.638369381e-04f, +2.936207276e-04f, -1.912843645e-04f, -4.486484045e-04f, -4.632360317e-04f, -3.209323254e-04f, -1.415994448e-04f, -1.408501704e-05f,
+ /* 24,11 */ -1.280977164e-05f, +8.483435780e-05f, +2.520602653e-04f, +4.217840695e-04f, +4.795613921e-04f, +3.180629927e-04f, -9.153116784e-05f, -6.535308606e-04f, -1.163433942e-03f, -1.389963631e-03f, -1.187664745e-03f, -5.804478655e-04f, +2.334309635e-04f, +9.636046528e-04f, +1.357221809e-03f, +1.309185436e-03f, +8.972916878e-04f, +3.288518263e-04f, -1.667927354e-04f, -4.401397816e-04f, -4.681390617e-04f, -3.321076713e-04f, -1.519214683e-04f, -1.970191739e-05f,
+ /* 24,12 */ -1.618998833e-05f, +7.634234963e-05f, +2.405272085e-04f, +4.131577529e-04f, +4.815127015e-04f, +3.357077999e-04f, -5.981976836e-05f, -6.174506312e-04f, -1.137666624e-03f, -1.387602061e-03f, -1.213381290e-03f, -6.272190697e-04f, +1.819112698e-04f, +9.257779427e-04f, +1.345410999e-03f, +1.324495465e-03f, +9.301281119e-04f, +3.643958409e-04f, -1.413884897e-04f, -4.306369033e-04f, -4.723889014e-04f, -3.431211940e-04f, -1.624524653e-04f, -2.564752013e-05f,
+ /* 24,13 */ -1.926869283e-05f, +6.815162122e-05f, +2.290451863e-04f, +4.041241778e-04f, +4.826023474e-04f, +3.523343557e-04f, -2.878109064e-05f, -5.812367254e-04f, -1.110816763e-03f, -1.383526171e-03f, -1.237427186e-03f, -6.730846905e-04f, +1.301264311e-04f, +8.866349827e-04f, +1.331815598e-03f, +1.338300241e-03f, +9.622858103e-04f, +4.002008253e-04f, -1.150943789e-04f, -4.201302650e-04f, -4.759566352e-04f, -3.539434193e-04f, -1.731761778e-04f, -3.192167036e-05f,
+ /* 24,14 */ -2.205234045e-05f, +6.026901850e-05f, +2.176372792e-04f, +3.947147844e-04f, +4.828529979e-04f, +3.679388598e-04f, +1.547839432e-06f, -5.449481703e-04f, -1.082939175e-03f, -1.377758125e-03f, -1.259777116e-03f, -7.179801999e-04f, +7.815185270e-05f, +8.462280606e-04f, +1.316442769e-03f, +1.350562575e-03f, +9.937048198e-04f, +4.362135407e-04f, -8.793526572e-05f, -4.086121277e-04f, -4.788140096e-04f, -3.645444067e-04f, -1.840753178e-04f, -3.852332445e-05f,
+ /* 24,15 */ -2.454794639e-05f, +5.270037440e-05f, +2.063256631e-04f, +3.849609275e-04f, +4.822884412e-04f, +3.825195300e-04f, +3.113193898e-05f, -5.086432784e-04f, -1.054089829e-03f, -1.370322771e-03f, -1.280408741e-03f, -7.618428442e-04f, +2.606329026e-05f, +8.046117557e-04f, +1.299302728e-03f, +1.361247582e-03f, +1.024325735e-03f, +4.723795438e-04f, -5.993810822e-05f, -3.960765690e-04f, -4.809335107e-04f, -3.748938080e-04f, -1.951315810e-04f, -4.545052445e-05f,
+ /* 24, 0 */ -1.702250368e-04f, -1.965005420e-04f, +1.103795304e-06f, +4.330784212e-04f, +8.784555707e-04f, +9.653328276e-04f, +4.315509563e-04f, -6.109575553e-04f, -1.641723450e-03f, -2.015827225e-03f, -1.400787443e-03f, -4.702498413e-05f, +1.332047630e-03f, +2.006889303e-03f, +1.690240096e-03f, +6.826705419e-04f, -3.776686811e-04f, -9.512688743e-04f, -8.983149818e-04f, -4.640234647e-04f, -2.230828855e-05f, +1.918067822e-04f, +1.759255972e-04f, +6.786242515e-05f,
+ /* 24, 1 */ -1.642126010e-04f, -2.002752798e-04f, -1.910126829e-05f, +4.022439121e-04f, +8.571608722e-04f, +9.768399670e-04f, +4.832977173e-04f, -5.392469404e-04f, -1.590532482e-03f, -2.020693110e-03f, -1.466475318e-03f, -1.409702826e-04f, +1.260398022e-03f, +1.993868298e-03f, +1.735939471e-03f, +7.542164043e-04f, -3.217397652e-04f, -9.346209288e-04f, -9.166430096e-04f, -4.949934945e-04f, -4.448641826e-05f, +1.861665779e-04f, +1.812738819e-04f, +7.451957718e-05f,
+ /* 24, 2 */ -1.579281336e-04f, -2.031605347e-04f, -3.828516688e-05f, +3.716026326e-04f, +8.345286135e-04f, +9.858238344e-04f, +5.328272649e-04f, -4.677058239e-04f, -1.536815378e-03f, -2.021508037e-03f, -1.528977139e-03f, -2.346018520e-04f, +1.185988431e-03f, +1.976763286e-03f, +1.778684302e-03f, +8.254237228e-04f, -2.638601140e-04f, -9.153683790e-04f, -9.333455225e-04f, -5.259003096e-04f, -6.760829922e-05f, +1.795547962e-04f, +1.862290729e-04f, +8.132190552e-05f,
+ /* 24, 3 */ -1.514107898e-04f, -2.051877883e-04f, -5.643017558e-05f, +3.412342375e-04f, +8.106578209e-04f, +9.923241157e-04f, +5.800651921e-04f, -3.964985305e-04f, -1.480725107e-03f, -2.018303000e-03f, -1.588167145e-03f, -3.277114722e-04f, +1.108975953e-03f, +1.955583535e-03f, +1.818343426e-03f, +8.961196099e-04f, -2.041325004e-04f, -8.934973649e-04f, -9.483306864e-04f, -5.566532714e-04f, -9.163993343e-05f, +1.719487619e-04f, +1.907500791e-04f, +8.824611727e-05f,
+ /* 24, 4 */ -1.446989102e-04f, -2.063902871e-04f, -7.352252002e-05f, +3.112151687e-04f, +7.856484910e-04f, +9.963864071e-04f, +6.249444785e-04f, -3.257861630e-04f, -1.422418959e-03f, -2.011118755e-03f, -1.643928243e-03f, -4.200923193e-04f, +1.029524574e-03f, +1.930348530e-03f, +1.854792197e-03f, +9.661301752e-04f, -1.426663759e-04f, -8.690009463e-04f, -9.615092978e-04f, -5.871595310e-04f, -1.165432034e-04f, +1.633284218e-04f, +1.947956873e-04f, +9.526723781e-05f,
+ /* 24, 5 */ -1.378299032e-04f, -2.068028652e-04f, -8.955230425e-05f, +2.816184974e-04f, +7.596012646e-04f, +9.980619660e-04f, +6.674055614e-04f, -2.557261963e-04f, -1.362058071e-03f, -2.000005648e-03f, -1.696152289e-03f, -5.115395181e-04f, +9.478047386e-04f, +1.901087985e-03f, +1.887912892e-03f, +1.035280999e-03f, -7.957765930e-05f, -8.418792522e-04f, -9.727951144e-04f, -6.173242692e-04f, -1.422758795e-04f, +1.536765045e-04f, +1.983247179e-04f, +1.023586489e-04f,
+ /* 24, 6 */ -1.308401336e-04f, -2.064617646e-04f, -1.045134271e-04f, +2.525137807e-04f, +7.326171060e-04f, +9.974074494e-04f, +7.073963828e-04f, -1.864720875e-04f, -1.299806951e-03f, -1.985023411e-03f, -1.744740344e-03f, -6.018506887e-04f, +8.639929140e-04f, +1.867841815e-03f, +1.917595086e-03f, +1.103397612e-03f, -1.498850339e-05f, -8.121396097e-04f, -9.821051828e-04f, -6.470509490e-04f, -1.687916421e-04f, +1.429786744e-04f, +2.012961856e-04f, +1.094921351e-04f,
+ /* 24, 7 */ -1.237648199e-04f, -2.054044567e-04f, -1.184034872e-04f, +2.239669341e-04f, +7.047969872e-04f, +9.944846402e-04f, +7.448724134e-04f, -1.181729029e-04f, -1.235832990e-03f, -1.966240936e-03f, -1.789602898e-03f, -6.908264855e-04f, +7.782711267e-04f, +1.830660078e-03f, +1.943736019e-03f, +1.170305979e-03f, +5.097296116e-05f, -7.797966533e-04f, -9.893601617e-04f, -6.762415789e-04f, -1.960401183e-04f, +1.312236785e-04f, +2.036694644e-04f, +1.166379381e-04f,
+ /* 24, 8 */ -1.166379381e-04f, -2.036694644e-04f, -1.312236785e-04f, +1.960401183e-04f, +6.762415789e-04f, +9.893601617e-04f, +7.797966533e-04f, -5.097296116e-05f, -1.170305979e-03f, -1.943736019e-03f, -1.830660078e-03f, -7.782711267e-04f, +6.908264855e-04f, +1.789602898e-03f, +1.966240936e-03f, +1.235832990e-03f, +1.181729029e-04f, -7.448724134e-04f, -9.944846402e-04f, -7.047969872e-04f, -2.239669341e-04f, +1.184034872e-04f, +2.054044567e-04f, +1.237648199e-04f,
+ /* 24, 9 */ -1.094921351e-04f, -2.012961856e-04f, -1.429786744e-04f, +1.687916421e-04f, +6.470509490e-04f, +9.821051828e-04f, +8.121396097e-04f, +1.498850339e-05f, -1.103397612e-03f, -1.917595086e-03f, -1.867841815e-03f, -8.639929140e-04f, +6.018506887e-04f, +1.744740344e-03f, +1.985023411e-03f, +1.299806951e-03f, +1.864720875e-04f, -7.073963828e-04f, -9.974074494e-04f, -7.326171060e-04f, -2.525137807e-04f, +1.045134271e-04f, +2.064617646e-04f, +1.308401336e-04f,
+ /* 24,10 */ -1.023586489e-04f, -1.983247179e-04f, -1.536765045e-04f, +1.422758795e-04f, +6.173242692e-04f, +9.727951144e-04f, +8.418792522e-04f, +7.957765930e-05f, -1.035280999e-03f, -1.887912892e-03f, -1.901087985e-03f, -9.478047386e-04f, +5.115395181e-04f, +1.696152289e-03f, +2.000005648e-03f, +1.362058071e-03f, +2.557261963e-04f, -6.674055614e-04f, -9.980619660e-04f, -7.596012646e-04f, -2.816184974e-04f, +8.955230425e-05f, +2.068028652e-04f, +1.378299032e-04f,
+ /* 24,11 */ -9.526723781e-05f, -1.947956873e-04f, -1.633284218e-04f, +1.165432034e-04f, +5.871595310e-04f, +9.615092978e-04f, +8.690009463e-04f, +1.426663759e-04f, -9.661301752e-04f, -1.854792197e-03f, -1.930348530e-03f, -1.029524574e-03f, +4.200923193e-04f, +1.643928243e-03f, +2.011118755e-03f, +1.422418959e-03f, +3.257861630e-04f, -6.249444785e-04f, -9.963864071e-04f, -7.856484910e-04f, -3.112151687e-04f, +7.352252002e-05f, +2.063902871e-04f, +1.446989102e-04f,
+ /* 24,12 */ -8.824611727e-05f, -1.907500791e-04f, -1.719487619e-04f, +9.163993343e-05f, +5.566532714e-04f, +9.483306864e-04f, +8.934973649e-04f, +2.041325004e-04f, -8.961196099e-04f, -1.818343426e-03f, -1.955583535e-03f, -1.108975953e-03f, +3.277114722e-04f, +1.588167145e-03f, +2.018303000e-03f, +1.480725107e-03f, +3.964985305e-04f, -5.800651921e-04f, -9.923241157e-04f, -8.106578209e-04f, -3.412342375e-04f, +5.643017558e-05f, +2.051877883e-04f, +1.514107898e-04f,
+ /* 24,13 */ -8.132190552e-05f, -1.862290729e-04f, -1.795547962e-04f, +6.760829922e-05f, +5.259003096e-04f, +9.333455225e-04f, +9.153683790e-04f, +2.638601140e-04f, -8.254237228e-04f, -1.778684302e-03f, -1.976763286e-03f, -1.185988431e-03f, +2.346018520e-04f, +1.528977139e-03f, +2.021508037e-03f, +1.536815378e-03f, +4.677058239e-04f, -5.328272649e-04f, -9.858238344e-04f, -8.345286135e-04f, -3.716026326e-04f, +3.828516688e-05f, +2.031605347e-04f, +1.579281336e-04f,
+ /* 24,14 */ -7.451957718e-05f, -1.812738819e-04f, -1.861665779e-04f, +4.448641826e-05f, +4.949934945e-04f, +9.166430096e-04f, +9.346209288e-04f, +3.217397652e-04f, -7.542164043e-04f, -1.735939471e-03f, -1.993868298e-03f, -1.260398022e-03f, +1.409702826e-04f, +1.466475318e-03f, +2.020693110e-03f, +1.590532482e-03f, +5.392469404e-04f, -4.832977173e-04f, -9.768399670e-04f, -8.571608722e-04f, -4.022439121e-04f, +1.910126829e-05f, +2.002752798e-04f, +1.642126010e-04f,
+ /* 24,15 */ -6.786242515e-05f, -1.759255972e-04f, -1.918067822e-04f, +2.230828855e-05f, +4.640234647e-04f, +8.983149818e-04f, +9.512688743e-04f, +3.776686811e-04f, -6.826705419e-04f, -1.690240096e-03f, -2.006889303e-03f, -1.332047630e-03f, +4.702498413e-05f, +1.400787443e-03f, +2.015827225e-03f, +1.641723450e-03f, +6.109575553e-04f, -4.315509563e-04f, -9.653328276e-04f, -8.784555707e-04f, -4.330784212e-04f, -1.103795304e-06f, +1.965005420e-04f, +1.702250368e-04f,
+ /* 24, 0 */ +3.919255962e-05f, -2.280943782e-04f, -5.361345988e-04f, -4.457457641e-04f, +2.990589649e-04f, +1.295797675e-03f, +1.605517166e-03f, +5.875816565e-04f, -1.289084098e-03f, -2.596166105e-03f, -2.129939921e-03f, -7.496988250e-05f, +2.037180601e-03f, +2.625542335e-03f, +1.404160874e-03f, -4.837783526e-04f, -1.582480410e-03f, -1.345619201e-03f, -3.621830939e-04f, +4.180945199e-04f, +5.469818219e-04f, +2.499414065e-04f, -2.888372260e-05f, -8.895700627e-05f,
+ /* 24, 1 */ +4.853777483e-05f, -2.065137544e-04f, -5.236754574e-04f, -4.705972357e-04f, +2.371311675e-04f, +1.243196859e-03f, +1.622959247e-03f, +6.876650067e-04f, -1.171710060e-03f, -2.559351067e-03f, -2.215991331e-03f, -2.246678327e-04f, +1.937986318e-03f, +2.647321756e-03f, +1.516528605e-03f, -3.765445934e-04f, -1.553807591e-03f, -1.392405213e-03f, -4.263006320e-04f, +3.876486968e-04f, +5.560961676e-04f, +2.719611444e-04f, -1.761075235e-05f, -9.068976925e-05f,
+ /* 24, 2 */ +5.692498928e-05f, -1.852878923e-04f, -5.097279107e-04f, -4.926555685e-04f, +1.765921503e-04f, +1.188077447e-03f, +1.634867875e-03f, +7.837567953e-04f, -1.052453928e-03f, -2.515280079e-03f, -2.295086316e-03f, -3.736412373e-04f, +1.832653524e-03f, +2.661371990e-03f, +1.625780509e-03f, -2.661868955e-04f, -1.519477670e-03f, -1.435905115e-03f, -4.911987788e-04f, +3.544256494e-04f, +5.633598944e-04f, +2.940548284e-04f, -5.378471232e-06f, -9.187426948e-05f,
+ /* 24, 3 */ +6.436469025e-05f, -1.644995777e-04f, -4.944173708e-04f, -5.119388451e-04f, +1.176233517e-04f, +1.130703462e-03f, +1.641323506e-03f, +8.756040923e-04f, -9.317326579e-04f, -2.464159993e-03f, -2.367001633e-03f, -5.214100591e-04f, +1.721501142e-03f, +2.667586958e-03f, +1.731516399e-03f, -1.530278412e-04f, -1.479490407e-03f, -1.475875084e-03f, -5.566555092e-04f, +3.184551797e-04f, +5.686591450e-04f, +3.161189305e-04f, +7.802761507e-06f, -9.246489856e-05f,
+ /* 24, 4 */ +7.087197068e-05f, -1.442258278e-04f, -4.778705046e-04f, -5.284761768e-04f, +6.039472401e-05f, +1.071341110e-03f, +1.642425167e-03f, +9.629733481e-04f, -8.099633882e-04f, -2.406220702e-03f, -2.431540042e-03f, -6.674987371e-04f, +1.604869446e-03f, +2.665887444e-03f, +1.833344283e-03f, -3.740504807e-05f, -1.433866725e-03f, -1.512079220e-03f, -6.224402836e-04f, +2.797797731e-04f, +5.718846156e-04f, +3.380454975e-04f, +2.191686946e-05f, -9.241721523e-05f,
+ /* 24, 5 */ +7.646625331e-05f, -1.245377292e-04f, -4.602146020e-04f, -5.423072437e-04f, +5.064318866e-06f, +1.010257658e-03f, +1.638289725e-03f, +1.045651008e-03f, -6.875618648e-04f, -2.341714107e-03f, -2.488530931e-03f, -8.114379517e-04f, +1.483118851e-03f, +2.656221571e-03f, +1.930881931e-03f, +8.032993590e-05f, -1.382648990e-03f, -1.544290670e-03f, -6.883148110e-04f, +2.384547825e-04f, +5.729322223e-04f, +3.597225244e-04f, +3.694190340e-05f, -9.168826568e-05f,
+ /* 24, 6 */ +8.117100143e-05f, -1.055003114e-04f, -4.415769617e-04f, -5.534817998e-04f, -4.822206513e-05f, +9.477203224e-04f, +1.629051096e-03f, +1.123444034e-03f, -5.649408783e-04f, -2.270913001e-03f, -2.537830838e-03f, -9.527663633e-04f, +1.356628624e-03f, +2.638565156e-03f, +2.023758423e-03f, +1.998128074e-04f, -1.325901212e-03f, -1.572292748e-03f, -7.540338642e-04f, +1.945485578e-04f, +5.717037624e-04f, +3.810343609e-04f, +5.284991195e-05f, -9.023690790e-05f,
+ /* 24, 7 */ +8.501341847e-05f, -8.717245610e-05f, -4.220842946e-04f, -5.620591450e-04f, -9.933117260e-05f, +8.839951872e-04f, +1.614859393e-03f, +1.196180345e-03f, -4.425087329e-04f, -2.194109877e-03f, -2.579323863e-03f, -1.091032318e-03f, +1.225795515e-03f, +2.612921966e-03f, +2.111615667e-03f, +3.206677492e-04f, -1.263709151e-03f, -1.595880025e-03f, -8.193461436e-04f, +1.481425192e-04f, +5.681075679e-04f, +4.018621494e-04f, +6.960683992e-05f, -8.802413824e-05f,
+ /* 24, 8 */ +8.802413824e-05f, -6.960683992e-05f, -4.018621494e-04f, -5.681075679e-04f, -1.481425192e-04f, +8.193461436e-04f, +1.595880025e-03f, +1.263709151e-03f, -3.206677492e-04f, -2.111615667e-03f, -2.612921966e-03f, -1.225795515e-03f, +1.091032318e-03f, +2.579323863e-03f, +2.194109877e-03f, +4.425087329e-04f, -1.196180345e-03f, -1.614859393e-03f, -8.839951872e-04f, +9.933117260e-05f, +5.620591450e-04f, +4.220842946e-04f, +8.717245610e-05f, -8.501341847e-05f,
+ /* 24, 9 */ +9.023690790e-05f, -5.284991195e-05f, -3.810343609e-04f, -5.717037624e-04f, -1.945485578e-04f, +7.540338642e-04f, +1.572292748e-03f, +1.325901212e-03f, -1.998128074e-04f, -2.023758423e-03f, -2.638565156e-03f, -1.356628624e-03f, +9.527663633e-04f, +2.537830838e-03f, +2.270913001e-03f, +5.649408783e-04f, -1.123444034e-03f, -1.629051096e-03f, -9.477203224e-04f, +4.822206513e-05f, +5.534817998e-04f, +4.415769617e-04f, +1.055003114e-04f, -8.117100143e-05f,
+ /* 24,10 */ +9.168826568e-05f, -3.694190340e-05f, -3.597225244e-04f, -5.729322223e-04f, -2.384547825e-04f, +6.883148110e-04f, +1.544290670e-03f, +1.382648990e-03f, -8.032993590e-05f, -1.930881931e-03f, -2.656221571e-03f, -1.483118851e-03f, +8.114379517e-04f, +2.488530931e-03f, +2.341714107e-03f, +6.875618648e-04f, -1.045651008e-03f, -1.638289725e-03f, -1.010257658e-03f, -5.064318866e-06f, +5.423072437e-04f, +4.602146020e-04f, +1.245377292e-04f, -7.646625331e-05f,
+ /* 24,11 */ +9.241721523e-05f, -2.191686946e-05f, -3.380454975e-04f, -5.718846156e-04f, -2.797797731e-04f, +6.224402836e-04f, +1.512079220e-03f, +1.433866725e-03f, +3.740504807e-05f, -1.833344283e-03f, -2.665887444e-03f, -1.604869446e-03f, +6.674987371e-04f, +2.431540042e-03f, +2.406220702e-03f, +8.099633882e-04f, -9.629733481e-04f, -1.642425167e-03f, -1.071341110e-03f, -6.039472401e-05f, +5.284761768e-04f, +4.778705046e-04f, +1.442258278e-04f, -7.087197068e-05f,
+ /* 24,12 */ +9.246489856e-05f, -7.802761507e-06f, -3.161189305e-04f, -5.686591450e-04f, -3.184551797e-04f, +5.566555092e-04f, +1.475875084e-03f, +1.479490407e-03f, +1.530278412e-04f, -1.731516399e-03f, -2.667586958e-03f, -1.721501142e-03f, +5.214100591e-04f, +2.367001633e-03f, +2.464159993e-03f, +9.317326579e-04f, -8.756040923e-04f, -1.641323506e-03f, -1.130703462e-03f, -1.176233517e-04f, +5.119388451e-04f, +4.944173708e-04f, +1.644995777e-04f, -6.436469025e-05f,
+ /* 24,13 */ +9.187426948e-05f, +5.378471232e-06f, -2.940548284e-04f, -5.633598944e-04f, -3.544256494e-04f, +4.911987788e-04f, +1.435905115e-03f, +1.519477670e-03f, +2.661868955e-04f, -1.625780509e-03f, -2.661371990e-03f, -1.832653524e-03f, +3.736412373e-04f, +2.295086316e-03f, +2.515280079e-03f, +1.052453928e-03f, -7.837567953e-04f, -1.634867875e-03f, -1.188077447e-03f, -1.765921503e-04f, +4.926555685e-04f, +5.097279107e-04f, +1.852878923e-04f, -5.692498928e-05f,
+ /* 24,14 */ +9.068976925e-05f, +1.761075235e-05f, -2.719611444e-04f, -5.560961676e-04f, -3.876486968e-04f, +4.263006320e-04f, +1.392405213e-03f, +1.553807591e-03f, +3.765445934e-04f, -1.516528605e-03f, -2.647321756e-03f, -1.937986318e-03f, +2.246678327e-04f, +2.215991331e-03f, +2.559351067e-03f, +1.171710060e-03f, -6.876650067e-04f, -1.622959247e-03f, -1.243196859e-03f, -2.371311675e-04f, +4.705972357e-04f, +5.236754574e-04f, +2.065137544e-04f, -4.853777483e-05f,
+ /* 24,15 */ +8.895700627e-05f, +2.888372260e-05f, -2.499414065e-04f, -5.469818219e-04f, -4.180945199e-04f, +3.621830939e-04f, +1.345619201e-03f, +1.582480410e-03f, +4.837783526e-04f, -1.404160874e-03f, -2.625542335e-03f, -2.037180601e-03f, +7.496988250e-05f, +2.129939921e-03f, +2.596166105e-03f, +1.289084098e-03f, -5.875816565e-04f, -1.605517166e-03f, -1.295797675e-03f, -2.990589649e-04f, +4.457457641e-04f, +5.361345988e-04f, +2.280943782e-04f, -3.919255962e-05f,
+ /* 24, 0 */ +1.848082291e-04f, +3.126544607e-04f, -8.381805218e-05f, -8.698090905e-04f, -1.028447094e-03f, +2.139154673e-04f, +1.954115341e-03f, +2.095678120e-03f, -1.635717275e-04f, -2.819157299e-03f, -2.940044791e-03f, -1.098945345e-04f, +2.833179926e-03f, +2.923929522e-03f, +3.511165299e-04f, -2.017938339e-03f, -2.030476715e-03f, -3.277888569e-04f, +9.926761418e-04f, +9.110442493e-04f, +1.284872781e-04f, -3.065935448e-04f, -1.998565163e-04f, +7.803305534e-06f,
+ /* 24, 1 */ +1.695814378e-04f, +3.164556508e-04f, -4.103650150e-05f, -8.260698464e-04f, -1.058100498e-03f, +1.024893805e-04f, +1.871044125e-03f, +2.162944507e-03f, +2.203366063e-05f, -2.703524226e-03f, -3.034115138e-03f, -3.291928088e-04f, +2.713944640e-03f, +3.017272284e-03f, +5.397663057e-04f, -1.929900383e-03f, -2.099607997e-03f, -4.436146208e-04f, +9.507629285e-04f, +9.494468230e-04f, +1.748714247e-04f, -2.981837386e-04f, -2.146007649e-04f, -5.699432396e-07f,
+ /* 24, 2 */ +1.542962580e-04f, +3.180964801e-04f, -2.971107404e-07f, -7.801571616e-04f, -1.081692695e-03f, -6.019646704e-06f, +1.781805749e-03f, +2.219616197e-03f, +2.048848004e-04f, -2.577645910e-03f, -3.115029215e-03f, -5.470211463e-04f, +2.582823494e-03f, +3.098667200e-03f, +7.286710477e-04f, -1.831793311e-03f, -2.161014579e-03f, -5.608747689e-04f, +9.027154107e-04f, +9.846924856e-04f, +2.227798586e-04f, -2.873471247e-04f, -2.289106872e-04f, -9.773337074e-06f,
+ /* 24, 3 */ +1.390667857e-04f, +3.176854393e-04f, +3.826416878e-05f, -7.324018434e-04f, -1.099310451e-03f, -1.111689527e-04f, +1.686962051e-03f, +2.265625589e-03f, +3.841903571e-04f, -2.442181508e-03f, -3.182489175e-03f, -7.624077328e-04f, +2.440359294e-03f, +3.167649091e-03f, +9.169693475e-04f, -1.723899657e-03f, -2.214230624e-03f, -6.790305367e-04f, +8.485750922e-04f, +1.016463150e-03f, +2.720045869e-04f, -2.740180422e-04f, -2.426519708e-04f, -1.978701792e-05f,
+ /* 24, 4 */ +1.240005643e-04f, +3.153390489e-04f, +7.453005747e-05f, -6.831329371e-04f, -1.111069621e-03f, -2.125447010e-04f, +1.587090707e-03f, +2.300958285e-03f, +5.591862212e-04f, -2.297830066e-03f, -3.236262287e-03f, -9.743929228e-04f, +2.287150577e-03f, +3.223808711e-03f, +1.103792665e-03f, -1.606554759e-03f, -2.258822083e-03f, -7.975248409e-04f, +7.884177261e-04f, +1.044449054e-03f, +3.223209063e-04f, -2.581440514e-04f, -2.556870681e-04f, -3.058317705e-05f,
+ /* 24, 5 */ +1.091981202e-04f, +3.111807515e-04f, +1.084019636e-04f, -6.326758693e-04f, -1.117113666e-03f, -3.097634105e-04f, +1.482781879e-03f, +2.325652312e-03f, +7.291390495e-04f, -2.145326692e-03f, -3.276181809e-03f, -1.182034015e-03f, +2.123848782e-03f, +3.266795190e-03f, +1.288269679e-03f, -1.480145805e-03f, -2.294389599e-03f, -9.157848908e-04f, +7.223538352e-04f, +1.068350860e-03f, +3.734881809e-04f, -2.396868442e-04f, -2.678760406e-04f, -4.212586861e-05f,
+ /* 24, 6 */ +9.475256757e-05f, +3.053397988e-04f, +1.397998805e-04f, -5.813506695e-04f, -1.117612060e-03f, -4.024732802e-04f, +1.374634870e-03f, +2.339797075e-03f, +8.933496022e-04f, -1.985438555e-03f, -3.302147511e-03f, -1.384409934e-03f, +1.951155148e-03f, +3.296318191e-03f, +1.469530695e-03f, -1.345110577e-03f, -2.320571262e-03f, -1.033224945e-03f, +6.505290403e-04f, +1.087881752e-03f, +4.252507475e-04f, -2.186230940e-04f, -2.790774568e-04f, -5.437087857e-05f,
+ /* 24, 7 */ +8.074928352e-05f, +2.979501429e-04f, +1.686621699e-04f, -5.294702777e-04f, -1.112758583e-03f, -4.903553074e-04f, +1.263254779e-03f, +2.343532047e-03f, +1.051155860e-03f, -1.818960757e-03f, -3.314125843e-03f, -1.580625796e-03f, +1.769817333e-03f, +3.312149758e-03f, +1.646712089e-03f, -1.201935910e-03f, -2.337045209e-03f, -1.149249197e-03f, +5.731241934e-04f, +1.102769514e-03f, +4.773389469e-04f, -1.949452358e-04f, -2.891493374e-04f, -6.726565227e-05f,
+ /* 24, 8 */ +6.726565227e-05f, +2.891493374e-04f, +1.949452358e-04f, -4.773389469e-04f, -1.102769514e-03f, -5.731241934e-04f, +1.149249197e-03f, +2.337045209e-03f, +1.201935910e-03f, -1.646712089e-03f, -3.312149758e-03f, -1.769817333e-03f, +1.580625796e-03f, +3.314125843e-03f, +1.818960757e-03f, -1.051155860e-03f, -2.343532047e-03f, -1.263254779e-03f, +4.903553074e-04f, +1.112758583e-03f, +5.294702777e-04f, -1.686621699e-04f, -2.979501429e-04f, -8.074928352e-05f,
+ /* 24, 9 */ +5.437087857e-05f, +2.790774568e-04f, +2.186230940e-04f, -4.252507475e-04f, -1.087881752e-03f, -6.505290403e-04f, +1.033224945e-03f, +2.320571262e-03f, +1.345110577e-03f, -1.469530695e-03f, -3.296318191e-03f, -1.951155148e-03f, +1.384409934e-03f, +3.302147511e-03f, +1.985438555e-03f, -8.933496022e-04f, -2.339797075e-03f, -1.374634870e-03f, +4.024732802e-04f, +1.117612060e-03f, +5.813506695e-04f, -1.397998805e-04f, -3.053397988e-04f, -9.475256757e-05f,
+ /* 24,10 */ +4.212586861e-05f, +2.678760406e-04f, +2.396868442e-04f, -3.734881809e-04f, -1.068350860e-03f, -7.223538352e-04f, +9.157848908e-04f, +2.294389599e-03f, +1.480145805e-03f, -1.288269679e-03f, -3.266795190e-03f, -2.123848782e-03f, +1.182034015e-03f, +3.276181809e-03f, +2.145326692e-03f, -7.291390495e-04f, -2.325652312e-03f, -1.482781879e-03f, +3.097634105e-04f, +1.117113666e-03f, +6.326758693e-04f, -1.084019636e-04f, -3.111807515e-04f, -1.091981202e-04f,
+ /* 24,11 */ +3.058317705e-05f, +2.556870681e-04f, +2.581440514e-04f, -3.223209063e-04f, -1.044449054e-03f, -7.884177261e-04f, +7.975248409e-04f, +2.258822083e-03f, +1.606554759e-03f, -1.103792665e-03f, -3.223808711e-03f, -2.287150577e-03f, +9.743929228e-04f, +3.236262287e-03f, +2.297830066e-03f, -5.591862212e-04f, -2.300958285e-03f, -1.587090707e-03f, +2.125447010e-04f, +1.111069621e-03f, +6.831329371e-04f, -7.453005747e-05f, -3.153390489e-04f, -1.240005643e-04f,
+ /* 24,12 */ +1.978701792e-05f, +2.426519708e-04f, +2.740180422e-04f, -2.720045869e-04f, -1.016463150e-03f, -8.485750922e-04f, +6.790305367e-04f, +2.214230624e-03f, +1.723899657e-03f, -9.169693475e-04f, -3.167649091e-03f, -2.440359294e-03f, +7.624077328e-04f, +3.182489175e-03f, +2.442181508e-03f, -3.841903571e-04f, -2.265625589e-03f, -1.686962051e-03f, +1.111689527e-04f, +1.099310451e-03f, +7.324018434e-04f, -3.826416878e-05f, -3.176854393e-04f, -1.390667857e-04f,
+ /* 24,13 */ +9.773337074e-06f, +2.289106872e-04f, +2.873471247e-04f, -2.227798586e-04f, -9.846924856e-04f, -9.027154107e-04f, +5.608747689e-04f, +2.161014579e-03f, +1.831793311e-03f, -7.286710477e-04f, -3.098667200e-03f, -2.582823494e-03f, +5.470211463e-04f, +3.115029215e-03f, +2.577645910e-03f, -2.048848004e-04f, -2.219616197e-03f, -1.781805749e-03f, +6.019646704e-06f, +1.081692695e-03f, +7.801571616e-04f, +2.971107404e-07f, -3.180964801e-04f, -1.542962580e-04f,
+ /* 24,14 */ +5.699432396e-07f, +2.146007649e-04f, +2.981837386e-04f, -1.748714247e-04f, -9.494468230e-04f, -9.507629285e-04f, +4.436146208e-04f, +2.099607997e-03f, +1.929900383e-03f, -5.397663057e-04f, -3.017272284e-03f, -2.713944640e-03f, +3.291928088e-04f, +3.034115138e-03f, +2.703524226e-03f, -2.203366063e-05f, -2.162944507e-03f, -1.871044125e-03f, -1.024893805e-04f, +1.058100498e-03f, +8.260698464e-04f, +4.103650150e-05f, -3.164556508e-04f, -1.695814378e-04f,
+ /* 24,15 */ -7.803305534e-06f, +1.998565163e-04f, +3.065935448e-04f, -1.284872781e-04f, -9.110442493e-04f, -9.926761418e-04f, +3.277888569e-04f, +2.030476715e-03f, +2.017938339e-03f, -3.511165299e-04f, -2.923929522e-03f, -2.833179926e-03f, +1.098945345e-04f, +2.940044791e-03f, +2.819157299e-03f, +1.635717275e-04f, -2.095678120e-03f, -1.954115341e-03f, -2.139154673e-04f, +1.028447094e-03f, +8.698090905e-04f, +8.381805218e-05f, -3.126544607e-04f, -1.848082291e-04f,
+ /* 24, 0 */ -1.364396009e-04f, -7.446376994e-05f, +5.066257662e-04f, +2.030015760e-04f, -9.054261715e-04f, -1.195525937e-03f, +4.683850093e-04f, +2.213825561e-03f, +1.188944940e-03f, -1.856378227e-03f, -2.833970964e-03f, -1.144377463e-04f, +2.758138339e-03f, +2.020697482e-03f, -1.023174933e-03f, -2.248631080e-03f, -6.097868283e-04f, +1.146194663e-03f, +9.693248739e-04f, -1.479047908e-04f, -5.177782008e-04f, -1.250536964e-04f, +1.414906982e-04f, +2.710774794e-05f,
+ /* 24, 1 */ -1.307026563e-04f, -8.975162518e-05f, +4.924131238e-04f, +2.542107757e-04f, -8.382130226e-04f, -1.235986710e-03f, +3.277877666e-04f, +2.166758574e-03f, +1.345406789e-03f, -1.683014413e-03f, -2.893234801e-03f, -3.426248829e-04f, +2.666119545e-03f, +2.174888063e-03f, -8.489895579e-04f, -2.270723567e-03f, -7.511023835e-04f, +1.088054225e-03f, +1.029345157e-03f, -8.915647260e-05f, -5.256253050e-04f, -1.535492882e-04f, +1.457592711e-04f, +3.374854096e-05f,
+ /* 24, 2 */ -1.243758393e-04f, -1.032931784e-04f, +4.753985127e-04f, +3.013338450e-04f, -7.682542954e-04f, -1.267577330e-03f, +1.888607322e-04f, +2.107952975e-03f, +1.491738775e-03f, -1.501737881e-03f, -2.935653267e-03f, -5.687514710e-04f, +2.558401145e-03f, +2.317921172e-03f, -6.673475630e-04f, -2.279727032e-03f, -8.914213340e-04f, +1.021228789e-03f, +1.084932315e-03f, -2.702967135e-05f, -5.299376467e-04f, -1.826837732e-04f, +1.491486840e-04f, +4.073257728e-05f,
+ /* 24, 3 */ -1.175537217e-04f, -1.151066589e-04f, +4.558506985e-04f, +3.442099484e-04f, -6.961194660e-04f, -1.290358261e-03f, +5.243891240e-05f, +2.037998203e-03f, +1.627194859e-03f, -1.313720334e-03f, -2.961057174e-03f, -7.914588446e-04f, +2.435570833e-03f, +2.448830599e-03f, -4.792680017e-04f, -2.275344863e-03f, -1.029819797e-03f, +9.459060659e-04f, +1.135545329e-03f, +3.816638860e-05f, -5.305040204e-04f, -2.122423012e-04f, +1.515631236e-04f, +4.801831197e-05f,
+ /* 24, 4 */ -1.103288160e-04f, -1.252215041e-04f, +4.340463917e-04f, +3.827158599e-04f, -6.223744454e-04f, -1.304448109e-03f, -8.067840470e-05f, +1.957545178e-03f, +1.751108674e-03f, -1.120165265e-03f, -2.969385358e-03f, -1.009410776e-03f, +2.298313921e-03f, +2.566719612e-03f, -2.858241016e-04f, -2.257363134e-03f, -1.165366520e-03f, +8.623375551e-04f, +1.180661312e-03f, +1.060874480e-04f, -5.271339238e-04f, -2.419953224e-04f, +1.529084143e-04f, +5.555842361e-05f,
+ /* 24, 5 */ -1.027909684e-04f, -1.336775649e-04f, +4.102676936e-04f, +4.167655723e-04f, -5.475775503e-04f, -1.310021272e-03f, -2.097323863e-04f, +1.867300846e-03f, +1.862896930e-03f, -9.222997333e-04f, -2.960684559e-03f, -1.221302229e-03f, +2.147409148e-03f, +2.670767418e-03f, -8.813668768e-05f, -2.225653372e-03f, -1.297129225e-03f, +7.708383352e-04f, +1.219779926e-03f, +1.763556677e-04f, -5.196599496e-04f, -2.716999419e-04f, +1.530928622e-04f, +6.329988035e-05f,
+ /* 24, 6 */ -9.502680145e-05f, -1.405242734e-04f, +3.847995909e-04f, +4.463096266e-04f, -4.722756447e-04f, -1.307305241e-03f, -3.340090076e-04f, +1.768022423e-03f, +1.962062202e-03f, -7.213660470e-04f, -2.935108571e-03f, -1.425867893e-03f, +1.983723834e-03f, +2.760235146e-03f, +1.126327965e-04f, -2.180174758e-03f, -1.424181074e-03f, +6.717863708e-04f, +1.252427754e-03f, +2.485613970e-04f, -5.079400707e-04f, -3.011014490e-04f, +1.520281231e-04f, +7.118405837e-05f,
+ /* 24, 7 */ -8.711921055e-05f, -1.458197836e-04f, +3.579275186e-04f, +4.713341756e-04f, -3.970004792e-04f, -1.296577576e-03f, -4.528429958e-04f, +1.660511380e-03f, +2.048195092e-03f, -5.186134147e-04f, -2.892916666e-03f, -1.621890436e-03f, +1.808208423e-03f, +2.834471303e-03f, +3.152896222e-04f, -2.120975750e-03f, -1.545607217e-03f, +5.656213428e-04f, +1.278162587e-03f, +3.222652495e-04f, -4.918597964e-04f, -3.299350101e-04f, +1.496300883e-04f, +7.914691395e-05f,
+ /* 24, 8 */ -7.914691395e-05f, -1.496300883e-04f, +3.299350101e-04f, +4.918597964e-04f, -3.222652495e-04f, -1.278162587e-03f, -5.656213428e-04f, +1.545607217e-03f, +2.120975750e-03f, -3.152896222e-04f, -2.834471303e-03f, -1.808208423e-03f, +1.621890436e-03f, +2.892916666e-03f, +5.186134147e-04f, -2.048195092e-03f, -1.660511380e-03f, +4.528429958e-04f, +1.296577576e-03f, +3.970004792e-04f, -4.713341756e-04f, -3.579275186e-04f, +1.458197836e-04f, +8.711921055e-05f,
+ /* 24, 9 */ -7.118405837e-05f, -1.520281231e-04f, +3.011014490e-04f, +5.079400707e-04f, -2.485613970e-04f, -1.252427754e-03f, -6.717863708e-04f, +1.424181074e-03f, +2.180174758e-03f, -1.126327965e-04f, -2.760235146e-03f, -1.983723834e-03f, +1.425867893e-03f, +2.935108571e-03f, +7.213660470e-04f, -1.962062202e-03f, -1.768022423e-03f, +3.340090076e-04f, +1.307305241e-03f, +4.722756447e-04f, -4.463096266e-04f, -3.847995909e-04f, +1.405242734e-04f, +9.502680145e-05f,
+ /* 24,10 */ -6.329988035e-05f, -1.530928622e-04f, +2.716999419e-04f, +5.196599496e-04f, -1.763556677e-04f, -1.219779926e-03f, -7.708383352e-04f, +1.297129225e-03f, +2.225653372e-03f, +8.813668768e-05f, -2.670767418e-03f, -2.147409148e-03f, +1.221302229e-03f, +2.960684559e-03f, +9.222997333e-04f, -1.862896930e-03f, -1.867300846e-03f, +2.097323863e-04f, +1.310021272e-03f, +5.475775503e-04f, -4.167655723e-04f, -4.102676936e-04f, +1.336775649e-04f, +1.027909684e-04f,
+ /* 24,11 */ -5.555842361e-05f, -1.529084143e-04f, +2.419953224e-04f, +5.271339238e-04f, -1.060874480e-04f, -1.180661312e-03f, -8.623375551e-04f, +1.165366520e-03f, +2.257363134e-03f, +2.858241016e-04f, -2.566719612e-03f, -2.298313921e-03f, +1.009410776e-03f, +2.969385358e-03f, +1.120165265e-03f, -1.751108674e-03f, -1.957545178e-03f, +8.067840470e-05f, +1.304448109e-03f, +6.223744454e-04f, -3.827158599e-04f, -4.340463917e-04f, +1.252215041e-04f, +1.103288160e-04f,
+ /* 24,12 */ -4.801831197e-05f, -1.515631236e-04f, +2.122423012e-04f, +5.305040204e-04f, -3.816638860e-05f, -1.135545329e-03f, -9.459060659e-04f, +1.029819797e-03f, +2.275344863e-03f, +4.792680017e-04f, -2.448830599e-03f, -2.435570833e-03f, +7.914588446e-04f, +2.961057174e-03f, +1.313720334e-03f, -1.627194859e-03f, -2.037998203e-03f, -5.243891240e-05f, +1.290358261e-03f, +6.961194660e-04f, -3.442099484e-04f, -4.558506985e-04f, +1.151066589e-04f, +1.175537217e-04f,
+ /* 24,13 */ -4.073257728e-05f, -1.491486840e-04f, +1.826837732e-04f, +5.299376467e-04f, +2.702967135e-05f, -1.084932315e-03f, -1.021228789e-03f, +8.914213340e-04f, +2.279727032e-03f, +6.673475630e-04f, -2.317921172e-03f, -2.558401145e-03f, +5.687514710e-04f, +2.935653267e-03f, +1.501737881e-03f, -1.491738775e-03f, -2.107952975e-03f, -1.888607322e-04f, +1.267577330e-03f, +7.682542954e-04f, -3.013338450e-04f, -4.753985127e-04f, +1.032931784e-04f, +1.243758393e-04f,
+ /* 24,14 */ -3.374854096e-05f, -1.457592711e-04f, +1.535492882e-04f, +5.256253050e-04f, +8.915647260e-05f, -1.029345157e-03f, -1.088054225e-03f, +7.511023835e-04f, +2.270723567e-03f, +8.489895579e-04f, -2.174888063e-03f, -2.666119545e-03f, +3.426248829e-04f, +2.893234801e-03f, +1.683014413e-03f, -1.345406789e-03f, -2.166758574e-03f, -3.277877666e-04f, +1.235986710e-03f, +8.382130226e-04f, -2.542107757e-04f, -4.924131238e-04f, +8.975162518e-05f, +1.307026563e-04f,
+ /* 24,15 */ -2.710774794e-05f, -1.414906982e-04f, +1.250536964e-04f, +5.177782008e-04f, +1.479047908e-04f, -9.693248739e-04f, -1.146194663e-03f, +6.097868283e-04f, +2.248631080e-03f, +1.023174933e-03f, -2.020697482e-03f, -2.758138339e-03f, +1.144377463e-04f, +2.833970964e-03f, +1.856378227e-03f, -1.188944940e-03f, -2.213825561e-03f, -4.683850093e-04f, +1.195525937e-03f, +9.054261715e-04f, -2.030015760e-04f, -5.066257662e-04f, +7.446376994e-05f, +1.364396009e-04f,
+ /* 20, 0 */ +8.618377023e-05f, +6.063813654e-04f, +5.504304823e-05f, -1.285351444e-03f, -7.884572117e-04f, +1.698526656e-03f, +2.051642156e-03f, -1.208844608e-03f, -3.071261118e-03f, -1.337669627e-04f, +3.018986987e-03f, +1.434631920e-03f, -1.928392685e-03f, -1.831072241e-03f, +6.629429882e-04f, +1.334851066e-03f, +2.665316224e-05f, -6.158469302e-04f, -1.222533602e-04f, +1.824770389e-04f,
+ /* 20, 1 */ +5.170459821e-05f, +5.921181369e-04f, +1.325211661e-04f, -1.227728603e-03f, -9.042412445e-04f, +1.556639033e-03f, +2.157910711e-03f, -9.769935819e-04f, -3.101316201e-03f, -4.002989059e-04f, +2.944767882e-03f, +1.652572896e-03f, -1.788832610e-03f, -1.953018956e-03f, +5.284364506e-04f, +1.375515478e-03f, +1.120226944e-04f, -6.201709543e-04f, -1.596279961e-04f, +5.435082024e-04f,
+ /* 20, 2 */ +1.907003227e-05f, +5.734309365e-04f, +2.052951315e-04f, -1.162740775e-03f, -1.009657150e-03f, +1.406715362e-03f, +2.246673287e-03f, -7.408907618e-04f, -3.109053425e-03f, -6.638330580e-04f, +2.849051730e-03f, +1.860929207e-03f, -1.633773999e-03f, -2.063170847e-03f, +3.857714352e-04f, +1.406686835e-03f, +2.004651158e-04f, -6.190441221e-04f, -1.979927117e-04f, +1.783734753e-04f,
+ /* 20, 3 */ -1.149811868e-05f, +5.507184044e-04f, +2.729399910e-04f, -1.091184321e-03f, -1.104169932e-03f, +1.250098855e-03f, +2.317552276e-03f, -5.023622502e-04f, -3.094549152e-03f, -9.223980063e-04f, +2.732457430e-03f, +2.058021578e-03f, -1.464165902e-03f, -2.160404235e-03f, +2.358727957e-04f, +1.427769061e-03f, +2.913280278e-04f, -6.121962531e-04f, -2.370049292e-04f, +1.734448317e-04f,
+ /* 20, 4 */ -3.981122763e-05f, +5.243991976e-04f, +3.350936324e-04f, -1.013885501e-03f, -1.187349554e-03f, +1.088157908e-03f, +2.370318438e-03f, -2.632332411e-04f, -3.058053364e-03f, -1.174062761e-03f, +2.595770512e-03f, +2.242244162e-03f, -1.281088328e-03f, -2.243678681e-03f, +7.975052491e-05f, +1.438235101e-03f, +3.839113875e-04f, -5.994006494e-04f, -2.762968272e-04f, +1.660093790e-04f,
+ /* 20, 5 */ -6.571426612e-05f, +4.949070444e-04f, +3.914578654e-04f, -9.316921975e-04f, -1.258871974e-03f, +9.222740706e-04f, +2.404890527e-03f, -2.531308203e-05f, -2.999986642e-03f, -1.416952434e-03f, +2.439937364e-03f, +2.412078410e-03f, -1.085745014e-03f, -2.312047403e-03f, -8.150702581e-05f, +1.437633739e-03f, +4.774724341e-04f, -5.804781630e-04f, -3.154780847e-04f, +1.559797103e-04f,
+ /* 20, 6 */ -8.908584503e-05f, +4.626858369e-04f, +4.417988543e-04f, -8.454656803e-04f, -1.318519207e-03f, +7.538301290e-04f, +2.421333651e-03f, +2.096193816e-04f, -2.920935727e-03f, -1.649263420e-03f, +2.266058084e-03f, +2.566106310e-03f, -8.794550343e-04f, -2.364667062e-03f, -2.467407834e-04f, +1.425595879e-03f, +5.712311871e-04f, -5.553009320e-04f, -3.541389831e-04f, +1.432933926e-04f,
+ /* 20, 7 */ -1.098378936e-04f, +4.281848093e-04f, +4.859469205e-04f, -7.560724855e-04f, -1.366178446e-03f, +5.841984075e-04f, +2.419856400e-03f, +4.398300532e-04f, -2.821647705e-03f, -1.869277969e-03f, +2.075378006e-03f, +2.703022864e-03f, -6.636433018e-04f, -2.400806791e-03f, -4.147293943e-04f, +1.401840253e-03f, +6.643764801e-04f, -5.237957356e-04f, -3.918538488e-04f, +1.279149940e-04f,
+ /* 20, 8 */ -1.279149940e-04f, +3.918538488e-04f, +5.237957356e-04f, -6.643764801e-04f, -1.401840253e-03f, +4.147293943e-04f, +2.400806791e-03f, +6.636433018e-04f, -2.703022864e-03f, -2.075378006e-03f, +1.869277969e-03f, +2.821647705e-03f, -4.398300532e-04f, -2.419856400e-03f, -5.841984075e-04f, +1.366178446e-03f, +7.560724855e-04f, -4.859469205e-04f, -4.281848093e-04f, +1.098378936e-04f,
+ /* 20, 9 */ -1.432933926e-04f, +3.541389831e-04f, +5.553009320e-04f, -5.712311871e-04f, -1.425595879e-03f, +2.467407834e-04f, +2.364667062e-03f, +8.794550343e-04f, -2.566106310e-03f, -2.266058084e-03f, +1.649263420e-03f, +2.920935727e-03f, -2.096193816e-04f, -2.421333651e-03f, -7.538301290e-04f, +1.318519207e-03f, +8.454656803e-04f, -4.417988543e-04f, -4.626858369e-04f, +8.908584503e-05f,
+ /* 20,10 */ -1.559797103e-04f, +3.154780847e-04f, +5.804781630e-04f, -4.774724341e-04f, -1.437633739e-03f, +8.150702581e-05f, +2.312047403e-03f, +1.085745014e-03f, -2.412078410e-03f, -2.439937364e-03f, +1.416952434e-03f, +2.999986642e-03f, +2.531308203e-05f, -2.404890527e-03f, -9.222740706e-04f, +1.258871974e-03f, +9.316921975e-04f, -3.914578654e-04f, -4.949070444e-04f, +6.571426612e-05f,
+ /* 20,11 */ -1.660093790e-04f, +2.762968272e-04f, +5.994006494e-04f, -3.839113875e-04f, -1.438235101e-03f, -7.975052491e-05f, +2.243678681e-03f, +1.281088328e-03f, -2.242244162e-03f, -2.595770512e-03f, +1.174062761e-03f, +3.058053364e-03f, +2.632332411e-04f, -2.370318438e-03f, -1.088157908e-03f, +1.187349554e-03f, +1.013885501e-03f, -3.350936324e-04f, -5.243991976e-04f, +3.981122763e-05f,
+ /* 20,12 */ -1.734448317e-04f, +2.370049292e-04f, +6.121962531e-04f, -2.913280278e-04f, -1.427769061e-03f, -2.358727957e-04f, +2.160404235e-03f, +1.464165902e-03f, -2.058021578e-03f, -2.732457430e-03f, +9.223980063e-04f, +3.094549152e-03f, +5.023622502e-04f, -2.317552276e-03f, -1.250098855e-03f, +1.104169932e-03f, +1.091184321e-03f, -2.729399910e-04f, -5.507184044e-04f, +1.149811868e-05f,
+ /* 20,13 */ -1.783734753e-04f, +1.979927117e-04f, +6.190441221e-04f, -2.004651158e-04f, -1.406686835e-03f, -3.857714352e-04f, +2.063170847e-03f, +1.633773999e-03f, -1.860929207e-03f, -2.849051730e-03f, +6.638330580e-04f, +3.109053425e-03f, +7.408907618e-04f, -2.246673287e-03f, -1.406715362e-03f, +1.009657150e-03f, +1.162740775e-03f, -2.052951315e-04f, -5.734309365e-04f, -1.907003227e-05f,
+ /* 20,14 */ -5.435082024e-04f, +1.596279961e-04f, +6.201709543e-04f, -1.120226944e-04f, -1.375515478e-03f, -5.284364506e-04f, +1.953018956e-03f, +1.788832610e-03f, -1.652572896e-03f, -2.944767882e-03f, +4.002989059e-04f, +3.101316201e-03f, +9.769935819e-04f, -2.157910711e-03f, -1.556639033e-03f, +9.042412445e-04f, +1.227728603e-03f, -1.325211661e-04f, -5.921181369e-04f, -5.170459821e-05f,
+ /* 20,15 */ -1.824770389e-04f, +1.222533602e-04f, +6.158469302e-04f, -2.665316224e-05f, -1.334851066e-03f, -6.629429882e-04f, +1.831072241e-03f, +1.928392685e-03f, -1.434631920e-03f, -3.018986987e-03f, +1.337669627e-04f, +3.071261118e-03f, +1.208844608e-03f, -2.051642156e-03f, -1.698526656e-03f, +7.884572117e-04f, +1.285351444e-03f, -5.504304823e-05f, -6.063813654e-04f, -8.618377023e-05f,
+ /* 20, 0 */ -2.034293425e-04f, +2.330977005e-04f, +6.663349221e-04f, -5.788237715e-04f, -1.543506114e-03f, +7.663264997e-04f, +2.637884518e-03f, -5.016073607e-04f, -3.414789539e-03f, -1.613262342e-04f, +3.393842146e-03f, +7.896927597e-04f, -2.589726790e-03f, -9.705894653e-04f, +1.498255744e-03f, +6.923557695e-04f, -6.435044748e-04f, -2.810018705e-04f, +2.009801156e-04f, +0.000000000e+00f,
+ /* 20, 1 */ -6.015260759e-04f, +1.858917095e-04f, +6.809814437e-04f, -4.649883812e-04f, -1.572899641e-03f, +5.610647582e-04f, +2.661959816e-03f, -2.131645492e-04f, -3.406214168e-03f, -4.825221542e-04f, +3.343371924e-03f, +1.074767465e-03f, -2.517456780e-03f, -1.171859801e-03f, +1.437039798e-03f, +8.043742580e-04f, -6.123036842e-04f, -3.290468323e-04f, +1.953154138e-04f, -3.513221827e-04f,
+ /* 20, 2 */ -1.932641301e-04f, +1.399021716e-04f, +6.877130848e-04f, -3.520154127e-04f, -1.586701669e-03f, +3.567578182e-04f, +2.662213263e-03f, +7.301175991e-05f, -3.368394423e-03f, -7.993627115e-04f, +3.263658730e-03f, +1.354174959e-03f, -2.421279702e-03f, -1.368123194e-03f, +1.359912061e-03f, +9.136368247e-04f, -5.726346524e-04f, -3.766412744e-04f, +1.862701081e-04f, +2.243392330e-05f,
+ /* 20, 3 */ -1.771389305e-04f, +9.560377684e-05f, +6.868748812e-04f, -2.410152618e-04f, -1.585326694e-03f, +1.553000173e-04f, +2.639129491e-03f, +3.543525656e-04f, -3.301882608e-03f, -1.108991788e-03f, +3.155261081e-03f, +1.625281932e-03f, -2.301637793e-03f, -1.557365345e-03f, +1.267093119e-03f, +1.018881552e-03f, -5.244930508e-04f, -4.231658296e-04f, +1.737162070e-04f, +3.471505729e-05f,
+ /* 20, 4 */ -1.604844080e-04f, +5.342390613e-05f, +6.788805869e-04f, -1.330327870e-04f, -1.569329509e-03f, -4.149146373e-05f, +2.593408320e-03f, +6.283684809e-04f, -3.207497769e-03f, -1.408623929e-03f, +3.019012048e-03f, +1.885504757e-03f, -2.159209806e-03f, -1.737592880e-03f, +1.158972903e-03f, +1.118840456e-03f, -4.679722330e-04f, -4.679795743e-04f, +1.575667726e-04f, +4.805250238e-05f,
+ /* 20, 5 */ -1.435528424e-04f, +1.373966937e-05f, +6.642048742e-04f, -2.903827106e-05f, -1.539395067e-03f, -2.318933016e-04f, +2.525953799e-03f, +8.926733333e-04f, -3.086315860e-03f, -1.695571566e-03f, +2.856012327e-03f, +2.132335710e-03f, -1.994908019e-03f, -1.906854484e-03f, +1.036111434e-03f, +1.212253447e-03f, -4.032663270e-04f, -5.104270987e-04f, +1.377794601e-04f, +6.235351094e-05f,
+ /* 20, 6 */ -1.265803873e-04f, -2.312428639e-05f, +6.433751213e-04f, +7.008046528e-05f, -1.496327216e-03f, -4.142913555e-04f, +2.437861323e-03f, +1.145006429e-03f, -2.939657349e-03f, -1.967271220e-03f, +2.667620552e-03f, +2.363368676e-03f, -1.809872756e-03f, -2.063262017e-03f, +8.992377119e-04f, +1.297882648e-03f, -3.306722314e-04f, -5.498460811e-04f, +1.143596169e-04f, +7.750368078e-05f,
+ /* 20, 7 */ -1.097853637e-04f, -5.689720211e-05f, +6.169629011e-04f, +1.635247423e-04f, -1.441036462e-03f, -5.871944806e-04f, +2.330402993e-03f, +1.383253258e-03f, -2.769072436e-03f, -2.221308400e-03f, +2.455440941e-03f, +2.576324026e-03f, -1.605464444e-03f, -2.205011397e-03f, +7.492467105e-04f, +1.374526925e-03f, -2.505904541e-04f, -5.855752858e-04f, +8.736287854e-05f, +9.336686615e-05f,
+ /* 20, 8 */ -9.336686615e-05f, -8.736287854e-05f, +5.855752858e-04f, +2.505904541e-04f, -1.374526925e-03f, -7.492467105e-04f, +2.205011397e-03f, +1.605464444e-03f, -2.576324026e-03f, -2.455440941e-03f, +2.221308400e-03f, +2.769072436e-03f, -1.383253258e-03f, -2.330402993e-03f, +5.871944806e-04f, +1.441036462e-03f, -1.635247423e-04f, -6.169629011e-04f, +5.689720211e-05f, +1.097853637e-04f,
+ /* 20, 9 */ -7.750368078e-05f, -1.143596169e-04f, +5.498460811e-04f, +3.306722314e-04f, -1.297882648e-03f, -8.992377119e-04f, +2.063262017e-03f, +1.809872756e-03f, -2.363368676e-03f, -2.667620552e-03f, +1.967271220e-03f, +2.939657349e-03f, -1.145006429e-03f, -2.437861323e-03f, +4.142913555e-04f, +1.496327216e-03f, -7.008046528e-05f, -6.433751213e-04f, +2.312428639e-05f, +1.265803873e-04f,
+ /* 20,10 */ -6.235351094e-05f, -1.377794601e-04f, +5.104270987e-04f, +4.032663270e-04f, -1.212253447e-03f, -1.036111434e-03f, +1.906854484e-03f, +1.994908019e-03f, -2.132335710e-03f, -2.856012327e-03f, +1.695571566e-03f, +3.086315860e-03f, -8.926733333e-04f, -2.525953799e-03f, +2.318933016e-04f, +1.539395067e-03f, +2.903827106e-05f, -6.642048742e-04f, -1.373966937e-05f, +1.435528424e-04f,
+ /* 20,11 */ -4.805250238e-05f, -1.575667726e-04f, +4.679795743e-04f, +4.679722330e-04f, -1.118840456e-03f, -1.158972903e-03f, +1.737592880e-03f, +2.159209806e-03f, -1.885504757e-03f, -3.019012048e-03f, +1.408623929e-03f, +3.207497769e-03f, -6.283684809e-04f, -2.593408320e-03f, +4.149146373e-05f, +1.569329509e-03f, +1.330327870e-04f, -6.788805869e-04f, -5.342390613e-05f, +1.604844080e-04f,
+ /* 20,12 */ -3.471505729e-05f, -1.737162070e-04f, +4.231658296e-04f, +5.244930508e-04f, -1.018881552e-03f, -1.267093119e-03f, +1.557365345e-03f, +2.301637793e-03f, -1.625281932e-03f, -3.155261081e-03f, +1.108991788e-03f, +3.301882608e-03f, -3.543525656e-04f, -2.639129491e-03f, -1.553000173e-04f, +1.585326694e-03f, +2.410152618e-04f, -6.868748812e-04f, -9.560377684e-05f, +1.771389305e-04f,
+ /* 20,13 */ -2.243392330e-05f, -1.862701081e-04f, +3.766412744e-04f, +5.726346524e-04f, -9.136368247e-04f, -1.359912061e-03f, +1.368123194e-03f, +2.421279702e-03f, -1.354174959e-03f, -3.263658730e-03f, +7.993627115e-04f, +3.368394423e-03f, -7.301175991e-05f, -2.662213263e-03f, -3.567578182e-04f, +1.586701669e-03f, +3.520154127e-04f, -6.877130848e-04f, -1.399021716e-04f, +1.932641301e-04f,
+ /* 20,14 */ +3.513221827e-04f, -1.953154138e-04f, +3.290468323e-04f, +6.123036842e-04f, -8.043742580e-04f, -1.437039798e-03f, +1.171859801e-03f, +2.517456780e-03f, -1.074767465e-03f, -3.343371924e-03f, +4.825221542e-04f, +3.406214168e-03f, +2.131645492e-04f, -2.661959816e-03f, -5.610647582e-04f, +1.572899641e-03f, +4.649883812e-04f, -6.809814437e-04f, -1.858917095e-04f, +6.015260759e-04f,
+ /* 20,15 */ +0.000000000e+00f, -2.009801156e-04f, +2.810018705e-04f, +6.435044748e-04f, -6.923557695e-04f, -1.498255744e-03f, +9.705894653e-04f, +2.589726790e-03f, -7.896927597e-04f, -3.393842146e-03f, +1.613262342e-04f, +3.414789539e-03f, +5.016073607e-04f, -2.637884518e-03f, -7.663264997e-04f, +1.543506114e-03f, +5.788237715e-04f, -6.663349221e-04f, -2.330977005e-04f, +2.034293425e-04f,
+ /* 20, 0 */ -1.941987182e-05f, -3.146481294e-04f, +5.561305343e-04f, +3.334278991e-04f, -1.561489082e-03f, -4.085266513e-04f, +2.806699025e-03f, +3.580334706e-04f, -3.695826941e-03f, -1.914605051e-04f, +3.720952014e-03f, -2.295171057e-05f, -2.868623587e-03f, +1.886978960e-04f, +1.629573547e-03f, -2.343761763e-04f, -6.035407960e-04f, +1.633790229e-04f, +3.476344875e-05f, +0.000000000e+00f,
+ /* 20, 1 */ +3.929324583e-04f, -3.051602666e-04f, +5.048306585e-04f, +4.229644027e-04f, -1.479104632e-03f, -6.165003319e-04f, +2.717079427e-03f, +6.839596419e-04f, -3.633185574e-03f, -5.723309145e-04f, +3.708003841e-03f, +3.177599071e-04f, -2.901501717e-03f, -4.082823094e-05f, +1.681921685e-03f, -1.265851889e-04f, -6.461214422e-04f, +1.369921977e-04f, +5.166761157e-05f, +0.000000000e+00f,
+ /* 20, 2 */ +0.000000000e+00f, -2.925136688e-04f, +4.505823818e-04f, +5.023683161e-04f, -1.383975926e-03f, -8.106644739e-04f, +2.601403151e-03f, +9.973590062e-04f, -3.534000256e-03f, -9.470733637e-04f, +3.656850180e-03f, +6.604608766e-04f, -2.904291326e-03f, -2.777120434e-04f, +1.717239595e-03f, -1.098579054e-05f, -6.829477483e-04f, +1.058859702e-04f, +7.000071077e-05f, +0.000000000e+00f,
+ /* 20, 3 */ +0.000000000e+00f, -2.771727451e-04f, +3.943146848e-04f, +5.711822345e-04f, -1.277754215e-03f, -9.892860040e-04f, +2.461570058e-03f, +1.295052213e-03f, -3.399644449e-03f, -1.311681723e-03f, +3.567787737e-03f, +1.001437562e-03f, -2.876278542e-03f, -5.194560271e-04f, +1.734397724e-03f, +1.113422841e-04f, -7.131247677e-04f, +7.019384523e-05f, +8.959420873e-05f, +0.000000000e+00f,
+ /* 20, 4 */ +0.000000000e+00f, -2.596009711e-04f, +3.369316672e-04f, +6.291078651e-04f, -1.162161945e-03f, -1.150868125e-03f, +2.299713337e-03f, +1.574086312e-03f, -3.231873732e-03f, -1.662267592e-03f, +3.441541225e-03f, +1.336946247e-03f, -2.817092852e-03f, -7.634316403e-04f, +1.732451285e-03f, +2.391787684e-04f, -7.358020638e-04f, +3.013243736e-05f, +1.102423612e-04f, +0.000000000e+00f,
+ /* 20, 5 */ +0.000000000e+00f, -2.402546692e-04f, +2.793008459e-04f, +6.760030262e-04f, -1.038968304e-03f, -1.294161821e-03f, +2.118169008e-03f, +1.831766066e-03f, -3.032802328e-03f, -1.995105343e-03f, +3.279257242e-03f, +1.663257052e-03f, -2.726718246e-03f, -1.006908470e-03f, +1.710658870e-03f, +3.711735089e-04f, -7.501884622e-04f, -1.399708473e-05f, +1.317024534e-04f, +0.000000000e+00f,
+ /* 20, 6 */ +0.000000000e+00f, -2.195772899e-04f, +2.222425350e-04f, +7.118766228e-04f, -9.099649801e-04f, -1.418173917e-03f, +1.919443545e-03f, +2.065681697e-03f, -2.804875489e-03f, -2.306675131e-03f, +3.082493013e-03f, +1.976698190e-03f, -2.605500127e-03f, -1.247085413e-03f, +1.668498942e-03f, +5.058593370e-04f, -7.555665992e-04f, -6.180883712e-05f, +1.536956226e-04f, +0.000000000e+00f,
+ /* 20, 7 */ +0.000000000e+00f, -1.979942392e-04f, +1.665204182e-04f, +7.368817426e-04f, -7.769424426e-04f, -1.522171671e-03f, +1.706180058e-03f, +2.273732749e-03f, -2.550838108e-03f, -2.593703365e-03f, +2.853200114e-03f, +2.273699984e-03f, -2.454147846e-03f, -1.481123511e-03f, +1.605683934e-03f, +6.416670612e-04f, -7.513070408e-04f, -1.128334053e-04f, +1.759082929e-04f, +0.000000000e+00f,
+ /* 20, 8 */ +0.000000000e+00f, -1.759082929e-04f, +1.128334053e-04f, +7.513070408e-04f, -6.416670612e-04f, -1.605683934e-03f, +1.481123511e-03f, +2.454147846e-03f, -2.273699984e-03f, -2.853200114e-03f, +2.593703365e-03f, +2.550838108e-03f, -2.273732749e-03f, -1.706180058e-03f, +1.522171671e-03f, +7.769424426e-04f, -7.368817426e-04f, -1.665204182e-04f, +1.979942392e-04f, +0.000000000e+00f,
+ /* 20, 9 */ +0.000000000e+00f, -1.536956226e-04f, +6.180883712e-05f, +7.555665992e-04f, -5.058593370e-04f, -1.668498942e-03f, +1.247085413e-03f, +2.605500127e-03f, -1.976698190e-03f, -3.082493013e-03f, +2.306675131e-03f, +2.804875489e-03f, -2.065681697e-03f, -1.919443545e-03f, +1.418173917e-03f, +9.099649801e-04f, -7.118766228e-04f, -2.222425350e-04f, +2.195772899e-04f, +0.000000000e+00f,
+ /* 20,10 */ +0.000000000e+00f, -1.317024534e-04f, +1.399708473e-05f, +7.501884622e-04f, -3.711735089e-04f, -1.710658870e-03f, +1.006908470e-03f, +2.726718246e-03f, -1.663257052e-03f, -3.279257242e-03f, +1.995105343e-03f, +3.032802328e-03f, -1.831766066e-03f, -2.118169008e-03f, +1.294161821e-03f, +1.038968304e-03f, -6.760030262e-04f, -2.793008459e-04f, +2.402546692e-04f, +0.000000000e+00f,
+ /* 20,11 */ +0.000000000e+00f, -1.102423612e-04f, -3.013243736e-05f, +7.358020638e-04f, -2.391787684e-04f, -1.732451285e-03f, +7.634316403e-04f, +2.817092852e-03f, -1.336946247e-03f, -3.441541225e-03f, +1.662267592e-03f, +3.231873732e-03f, -1.574086312e-03f, -2.299713337e-03f, +1.150868125e-03f, +1.162161945e-03f, -6.291078651e-04f, -3.369316672e-04f, +2.596009711e-04f, +0.000000000e+00f,
+ /* 20,12 */ +0.000000000e+00f, -8.959420873e-05f, -7.019384523e-05f, +7.131247677e-04f, -1.113422841e-04f, -1.734397724e-03f, +5.194560271e-04f, +2.876278542e-03f, -1.001437562e-03f, -3.567787737e-03f, +1.311681723e-03f, +3.399644449e-03f, -1.295052213e-03f, -2.461570058e-03f, +9.892860040e-04f, +1.277754215e-03f, -5.711822345e-04f, -3.943146848e-04f, +2.771727451e-04f, +0.000000000e+00f,
+ /* 20,13 */ +0.000000000e+00f, -7.000071077e-05f, -1.058859702e-04f, +6.829477483e-04f, +1.098579054e-05f, -1.717239595e-03f, +2.777120434e-04f, +2.904291326e-03f, -6.604608766e-04f, -3.656850180e-03f, +9.470733637e-04f, +3.534000256e-03f, -9.973590062e-04f, -2.601403151e-03f, +8.106644739e-04f, +1.383975926e-03f, -5.023683161e-04f, -4.505823818e-04f, +2.925136688e-04f, +0.000000000e+00f,
+ /* 20,14 */ +0.000000000e+00f, -5.166761157e-05f, -1.369921977e-04f, +6.461214422e-04f, +1.265851889e-04f, -1.681921685e-03f, +4.082823094e-05f, +2.901501717e-03f, -3.177599071e-04f, -3.708003841e-03f, +5.723309145e-04f, +3.633185574e-03f, -6.839596419e-04f, -2.717079427e-03f, +6.165003319e-04f, +1.479104632e-03f, -4.229644027e-04f, -5.048306585e-04f, +3.051602666e-04f, -3.929324583e-04f,
+ /* 20,15 */ +0.000000000e+00f, -3.476344875e-05f, -1.633790229e-04f, +6.035407960e-04f, +2.343761763e-04f, -1.629573547e-03f, -1.886978960e-04f, +2.868623587e-03f, +2.295171057e-05f, -3.720952014e-03f, +1.914605051e-04f, +3.695826941e-03f, -3.580334706e-04f, -2.806699025e-03f, +4.085266513e-04f, +1.561489082e-03f, -3.334278991e-04f, -5.561305343e-04f, +3.146481294e-04f, +1.941987182e-05f,
+ /* 16, 0 */ +5.220390682e-05f, +8.171943113e-04f, -8.986497643e-04f, -1.446340428e-03f, +2.494478678e-03f, +1.297377101e-03f, -3.898391184e-03f, -2.241676001e-04f, +3.985236927e-03f, -9.413140896e-04f, -2.682700956e-03f, +1.283836927e-03f, +1.053222343e-03f, -7.989322796e-04f, -1.116939505e-04f, +1.571395541e-04f,
+ /* 16, 1 */ -3.017522584e-06f, +8.224554322e-04f, -7.403312787e-04f, -1.584058293e-03f, +2.281207335e-03f, +1.631019258e-03f, -3.765802305e-03f, -6.696927435e-04f, +4.024834602e-03f, -5.670028406e-04f, -2.842687093e-03f, +1.097826180e-03f, +1.201600277e-03f, -7.671194843e-04f, -1.747127487e-04f, +1.853334990e-04f,
+ /* 16, 2 */ -5.335264618e-05f, +8.154372286e-04f, -5.806604605e-04f, -1.696100138e-03f, +2.046328714e-03f, +1.938434809e-03f, -3.589560871e-03f, -1.106825943e-03f, +4.016290169e-03f, -1.789305351e-04f, -2.971556495e-03f, +8.899684644e-04f, +1.341315594e-03f, -7.213960065e-04f, -2.404043435e-04f, +2.137577131e-04f,
+ /* 16, 3 */ -9.830954357e-05f, +7.970128377e-04f, -4.219420013e-04f, -1.781963746e-03f, +1.793485018e-03f, +2.216231187e-03f, -3.372309802e-03f, -1.530099436e-03f, +3.959337237e-03f, +2.181586899e-04f, -3.066783450e-03f, +6.622938144e-04f, +1.469918710e-03f, -6.616076810e-04f, -3.078052257e-04f, +7.052925564e-04f,
+ /* 16, 4 */ -1.375232535e-04f, +7.681852053e-04f, -2.663606532e-04f, -1.841529450e-03f, +1.526462906e-03f, +2.461468734e-03f, -3.117203525e-03f, -1.934233820e-03f, +3.854345030e-03f, +6.193258599e-04f, -3.126241364e-03f, +4.171838871e-04f, +1.585017189e-03f, -5.878191605e-04f, -3.758553213e-04f, +2.457392598e-04f,
+ /* 16, 5 */ -1.707546409e-04f, +7.300642099e-04f, -1.159532388e-04f, -1.875048978e-03f, +1.249136740e-03f, +2.671693350e-03f, -2.827860277e-03f, -2.314209556e-03f, +3.702317390e-03f, +1.019502933e-03f, -3.148242059e-03f, +1.573479538e-04f, +1.684315055e-03f, -5.003238841e-04f, -4.434113338e-04f, +2.470336005e-04f,
+ /* 16, 6 */ -1.978870754e-04f, +6.838430878e-04f, +2.741593655e-05f, -1.883129095e-03f, +9.654119112e-04f, +2.844961691e-03f, -2.508308289e-03f, -2.665334690e-03f, +3.504882792e-03f, +1.413561295e-03f, -3.131569469e-03f, -1.142067707e-04f, +1.765652028e-03f, -3.996506493e-04f, -5.092623113e-04f, +2.432370997e-04f,
+ /* 16, 7 */ -2.189210857e-04f, +6.307745862e-04f, +1.620759979e-04f, -1.866710442e-03f, +6.791690772e-04f, +2.979858667e-03f, -2.162926680e-03f, -2.983307830e-03f, +3.264275462e-03f, +1.796381989e-03f, -3.075507089e-03f, -3.942101476e-04f, +1.827042047e-03f, -2.865665382e-04f, -5.721472605e-04f, +2.339671870e-04f,
+ /* 16, 8 */ -2.339671870e-04f, +5.721472605e-04f, +2.865665382e-04f, -1.827042047e-03f, +3.942101476e-04f, +3.075507089e-03f, -1.796381989e-03f, -3.264275462e-03f, +2.983307830e-03f, +2.162926680e-03f, -2.979858667e-03f, -6.791690772e-04f, +1.866710442e-03f, -1.620759979e-04f, -6.307745862e-04f, +2.189210857e-04f,
+ /* 16, 9 */ -2.432370997e-04f, +5.092623113e-04f, +3.996506493e-04f, -1.765652028e-03f, +1.142067707e-04f, +3.131569469e-03f, -1.413561295e-03f, -3.504882792e-03f, +2.665334690e-03f, +2.508308289e-03f, -2.844961691e-03f, -9.654119112e-04f, +1.883129095e-03f, -2.741593655e-05f, -6.838430878e-04f, +1.978870754e-04f,
+ /* 16,10 */ -2.470336005e-04f, +4.434113338e-04f, +5.003238841e-04f, -1.684315055e-03f, -1.573479538e-04f, +3.148242059e-03f, -1.019502933e-03f, -3.702317390e-03f, +2.314209556e-03f, +2.827860277e-03f, -2.671693350e-03f, -1.249136740e-03f, +1.875048978e-03f, +1.159532388e-04f, -7.300642099e-04f, +1.707546409e-04f,
+ /* 16,11 */ -2.457392598e-04f, +3.758553213e-04f, +5.878191605e-04f, -1.585017189e-03f, -4.171838871e-04f, +3.126241364e-03f, -6.193258599e-04f, -3.854345030e-03f, +1.934233820e-03f, +3.117203525e-03f, -2.461468734e-03f, -1.526462906e-03f, +1.841529450e-03f, +2.663606532e-04f, -7.681852053e-04f, +1.375232535e-04f,
+ /* 16,12 */ -7.052925564e-04f, +3.078052257e-04f, +6.616076810e-04f, -1.469918710e-03f, -6.622938144e-04f, +3.066783450e-03f, -2.181586899e-04f, -3.959337237e-03f, +1.530099436e-03f, +3.372309802e-03f, -2.216231187e-03f, -1.793485018e-03f, +1.781963746e-03f, +4.219420013e-04f, -7.970128377e-04f, +9.830954357e-05f,
+ /* 16,13 */ -2.137577131e-04f, +2.404043435e-04f, +7.213960065e-04f, -1.341315594e-03f, -8.899684644e-04f, +2.971556495e-03f, +1.789305351e-04f, -4.016290169e-03f, +1.106825943e-03f, +3.589560871e-03f, -1.938434809e-03f, -2.046328714e-03f, +1.696100138e-03f, +5.806604605e-04f, -8.154372286e-04f, +5.335264618e-05f,
+ /* 16,14 */ -1.853334990e-04f, +1.747127487e-04f, +7.671194843e-04f, -1.201600277e-03f, -1.097826180e-03f, +2.842687093e-03f, +5.670028406e-04f, -4.024834602e-03f, +6.696927435e-04f, +3.765802305e-03f, -1.631019258e-03f, -2.281207335e-03f, +1.584058293e-03f, +7.403312787e-04f, -8.224554322e-04f, +3.017522584e-06f,
+ /* 16,15 */ -1.571395541e-04f, +1.116939505e-04f, +7.989322796e-04f, -1.053222343e-03f, -1.283836927e-03f, +2.682700956e-03f, +9.413140896e-04f, -3.985236927e-03f, +2.241676001e-04f, +3.898391184e-03f, -1.297377101e-03f, -2.494478678e-03f, +1.446340428e-03f, +8.986497643e-04f, -8.171943113e-04f, -5.220390682e-05f,
+ /* 16, 0 */ -2.607744081e-04f, +6.609893225e-04f, +4.777614003e-05f, -2.019079564e-03f, +1.736921610e-03f, +2.230081148e-03f, -4.008512761e-03f, -2.594451583e-04f, +4.172957467e-03f, -1.888269495e-03f, -2.040920379e-03f, +1.975903291e-03f, +1.180452271e-04f, -7.248571600e-04f, +2.468008838e-04f, +0.000000000e+00f,
+ /* 16, 1 */ -2.676863913e-04f, +5.906930705e-04f, +2.025069901e-04f, -2.030408814e-03f, +1.418499470e-03f, +2.533235894e-03f, -3.790472440e-03f, -7.745724648e-04f, +4.280846994e-03f, -1.512096765e-03f, -2.325335551e-03f, +1.900137256e-03f, +2.927280105e-04f, -7.805529904e-04f, +2.254162899e-04f, +0.000000000e+00f,
+ /* 16, 2 */ -2.680102581e-04f, +5.157202047e-04f, +3.442245196e-04f, -2.011119828e-03f, +1.090886046e-03f, +2.794113365e-03f, -3.522578151e-03f, -1.278469954e-03f, +4.330057965e-03f, -1.106477171e-03f, -2.585166870e-03f, +1.791556445e-03f, +4.737630093e-04f, -8.263772041e-04f, +1.964117366e-04f, +0.000000000e+00f,
+ /* 16, 3 */ -7.633646088e-04f, +4.377966605e-04f, +4.713317060e-04f, -1.962888420e-03f, +7.592982470e-04f, +3.009813640e-03f, -3.209287239e-03f, -1.763847458e-03f, +4.319343992e-03f, -6.768749158e-04f, -2.815661672e-03f, +1.650477084e-03f, +6.583936022e-04f, -8.607109932e-04f, +1.597335965e-04f, -4.634120047e-04f,
+ /* 16, 4 */ -2.423668462e-04f, +3.585907293e-04f, +5.825699836e-04f, -1.887792011e-03f, +4.288533077e-04f, +3.178189562e-03f, -2.855695312e-03f, -2.223705909e-03f, +4.248362401e-03f, -2.292254995e-04f, -3.012400483e-03f, +1.477771292e-03f, +8.436545409e-04f, -8.820535056e-04f, +1.154955663e-04f, +2.338334874e-05f,
+ /* 16, 5 */ -2.066858426e-04f, +2.796840991e-04f, +6.770251471e-04f, -1.788258811e-03f, +1.044882353e-04f, +3.297866045e-03f, -2.467449129e-03f, -2.651446905e-03f, +4.117686315e-03f, +2.301520823e-04f, -3.171379014e-03f, +1.274872332e-03f, +1.026416356e-03f, -8.890585891e-04f, +6.398775754e-05f, +4.782938304e-05f,
+ /* 16, 6 */ -1.715009195e-04f, +2.025461567e-04f, +7.541266524e-04f, -1.667012713e-03f, -2.091154912e-04f, +3.368246274e-03f, -2.050651409e-03f, -3.040975547e-03f, +3.928801804e-03f, +6.946508648e-04f, -3.289085050e-03f, +1.043770075e-03f, +1.203434747e-03f, -8.805703554e-04f, +5.682450650e-06f, +7.520965874e-05f,
+ /* 16, 7 */ -1.374865801e-04f, +1.285119093e-04f, +8.136405975e-04f, -1.527015027e-03f, -5.076007987e-04f, +3.389504923e-03f, -1.611759203e-03f, -3.386794836e-03f, +3.684090065e-03f, +1.157477637e-03f, -3.362568736e-03f, +7.869964389e-04f, +1.371404208e-03f, -8.556567843e-04f, -5.876379361e-05f, +1.052264476e-04f,
+ /* 16, 8 */ -1.052264476e-04f, +5.876379361e-05f, +8.556567843e-04f, -1.371404208e-03f, -7.869964389e-04f, +3.362568736e-03f, -1.157477637e-03f, -3.684090065e-03f, +3.386794836e-03f, +1.611759203e-03f, -3.389504923e-03f, +5.076007987e-04f, +1.527015027e-03f, -8.136405975e-04f, -1.285119093e-04f, +1.374865801e-04f,
+ /* 16, 9 */ -7.520965874e-05f, -5.682450650e-06f, +8.805703554e-04f, -1.203434747e-03f, -1.043770075e-03f, +3.289085050e-03f, -6.946508648e-04f, -3.928801804e-03f, +3.040975547e-03f, +2.050651409e-03f, -3.368246274e-03f, +2.091154912e-04f, +1.667012713e-03f, -7.541266524e-04f, -2.025461567e-04f, +1.715009195e-04f,
+ /* 16,10 */ -4.782938304e-05f, -6.398775754e-05f, +8.890585891e-04f, -1.026416356e-03f, -1.274872332e-03f, +3.171379014e-03f, -2.301520823e-04f, -4.117686315e-03f, +2.651446905e-03f, +2.467449129e-03f, -3.297866045e-03f, -1.044882353e-04f, +1.788258811e-03f, -6.770251471e-04f, -2.796840991e-04f, +2.066858426e-04f,
+ /* 16,11 */ -2.338334874e-05f, -1.154955663e-04f, +8.820535056e-04f, -8.436545409e-04f, -1.477771292e-03f, +3.012400483e-03f, +2.292254995e-04f, -4.248362401e-03f, +2.223705909e-03f, +2.855695312e-03f, -3.178189562e-03f, -4.288533077e-04f, +1.887792011e-03f, -5.825699836e-04f, -3.585907293e-04f, +2.423668462e-04f,
+ /* 16,12 */ +4.634120047e-04f, -1.597335965e-04f, +8.607109932e-04f, -6.583936022e-04f, -1.650477084e-03f, +2.815661672e-03f, +6.768749158e-04f, -4.319343992e-03f, +1.763847458e-03f, +3.209287239e-03f, -3.009813640e-03f, -7.592982470e-04f, +1.962888420e-03f, -4.713317060e-04f, -4.377966605e-04f, +7.633646088e-04f,
+ /* 16,13 */ +0.000000000e+00f, -1.964117366e-04f, +8.263772041e-04f, -4.737630093e-04f, -1.791556445e-03f, +2.585166870e-03f, +1.106477171e-03f, -4.330057965e-03f, +1.278469954e-03f, +3.522578151e-03f, -2.794113365e-03f, -1.090886046e-03f, +2.011119828e-03f, -3.442245196e-04f, -5.157202047e-04f, +2.680102581e-04f,
+ /* 16,14 */ +0.000000000e+00f, -2.254162899e-04f, +7.805529904e-04f, -2.927280105e-04f, -1.900137256e-03f, +2.325335551e-03f, +1.512096765e-03f, -4.280846994e-03f, +7.745724648e-04f, +3.790472440e-03f, -2.533235894e-03f, -1.418499470e-03f, +2.030408814e-03f, -2.025069901e-04f, -5.906930705e-04f, +2.676863913e-04f,
+ /* 16,15 */ +0.000000000e+00f, -2.468008838e-04f, +7.248571600e-04f, -1.180452271e-04f, -1.975903291e-03f, +2.040920379e-03f, +1.888269495e-03f, -4.172957467e-03f, +2.594451583e-04f, +4.008512761e-03f, -2.230081148e-03f, -1.736921610e-03f, +2.019079564e-03f, -4.777614003e-05f, -6.609893225e-04f, +2.607744081e-04f,
+ /* 16, 0 */ -1.129954761e-04f, -3.969443331e-04f, +7.863457700e-04f, -1.968627401e-03f, +6.635626436e-04f, +3.065104554e-03f, -4.014723865e-03f, -2.972906332e-04f, +4.272130602e-03f, -2.778972616e-03f, -1.044103847e-03f, +2.069667087e-03f, -6.906315332e-04f, -2.376896670e-04f, +1.523656204e-04f, +0.000000000e+00f,
+ /* 16, 1 */ -7.672972562e-05f, -4.458313625e-04f, +8.604609066e-04f, -1.839340292e-03f, +2.869810557e-04f, +3.294943885e-03f, -3.696990655e-03f, -8.869321804e-04f, +4.464175630e-03f, -2.440111513e-03f, -1.421957113e-03f, +2.139058837e-03f, -5.737860098e-04f, -3.273087897e-04f, +1.941703587e-04f, +0.000000000e+00f,
+ /* 16, 2 */ -4.409159553e-05f, -4.801879450e-04f, +9.129725459e-04f, -1.685578963e-03f, -7.929130936e-05f, +3.465994861e-03f, -3.324955442e-03f, -1.461843594e-03f, +4.586914931e-03f, -2.053108579e-03f, -1.790295465e-03f, +2.173860444e-03f, -4.367566844e-04f, -4.185294039e-04f, +2.375950982e-04f, +0.000000000e+00f,
+ /* 16, 3 */ +4.855802427e-04f, -5.008892512e-04f, +9.443143993e-04f, -1.511399569e-03f, -4.293120730e-04f, +3.576852207e-03f, -2.905512498e-03f, -2.012499819e-03f, +4.637578076e-03f, -1.623510702e-03f, -2.142238116e-03f, +2.171667537e-03f, -2.809771210e-04f, -5.093533546e-04f, +2.816859426e-04f, +0.000000000e+00f,
+ /* 16, 4 */ +0.000000000e+00f, -5.090007623e-04f, +9.553248878e-04f, -1.321049384e-03f, -7.576441950e-04f, +3.627202827e-03f, -2.446291464e-03f, -2.529812382e-03f, +4.614629236e-03f, -1.157740361e-03f, -2.470980778e-03f, +2.130685105e-03f, -1.083629217e-04f, -5.976383603e-04f, +3.253590588e-04f, +0.000000000e+00f,
+ /* 16, 5 */ +0.000000000e+00f, -5.057402285e-04f, +9.472067544e-04f, -1.118874842e-03f, -1.059441268e-03f, +3.617806804e-03f, -1.955510679e-03f, -3.005292216e-03f, +4.517805471e-03f, -6.629933593e-04f, -2.769928158e-03f, +2.049789183e-03f, +7.870314989e-05f, -6.811391839e-04f, +3.674140144e-04f, +0.000000000e+00f,
+ /* 16, 6 */ +0.000000000e+00f, -4.924395299e-04f, +9.214808972e-04f, -9.092313688e-04f, -1.330518654e-03f, +3.550458465e-03f, -1.441821213e-03f, -3.431200966e-03f, +4.348131386e-03f, -1.471199733e-04f, -3.032825993e-03f, +1.928577081e-03f, +2.773970394e-04f, -7.575537377e-04f, +4.065510896e-04f, +0.000000000e+00f,
+ /* 16, 7 */ +0.000000000e+00f, -4.705072223e-04f, +8.799357120e-04f, -6.963968181e-04f, -1.567409460e-03f, +3.427928686e-03f, -9.141447359e-04f, -3.800687882e-03f, +4.107909720e-03f, +3.815084058e-04f, -3.253889950e-03f, +1.767404663e-03f, +4.844901765e-04f, -8.245732787e-04f, +4.413924818e-04f, +0.000000000e+00f,
+ /* 16, 8 */ +0.000000000e+00f, -4.413924818e-04f, +8.245732787e-04f, -4.844901765e-04f, -1.767404663e-03f, +3.253889950e-03f, -3.815084058e-04f, -4.107909720e-03f, +3.800687882e-03f, +9.141447359e-04f, -3.427928686e-03f, +1.567409460e-03f, +6.963968181e-04f, -8.799357120e-04f, +4.705072223e-04f, +0.000000000e+00f,
+ /* 16, 9 */ +0.000000000e+00f, -4.065510896e-04f, +7.575537377e-04f, -2.773970394e-04f, -1.928577081e-03f, +3.032825993e-03f, +1.471199733e-04f, -4.348131386e-03f, +3.431200966e-03f, +1.441821213e-03f, -3.550458465e-03f, +1.330518654e-03f, +9.092313688e-04f, -9.214808972e-04f, +4.924395299e-04f, +0.000000000e+00f,
+ /* 16,10 */ +0.000000000e+00f, -3.674140144e-04f, +6.811391839e-04f, -7.870314989e-05f, -2.049789183e-03f, +2.769928158e-03f, +6.629933593e-04f, -4.517805471e-03f, +3.005292216e-03f, +1.955510679e-03f, -3.617806804e-03f, +1.059441268e-03f, +1.118874842e-03f, -9.472067544e-04f, +5.057402285e-04f, +0.000000000e+00f,
+ /* 16,11 */ +0.000000000e+00f, -3.253590588e-04f, +5.976383603e-04f, +1.083629217e-04f, -2.130685105e-03f, +2.470980778e-03f, +1.157740361e-03f, -4.614629236e-03f, +2.529812382e-03f, +2.446291464e-03f, -3.627202827e-03f, +7.576441950e-04f, +1.321049384e-03f, -9.553248878e-04f, +5.090007623e-04f, +0.000000000e+00f,
+ /* 16,12 */ +0.000000000e+00f, -2.816859426e-04f, +5.093533546e-04f, +2.809771210e-04f, -2.171667537e-03f, +2.142238116e-03f, +1.623510702e-03f, -4.637578076e-03f, +2.012499819e-03f, +2.905512498e-03f, -3.576852207e-03f, +4.293120730e-04f, +1.511399569e-03f, -9.443143993e-04f, +5.008892512e-04f, -4.855802427e-04f,
+ /* 16,13 */ +0.000000000e+00f, -2.375950982e-04f, +4.185294039e-04f, +4.367566844e-04f, -2.173860444e-03f, +1.790295465e-03f, +2.053108579e-03f, -4.586914931e-03f, +1.461843594e-03f, +3.324955442e-03f, -3.465994861e-03f, +7.929130936e-05f, +1.685578963e-03f, -9.129725459e-04f, +4.801879450e-04f, +4.409159553e-05f,
+ /* 16,14 */ +0.000000000e+00f, -1.941703587e-04f, +3.273087897e-04f, +5.737860098e-04f, -2.139058837e-03f, +1.421957113e-03f, +2.440111513e-03f, -4.464175630e-03f, +8.869321804e-04f, +3.696990655e-03f, -3.294943885e-03f, -2.869810557e-04f, +1.839340292e-03f, -8.604609066e-04f, +4.458313625e-04f, +7.672972562e-05f,
+ /* 16,15 */ +0.000000000e+00f, -1.523656204e-04f, +2.376896670e-04f, +6.906315332e-04f, -2.069667087e-03f, +1.044103847e-03f, +2.778972616e-03f, -4.272130602e-03f, +2.972906332e-04f, +4.014723865e-03f, -3.065104554e-03f, -6.635626436e-04f, +1.968627401e-03f, -7.863457700e-04f, +3.969443331e-04f, +1.129954761e-04f,
+ /* 12, 0 */ +1.006092301e-03f, -1.356592138e-03f, -5.291224839e-04f, +3.716365432e-03f, -3.908475818e-03f, -3.377012930e-04f, +4.272902045e-03f, -3.529241849e-03f, +1.347121185e-04f, +1.576582805e-03f, -1.021094463e-03f, +2.080147558e-04f,
+ /* 12, 1 */ +9.703330579e-04f, -1.123568815e-03f, -8.960631472e-04f, +3.830455785e-03f, -3.478978472e-03f, -1.006731283e-03f, +4.564422369e-03f, -3.270752231e-03f, -2.802589631e-04f, +1.777910422e-03f, -1.013271813e-03f, +1.540375404e-04f,
+ /* 12, 2 */ +9.162319547e-04f, -8.831264337e-04f, -1.229457804e-03f, +3.871345986e-03f, -2.993425932e-03f, -1.656773890e-03f, +4.776559314e-03f, -2.944064628e-03f, -7.081711396e-04f, +1.955059288e-03f, -9.809799530e-04f, +8.895597490e-05f,
+ /* 12, 3 */ +8.464715149e-04f, -6.407365814e-04f, -1.524162434e-03f, +3.840336583e-03f, -2.461816027e-03f, -2.275602698e-03f, +4.904341682e-03f, -2.553815646e-03f, -1.140836495e-03f, +2.102763165e-03f, -9.230670815e-04f, +1.349777819e-05f,
+ /* 12, 4 */ +7.639192828e-04f, -4.016125871e-04f, -1.776040886e-03f, +3.740131991e-03f, -1.894910812e-03f, -2.851629129e-03f, +4.944422783e-03f, -2.106045312e-03f, -1.569658753e-03f, +2.216140176e-03f, -8.389345160e-04f, -7.124952580e-05f,
+ /* 12, 5 */ +6.715456333e-04f, -1.706046467e-04f, -1.982015497e-03f, +3.574748146e-03f, -1.304005398e-03f, -3.374137989e-03f, +4.895165032e-03f, -1.608099956e-03f, -1.985807614e-03f, +2.290824513e-03f, -7.285864297e-04f, -1.638417811e-04f,
+ /* 12, 6 */ +5.723437636e-04f, +4.789167018e-05f, -2.140092391e-03f, +3.349394124e-03f, -7.006885404e-04f, -3.833503957e-03f, +4.756688774e-03f, -1.068504673e-03f, -2.380403858e-03f, +2.323091638e-03f, -5.926669574e-04f, -2.624916697e-04f,
+ /* 12, 7 */ +4.692537952e-04f, +2.500119139e-04f, -2.249361715e-03f, +3.070330944e-03f, -9.660032268e-05f, -4.221384345e-03f, +4.530883988e-03f, -4.968076992e-04f, -2.744711242e-03f, +2.309973659e-03f, -4.324830696e-04f, -3.650927179e-04f,
+ /* 12, 8 */ +3.650927179e-04f, +4.324830696e-04f, -2.309973659e-03f, +2.744711242e-03f, +4.968076992e-04f, -4.530883988e-03f, +4.221384345e-03f, +9.660032268e-05f, -3.070330944e-03f, +2.249361715e-03f, -2.500119139e-04f, -4.692537952e-04f,
+ /* 12, 9 */ +2.624916697e-04f, +5.926669574e-04f, -2.323091638e-03f, +2.380403858e-03f, +1.068504673e-03f, -4.756688774e-03f, +3.833503957e-03f, +7.006885404e-04f, -3.349394124e-03f, +2.140092391e-03f, -4.789167018e-05f, -5.723437636e-04f,
+ /* 12,10 */ +1.638417811e-04f, +7.285864297e-04f, -2.290824513e-03f, +1.985807614e-03f, +1.608099956e-03f, -4.895165032e-03f, +3.374137989e-03f, +1.304005398e-03f, -3.574748146e-03f, +1.982015497e-03f, +1.706046467e-04f, -6.715456333e-04f,
+ /* 12,11 */ +7.124952580e-05f, +8.389345160e-04f, -2.216140176e-03f, +1.569658753e-03f, +2.106045312e-03f, -4.944422783e-03f, +2.851629129e-03f, +1.894910812e-03f, -3.740131991e-03f, +1.776040886e-03f, +4.016125871e-04f, -7.639192828e-04f,
+ /* 12,12 */ -1.349777819e-05f, +9.230670815e-04f, -2.102763165e-03f, +1.140836495e-03f, +2.553815646e-03f, -4.904341682e-03f, +2.275602698e-03f, +2.461816027e-03f, -3.840336583e-03f, +1.524162434e-03f, +6.407365814e-04f, -8.464715149e-04f,
+ /* 12,13 */ -8.895597490e-05f, +9.809799530e-04f, -1.955059288e-03f, +7.081711396e-04f, +2.944064628e-03f, -4.776559314e-03f, +1.656773890e-03f, +2.993425932e-03f, -3.871345986e-03f, +1.229457804e-03f, +8.831264337e-04f, -9.162319547e-04f,
+ /* 12,14 */ -1.540375404e-04f, +1.013271813e-03f, -1.777910422e-03f, +2.802589631e-04f, +3.270752231e-03f, -4.564422369e-03f, +1.006731283e-03f, +3.478978472e-03f, -3.830455785e-03f, +8.960631472e-04f, +1.123568815e-03f, -9.703330579e-04f,
+ /* 12,15 */ -2.080147558e-04f, +1.021094463e-03f, -1.576582805e-03f, -1.347121185e-04f, +3.529241849e-03f, -4.272902045e-03f, +3.377012930e-04f, +3.908475818e-03f, -3.716365432e-03f, +5.291224839e-04f, +1.356592138e-03f, -1.006092301e-03f,
+ /* 12, 0 */ +7.165252154e-04f, -4.291307465e-04f, -1.619691310e-03f, +4.112050532e-03f, -3.684471854e-03f, -3.806742210e-04f, +4.167864669e-03f, -4.064044128e-03f, +1.285631838e-03f, +6.994376016e-04f, -8.205283947e-04f, +3.212754781e-04f,
+ /* 12, 1 */ +6.042449626e-04f, -1.684748882e-04f, -1.902468489e-03f, +4.073990388e-03f, -3.134198780e-03f, -1.133926469e-03f, +4.572939653e-03f, -3.928365474e-03f, +9.055999228e-04f, +9.731965741e-04f, -9.124383184e-04f, +3.311614162e-04f,
+ /* 12, 2 */ +4.874350434e-04f, +7.694308689e-05f, -2.130082097e-03f, +3.953363211e-03f, -2.529802622e-03f, -1.863076830e-03f, +4.889863669e-03f, -3.705392569e-03f, +4.862599326e-04f, +1.243729140e-03f, -9.884795125e-04f, +3.301883495e-04f,
+ /* 12, 3 */ +3.696734183e-04f, +3.022578517e-04f, -2.300114973e-03f, +3.755428771e-03f, -1.885047396e-03f, -2.552675098e-03f, +5.110657479e-03f, -3.397530000e-03f, +3.551878686e-05f, +1.504029611e-03f, -1.045032679e-03f, +3.171093301e-04f,
+ /* 12, 4 */ +2.542791637e-04f, +5.034105172e-04f, -2.411611526e-03f, +3.487034212e-03f, -1.214371318e-03f, -3.188181667e-03f, +5.229403271e-03f, -3.009202669e-03f, -4.376222644e-04f, +1.746934410e-03f, -1.078752986e-03f, +2.909691299e-04f,
+ /* 12, 5 */ +1.442362351e-04f, +6.772076791e-04f, -2.465038541e-03f, +3.156407157e-03f, -5.325427440e-04f, -3.756300237e-03f, +5.242404627e-03f, -2.546799451e-03f, -9.232494237e-04f, +1.965304174e-03f, -1.086687765e-03f, +2.511615343e-04f,
+ /* 12, 6 */ +4.213190220e-05f, +8.213542577e-04f, -2.462211671e-03f, +2.772920825e-03f, +1.456866600e-04f, -4.245279979e-03f, +5.148294544e-03f, -2.018567160e-03f, -1.410748009e-03f, +2.152214196e-03f, -1.066390037e-03f, +1.974793328e-04f,
+ /* 12, 7 */ -4.988918599e-05f, +9.344605010e-04f, -2.406190818e-03f, +2.346837790e-03f, +8.059229054e-04f, -4.645179801e-03f, +4.948088353e-03f, -1.434456490e-03f, -1.889039390e-03f, +2.301148282e-03f, -1.016024228e-03f, +1.301548676e-04f,
+ /* 12, 8 */ -1.301548676e-04f, +1.016024228e-03f, -2.301148282e-03f, +1.889039390e-03f, +1.434456490e-03f, -4.948088353e-03f, +4.645179801e-03f, -8.059229054e-04f, -2.346837790e-03f, +2.406190818e-03f, -9.344605010e-04f, +4.988918599e-05f,
+ /* 12, 9 */ -1.974793328e-04f, +1.066390037e-03f, -2.152214196e-03f, +1.410748009e-03f, +2.018567160e-03f, -5.148294544e-03f, +4.245279979e-03f, -1.456866600e-04f, -2.772920825e-03f, +2.462211671e-03f, -8.213542577e-04f, -4.213190220e-05f,
+ /* 12,10 */ -2.511615343e-04f, +1.086687765e-03f, -1.965304174e-03f, +9.232494237e-04f, +2.546799451e-03f, -5.242404627e-03f, +3.756300237e-03f, +5.325427440e-04f, -3.156407157e-03f, +2.465038541e-03f, -6.772076791e-04f, -1.442362351e-04f,
+ /* 12,11 */ -2.909691299e-04f, +1.078752986e-03f, -1.746934410e-03f, +4.376222644e-04f, +3.009202669e-03f, -5.229403271e-03f, +3.188181667e-03f, +1.214371318e-03f, -3.487034212e-03f, +2.411611526e-03f, -5.034105172e-04f, -2.542791637e-04f,
+ /* 12,12 */ -3.171093301e-04f, +1.045032679e-03f, -1.504029611e-03f, -3.551878686e-05f, +3.397530000e-03f, -5.110657479e-03f, +2.552675098e-03f, +1.885047396e-03f, -3.755428771e-03f, +2.300114973e-03f, -3.022578517e-04f, -3.696734183e-04f,
+ /* 12,13 */ -3.301883495e-04f, +9.884795125e-04f, -1.243729140e-03f, -4.862599326e-04f, +3.705392569e-03f, -4.889863669e-03f, +1.863076830e-03f, +2.529802622e-03f, -3.953363211e-03f, +2.130082097e-03f, -7.694308689e-05f, -4.874350434e-04f,
+ /* 12,14 */ -3.311614162e-04f, +9.124383184e-04f, -9.731965741e-04f, -9.055999228e-04f, +3.928365474e-03f, -4.572939653e-03f, +1.133926469e-03f, +3.134198780e-03f, -4.073990388e-03f, +1.902468489e-03f, +1.684748882e-04f, -6.042449626e-04f,
+ /* 12,15 */ -3.212754781e-04f, +8.205283947e-04f, -6.994376016e-04f, -1.285631838e-03f, +4.064044128e-03f, -4.167864669e-03f, +3.806742210e-04f, +3.684471854e-03f, -4.112050532e-03f, +1.619691310e-03f, +4.291307465e-04f, -7.165252154e-04f
+};
diff --git a/Alc/effects/autowah.c b/Alc/effects/autowah.c
index c8317c8b..6770f719 100644
--- a/Alc/effects/autowah.c
+++ b/Alc/effects/autowah.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -31,15 +31,15 @@
/* Auto-wah is simply a low-pass filter with a cutoff frequency that shifts up
* or down depending on the input signal, and a resonant peak at the cutoff.
*
- * Currently, we assume a cutoff frequency range of 500hz (no amplitude) to
- * 3khz (peak gain). Peak gain is assumed to be in normalized scale.
+ * Currently, we assume a cutoff frequency range of 20hz (no amplitude) to
+ * 20khz (peak gain). Peak gain is assumed to be in normalized scale.
*/
typedef struct ALautowahState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
- ALfloat Gain[MaxChannels];
+ ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALfloat AttackRate;
@@ -66,7 +66,6 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *d
static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, const ALeffectslot *slot)
{
ALfloat attackTime, releaseTime;
- ALfloat gain;
attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency;
releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency;
@@ -76,19 +75,18 @@ static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, co
state->PeakGain = slot->EffectProps.Autowah.PeakGain;
state->Resonance = slot->EffectProps.Autowah.Resonance;
- gain = sqrtf(1.0f / device->NumChan) * slot->Gain;
- SetGains(device, gain, state->Gain);
+ ComputeAmbientGains(device, slot->Gain, state->Gain);
}
-static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
+static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint it, kt;
ALuint base;
for(base = 0;base < SamplesToDo;)
{
- ALfloat temps[64];
- ALuint td = minu(SamplesToDo-base, 64);
+ ALfloat temps[256];
+ ALuint td = minu(256, SamplesToDo-base);
ALfloat gain = state->GainCtrl;
for(it = 0;it < td;it++)
@@ -114,7 +112,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
* ALfilterType_LowPass. However, instead of passing a bandwidth,
* we use the resonance property for Q. This also inlines the call.
*/
- w0 = F_2PI * cutoff / state->Frequency;
+ w0 = F_TAU * cutoff / state->Frequency;
/* FIXME: Resonance controls the resonant peak, or Q. How? Not sure
* that Q = resonance*0.1. */
@@ -137,10 +135,10 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
}
state->GainCtrl = gain;
- for(kt = 0;kt < MaxChannels;kt++)
+ for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[kt];
- if(!(gain > GAIN_SILENCE_THRESHOLD))
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
diff --git a/Alc/effects/chorus.c b/Alc/effects/chorus.c
index a6bb199e..7aa5898b 100644
--- a/Alc/effects/chorus.c
+++ b/Alc/effects/chorus.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -46,7 +46,7 @@ typedef struct ALchorusState {
ALint lfo_disp;
/* Gains for left and right sides */
- ALfloat Gain[2][MaxChannels];
+ ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
/* effect parameters */
enum ChorusWaveForm waveform;
@@ -93,6 +93,8 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev
static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot)
{
+ static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f };
+ static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f };
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat rate;
ALint phase;
@@ -111,8 +113,8 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency);
/* Gains for left and right sides */
- ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]);
- ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]);
+ ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]);
+ ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]);
phase = Slot->EffectProps.Chorus.Phase;
rate = Slot->EffectProps.Chorus.Rate;
@@ -132,7 +134,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
state->lfo_scale = 4.0f / state->lfo_range;
break;
case CWF_Sinusoid:
- state->lfo_scale = F_2PI / state->lfo_range;
+ state->lfo_scale = F_TAU / state->lfo_range;
break;
}
@@ -201,15 +203,15 @@ DECL_TEMPLATE(Sinusoid)
#undef DECL_TEMPLATE
-static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint it, kt;
ALuint base;
for(base = 0;base < SamplesToDo;)
{
- ALfloat temps[64][2];
- ALuint td = minu(SamplesToDo-base, 64);
+ ALfloat temps[128][2];
+ ALuint td = minu(128, SamplesToDo-base);
switch(state->waveform)
{
@@ -221,17 +223,17 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co
break;
}
- for(kt = 0;kt < MaxChannels;kt++)
+ for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[0][kt];
- if(gain > GAIN_SILENCE_THRESHOLD)
+ if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(it = 0;it < td;it++)
SamplesOut[kt][it+base] += temps[it][0] * gain;
}
gain = state->Gain[1][kt];
- if(gain > GAIN_SILENCE_THRESHOLD)
+ if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(it = 0;it < td;it++)
SamplesOut[kt][it+base] += temps[it][1] * gain;
diff --git a/Alc/effects/compressor.c b/Alc/effects/compressor.c
index 9728cabe..9859a085 100644
--- a/Alc/effects/compressor.c
+++ b/Alc/effects/compressor.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -31,7 +31,7 @@ typedef struct ALcompressorState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
- ALfloat Gain[MaxChannels];
+ ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALboolean Enabled;
@@ -55,25 +55,22 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev
return AL_TRUE;
}
-static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *Device, const ALeffectslot *Slot)
+static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *device, const ALeffectslot *slot)
{
- ALfloat gain;
+ state->Enabled = slot->EffectProps.Compressor.OnOff;
- state->Enabled = Slot->EffectProps.Compressor.OnOff;
-
- gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
- SetGains(Device, gain, state->Gain);
+ ComputeAmbientGains(device, slot->Gain, state->Gain);
}
-static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
+static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint it, kt;
ALuint base;
for(base = 0;base < SamplesToDo;)
{
- ALfloat temps[64];
- ALuint td = minu(SamplesToDo-base, 64);
+ ALfloat temps[256];
+ ALuint td = minu(256, SamplesToDo-base);
if(state->Enabled)
{
@@ -119,10 +116,10 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples
}
- for(kt = 0;kt < MaxChannels;kt++)
+ for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[kt];
- if(!(gain > GAIN_SILENCE_THRESHOLD))
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
diff --git a/Alc/effects/dedicated.c b/Alc/effects/dedicated.c
index 89af1c84..e09cc682 100644
--- a/Alc/effects/dedicated.c
+++ b/Alc/effects/dedicated.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -32,7 +32,7 @@
typedef struct ALdedicatedState {
DERIVE_FROM_TYPE(ALeffectState);
- ALfloat gains[MaxChannels];
+ ALfloat gains[MAX_OUTPUT_CHANNELS];
} ALdedicatedState;
@@ -48,27 +48,41 @@ static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state),
static ALvoid ALdedicatedState_update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot)
{
ALfloat Gain;
- ALsizei s;
+ ALuint i;
+
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ state->gains[i] = 0.0f;
Gain = Slot->Gain * Slot->EffectProps.Dedicated.Gain;
- if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
- ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains);
- else if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
+ if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
+ {
+ int idx;
+ if((idx=GetChannelIdxByName(device, LFE)) != -1)
+ state->gains[idx] = Gain;
+ }
+ else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
{
- for(s = 0;s < MaxChannels;s++)
- state->gains[s] = 0.0f;
- state->gains[LFE] = Gain;
+ int idx;
+ /* Dialog goes to the front-center speaker if it exists, otherwise it
+ * plays from the front-center location. */
+ if((idx=GetChannelIdxByName(device, FrontCenter)) != -1)
+ state->gains[idx] = Gain;
+ else
+ {
+ static const ALfloat front_dir[3] = { 0.0f, 0.0f, -1.0f };
+ ComputeDirectionalGains(device, front_dir, Gain, state->gains);
+ }
}
}
-static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
const ALfloat *gains = state->gains;
ALuint i, c;
- for(c = 0;c < MaxChannels;c++)
+ for(c = 0;c < NumChannels;c++)
{
- if(!(gains[c] > GAIN_SILENCE_THRESHOLD))
+ if(!(fabsf(gains[c]) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < SamplesToDo;i++)
@@ -94,7 +108,7 @@ ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(fa
if(!state) return NULL;
SET_VTABLE2(ALdedicatedState, ALeffectState, state);
- for(s = 0;s < MaxChannels;s++)
+ for(s = 0;s < MAX_OUTPUT_CHANNELS;s++)
state->gains[s] = 0.0f;
return STATIC_CAST(ALeffectState, state);
diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c
index b535655b..221cec39 100644
--- a/Alc/effects/distortion.c
+++ b/Alc/effects/distortion.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -34,7 +34,7 @@ typedef struct ALdistortionState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
- ALfloat Gain[MaxChannels];
+ ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALfilterState lowpass;
@@ -58,7 +58,6 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi
ALfloat bandwidth;
ALfloat cutoff;
ALfloat edge;
- ALfloat gain;
/* Store distorted signal attenuation settings */
state->attenuation = Slot->EffectProps.Distortion.Gain;
@@ -73,23 +72,23 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi
/* Bandwidth value is constant in octaves */
bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
- cutoff / (frequency*4.0f), bandwidth);
+ cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
+ );
/* Bandpass filter */
cutoff = Slot->EffectProps.Distortion.EQCenter;
/* Convert bandwidth in Hz to octaves */
bandwidth = Slot->EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f);
ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
- cutoff / (frequency*4.0f), bandwidth);
+ cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
+ );
- gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
- SetGains(Device, gain, state->Gain);
+ ComputeAmbientGains(Device, Slot->Gain, state->Gain);
}
-static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
const ALfloat fc = state->edge_coeff;
- float oversample_buffer[64][4];
ALuint base;
ALuint it;
ALuint ot;
@@ -97,8 +96,8 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples
for(base = 0;base < SamplesToDo;)
{
- ALfloat temps[64];
- ALuint td = minu(SamplesToDo-base, 64);
+ float oversample_buffer[64][4];
+ ALuint td = minu(64, SamplesToDo-base);
/* Perform 4x oversampling to avoid aliasing. */
/* Oversampling greatly improves distortion */
@@ -150,20 +149,19 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples
smp = ALfilterState_processSingle(&state->bandpass, smp);
oversample_buffer[it][ot] = smp;
}
-
- /* Fourth step, final, do attenuation and perform decimation, */
- /* store only one sample out of 4. */
- temps[it] = oversample_buffer[it][0] * state->attenuation;
}
- for(kt = 0;kt < MaxChannels;kt++)
+ for(kt = 0;kt < NumChannels;kt++)
{
- ALfloat gain = state->Gain[kt];
- if(!(gain > GAIN_SILENCE_THRESHOLD))
+ /* Fourth step, final, do attenuation and perform decimation,
+ * store only one sample out of 4.
+ */
+ ALfloat gain = state->Gain[kt] * state->attenuation;
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
- SamplesOut[kt][base+it] += gain * temps[it];
+ SamplesOut[kt][base+it] += gain * oversample_buffer[it][0];
}
base += td;
diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c
index 049ae9c7..f5a53c36 100644
--- a/Alc/effects/echo.c
+++ b/Alc/effects/echo.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -43,7 +43,7 @@ typedef struct ALechoState {
} Tap[2];
ALuint Offset;
/* The panning gains for the two taps */
- ALfloat Gain[2][MaxChannels];
+ ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
ALfloat FeedGain;
@@ -83,9 +83,9 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const ALeffectslot *Slot)
{
+ ALfloat pandir[3] = { 0.0f, 0.0f, 0.0f };
ALuint frequency = Device->Frequency;
- ALfloat lrpan, gain;
- ALfloat dirGain;
+ ALfloat gain, lrpan;
state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1;
state->Tap[1].delay = fastf2u(Slot->EffectProps.Echo.LRDelay * frequency);
@@ -95,21 +95,23 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL
state->FeedGain = Slot->EffectProps.Echo.Feedback;
+ gain = minf(1.0f - Slot->EffectProps.Echo.Damping, 0.01f);
ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
- 1.0f - Slot->EffectProps.Echo.Damping,
- LOWPASSFREQREF/frequency, 0.0f);
+ gain, LOWPASSFREQREF/frequency,
+ calc_rcpQ_from_slope(gain, 0.75f));
gain = Slot->Gain;
- dirGain = fabsf(lrpan);
/* First tap panning */
- ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]);
+ pandir[0] = -lrpan;
+ ComputeDirectionalGains(Device, pandir, gain, state->Gain[0]);
/* Second tap panning */
- ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]);
+ pandir[0] = +lrpan;
+ ComputeDirectionalGains(Device, pandir, gain, state->Gain[1]);
}
-static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
const ALuint mask = state->BufferLength-1;
const ALuint tap1 = state->Tap[0].delay;
@@ -121,8 +123,8 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const
for(base = 0;base < SamplesToDo;)
{
- ALfloat temps[64][2];
- ALuint td = minu(SamplesToDo-base, 64);
+ ALfloat temps[128][2];
+ ALuint td = minu(128, SamplesToDo-base);
for(i = 0;i < td;i++)
{
@@ -138,17 +140,17 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const
offset++;
}
- for(k = 0;k < MaxChannels;k++)
+ for(k = 0;k < NumChannels;k++)
{
ALfloat gain = state->Gain[0][k];
- if(gain > GAIN_SILENCE_THRESHOLD)
+ if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < td;i++)
SamplesOut[k][i+base] += temps[i][0] * gain;
}
gain = state->Gain[1][k];
- if(gain > GAIN_SILENCE_THRESHOLD)
+ if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(i = 0;i < td;i++)
SamplesOut[k][i+base] += temps[i][1] * gain;
diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c
index cfe7c46c..244667ab 100644
--- a/Alc/effects/equalizer.c
+++ b/Alc/effects/equalizer.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -75,7 +75,7 @@ typedef struct ALequalizerState {
DERIVE_FROM_TYPE(ALeffectState);
/* Effect gains for each channel */
- ALfloat Gain[MaxChannels];
+ ALfloat Gain[MAX_OUTPUT_CHANNELS];
/* Effect parameters */
ALfilterState filter[4];
@@ -93,33 +93,40 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state),
static ALvoid ALequalizerState_update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot)
{
ALfloat frequency = (ALfloat)device->Frequency;
- ALfloat gain = sqrtf(1.0f / device->NumChan) * slot->Gain;
+ ALfloat gain, freq_mult;
- SetGains(device, gain, state->Gain);
+ ComputeAmbientGains(device, slot->Gain, state->Gain);
- /* Calculate coefficients for the each type of filter */
+ /* Calculate coefficients for the each type of filter. Note that the shelf
+ * filters' gain is for the reference frequency, which is the centerpoint
+ * of the transition band.
+ */
+ gain = sqrtf(slot->EffectProps.Equalizer.LowGain);
+ freq_mult = slot->EffectProps.Equalizer.LowCutoff/frequency;
ALfilterState_setParams(&state->filter[0], ALfilterType_LowShelf,
- sqrtf(slot->EffectProps.Equalizer.LowGain),
- slot->EffectProps.Equalizer.LowCutoff/frequency,
- 0.0f);
+ gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
+ );
+ gain = slot->EffectProps.Equalizer.Mid1Gain;
+ freq_mult = slot->EffectProps.Equalizer.Mid1Center/frequency;
ALfilterState_setParams(&state->filter[1], ALfilterType_Peaking,
- sqrtf(slot->EffectProps.Equalizer.Mid1Gain),
- slot->EffectProps.Equalizer.Mid1Center/frequency,
- slot->EffectProps.Equalizer.Mid1Width);
+ gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid1Width)
+ );
+ gain = slot->EffectProps.Equalizer.Mid2Gain;
+ freq_mult = slot->EffectProps.Equalizer.Mid2Center/frequency;
ALfilterState_setParams(&state->filter[2], ALfilterType_Peaking,
- sqrtf(slot->EffectProps.Equalizer.Mid2Gain),
- slot->EffectProps.Equalizer.Mid2Center/frequency,
- slot->EffectProps.Equalizer.Mid2Width);
+ gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid2Width)
+ );
+ gain = sqrtf(slot->EffectProps.Equalizer.HighGain);
+ freq_mult = slot->EffectProps.Equalizer.HighCutoff/frequency;
ALfilterState_setParams(&state->filter[3], ALfilterType_HighShelf,
- sqrtf(slot->EffectProps.Equalizer.HighGain),
- slot->EffectProps.Equalizer.HighCutoff/frequency,
- 0.0f);
+ gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
+ );
}
-static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint base;
ALuint it;
@@ -128,8 +135,8 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo
for(base = 0;base < SamplesToDo;)
{
- ALfloat temps[64];
- ALuint td = minu(SamplesToDo-base, 64);
+ ALfloat temps[256];
+ ALuint td = minu(256, SamplesToDo-base);
for(it = 0;it < td;it++)
{
@@ -141,10 +148,10 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo
temps[it] = smp;
}
- for(kt = 0;kt < MaxChannels;kt++)
+ for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[kt];
- if(!(gain > GAIN_SILENCE_THRESHOLD))
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(it = 0;it < td;it++)
diff --git a/Alc/effects/flanger.c b/Alc/effects/flanger.c
index 117cd1f2..f6191abd 100644
--- a/Alc/effects/flanger.c
+++ b/Alc/effects/flanger.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -46,7 +46,7 @@ typedef struct ALflangerState {
ALint lfo_disp;
/* Gains for left and right sides */
- ALfloat Gain[2][MaxChannels];
+ ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
/* effect parameters */
enum FlangerWaveForm waveform;
@@ -93,6 +93,8 @@ static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *D
static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, const ALeffectslot *Slot)
{
+ static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f };
+ static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f };
ALfloat frequency = (ALfloat)Device->Frequency;
ALfloat rate;
ALint phase;
@@ -111,8 +113,8 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
/* Gains for left and right sides */
- ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]);
- ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]);
+ ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]);
+ ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]);
phase = Slot->EffectProps.Flanger.Phase;
rate = Slot->EffectProps.Flanger.Rate;
@@ -132,7 +134,7 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
state->lfo_scale = 4.0f / state->lfo_range;
break;
case FWF_Sinusoid:
- state->lfo_scale = F_2PI / state->lfo_range;
+ state->lfo_scale = F_TAU / state->lfo_range;
break;
}
@@ -201,15 +203,15 @@ DECL_TEMPLATE(Sinusoid)
#undef DECL_TEMPLATE
-static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALuint it, kt;
ALuint base;
for(base = 0;base < SamplesToDo;)
{
- ALfloat temps[64][2];
- ALuint td = minu(SamplesToDo-base, 64);
+ ALfloat temps[128][2];
+ ALuint td = minu(128, SamplesToDo-base);
switch(state->waveform)
{
@@ -221,17 +223,17 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo,
break;
}
- for(kt = 0;kt < MaxChannels;kt++)
+ for(kt = 0;kt < NumChannels;kt++)
{
ALfloat gain = state->Gain[0][kt];
- if(gain > GAIN_SILENCE_THRESHOLD)
+ if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(it = 0;it < td;it++)
SamplesOut[kt][it+base] += temps[it][0] * gain;
}
gain = state->Gain[1][kt];
- if(gain > GAIN_SILENCE_THRESHOLD)
+ if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
{
for(it = 0;it < td;it++)
SamplesOut[kt][it+base] += temps[it][1] * gain;
diff --git a/Alc/effects/modulator.c b/Alc/effects/modulator.c
index a5475708..dceb408e 100644
--- a/Alc/effects/modulator.c
+++ b/Alc/effects/modulator.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -42,7 +42,7 @@ typedef struct ALmodulatorState {
ALuint index;
ALuint step;
- ALfloat Gain[MaxChannels];
+ ALfloat Gain[MAX_OUTPUT_CHANNELS];
ALfilterState Filter;
} ALmodulatorState;
@@ -53,7 +53,7 @@ typedef struct ALmodulatorState {
static inline ALfloat Sin(ALuint index)
{
- return sinf(index*(F_2PI/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
+ return sinf(index*(F_TAU/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
}
static inline ALfloat Saw(ALuint index)
@@ -69,7 +69,7 @@ static inline ALfloat Square(ALuint index)
#define DECL_TEMPLATE(func) \
static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \
const ALfloat *restrict SamplesIn, \
- ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \
+ ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) \
{ \
const ALuint step = state->step; \
ALuint index = state->index; \
@@ -77,8 +77,8 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \
\
for(base = 0;base < SamplesToDo;) \
{ \
- ALfloat temps[64]; \
- ALuint td = minu(SamplesToDo-base, 64); \
+ ALfloat temps[256]; \
+ ALuint td = minu(256, SamplesToDo-base); \
ALuint i, k; \
\
for(i = 0;i < td;i++) \
@@ -92,10 +92,10 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \
temps[i] = samp * func(index); \
} \
\
- for(k = 0;k < MaxChannels;k++) \
+ for(k = 0;k < NumChannels;k++) \
{ \
ALfloat gain = state->Gain[k]; \
- if(!(gain > GAIN_SILENCE_THRESHOLD)) \
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) \
continue; \
\
for(i = 0;i < td;i++) \
@@ -125,7 +125,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state),
static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot)
{
- ALfloat gain, cw, a;
+ ALfloat cw, a;
if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
state->Waveform = SINUSOID;
@@ -139,7 +139,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device
if(state->step == 0) state->step = 1;
/* Custom filter coeffs, which match the old version instead of a low-shelf. */
- cw = cosf(F_2PI * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency);
+ cw = cosf(F_TAU * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency);
a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
state->Filter.b[0] = a;
@@ -149,24 +149,23 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device
state->Filter.a[1] = -a;
state->Filter.a[2] = 0.0f;
- gain = sqrtf(1.0f/Device->NumChan) * Slot->Gain;
- SetGains(Device, gain, state->Gain);
+ ComputeAmbientGains(Device, Slot->Gain, state->Gain);
}
-static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
switch(state->Waveform)
{
case SINUSOID:
- ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut);
+ ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
break;
case SAWTOOTH:
- ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut);
+ ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
break;
case SQUARE:
- ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut);
+ ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
break;
}
}
diff --git a/Alc/effects/null.c b/Alc/effects/null.c
index 6dacd021..adc4ca81 100644
--- a/Alc/effects/null.c
+++ b/Alc/effects/null.c
@@ -41,11 +41,8 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), ALCdevice* UNUSED(d
* input to the output buffer. The result should be added to the output buffer,
* not replace it.
*/
-static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloat (*restrict samplesOut)[BUFFERSIZE])
+static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels))
{
- /* NOTE: Couldn't use the UNUSED macro on samplesOut due to the way GCC's
- * __attribute__ declaration interacts with the parenthesis. */
- (void)samplesOut;
}
/* This allocates memory to store the object, before it gets constructed.
diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c
index 245aed41..e1013309 100644
--- a/Alc/effects/reverb.c
+++ b/Alc/effects/reverb.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -32,6 +32,10 @@
#include "alError.h"
+/* This is the maximum number of samples processed for each inner loop
+ * iteration. */
+#define MAX_UPDATE_SAMPLES 256
+
typedef struct DelayLine
{
// The delay lines use sample lengths that are powers of 2 to allow the
@@ -86,7 +90,7 @@ typedef struct ALreverbState {
// The gain for each output channel based on 3D panning (only for the
// EAX path).
- ALfloat PanGain[MaxChannels];
+ ALfloat PanGain[4][MAX_OUTPUT_CHANNELS];
} Early;
// Decorrelator delay line.
@@ -125,7 +129,7 @@ typedef struct ALreverbState {
// The gain for each output channel based on 3D panning (only for the
// EAX path).
- ALfloat PanGain[MaxChannels];
+ ALfloat PanGain[4][MAX_OUTPUT_CHANNELS];
} Late;
struct {
@@ -148,8 +152,8 @@ typedef struct ALreverbState {
ALfloat LpCoeff;
ALfloat LpSample;
- // Echo mixing coefficients.
- ALfloat MixCoeff[2];
+ // Echo mixing coefficient.
+ ALfloat MixCoeff;
} Echo;
// The current read offset for all delay lines.
@@ -157,11 +161,11 @@ typedef struct ALreverbState {
// The gain for each output channel (non-EAX path only; aliased from
// Late.PanGain)
- ALfloat *Gain;
+ ALfloat (*Gain)[MAX_OUTPUT_CHANNELS];
- /* Temporary storage used when processing, before deinterlacing. */
- ALfloat ReverbSamples[BUFFERSIZE][4];
- ALfloat EarlySamples[BUFFERSIZE][4];
+ /* Temporary storage used when processing. */
+ ALfloat ReverbSamples[MAX_UPDATE_SAMPLES][4];
+ ALfloat EarlySamples[MAX_UPDATE_SAMPLES][4];
} ALreverbState;
/* This is a user config option for modifying the overall output of the reverb
@@ -234,39 +238,21 @@ static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
Delay->Line[offset&Delay->Mask] = in;
}
-// Attenuated delay line output routine.
-static inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
-{
- return coeff * Delay->Line[offset&Delay->Mask];
-}
-
-// Basic attenuated all-pass input/output routine.
-static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
-{
- ALfloat out, feed;
-
- out = DelayLineOut(Delay, outOffset);
- feed = feedCoeff * in;
- DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in);
-
- // The time-based attenuation is only applied to the delay output to
- // keep it from affecting the feed-back path (which is already controlled
- // by the all-pass feed coefficient).
- return (coeff * out) - feed;
-}
-
// Given an input sample, this function produces modulation for the late
// reverb.
-static inline ALfloat EAXModulation(ALreverbState *State, ALfloat in)
+static inline ALfloat EAXModulation(ALreverbState *State, ALuint offset, ALfloat in)
{
- ALfloat sinus, frac;
- ALuint offset;
+ ALfloat sinus, frac, fdelay;
ALfloat out0, out1;
+ ALuint delay;
// Calculate the sinus rythm (dependent on modulation time and the
// sampling rate). The center of the sinus is moved to reduce the delay
// of the effect when the time or depth are low.
- sinus = 1.0f - cosf(F_2PI * State->Mod.Index / State->Mod.Range);
+ sinus = 1.0f - cosf(F_TAU * State->Mod.Index / State->Mod.Range);
+
+ // Step the modulation index forward, keeping it bound to its range.
+ State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range;
// The depth determines the range over which to read the input samples
// from, so it must be filtered to reduce the distortion caused by even
@@ -275,95 +261,96 @@ static inline ALfloat EAXModulation(ALreverbState *State, ALfloat in)
State->Mod.Coeff);
// Calculate the read offset and fraction between it and the next sample.
- frac = (1.0f + (State->Mod.Filter * sinus));
- offset = fastf2u(frac);
- frac -= offset;
+ frac = modff(State->Mod.Filter*sinus + 1.0f, &fdelay);
+ delay = fastf2u(fdelay);
// Get the two samples crossed by the offset, and feed the delay line
// with the next input sample.
- out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset);
- out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1);
- DelayLineIn(&State->Mod.Delay, State->Offset, in);
-
- // Step the modulation index forward, keeping it bound to its range.
- State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range;
+ out0 = DelayLineOut(&State->Mod.Delay, offset - delay);
+ out1 = DelayLineOut(&State->Mod.Delay, offset - delay - 1);
+ DelayLineIn(&State->Mod.Delay, offset, in);
// The output is obtained by linearly interpolating the two samples that
// were acquired above.
return lerp(out0, out1, frac);
}
-// Delay line output routine for early reflections.
-static inline ALfloat EarlyDelayLineOut(ALreverbState *State, ALuint index)
+// Given some input sample, this function produces four-channel outputs for the
+// early reflections.
+static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4])
{
- return AttenuatedDelayLineOut(&State->Early.Delay[index],
- State->Offset - State->Early.Offset[index],
- State->Early.Coeff[index]);
+ ALfloat d[4], v, f[4];
+ ALuint i;
+
+ for(i = 0;i < todo;i++)
+ {
+ ALuint offset = State->Offset+i;
+
+ // Obtain the decayed results of each early delay line.
+ d[0] = DelayLineOut(&State->Early.Delay[0], offset-State->Early.Offset[0]) * State->Early.Coeff[0];
+ d[1] = DelayLineOut(&State->Early.Delay[1], offset-State->Early.Offset[1]) * State->Early.Coeff[1];
+ d[2] = DelayLineOut(&State->Early.Delay[2], offset-State->Early.Offset[2]) * State->Early.Coeff[2];
+ d[3] = DelayLineOut(&State->Early.Delay[3], offset-State->Early.Offset[3]) * State->Early.Coeff[3];
+
+ /* The following uses a lossless scattering junction from waveguide
+ * theory. It actually amounts to a householder mixing matrix, which
+ * will produce a maximally diffuse response, and means this can
+ * probably be considered a simple feed-back delay network (FDN).
+ * N
+ * ---
+ * \
+ * v = 2/N / d_i
+ * ---
+ * i=1
+ */
+ v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
+ // The junction is loaded with the input here.
+ v += DelayLineOut(&State->Delay, offset-State->DelayTap[0]);
+
+ // Calculate the feed values for the delay lines.
+ f[0] = v - d[0];
+ f[1] = v - d[1];
+ f[2] = v - d[2];
+ f[3] = v - d[3];
+
+ // Re-feed the delay lines.
+ DelayLineIn(&State->Early.Delay[0], offset, f[0]);
+ DelayLineIn(&State->Early.Delay[1], offset, f[1]);
+ DelayLineIn(&State->Early.Delay[2], offset, f[2]);
+ DelayLineIn(&State->Early.Delay[3], offset, f[3]);
+
+ // Output the results of the junction for all four channels.
+ out[i][0] = State->Early.Gain * f[0];
+ out[i][1] = State->Early.Gain * f[1];
+ out[i][2] = State->Early.Gain * f[2];
+ out[i][3] = State->Early.Gain * f[3];
+ }
}
-// Given an input sample, this function produces four-channel output for the
-// early reflections.
-static inline ALvoid EarlyReflection(ALreverbState *State, ALfloat in, ALfloat *restrict out)
+// Basic attenuated all-pass input/output routine.
+static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
{
- ALfloat d[4], v, f[4];
+ ALfloat out, feed;
- // Obtain the decayed results of each early delay line.
- d[0] = EarlyDelayLineOut(State, 0);
- d[1] = EarlyDelayLineOut(State, 1);
- d[2] = EarlyDelayLineOut(State, 2);
- d[3] = EarlyDelayLineOut(State, 3);
-
- /* The following uses a lossless scattering junction from waveguide
- * theory. It actually amounts to a householder mixing matrix, which
- * will produce a maximally diffuse response, and means this can probably
- * be considered a simple feed-back delay network (FDN).
- * N
- * ---
- * \
- * v = 2/N / d_i
- * ---
- * i=1
- */
- v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
- // The junction is loaded with the input here.
- v += in;
-
- // Calculate the feed values for the delay lines.
- f[0] = v - d[0];
- f[1] = v - d[1];
- f[2] = v - d[2];
- f[3] = v - d[3];
-
- // Re-feed the delay lines.
- DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]);
- DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]);
- DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]);
- DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]);
-
- // Output the results of the junction for all four channels.
- out[0] = State->Early.Gain * f[0];
- out[1] = State->Early.Gain * f[1];
- out[2] = State->Early.Gain * f[2];
- out[3] = State->Early.Gain * f[3];
+ out = DelayLineOut(Delay, outOffset);
+ feed = feedCoeff * in;
+ DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in);
+
+ // The time-based attenuation is only applied to the delay output to
+ // keep it from affecting the feed-back path (which is already controlled
+ // by the all-pass feed coefficient).
+ return (coeff * out) - feed;
}
// All-pass input/output routine for late reverb.
-static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint index, ALfloat in)
+static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint offset, ALuint index, ALfloat in)
{
return AllpassInOut(&State->Late.ApDelay[index],
- State->Offset - State->Late.ApOffset[index],
- State->Offset, in, State->Late.ApFeedCoeff,
+ offset - State->Late.ApOffset[index],
+ offset, in, State->Late.ApFeedCoeff,
State->Late.ApCoeff[index]);
}
-// Delay line output routine for late reverb.
-static inline ALfloat LateDelayLineOut(ALreverbState *State, ALuint index)
-{
- return AttenuatedDelayLineOut(&State->Late.Delay[index],
- State->Offset - State->Late.Offset[index],
- State->Late.Coeff[index]);
-}
-
// Low-pass filter input/output routine for late reverb.
static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALfloat in)
{
@@ -374,260 +361,296 @@ static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALflo
// Given four decorrelated input samples, this function produces four-channel
// output for the late reverb.
-static inline ALvoid LateReverb(ALreverbState *State, const ALfloat *restrict in, ALfloat *restrict out)
+static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4])
{
ALfloat d[4], f[4];
+ ALuint i;
- // Obtain the decayed results of the cyclical delay lines, and add the
- // corresponding input channels. Then pass the results through the
- // low-pass filters.
-
- // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back
- // to 0.
- d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2));
- d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0));
- d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3));
- d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1));
-
- // To help increase diffusion, run each line through an all-pass filter.
- // When there is no diffusion, the shortest all-pass filter will feed the
- // shortest delay line.
- d[0] = LateAllPassInOut(State, 0, d[0]);
- d[1] = LateAllPassInOut(State, 1, d[1]);
- d[2] = LateAllPassInOut(State, 2, d[2]);
- d[3] = LateAllPassInOut(State, 3, d[3]);
-
- /* Late reverb is done with a modified feed-back delay network (FDN)
- * topology. Four input lines are each fed through their own all-pass
- * filter and then into the mixing matrix. The four outputs of the
- * mixing matrix are then cycled back to the inputs. Each output feeds
- * a different input to form a circlular feed cycle.
- *
- * The mixing matrix used is a 4D skew-symmetric rotation matrix derived
- * using a single unitary rotational parameter:
- *
- * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
- * [ -a, d, c, -b ]
- * [ -b, -c, d, a ]
- * [ -c, b, -a, d ]
- *
- * The rotation is constructed from the effect's diffusion parameter,
- * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
- * with differing signs, and d is the coefficient x. The matrix is thus:
- *
- * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
- * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
- * [ y, -y, x, y ] x = cos(t)
- * [ -y, -y, -y, x ] y = sin(t) / n
- *
- * To reduce the number of multiplies, the x coefficient is applied with
- * the cyclical delay line coefficients. Thus only the y coefficient is
- * applied when mixing, and is modified to be: y / x.
- */
- f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3]));
- f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
- f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3]));
- f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] ));
-
- // Output the results of the matrix for all four channels, attenuated by
- // the late reverb gain (which is attenuated by the 'x' mix coefficient).
- out[0] = State->Late.Gain * f[0];
- out[1] = State->Late.Gain * f[1];
- out[2] = State->Late.Gain * f[2];
- out[3] = State->Late.Gain * f[3];
-
- // Re-feed the cyclical delay lines.
- DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]);
- DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]);
- DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]);
- DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]);
+ for(i = 0;i < todo;i++)
+ {
+ ALuint offset = State->Offset+i;
+
+ f[0] = DelayLineOut(&State->Decorrelator, offset);
+ f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]);
+ f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]);
+ f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]);
+
+ // Obtain the decayed results of the cyclical delay lines, and add the
+ // corresponding input channels. Then pass the results through the
+ // low-pass filters.
+ f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0];
+ f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1];
+ f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2];
+ f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3];
+
+ // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and
+ // back to 0.
+ d[0] = LateLowPassInOut(State, 2, f[2]);
+ d[1] = LateLowPassInOut(State, 0, f[0]);
+ d[2] = LateLowPassInOut(State, 3, f[3]);
+ d[3] = LateLowPassInOut(State, 1, f[1]);
+
+ // To help increase diffusion, run each line through an all-pass filter.
+ // When there is no diffusion, the shortest all-pass filter will feed
+ // the shortest delay line.
+ d[0] = LateAllPassInOut(State, offset, 0, d[0]);
+ d[1] = LateAllPassInOut(State, offset, 1, d[1]);
+ d[2] = LateAllPassInOut(State, offset, 2, d[2]);
+ d[3] = LateAllPassInOut(State, offset, 3, d[3]);
+
+ /* Late reverb is done with a modified feed-back delay network (FDN)
+ * topology. Four input lines are each fed through their own all-pass
+ * filter and then into the mixing matrix. The four outputs of the
+ * mixing matrix are then cycled back to the inputs. Each output feeds
+ * a different input to form a circlular feed cycle.
+ *
+ * The mixing matrix used is a 4D skew-symmetric rotation matrix
+ * derived using a single unitary rotational parameter:
+ *
+ * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2
+ * [ -a, d, c, -b ]
+ * [ -b, -c, d, a ]
+ * [ -c, b, -a, d ]
+ *
+ * The rotation is constructed from the effect's diffusion parameter,
+ * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
+ * with differing signs, and d is the coefficient x. The matrix is
+ * thus:
+ *
+ * [ x, y, -y, y ] n = sqrt(matrix_order - 1)
+ * [ -y, x, y, y ] t = diffusion_parameter * atan(n)
+ * [ y, -y, x, y ] x = cos(t)
+ * [ -y, -y, -y, x ] y = sin(t) / n
+ *
+ * To reduce the number of multiplies, the x coefficient is applied
+ * with the cyclical delay line coefficients. Thus only the y
+ * coefficient is applied when mixing, and is modified to be: y / x.
+ */
+ f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3]));
+ f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3]));
+ f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3]));
+ f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] ));
+
+ // Output the results of the matrix for all four channels, attenuated by
+ // the late reverb gain (which is attenuated by the 'x' mix coefficient).
+ // Mix early reflections and late reverb.
+ out[i][0] += State->Late.Gain * f[0];
+ out[i][1] += State->Late.Gain * f[1];
+ out[i][2] += State->Late.Gain * f[2];
+ out[i][3] += State->Late.Gain * f[3];
+
+ // Re-feed the cyclical delay lines.
+ DelayLineIn(&State->Late.Delay[0], offset, f[0]);
+ DelayLineIn(&State->Late.Delay[1], offset, f[1]);
+ DelayLineIn(&State->Late.Delay[2], offset, f[2]);
+ DelayLineIn(&State->Late.Delay[3], offset, f[3]);
+ }
}
// Given an input sample, this function mixes echo into the four-channel late
// reverb.
-static inline ALvoid EAXEcho(ALreverbState *State, ALfloat in, ALfloat *restrict late)
+static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[4])
{
ALfloat out, feed;
+ ALuint i;
- // Get the latest attenuated echo sample for output.
- feed = AttenuatedDelayLineOut(&State->Echo.Delay,
- State->Offset - State->Echo.Offset,
- State->Echo.Coeff);
-
- // Mix the output into the late reverb channels.
- out = State->Echo.MixCoeff[0] * feed;
- late[0] = (State->Echo.MixCoeff[1] * late[0]) + out;
- late[1] = (State->Echo.MixCoeff[1] * late[1]) + out;
- late[2] = (State->Echo.MixCoeff[1] * late[2]) + out;
- late[3] = (State->Echo.MixCoeff[1] * late[3]) + out;
-
- // Mix the energy-attenuated input with the output and pass it through
- // the echo low-pass filter.
- feed += State->Echo.DensityGain * in;
- feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff);
- State->Echo.LpSample = feed;
-
- // Then the echo all-pass filter.
- feed = AllpassInOut(&State->Echo.ApDelay,
- State->Offset - State->Echo.ApOffset,
- State->Offset, feed, State->Echo.ApFeedCoeff,
- State->Echo.ApCoeff);
-
- // Feed the delay with the mixed and filtered sample.
- DelayLineIn(&State->Echo.Delay, State->Offset, feed);
+ for(i = 0;i < todo;i++)
+ {
+ ALuint offset = State->Offset+i;
+
+ // Get the latest attenuated echo sample for output.
+ feed = DelayLineOut(&State->Echo.Delay, offset-State->Echo.Offset) *
+ State->Echo.Coeff;
+
+ // Mix the output into the late reverb channels.
+ out = State->Echo.MixCoeff * feed;
+ late[i][0] += out;
+ late[i][1] += out;
+ late[i][2] += out;
+ late[i][3] += out;
+
+ // Mix the energy-attenuated input with the output and pass it through
+ // the echo low-pass filter.
+ feed += DelayLineOut(&State->Delay, offset-State->DelayTap[1]) *
+ State->Echo.DensityGain;
+ feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff);
+ State->Echo.LpSample = feed;
+
+ // Then the echo all-pass filter.
+ feed = AllpassInOut(&State->Echo.ApDelay, offset-State->Echo.ApOffset,
+ offset, feed, State->Echo.ApFeedCoeff,
+ State->Echo.ApCoeff);
+
+ // Feed the delay with the mixed and filtered sample.
+ DelayLineIn(&State->Echo.Delay, offset, feed);
+ }
}
// Perform the non-EAX reverb pass on a given input sample, resulting in
// four-channel output.
-static inline ALvoid VerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict out)
+static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *in, ALfloat (*restrict out)[4])
{
- ALfloat feed, late[4], taps[4];
+ ALuint i;
- // Filter the incoming sample.
- in = ALfilterState_processSingle(&State->LpFilter, in);
-
- // Feed the initial delay line.
- DelayLineIn(&State->Delay, State->Offset, in);
+ // Low-pass filter the incoming samples.
+ for(i = 0;i < todo;i++)
+ DelayLineIn(&State->Delay, State->Offset+i,
+ ALfilterState_processSingle(&State->LpFilter, in[i])
+ );
// Calculate the early reflection from the first delay tap.
- in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
- EarlyReflection(State, in, out);
+ EarlyReflection(State, todo, out);
// Feed the decorrelator from the energy-attenuated output of the second
// delay tap.
- in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
- feed = in * State->Late.DensityGain;
- DelayLineIn(&State->Decorrelator, State->Offset, feed);
+ for(i = 0;i < todo;i++)
+ {
+ ALuint offset = State->Offset+i;
+ ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) *
+ State->Late.DensityGain;
+ DelayLineIn(&State->Decorrelator, offset, sample);
+ }
// Calculate the late reverb from the decorrelator taps.
- taps[0] = feed;
- taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
- taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
- taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
- LateReverb(State, taps, late);
-
- // Mix early reflections and late reverb.
- out[0] += late[0];
- out[1] += late[1];
- out[2] += late[2];
- out[3] += late[3];
+ LateReverb(State, todo, out);
// Step all delays forward one sample.
- State->Offset++;
+ State->Offset += todo;
}
// Perform the EAX reverb pass on a given input sample, resulting in four-
// channel output.
-static inline ALvoid EAXVerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict early, ALfloat *restrict late)
+static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4])
{
- ALfloat feed, taps[4];
+ ALuint i;
- // Low-pass filter the incoming sample.
- in = ALfilterState_processSingle(&State->LpFilter, in);
- in = ALfilterState_processSingle(&State->HpFilter, in);
+ // Band-pass and modulate the incoming samples.
+ for(i = 0;i < todo;i++)
+ {
+ ALfloat sample = input[i];
+ sample = ALfilterState_processSingle(&State->LpFilter, sample);
+ sample = ALfilterState_processSingle(&State->HpFilter, sample);
- // Perform any modulation on the input.
- in = EAXModulation(State, in);
+ // Perform any modulation on the input.
+ sample = EAXModulation(State, State->Offset+i, sample);
- // Feed the initial delay line.
- DelayLineIn(&State->Delay, State->Offset, in);
+ // Feed the initial delay line.
+ DelayLineIn(&State->Delay, State->Offset+i, sample);
+ }
// Calculate the early reflection from the first delay tap.
- in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
- EarlyReflection(State, in, early);
+ EarlyReflection(State, todo, early);
// Feed the decorrelator from the energy-attenuated output of the second
// delay tap.
- in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
- feed = in * State->Late.DensityGain;
- DelayLineIn(&State->Decorrelator, State->Offset, feed);
+ for(i = 0;i < todo;i++)
+ {
+ ALuint offset = State->Offset+i;
+ ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) *
+ State->Late.DensityGain;
+ DelayLineIn(&State->Decorrelator, offset, sample);
+ }
// Calculate the late reverb from the decorrelator taps.
- taps[0] = feed;
- taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
- taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
- taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
- LateReverb(State, taps, late);
+ memset(late, 0, sizeof(*late)*todo);
+ LateReverb(State, todo, late);
// Calculate and mix in any echo.
- EAXEcho(State, in, late);
+ EAXEcho(State, todo, late);
- // Step all delays forward one sample.
- State->Offset++;
+ // Step all delays forward.
+ State->Offset += todo;
}
-static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALfloat (*restrict out)[4] = State->ReverbSamples;
- ALuint index, c;
+ ALuint index, c, i, l;
/* Process reverb for these samples. */
- for(index = 0;index < SamplesToDo;index++)
- VerbPass(State, SamplesIn[index], out[index]);
-
- for(c = 0;c < MaxChannels;c++)
+ for(index = 0;index < SamplesToDo;)
{
- ALfloat gain = State->Gain[c];
- if(!(gain > GAIN_SILENCE_THRESHOLD))
- continue;
+ ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES);
+
+ VerbPass(State, todo, &SamplesIn[index], out);
- for(index = 0;index < SamplesToDo;index++)
- SamplesOut[c][index] += gain * out[index][c&3];
+ for(l = 0;l < 4;l++)
+ {
+ for(c = 0;c < NumChannels;c++)
+ {
+ ALfloat gain = State->Gain[l][c];
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
+ continue;
+ for(i = 0;i < todo;i++)
+ SamplesOut[c][index+i] += gain*out[i][l];
+ }
+ }
+
+ index += todo;
}
}
-static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
ALfloat (*restrict early)[4] = State->EarlySamples;
ALfloat (*restrict late)[4] = State->ReverbSamples;
- ALuint index, c;
+ ALuint index, c, i, l;
+ ALfloat gain;
/* Process reverb for these samples. */
- for(index = 0;index < SamplesToDo;index++)
- EAXVerbPass(State, SamplesIn[index], early[index], late[index]);
-
- for(c = 0;c < MaxChannels;c++)
+ for(index = 0;index < SamplesToDo;)
{
- ALfloat earlyGain, lateGain;
+ ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES);
- earlyGain = State->Early.PanGain[c];
- if(earlyGain > GAIN_SILENCE_THRESHOLD)
- {
- for(index = 0;index < SamplesToDo;index++)
- SamplesOut[c][index] += earlyGain*early[index][c&3];
- }
- lateGain = State->Late.PanGain[c];
- if(lateGain > GAIN_SILENCE_THRESHOLD)
+ EAXVerbPass(State, todo, &SamplesIn[index], early, late);
+
+ for(l = 0;l < 4;l++)
{
- for(index = 0;index < SamplesToDo;index++)
- SamplesOut[c][index] += lateGain*late[index][c&3];
+ for(c = 0;c < NumChannels;c++)
+ {
+ gain = State->Early.PanGain[l][c];
+ if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
+ {
+ for(i = 0;i < todo;i++)
+ SamplesOut[c][index+i] += gain*early[i][l];
+ }
+ gain = State->Late.PanGain[l][c];
+ if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
+ {
+ for(i = 0;i < todo;i++)
+ SamplesOut[c][index+i] += gain*late[i][l];
+ }
+ }
}
+
+ index += todo;
}
}
-static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
{
if(State->IsEax)
- ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut);
+ ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
else
- ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut);
+ ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
}
// Given the allocated sample buffer, this function updates each delay line
// offset.
static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay)
{
- Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line];
+ Delay->Line = &sampleBuffer[(ptrdiff_t)Delay->Line];
}
// Calculate the length of a delay line and store its mask and offset.
-static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay)
+static ALuint CalcLineLength(ALfloat length, ptrdiff_t offset, ALuint frequency, ALuint extra, DelayLine *Delay)
{
ALuint samples;
// All line lengths are powers of 2, calculated from their lengths, with
// an additional sample in case of rounding errors.
- samples = NextPowerOf2(fastf2u(length * frequency) + 1);
+ samples = fastf2u(length*frequency) + extra;
+ samples = NextPowerOf2(samples + 1);
// All lines share a single sample buffer.
Delay->Mask = samples - 1;
Delay->Line = (ALfloat*)offset;
@@ -654,48 +677,49 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State)
* swing. An additional sample is added to keep it stable when there is no
* modulation.
*/
- length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f) +
- (1.0f / frequency);
- totalSamples += CalcLineLength(length, totalSamples, frequency,
+ length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f);
+ totalSamples += CalcLineLength(length, totalSamples, frequency, 1,
&State->Mod.Delay);
// The initial delay is the sum of the reflections and late reverb
- // delays.
+ // delays. This must include space for storing a loop update to feed the
+ // early reflections, decorrelator, and echo.
length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
AL_EAXREVERB_MAX_LATE_REVERB_DELAY;
totalSamples += CalcLineLength(length, totalSamples, frequency,
- &State->Delay);
+ MAX_UPDATE_SAMPLES, &State->Delay);
// The early reflection lines.
for(index = 0;index < 4;index++)
totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples,
- frequency, &State->Early.Delay[index]);
+ frequency, 0, &State->Early.Delay[index]);
// The decorrelator line is calculated from the lowest reverb density (a
- // parameter value of 1).
+ // parameter value of 1). This must include space for storing a loop update
+ // to feed the late reverb.
length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) *
LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER);
- totalSamples += CalcLineLength(length, totalSamples, frequency,
+ totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES,
&State->Decorrelator);
// The late all-pass lines.
for(index = 0;index < 4;index++)
totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples,
- frequency, &State->Late.ApDelay[index]);
+ frequency, 0, &State->Late.ApDelay[index]);
// The late delay lines are calculated from the lowest reverb density.
for(index = 0;index < 4;index++)
{
length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER);
- totalSamples += CalcLineLength(length, totalSamples, frequency,
+ totalSamples += CalcLineLength(length, totalSamples, frequency, 0,
&State->Late.Delay[index]);
}
// The echo all-pass and delay lines.
totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples,
- frequency, &State->Echo.ApDelay);
+ frequency, 0, &State->Echo.ApDelay);
totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples,
- frequency, &State->Echo.Delay);
+ frequency, 0, &State->Echo.Delay);
if(totalSamples != State->TotalSamples)
{
@@ -939,7 +963,7 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbStat
}
// Update the late reverb gains, line lengths, and line coefficients.
-static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State)
+static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State)
{
ALfloat length;
ALuint index;
@@ -947,9 +971,13 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix
/* Calculate the late reverb gain (from the master effect gain, and late
* reverb gain parameters). Since the output is tapped prior to the
* application of the next delay line coefficients, this gain needs to be
- * attenuated by the 'x' mixing matrix coefficient as well.
+ * attenuated by the 'x' mixing matrix coefficient as well. Also attenuate
+ * the late reverb when echo depth is high and diffusion is low, so the
+ * echo is slightly stronger than the decorrelated echos in the reverb
+ * tail.
*/
- State->Late.Gain = reverbGain * lateGain * xMix;
+ State->Late.Gain = reverbGain * lateGain * xMix *
+ (1.0f - (echoDepth*0.5f*(1.0f - diffusion)));
/* To compensate for changes in modal density and decay time of the late
* reverb signal, the input is attenuated based on the maximal energy of
@@ -962,8 +990,9 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix
length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f;
length *= 1.0f + (density * LATE_LINE_MULTIPLIER);
- State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length,
- decayTime));
+ State->Late.DensityGain = CalcDensityGain(
+ CalcDecayCoeff(length, decayTime)
+ );
// Calculate the all-pass feed-back and feed-forward coefficient.
State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f);
@@ -971,12 +1000,13 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix
for(index = 0;index < 4;index++)
{
// Calculate the gain (coefficient) for each all-pass line.
- State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index],
- decayTime);
+ State->Late.ApCoeff[index] = CalcDecayCoeff(
+ ALLPASS_LINE_LENGTH[index], decayTime
+ );
// Calculate the length (in seconds) of each cyclical delay line.
- length = LATE_LINE_LENGTH[index] * (1.0f + (density *
- LATE_LINE_MULTIPLIER));
+ length = LATE_LINE_LENGTH[index] *
+ (1.0f + (density * LATE_LINE_MULTIPLIER));
// Calculate the delay offset for each cyclical delay line.
State->Late.Offset[index] = fastf2u(length * frequency);
@@ -985,9 +1015,9 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix
State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime);
// Calculate the damping coefficient for each low-pass filter.
- State->Late.LpCoeff[index] =
- CalcDampingCoeff(hfRatio, length, decayTime,
- State->Late.Coeff[index], cw);
+ State->Late.LpCoeff[index] = CalcDampingCoeff(
+ hfRatio, length, decayTime, State->Late.Coeff[index], cw
+ );
// Attenuate the cyclical line coefficients by the mixing coefficient
// (x).
@@ -1024,57 +1054,74 @@ static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoT
* echo depth is high and diffusion is low, so the echo is slightly
* stronger than the decorrelated echos in the reverb tail.
*/
- State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth;
- State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion));
+ State->Echo.MixCoeff = reverbGain * lateGain * echoDepth;
}
// Update the early and late 3D panning gains.
static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State)
{
- ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1],
- ReflectionsPan[2] };
- ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1],
- LateReverbPan[2] };
- ALfloat ambientGain;
- ALfloat dirGain;
- ALfloat length;
-
- Gain *= ReverbBoost;
-
- /* Attenuate reverb according to its coverage (dirGain=0 will give
- * Gain*ambientGain, and dirGain=1 will give Gain). */
- ambientGain = minf(sqrtf(2.0f/Device->NumChan), 1.0f);
-
- length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
- if(length > 1.0f)
+ static const ALfloat EarlyPanAngles[4] = {
+ DEG2RAD(0.0f), DEG2RAD(-90.0f), DEG2RAD(90.0f), DEG2RAD(180.0f)
+ }, LatePanAngles[4] = {
+ DEG2RAD(45.0f), DEG2RAD(-45.0f), DEG2RAD(135.0f), DEG2RAD(-135.0f)
+ };
+ ALfloat length, ev, az;
+ ALuint i;
+
+ length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]);
+ if(!(length > FLT_EPSILON))
{
- length = 1.0f / sqrtf(length);
- earlyPan[0] *= length;
- earlyPan[1] *= length;
- earlyPan[2] *= length;
+ for(i = 0;i < 4;i++)
+ ComputeAngleGains(Device, EarlyPanAngles[i], 0.0f, Gain, State->Early.PanGain[i]);
}
- length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2];
- if(length > 1.0f)
+ else
{
- length = 1.0f / sqrtf(length);
- latePan[0] *= length;
- latePan[1] *= length;
- latePan[2] *= length;
+ ev = asinf(clampf(ReflectionsPan[1]/length, -1.0f, 1.0f));
+ az = atan2f(ReflectionsPan[0], ReflectionsPan[2]);
+
+ length = minf(length, 1.0f);
+ for(i = 0;i < 4;i++)
+ {
+ /* This is essentially just a lerp, but takes the shortest path
+ * with respect to circular wrapping. e.g.
+ * -135 -> +/-180 -> +135
+ * instead of
+ * -135 -> 0 -> +135 */
+ float offset, naz, nev;
+ naz = EarlyPanAngles[i] + (modff((az-EarlyPanAngles[i])*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU;
+ nev = (modff((ev )*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU;
+ ComputeAngleGains(Device, naz, nev, Gain, State->Early.PanGain[i]);
+ }
}
- dirGain = sqrtf(earlyPan[0]*earlyPan[0] + earlyPan[2]*earlyPan[2]);
- ComputeAngleGains(Device, atan2f(earlyPan[0], earlyPan[2]), (1.0f-dirGain)*F_PI,
- lerp(ambientGain, 1.0f, dirGain) * Gain, State->Early.PanGain);
+ length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]);
+ if(!(length > FLT_EPSILON))
+ {
+ for(i = 0;i < 4;i++)
+ ComputeAngleGains(Device, LatePanAngles[i], 0.0f, Gain, State->Late.PanGain[i]);
+ }
+ else
+ {
+ ev = asinf(clampf(LateReverbPan[1]/length, -1.0f, 1.0f));
+ az = atan2f(LateReverbPan[0], LateReverbPan[2]);
- dirGain = sqrtf(latePan[0]*latePan[0] + latePan[2]*latePan[2]);
- ComputeAngleGains(Device, atan2f(latePan[0], latePan[2]), (1.0f-dirGain)*F_PI,
- lerp(ambientGain, 1.0f, dirGain) * Gain, State->Late.PanGain);
+ length = minf(length, 1.0f);
+ for(i = 0;i < 4;i++)
+ {
+ float offset, naz, nev;
+ naz = LatePanAngles[i] + (modff((az-LatePanAngles[i])*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU;
+ nev = (modff((ev )*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU;
+ ComputeAngleGains(Device, naz, nev, Gain, State->Late.PanGain[i]);
+ }
+ }
}
static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, const ALeffectslot *Slot)
{
+ const ALeffectProps *props = &Slot->EffectProps;
ALuint frequency = Device->Frequency;
ALfloat lfscale, hfscale, hfRatio;
+ ALfloat gainlf, gainhf;
ALfloat cw, x, y;
if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb)
@@ -1082,85 +1129,60 @@ static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, cons
else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb)
State->IsEax = AL_FALSE;
- // Calculate the master low-pass filter (from the master effect HF gain).
- if(State->IsEax)
- {
- hfscale = Slot->EffectProps.Reverb.HFReference / frequency;
- ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
- Slot->EffectProps.Reverb.GainHF,
- hfscale, 0.0f);
- lfscale = Slot->EffectProps.Reverb.LFReference / frequency;
- ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf,
- Slot->EffectProps.Reverb.GainLF,
- lfscale, 0.0f);
- }
- else
- {
- hfscale = LOWPASSFREQREF / frequency;
- ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
- Slot->EffectProps.Reverb.GainHF,
- hfscale, 0.0f);
- }
-
- if(State->IsEax)
- {
- // Update the modulator line.
- UpdateModulator(Slot->EffectProps.Reverb.ModulationTime,
- Slot->EffectProps.Reverb.ModulationDepth,
- frequency, State);
- }
+ // Calculate the master filters
+ hfscale = props->Reverb.HFReference / frequency;
+ gainhf = maxf(props->Reverb.GainHF, 0.0001f);
+ ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf,
+ gainhf, hfscale, calc_rcpQ_from_slope(gainhf, 0.75f));
+ lfscale = props->Reverb.LFReference / frequency;
+ gainlf = maxf(props->Reverb.GainLF, 0.0001f);
+ ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf,
+ gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f));
+
+ // Update the modulator line.
+ UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth,
+ frequency, State);
// Update the initial effect delay.
- UpdateDelayLine(Slot->EffectProps.Reverb.ReflectionsDelay,
- Slot->EffectProps.Reverb.LateReverbDelay,
+ UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay,
frequency, State);
// Update the early lines.
- UpdateEarlyLines(Slot->EffectProps.Reverb.Gain,
- Slot->EffectProps.Reverb.ReflectionsGain,
- Slot->EffectProps.Reverb.LateReverbDelay, State);
+ UpdateEarlyLines(props->Reverb.Gain, props->Reverb.ReflectionsGain,
+ props->Reverb.LateReverbDelay, State);
// Update the decorrelator.
- UpdateDecorrelator(Slot->EffectProps.Reverb.Density, frequency, State);
+ UpdateDecorrelator(props->Reverb.Density, frequency, State);
// Get the mixing matrix coefficients (x and y).
- CalcMatrixCoeffs(Slot->EffectProps.Reverb.Diffusion, &x, &y);
+ CalcMatrixCoeffs(props->Reverb.Diffusion, &x, &y);
// Then divide x into y to simplify the matrix calculation.
State->Late.MixCoeff = y / x;
// If the HF limit parameter is flagged, calculate an appropriate limit
// based on the air absorption parameter.
- hfRatio = Slot->EffectProps.Reverb.DecayHFRatio;
- if(Slot->EffectProps.Reverb.DecayHFLimit &&
- Slot->EffectProps.Reverb.AirAbsorptionGainHF < 1.0f)
- hfRatio = CalcLimitedHfRatio(hfRatio,
- Slot->EffectProps.Reverb.AirAbsorptionGainHF,
- Slot->EffectProps.Reverb.DecayTime);
-
- cw = cosf(F_2PI * hfscale);
- // Update the late lines.
- UpdateLateLines(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain,
- x, Slot->EffectProps.Reverb.Density, Slot->EffectProps.Reverb.DecayTime,
- Slot->EffectProps.Reverb.Diffusion, hfRatio, cw, frequency, State);
+ hfRatio = props->Reverb.DecayHFRatio;
+ if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f)
+ hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF,
+ props->Reverb.DecayTime);
- if(State->IsEax)
- {
- // Update the echo line.
- UpdateEchoLine(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain,
- Slot->EffectProps.Reverb.EchoTime, Slot->EffectProps.Reverb.DecayTime,
- Slot->EffectProps.Reverb.Diffusion, Slot->EffectProps.Reverb.EchoDepth,
- hfRatio, cw, frequency, State);
-
- // Update early and late 3D panning.
- Update3DPanning(Device, Slot->EffectProps.Reverb.ReflectionsPan,
- Slot->EffectProps.Reverb.LateReverbPan, Slot->Gain, State);
- }
- else
- {
- /* Update channel gains */
- ALfloat gain = sqrtf(2.0f/Device->NumChan) * ReverbBoost * Slot->Gain;
- SetGains(Device, gain, State->Gain);
- }
+ cw = cosf(F_TAU * hfscale);
+ // Update the late lines.
+ UpdateLateLines(props->Reverb.Gain, props->Reverb.LateReverbGain, x,
+ props->Reverb.Density, props->Reverb.DecayTime,
+ props->Reverb.Diffusion, props->Reverb.EchoDepth,
+ hfRatio, cw, frequency, State);
+
+ // Update the echo line.
+ UpdateEchoLine(props->Reverb.Gain, props->Reverb.LateReverbGain,
+ props->Reverb.EchoTime, props->Reverb.DecayTime,
+ props->Reverb.Diffusion, props->Reverb.EchoDepth,
+ hfRatio, cw, frequency, State);
+
+ // Update early and late 3D panning.
+ Update3DPanning(Device, props->Reverb.ReflectionsPan,
+ props->Reverb.LateReverbPan,
+ Slot->Gain * ReverbBoost, State);
}
@@ -1182,7 +1204,7 @@ typedef struct ALreverbStateFactory {
static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory))
{
ALreverbState *state;
- ALuint index;
+ ALuint index, l;
state = ALreverbState_New(sizeof(*state));
if(!state) return NULL;
@@ -1242,10 +1264,13 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f
state->Late.LpSample[index] = 0.0f;
}
- for(index = 0;index < MaxChannels;index++)
+ for(l = 0;l < 4;l++)
{
- state->Early.PanGain[index] = 0.0f;
- state->Late.PanGain[index] = 0.0f;
+ for(index = 0;index < MAX_OUTPUT_CHANNELS;index++)
+ {
+ state->Early.PanGain[l][index] = 0.0f;
+ state->Late.PanGain[l][index] = 0.0f;
+ }
}
state->Echo.DensityGain = 0.0f;
@@ -1260,8 +1285,7 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f
state->Echo.ApOffset = 0;
state->Echo.LpCoeff = 0.0f;
state->Echo.LpSample = 0.0f;
- state->Echo.MixCoeff[0] = 0.0f;
- state->Echo.MixCoeff[1] = 0.0f;
+ state->Echo.MixCoeff = 0.0f;
state->Offset = 0;
diff --git a/Alc/evtqueue.h b/Alc/evtqueue.h
deleted file mode 100644
index 95702d79..00000000
--- a/Alc/evtqueue.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef AL_EVTQUEUE_H
-#define AL_EVTQUEUE_H
-
-#include "AL/al.h"
-
-#include "alMain.h"
-
-typedef struct MidiEvent {
- ALuint64 time;
- ALuint event;
- union {
- ALuint val[2];
- struct {
- ALvoid *data;
- ALsizei size;
- } sysex;
- } param;
-} MidiEvent;
-
-typedef struct EvtQueue {
- MidiEvent *events;
- ALsizei pos;
- ALsizei size;
- ALsizei maxsize;
-} EvtQueue;
-
-void InitEvtQueue(EvtQueue *queue);
-void ResetEvtQueue(EvtQueue *queue);
-ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt);
-
-#endif /* AL_EVTQUEUE_H */
diff --git a/Alc/helpers.c b/Alc/helpers.c
index e1220fd4..7b9e58e0 100644
--- a/Alc/helpers.c
+++ b/Alc/helpers.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -35,6 +35,9 @@
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
#ifndef AL_NO_UID_DEFS
#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
@@ -55,10 +58,13 @@ DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6);
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
+DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17);
#ifdef HAVE_MMDEVAPI
#include <devpropdef.h>
+#include <propkeydef.h>
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
+DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
#endif
#endif
#endif /* AL_NO_UID_DEFS */
@@ -66,6 +72,9 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
+#ifdef HAVE_INTRIN_H
+#include <intrin.h>
+#endif
#ifdef HAVE_CPUID_H
#include <cpuid.h>
#endif
@@ -79,7 +88,9 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
#include <ieeefp.h>
#endif
-#ifdef _WIN32_IE
+#ifndef _WIN32
+#include <unistd.h>
+#elif defined(_WIN32_IE)
#include <shlobj.h>
#endif
@@ -107,8 +118,8 @@ void FillCPUCaps(ALuint capfilter)
/* FIXME: We really should get this for all available CPUs in case different
* CPUs have different caps (is that possible on one machine?). */
-#if defined(HAVE_CPUID_H) && (defined(__i386__) || defined(__x86_64__) || \
- defined(_M_IX86) || defined(_M_X64))
+#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])];
@@ -141,36 +152,89 @@ void FillCPUCaps(ALuint capfilter)
if((cpuinf[0].regs[3]&(1<<26)))
{
caps |= CPU_CAP_SSE2;
- if((cpuinf[0].regs[2]&(1<<19)))
- caps |= CPU_CAP_SSE4_1;
+ if((cpuinf[0].regs[2]&(1<<0)))
+ {
+ caps |= CPU_CAP_SSE3;
+ if((cpuinf[0].regs[2]&(1<<19)))
+ caps |= CPU_CAP_SSE4_1;
+ }
}
}
}
}
-#elif defined(HAVE_WINDOWS_H)
- HMODULE k32 = GetModuleHandleA("kernel32.dll");
- BOOL (WINAPI*IsProcessorFeaturePresent)(DWORD ProcessorFeature);
- IsProcessorFeaturePresent = (BOOL(WINAPI*)(DWORD))GetProcAddress(k32, "IsProcessorFeaturePresent");
- if(!IsProcessorFeaturePresent)
- ERR("IsProcessorFeaturePresent not available; CPU caps not detected\n");
+#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
{
- if(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE))
+ 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)
{
- caps |= CPU_CAP_SSE;
- if(IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE))
- caps |= CPU_CAP_SSE2;
+ (__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<<0)))
+ {
+ caps |= CPU_CAP_SSE3;
+ 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!"
+ caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
+#elif defined(HAVE_SSE3)
+#warning "Assuming SSE 3 run-time support!"
+ caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
+#elif defined(HAVE_SSE2)
+#warning "Assuming SSE 2 run-time support!"
+ caps |= CPU_CAP_SSE | CPU_CAP_SSE2;
+#elif defined(HAVE_SSE)
+#warning "Assuming SSE run-time support!"
+ caps |= 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",
+ TRACE("Extensions:%s%s%s%s%s%s\n",
((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""),
((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""),
+ ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""),
((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""),
((!capfilter) ? " -none-" : "")
@@ -196,7 +260,7 @@ void *al_malloc(size_t alignment, size_t size)
if(ret != NULL)
{
*(ret++) = 0x00;
- while(((ALintptrEXT)ret&(alignment-1)) != 0)
+ while(((ptrdiff_t)ret&(alignment-1)) != 0)
*(ret++) = 0x55;
}
return ret;
@@ -229,17 +293,13 @@ void al_free(void *ptr)
}
-#if (defined(HAVE___CONTROL87_2) || defined(HAVE__CONTROLFP)) && (defined(__x86_64__) || defined(_M_X64))
-/* Win64 doesn't allow us to set the precision control. */
-#undef _MCW_PC
-#define _MCW_PC 0
-#endif
-
void SetMixerFPUMode(FPUCtl *ctl)
{
#ifdef HAVE_FENV_H
fegetenv(STATIC_CAST(fenv_t, ctl));
#if defined(__GNUC__) && defined(HAVE_SSE)
+ /* FIXME: Some fegetenv implementations can get the SSE environment too?
+ * How to tell when it does? */
if((CPUCapFlags&CPU_CAP_SSE))
__asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state));
#endif
@@ -263,7 +323,7 @@ void SetMixerFPUMode(FPUCtl *ctl)
int mode;
__control87_2(0, 0, &ctl->state, NULL);
- __control87_2(_RC_CHOP|_PC_24, _MCW_RC|_MCW_PC, &mode, NULL);
+ __control87_2(_RC_CHOP, _MCW_RC, &mode, NULL);
#ifdef HAVE_SSE
if((CPUCapFlags&CPU_CAP_SSE))
{
@@ -275,7 +335,7 @@ void SetMixerFPUMode(FPUCtl *ctl)
#elif defined(HAVE__CONTROLFP)
ctl->state = _controlfp(0, 0);
- (void)_controlfp(_RC_CHOP|_PC_24, _MCW_RC|_MCW_PC);
+ (void)_controlfp(_RC_CHOP, _MCW_RC);
#endif
}
@@ -291,7 +351,7 @@ void RestoreFPUMode(const FPUCtl *ctl)
#elif defined(HAVE___CONTROL87_2)
int mode;
- __control87_2(ctl->state, _MCW_RC|_MCW_PC, &mode, NULL);
+ __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);
@@ -299,7 +359,7 @@ void RestoreFPUMode(const FPUCtl *ctl)
#elif defined(HAVE__CONTROLFP)
- _controlfp(ctl->state, _MCW_RC|_MCW_PC);
+ _controlfp(ctl->state, _MCW_RC);
#endif
}
@@ -383,55 +443,31 @@ FILE *al_fopen(const char *fname, const char *mode)
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, ...)
{
+ char str[1024];
+ WCHAR *wstr;
va_list ap;
va_start(ap, fmt);
- fprintf(LogFile, "AL lib: %s %s: ", type, func);
- vfprintf(LogFile, fmt, ap);
+ vsnprintf(str, sizeof(str), fmt, ap);
va_end(ap);
+ str[sizeof(str)-1] = 0;
+ wstr = FromUTF8(str);
+ if(!wstr)
+ fprintf(LogFile, "AL lib: %s %s: <UTF-8 error> %s", type, func, str);
+ else
+ {
+ fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr);
+ free(wstr);
+ wstr = NULL;
+ }
fflush(LogFile);
}
-#ifdef _WIN32
+
static inline int is_slash(int c)
{ return (c == '\\' || c == '/'); }
@@ -439,32 +475,46 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
{
static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
WCHAR *wname=NULL, *wsubdir=NULL;
- int i;
+ FILE *f;
+ size_t i;
- /* If the path is absolute, open it directly. */
- if(fname[0] != '\0' && fname[1] == ':' && is_slash(fname[2]))
+ wname = FromUTF8(fname);
+ if(!wname)
{
- FILE *f;
- if((f=al_fopen(fname, "rb")) != NULL)
- {
- TRACE("Opened %s\n", fname);
- return f;
- }
- WARN("Could not open %s\n", fname);
+ ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
return NULL;
}
- wname = FromUTF8(fname);
+ /* If the path is absolute, open it directly. */
+ if(wname[0] != '\0' && wname[1] == ':' && is_slash(wname[2]))
+ {
+ f = _wfopen(wname, L"rb");
+ if(f) TRACE("Opened %s\n", fname);
+ else WARN("Could not open %s\n", fname);
+ free(wname);
+ return f;
+ }
+
+ /* Try the current directory first before the data directories. */
+ if((f=_wfopen(wname, L"rb")) != NULL)
+ {
+ TRACE("Opened %s\n", fname);
+ free(wname);
+ return f;
+ }
+
wsubdir = FromUTF8(subdir);
- if(!wname)
- ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
- else if(!wsubdir)
+ if(!wsubdir)
+ {
ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir);
- else for(i = 0;i < 2;i++)
+ free(wname);
+ return NULL;
+ }
+
+ for(i = 0;i < COUNTOF(ids);i++)
{
WCHAR buffer[PATH_MAX];
size_t len;
- FILE *f;
if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE)
continue;
@@ -483,17 +533,347 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
if((f=_wfopen(buffer, L"rb")) != NULL)
{
- TRACE("Opened %ls\n", buffer);
- return f;
+ al_string filepath = AL_STRING_INIT_STATIC();
+ al_string_copy_wcstr(&filepath, buffer);
+ TRACE("Opened %s\n", al_string_get_cstr(filepath));
+ al_string_deinit(&filepath);
+ break;
}
- WARN("Could not open %ls\n", buffer);
}
free(wname);
free(wsubdir);
+ if(f == NULL)
+ WARN("Could not open %s\\%s\n", subdir, fname);
+ return f;
+}
+
+
+static const WCHAR *strchrW(const WCHAR *str, WCHAR ch)
+{
+ for(;*str != 0;++str)
+ {
+ if(*str == ch)
+ return str;
+ }
return NULL;
}
+
+static const WCHAR *strrchrW(const WCHAR *str, WCHAR ch)
+{
+ const WCHAR *ret = NULL;
+ for(;*str != 0;++str)
+ {
+ if(*str == ch)
+ ret = str;
+ }
+ return ret;
+}
+
+/* Compares the filename in the find data with the match string. The match
+ * string may contain the "%r" marker to signifiy a sample rate (really any
+ * positive integer), or "%%" to signify a single '%'.
+ */
+static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata)
+{
+ const WCHAR *name = fdata->cFileName;
+ int ret = 1;
+
+ do {
+ const WCHAR *p = strchrW(match, '%');
+ if(!p)
+ ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
+ match, -1, name, -1) == CSTR_EQUAL;
+ else
+ {
+ int len = p-match;
+ ret = lstrlenW(name) >= len;
+ if(ret)
+ ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
+ match, len, name, len) == CSTR_EQUAL;
+ if(ret)
+ {
+ match += len;
+ name += len;
+
+ ++p;
+ if(*p == 'r')
+ {
+ unsigned long l = 0;
+ while(*name >= '0' && *name <= '9')
+ {
+ l = l*10 + (*name-'0');
+ ++name;
+ }
+ ret = l > 0;
+ ++p;
+ }
+ }
+ }
+
+ match = p;
+ } while(ret && match && *match);
+
+ return ret;
+}
+
+static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_al_string *results)
+{
+ WIN32_FIND_DATAW fdata;
+ const WCHAR *sep, *p;
+ HANDLE hdl;
+
+ if(!match[0])
+ return;
+
+ /* Find the last directory separator and the next '%' marker in the match
+ * string. */
+ sep = strrchrW(match, '\\');
+ p = strchrW(match, '%');
+
+ /* If there's no separator, test the files in the specified path against
+ * the match string, and add the results. */
+ if(!sep)
+ {
+ al_string pathstr = AL_STRING_INIT_STATIC();
+ WCHAR *wpath;
+
+ TRACE("Searching %s for %ls\n", path, match);
+
+ al_string_append_cstr(&pathstr, path);
+ al_string_append_cstr(&pathstr, "\\*.*");
+ wpath = FromUTF8(al_string_get_cstr(pathstr));
+
+ hdl = FindFirstFileW(wpath, &fdata);
+ if(hdl != INVALID_HANDLE_VALUE)
+ {
+ do {
+ if(MatchFilter(match, &fdata))
+ {
+ al_string str = AL_STRING_INIT_STATIC();
+ al_string_copy_cstr(&str, path);
+ al_string_append_char(&str, '\\');
+ al_string_append_wcstr(&str, fdata.cFileName);
+ TRACE("Got result %s\n", al_string_get_cstr(str));
+ VECTOR_PUSH_BACK(*results, str);
+ }
+ } while(FindNextFileW(hdl, &fdata));
+ FindClose(hdl);
+ }
+
+ free(wpath);
+ al_string_deinit(&pathstr);
+
+ return;
+ }
+
+ /* If there's no '%' marker, or it's after the final separator, append the
+ * remaining directories to the path and recurse into it with the remaining
+ * filename portion. */
+ if(!p || p-sep >= 0)
+ {
+ al_string npath = AL_STRING_INIT_STATIC();
+ al_string_append_cstr(&npath, path);
+ al_string_append_char(&npath, '\\');
+ al_string_append_wrange(&npath, match, sep);
+
+ TRACE("Recursing into %s with %ls\n", al_string_get_cstr(npath), sep+1);
+ RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results);
+
+ al_string_deinit(&npath);
+ return;
+ }
+
+ /* Look for the last separator before the '%' marker, and the first
+ * separator after it. */
+ sep = strchrW(match, '\\');
+ if(sep-p >= 0) sep = NULL;
+ for(;;)
+ {
+ const WCHAR *next = strchrW(sep?sep+1:match, '\\');
+ if(next-p < 0)
+ {
+ al_string npath = AL_STRING_INIT_STATIC();
+ WCHAR *nwpath, *nwmatch;
+
+ /* Append up to the last directory before the one with a '%'. */
+ al_string_copy_cstr(&npath, path);
+ if(sep)
+ {
+ al_string_append_char(&npath, '\\');
+ al_string_append_wrange(&npath, match, sep);
+ }
+ al_string_append_cstr(&npath, "\\*.*");
+ nwpath = FromUTF8(al_string_get_cstr(npath));
+
+ /* Take the directory name containing a '%' as a new string to
+ * match against. */
+ if(!sep)
+ {
+ nwmatch = calloc(2, next-match+1);
+ memcpy(nwmatch, match, (next-match)*2);
+ }
+ else
+ {
+ nwmatch = calloc(2, next-(sep+1)+1);
+ memcpy(nwmatch, sep+1, (next-(sep+1))*2);
+ }
+
+ /* For each matching directory name, recurse into it with the
+ * remaining string. */
+ TRACE("Searching %s for %ls\n", al_string_get_cstr(npath), nwmatch);
+ hdl = FindFirstFileW(nwpath, &fdata);
+ if(hdl != INVALID_HANDLE_VALUE)
+ {
+ do {
+ if(MatchFilter(nwmatch, &fdata))
+ {
+ al_string ndir = AL_STRING_INIT_STATIC();
+ al_string_copy(&ndir, npath);
+ al_string_append_char(&ndir, '\\');
+ al_string_append_wcstr(&ndir, fdata.cFileName);
+ TRACE("Recursing %s with %ls\n", al_string_get_cstr(ndir), next+1);
+ RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results);
+ al_string_deinit(&ndir);
+ }
+ } while(FindNextFileW(hdl, &fdata));
+ FindClose(hdl);
+ }
+
+ free(nwmatch);
+ free(nwpath);
+ al_string_deinit(&npath);
+ break;
+ }
+ sep = next;
+ }
+}
+
+vector_al_string SearchDataFiles(const char *match, const char *subdir)
+{
+ static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
+ static RefCount search_lock;
+ vector_al_string results = VECTOR_INIT_STATIC();
+ WCHAR *wmatch;
+ size_t i;
+
+ while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
+ althrd_yield();
+
+ wmatch = FromUTF8(match);
+ if(!wmatch)
+ {
+ ERR("Failed to convert UTF-8 filename: \"%s\"\n", match);
+ return results;
+ }
+ for(i = 0;wmatch[i];++i)
+ {
+ if(wmatch[i] == '/')
+ wmatch[i] = '\\';
+ }
+
+ /* If the path is absolute, use it directly. */
+ if(isalpha(wmatch[0]) && wmatch[1] == ':' && is_slash(wmatch[2]))
+ {
+ char drv[3] = { (char)wmatch[0], ':', 0 };
+ RecurseDirectorySearch(drv, wmatch+3, &results);
+ }
+ else if(wmatch[0] == '\\' && wmatch[1] == '\\' && wmatch[2] == '?' && wmatch[3] == '\\')
+ RecurseDirectorySearch("\\\\?", wmatch+4, &results);
+ else
+ {
+ al_string path = AL_STRING_INIT_STATIC();
+ WCHAR *cwdbuf;
+
+ /* Search the CWD. */
+ if(!(cwdbuf=_wgetcwd(NULL, 0)))
+ al_string_copy_cstr(&path, ".");
+ else
+ {
+ al_string_copy_wcstr(&path, cwdbuf);
+ if(is_slash(VECTOR_BACK(path)))
+ {
+ VECTOR_POP_BACK(path);
+ *VECTOR_ITER_END(path) = 0;
+ }
+ free(cwdbuf);
+ }
+ RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results);
+
+ /* Search the local and global data dirs. */
+ for(i = 0;i < COUNTOF(ids);i++)
+ {
+ WCHAR buffer[PATH_MAX];
+ if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE)
+ {
+ al_string_copy_wcstr(&path, buffer);
+ if(!is_slash(VECTOR_BACK(path)))
+ al_string_append_char(&path, '\\');
+ al_string_append_cstr(&path, subdir);
+#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
+ VECTOR_FOR_EACH(char, path, FIX_SLASH);
+#undef FIX_SLASH
+
+ RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results);
+ }
+ }
+
+ al_string_deinit(&path);
+ }
+
+ free(wmatch);
+ ATOMIC_STORE(&search_lock, 0);
+
+ return results;
+}
+
#else
+
+#ifdef HAVE_DLFCN_H
+
+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 /* HAVE_DLFCN_H */
+
+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);
+}
+
+
FILE *OpenDataFile(const char *fname, const char *subdir)
{
char buffer[PATH_MAX] = "";
@@ -511,6 +891,12 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
return NULL;
}
+ if((f=al_fopen(fname, "rb")) != NULL)
+ {
+ TRACE("Opened %s\n", fname);
+ return f;
+ }
+
if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
snprintf(buffer, sizeof(buffer), "%s/%s/%s", str, subdir, fname);
else if((str=getenv("HOME")) != NULL && str[0] != '\0')
@@ -522,7 +908,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
TRACE("Opened %s\n", buffer);
return f;
}
- WARN("Could not open %s\n", buffer);
}
if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
@@ -553,11 +938,221 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
TRACE("Opened %s\n", buffer);
return f;
}
- WARN("Could not open %s\n", buffer);
}
+ WARN("Could not open %s/%s\n", subdir, fname);
return NULL;
}
+
+
+static const char *MatchString;
+static int MatchFilter(const struct dirent *dir)
+{
+ const char *match = MatchString;
+ const char *name = dir->d_name;
+ int ret = 1;
+
+ do {
+ const char *p = strchr(match, '%');
+ if(!p)
+ ret = strcmp(match, name) == 0;
+ else
+ {
+ size_t len = p-match;
+ ret = strncmp(match, name, len) == 0;
+ if(ret)
+ {
+ match += len;
+ name += len;
+
+ ++p;
+ if(*p == 'r')
+ {
+ char *end;
+ ret = strtoul(name, &end, 10) > 0;
+ if(ret) name = end;
+ ++p;
+ }
+ }
+ }
+
+ match = p;
+ } while(ret && match && *match);
+
+ return ret;
+}
+
+static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results)
+{
+ struct dirent **namelist;
+ char *sep, *p;
+ int n, i;
+
+ if(!match[0])
+ return;
+
+ sep = strrchr(match, '/');
+ p = strchr(match, '%');
+
+ if(!sep)
+ {
+ MatchString = match;
+ TRACE("Searching %s for %s\n", path?path:"/", match);
+ n = scandir(path?path:"/", &namelist, MatchFilter, alphasort);
+ if(n >= 0)
+ {
+ for(i = 0;i < n;++i)
+ {
+ al_string str = AL_STRING_INIT_STATIC();
+ if(path) al_string_copy_cstr(&str, path);
+ al_string_append_char(&str, '/');
+ al_string_append_cstr(&str, namelist[i]->d_name);
+ TRACE("Got result %s\n", al_string_get_cstr(str));
+ VECTOR_PUSH_BACK(*results, str);
+ free(namelist[i]);
+ }
+ free(namelist);
+ }
+
+ return;
+ }
+
+ if(!p || p-sep >= 0)
+ {
+ al_string npath = AL_STRING_INIT_STATIC();
+ if(path) al_string_append_cstr(&npath, path);
+ al_string_append_char(&npath, '/');
+ al_string_append_range(&npath, match, sep);
+
+ TRACE("Recursing into %s with %s\n", al_string_get_cstr(npath), sep+1);
+ RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results);
+
+ al_string_deinit(&npath);
+ return;
+ }
+
+ sep = strchr(match, '/');
+ if(sep-p >= 0) sep = NULL;
+ for(;;)
+ {
+ char *next = strchr(sep?sep+1:match, '/');
+ if(next-p < 0)
+ {
+ al_string npath = AL_STRING_INIT_STATIC();
+ al_string nmatch = AL_STRING_INIT_STATIC();
+
+ if(!sep)
+ {
+ al_string_append_cstr(&npath, path?path:"/.");
+ MatchString = match;
+ }
+ else
+ {
+ if(path) al_string_append_cstr(&npath, path);
+ al_string_append_char(&npath, '/');
+ al_string_append_range(&npath, match, sep);
+
+ al_string_append_range(&nmatch, sep+1, next);
+ MatchString = al_string_get_cstr(nmatch);
+ }
+
+ TRACE("Searching %s for %s\n", al_string_get_cstr(npath), MatchString);
+ n = scandir(al_string_get_cstr(npath), &namelist, MatchFilter, alphasort);
+ if(n >= 0)
+ {
+ al_string ndir = AL_STRING_INIT_STATIC();
+ for(i = 0;i < n;++i)
+ {
+ al_string_copy(&ndir, npath);
+ al_string_append_char(&ndir, '/');
+ al_string_append_cstr(&ndir, namelist[i]->d_name);
+ free(namelist[i]);
+ TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1);
+ RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results);
+ }
+ al_string_deinit(&ndir);
+ free(namelist);
+ }
+
+ al_string_deinit(&nmatch);
+ al_string_deinit(&npath);
+ break;
+ }
+
+ sep = next;
+ }
+}
+
+vector_al_string SearchDataFiles(const char *match, const char *subdir)
+{
+ static RefCount search_lock;
+ vector_al_string results = VECTOR_INIT_STATIC();
+
+ while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
+ althrd_yield();
+
+ if(match[0] == '/')
+ RecurseDirectorySearch(NULL, match+1, &results);
+ else
+ {
+ al_string path = AL_STRING_INIT_STATIC();
+ const char *str, *next;
+ char cwdbuf[PATH_MAX];
+
+ // Search CWD
+ if(!getcwd(cwdbuf, sizeof(cwdbuf)))
+ strcpy(cwdbuf, ".");
+ RecurseDirectorySearch(cwdbuf, match, &results);
+
+ // Search local data dir
+ if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
+ {
+ al_string_append_cstr(&path, str);
+ al_string_append_char(&path, '/');
+ al_string_append_cstr(&path, subdir);
+ }
+ else if((str=getenv("HOME")) != NULL && str[0] != '\0')
+ {
+ al_string_append_cstr(&path, str);
+ al_string_append_cstr(&path, "/.local/share/");
+ al_string_append_cstr(&path, subdir);
+ }
+ if(!al_string_empty(path))
+ RecurseDirectorySearch(al_string_get_cstr(path), match, &results);
+
+ // Search global data dirs
+ if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
+ str = "/usr/local/share/:/usr/share/";
+
+ next = str;
+ while((str=next) != NULL && str[0] != '\0')
+ {
+ next = strchr(str, ':');
+ if(!next)
+ al_string_copy_cstr(&path, str);
+ else
+ {
+ al_string_clear(&path);
+ al_string_append_range(&path, str, next);
+ ++next;
+ }
+ if(!al_string_empty(path))
+ {
+ al_string_append_char(&path, '/');
+ al_string_append_cstr(&path, subdir);
+
+ RecurseDirectorySearch(al_string_get_cstr(path), match, &results);
+ }
+ }
+
+ al_string_deinit(&path);
+ }
+
+ ATOMIC_STORE(&search_lock, 0);
+
+ return results;
+}
+
#endif
@@ -586,24 +1181,19 @@ void SetRTPriority(void)
}
-ALboolean vector_reserve(void *ptr, size_t base_size, size_t obj_count, size_t obj_size, ALboolean exact)
+ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact)
{
- vector_ *vecptr = ptr;
- if((size_t)(*vecptr ? (*vecptr)->Capacity : 0) < obj_count)
+ vector_ *vecptr = (vector_*)ptr;
+ if((*vecptr ? (*vecptr)->Capacity : 0) < obj_count)
{
- ALsizei old_size = (*vecptr ? (*vecptr)->Size : 0);
+ size_t old_size = (*vecptr ? (*vecptr)->Size : 0);
void *temp;
- /* Limit vector sizes to the greatest power-of-two value that an
- * ALsizei can hold. */
- if(obj_count > (INT_MAX>>1)+1)
- return AL_FALSE;
-
/* Use the next power-of-2 size if we don't need to allocate the exact
* amount. This is preferred when regularly increasing the vector since
* it means fewer reallocations. Though it means it also wastes some
* memory. */
- if(exact == AL_FALSE)
+ if(exact == AL_FALSE && obj_count < INT_MAX)
obj_count = NextPowerOf2((ALuint)obj_count);
/* Need to be explicit with the caller type's base size, because it
@@ -613,39 +1203,41 @@ ALboolean vector_reserve(void *ptr, size_t base_size, size_t obj_count, size_t o
if(temp == NULL) return AL_FALSE;
*vecptr = temp;
- (*vecptr)->Capacity = (ALsizei)obj_count;
+ (*vecptr)->Capacity = obj_count;
(*vecptr)->Size = old_size;
}
return AL_TRUE;
}
-ALboolean vector_resize(void *ptr, size_t base_size, size_t obj_count, size_t obj_size)
+ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count)
{
- vector_ *vecptr = ptr;
+ vector_ *vecptr = (vector_*)ptr;
if(*vecptr || obj_count > 0)
{
- if(!vector_reserve(vecptr, base_size, obj_count, obj_size, AL_TRUE))
+ if(!vector_reserve((char*)vecptr, base_size, obj_size, obj_count, AL_TRUE))
return AL_FALSE;
- (*vecptr)->Size = (ALsizei)obj_count;
+ (*vecptr)->Size = obj_count;
}
return AL_TRUE;
}
-ALboolean vector_insert(void *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend)
+ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend)
{
- vector_ *vecptr = ptr;
+ vector_ *vecptr = (vector_*)ptr;
if(datstart != datend)
{
- ptrdiff_t ins_elem = ((char*)ins_pos - ((char*)(*vecptr) + base_size)) / obj_size;
+ 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(vecptr, base_size, VECTOR_SIZE(*vecptr)+numins, obj_size, AL_TRUE))
+ if((size_t)numins + VECTOR_SIZE(*vecptr) < (size_t)numins ||
+ !vector_reserve((char*)vecptr, base_size, obj_size, VECTOR_SIZE(*vecptr)+numins, AL_TRUE))
return AL_FALSE;
/* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */
- if(ins_elem < (*vecptr)->Size)
+ if((size_t)ins_elem < (*vecptr)->Size)
{
memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size),
(char*)(*vecptr) + base_size + ((ins_elem )*obj_size),
@@ -653,13 +1245,14 @@ ALboolean vector_insert(void *ptr, size_t base_size, size_t obj_size, void *ins_
}
memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size),
datstart, numins*obj_size);
- (*vecptr)->Size += (ALsizei)numins;
+ (*vecptr)->Size += numins;
}
return AL_TRUE;
}
-extern inline ALsizei al_string_length(const_al_string str);
+extern inline void al_string_deinit(al_string *str);
+extern inline size_t al_string_length(const_al_string str);
extern inline ALboolean al_string_empty(const_al_string str);
extern inline const al_string_char_type *al_string_get_cstr(const_al_string str);
@@ -673,10 +1266,10 @@ void al_string_clear(al_string *str)
*VECTOR_ITER_END(*str) = 0;
}
-static inline int al_string_compare(const al_string_char_type *str1, ALsizei str1len,
- const al_string_char_type *str2, ALsizei str2len)
+static inline int al_string_compare(const al_string_char_type *str1, size_t str1len,
+ const al_string_char_type *str2, size_t str2len)
{
- ALsizei complen = mini(str1len, str2len);
+ size_t complen = (str1len < str2len) ? str1len : str2len;
int ret = memcmp(str1, str2, complen);
if(ret == 0)
{
@@ -693,12 +1286,12 @@ int al_string_cmp(const_al_string str1, const_al_string str2)
int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2)
{
return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
- str2, (ALsizei)strlen(str2));
+ str2, strlen(str2));
}
void al_string_copy(al_string *str, const_al_string from)
{
- ALsizei len = VECTOR_SIZE(from);
+ size_t len = al_string_length(from);
VECTOR_RESERVE(*str, len+1);
VECTOR_RESIZE(*str, 0);
VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len);
@@ -754,4 +1347,30 @@ void al_string_copy_wcstr(al_string *str, const wchar_t *from)
*VECTOR_ITER_END(*str) = 0;
}
}
+
+void al_string_append_wcstr(al_string *str, const wchar_t *from)
+{
+ int len;
+ if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
+ {
+ size_t strlen = al_string_length(*str);
+ VECTOR_RESERVE(*str, strlen+len);
+ VECTOR_RESIZE(*str, strlen+len-1);
+ WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str) + strlen, len, NULL, NULL);
+ *VECTOR_ITER_END(*str) = 0;
+ }
+}
+
+void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to)
+{
+ int len;
+ if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0)
+ {
+ size_t strlen = al_string_length(*str);
+ VECTOR_RESERVE(*str, strlen+len+1);
+ VECTOR_RESIZE(*str, strlen+len);
+ WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str) + strlen, len+1, NULL, NULL);
+ *VECTOR_ITER_END(*str) = 0;
+ }
+}
#endif
diff --git a/Alc/hrtf.c b/Alc/hrtf.c
index a0f8833b..71dd9d79 100644
--- a/Alc/hrtf.c
+++ b/Alc/hrtf.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -30,6 +30,8 @@
#include "alu.h"
#include "hrtf.h"
+#include "compat.h"
+
/* Current data set limits defined by the makehrtf utility. */
#define MIN_IR_SIZE (8)
@@ -52,108 +54,72 @@ struct Hrtf {
const ALshort *coeffs;
const ALubyte *delays;
+ al_string filename;
struct Hrtf *next;
};
static const ALchar magicMarker00[8] = "MinPHR00";
static const ALchar magicMarker01[8] = "MinPHR01";
+/* First value for pass-through coefficients (remaining are 0), used for omni-
+ * directional sounds. */
+static const ALfloat PassthruCoeff = 32767.0f * 0.707106781187f/*sqrt(0.5)*/;
+
static 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_TAU + az) * azcount / F_TAU;
+ azidx[0] = fastf2u(az) % azcount;
+ azidx[1] = (azidx[0] + 1) % azcount;
*azmu = az - floorf(az);
}
-/* Calculates the normalized HRTF transition factor (delta) from the changes
- * in gain and listener to source angle between updates. The result is a
- * normalized delta factor that can be used to calculate moving HRIR stepping
- * values.
- */
-ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3])
-{
- ALfloat gainChange, angleChange, change;
-
- // Calculate the normalized dB gain change.
- newGain = maxf(newGain, 0.0001f);
- oldGain = maxf(oldGain, 0.0001f);
- gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
-
- // Calculate the normalized listener to source angle change 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;
-
- }
-
- // Use the largest of the two changes for the delta factor, and apply a
- // significance shaping function to it.
- change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
- return minf(change, 1.0f);
-}
-
/* Calculates static HRIR coefficients and delays for the given polar
* elevation and azimuth in radians. Linear interpolation is used to
* increase the apparent resolution of the HRIR data set. The coefficients
* 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]);
-
- // 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 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]]);
+ for(i = 0;i < 2;i++)
+ {
+ ALuint azcount = Hrtf->azCount[evidx[i]];
+ ALuint evoffset = Hrtf->evOffset[evidx[i]];
+ ALuint azidx[2];
+
+ /* Calculate azimuth indices and interpolation factor for this elevation. */
+ CalcAzIndices(azcount, azimuth, azidx, &mu[i]);
+
+ /* Calculate a set of linear HRIR indices for left and right channels. */
+ lidx[i*2 + 0] = evoffset + azidx[0];
+ lidx[i*2 + 1] = evoffset + azidx[1];
+ ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount);
+ ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount);
+ }
/* Calculate 4 blending weights for 2D bilinear interpolation. */
blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]);
@@ -162,12 +128,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;
@@ -185,17 +151,24 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
*/
if(gain > 0.0001f)
{
- gain *= 1.0f/32767.0f;
- for(i = 0;i < Hrtf->irSize;i++)
+ ALfloat c;
+
+ i = 0;
+ c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
+ Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
+ coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
+ c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
+ Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
+ coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
+
+ 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 * (1.0f/32767.0f);
+ c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
+ Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
+ coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
}
}
else
@@ -215,43 +188,36 @@ 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;
+ ALfloat steps;
ALuint i;
- // Claculate elevation indices and interpolation factor.
- CalcEvIndices(Hrtf, elevation, evidx, &mu[2]);
-
- // Calculate azimuth indices and interpolation factor for the first
- // elevation.
- CalcAzIndices(Hrtf, evidx[0], azimuth, azidx, &mu[0]);
+ /* Claculate elevation indices and interpolation factor. */
+ CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[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 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]]);
+ for(i = 0;i < 2;i++)
+ {
+ ALuint azcount = Hrtf->azCount[evidx[i]];
+ ALuint evoffset = Hrtf->evOffset[evidx[i]];
+ ALuint azidx[2];
+
+ /* Calculate azimuth indices and interpolation factor for this elevation. */
+ CalcAzIndices(azcount, azimuth, azidx, &mu[i]);
+
+ /* Calculate a set of linear HRIR indices for left and right channels. */
+ lidx[i*2 + 0] = evoffset + azidx[0];
+ lidx[i*2 + 1] = evoffset + azidx[1];
+ ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount);
+ ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount);
+ }
// Calculate the stepping parameters.
- delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f);
- step = 1.0f / delta;
+ steps = maxf(floorf(delta*Hrtf->sampleRate + 0.5f), 1.0f);
+ delta = 1.0f / steps;
/* Calculate 4 blending weights for 2D bilinear interpolation. */
blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]);
@@ -266,15 +232,15 @@ 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));
+ delayStep[0] = fastf2i(delta * (delays[0] - left));
+ delayStep[1] = fastf2i(delta * (delays[1] - right));
/* Calculate the sample offsets for the HRIR indices. */
lidx[0] *= Hrtf->irSize;
@@ -294,28 +260,41 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
*/
if(gain > 0.0001f)
{
- gain *= 1.0f/32767.0f;
- for(i = 0;i < HRIR_LENGTH;i++)
+ ALfloat c;
+
+ i = 0;
+ left = coeffs[i][0] - (coeffStep[i][0] * counter);
+ right = coeffs[i][1] - (coeffStep[i][1] * counter);
+
+ c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
+ Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
+ coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
+ c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
+ Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
+ coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
+
+ coeffStep[i][0] = delta * (coeffs[i][0] - left);
+ coeffStep[i][1] = delta * (coeffs[i][1] - right);
+
+ for(i = 1;i < Hrtf->irSize;i++)
{
left = coeffs[i][0] - (coeffStep[i][0] * counter);
right = coeffs[i][1] - (coeffStep[i][1] * counter);
- 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;
-
- coeffStep[i][0] = step * (coeffs[i][0] - left);
- coeffStep[i][1] = step * (coeffs[i][1] - right);
+ c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
+ Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
+ coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
+ c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
+ Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
+ coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
+
+ coeffStep[i][0] = delta * (coeffs[i][0] - left);
+ coeffStep[i][1] = delta * (coeffs[i][1] - right);
}
}
else
{
- for(i = 0;i < 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);
@@ -323,8 +302,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
coeffs[i][0] = 0.0f;
coeffs[i][1] = 0.0f;
- coeffStep[i][0] = step * -left;
- coeffStep[i][1] = step * -right;
+ coeffStep[i][0] = delta * -left;
+ coeffStep[i][1] = delta * -right;
}
}
@@ -332,13 +311,118 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
* complete its transition. The mixer will only apply stepping for this
* many samples.
*/
- return fastf2u(delta);
+ return fastf2u(steps);
}
-static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
+/* Calculates HRTF coefficients for B-Format channels (only up to first-order).
+ * Note that these will decode a B-Format output mix, which uses FuMa ordering
+ * and scaling, not N3D!
+ */
+void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list)
{
- const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
+ ALuint elev_idx, azi_idx;
+ ALfloat scale;
+ ALuint i, c;
+
+ assert(num_chans <= 4);
+
+ for(c = 0;c < num_chans;c++)
+ {
+ ALfloat (*coeffs)[2] = coeffs_list[c];
+ ALuint *delay = delay_list[c];
+
+ for(i = 0;i < Hrtf->irSize;i++)
+ {
+ coeffs[i][0] = 0.0f;
+ coeffs[i][1] = 0.0f;
+ }
+ delay[0] = 0;
+ delay[1] = 0;
+ }
+
+ /* NOTE: HRTF coefficients are generated by combining all the HRIRs in the
+ * dataset, with each entry scaled according to how much it contributes to
+ * the given B-Format channel based on its direction (including negative
+ * contributions!).
+ */
+ scale = 0.0f;
+ for(elev_idx = 0;elev_idx < Hrtf->evCount;elev_idx++)
+ {
+ ALfloat elev = (ALfloat)elev_idx/(ALfloat)(Hrtf->evCount-1)*F_PI - F_PI_2;
+ ALuint evoffset = Hrtf->evOffset[elev_idx];
+ ALuint azcount = Hrtf->azCount[elev_idx];
+
+ scale += (ALfloat)azcount;
+
+ for(azi_idx = 0;azi_idx < azcount;azi_idx++)
+ {
+ ALuint lidx, ridx;
+ ALfloat ambi_coeffs[4];
+ ALfloat az, gain;
+ ALfloat x, y, z;
+
+ lidx = evoffset + azi_idx;
+ ridx = evoffset + ((azcount-azi_idx) % azcount);
+
+ az = (ALfloat)azi_idx / (ALfloat)azcount * F_TAU;
+ if(az > F_PI) az -= F_TAU;
+
+ x = cosf(-az) * cosf(elev);
+ y = sinf(-az) * cosf(elev);
+ z = sinf(elev);
+
+ ambi_coeffs[0] = 1.414213562f;
+ ambi_coeffs[1] = x;
+ ambi_coeffs[2] = y;
+ ambi_coeffs[3] = z;
+
+ for(c = 0;c < num_chans;c++)
+ {
+ ALfloat (*coeffs)[2] = coeffs_list[c];
+ ALuint *delay = delay_list[c];
+
+ /* NOTE: Always include the total delay average since the
+ * channels need to have matching delays. */
+ delay[0] += Hrtf->delays[lidx];
+ delay[1] += Hrtf->delays[ridx];
+
+ gain = ambi_coeffs[c];
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
+ continue;
+
+ for(i = 0;i < Hrtf->irSize;i++)
+ {
+ coeffs[i][0] += Hrtf->coeffs[lidx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain;
+ coeffs[i][1] += Hrtf->coeffs[ridx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain;
+ }
+ }
+ }
+ }
+
+ scale = 1.0f/scale;
+
+ for(c = 0;c < num_chans;c++)
+ {
+ ALfloat (*coeffs)[2] = coeffs_list[c];
+ ALuint *delay = delay_list[c];
+
+ for(i = 0;i < Hrtf->irSize;i++)
+ {
+ coeffs[i][0] *= scale;
+ coeffs[i][1] *= scale;
+ }
+ delay[0] = minu((ALuint)((ALfloat)delay[0] * scale), HRTF_HISTORY_LENGTH-1);
+ delay[0] <<= HRTFDELAY_BITS;
+ delay[1] = minu((ALuint)((ALfloat)delay[1] * scale), HRTF_HISTORY_LENGTH-1);
+ delay[1] <<= HRTFDELAY_BITS;
+ }
+}
+
+
+static struct Hrtf *LoadHrtf00(FILE *f)
+{
+ const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
struct Hrtf *Hrtf = NULL;
ALboolean failed = AL_FALSE;
ALuint rate = 0, irCount = 0;
@@ -363,12 +447,6 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
evCount = fgetc(f);
- if(rate != deviceRate)
- {
- ERR("HRIR rate does not match device rate: rate=%d (%d)\n",
- rate, deviceRate);
- failed = AL_TRUE;
- }
if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
{
ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
@@ -491,6 +569,7 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
Hrtf->evOffset = evOffset;
Hrtf->coeffs = coeffs;
Hrtf->delays = delays;
+ AL_STRING_INIT(Hrtf->filename);
Hrtf->next = NULL;
return Hrtf;
}
@@ -503,9 +582,9 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
}
-static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
+static struct Hrtf *LoadHrtf01(FILE *f)
{
- const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
+ const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
struct Hrtf *Hrtf = NULL;
ALboolean failed = AL_FALSE;
ALuint rate = 0, irCount = 0;
@@ -525,12 +604,6 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
evCount = fgetc(f);
- if(rate != deviceRate)
- {
- ERR("HRIR rate does not match device rate: rate=%d (%d)\n",
- rate, deviceRate);
- failed = AL_TRUE;
- }
if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
{
ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
@@ -636,6 +709,7 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
Hrtf->evOffset = evOffset;
Hrtf->coeffs = coeffs;
Hrtf->delays = delays;
+ AL_STRING_INIT(Hrtf->filename);
Hrtf->next = NULL;
return Hrtf;
}
@@ -648,145 +722,167 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
}
-static struct Hrtf *LoadHrtf(ALuint deviceRate)
+static void AddFileEntry(vector_HrtfEntry *list, al_string *filename)
{
- const char *fnamelist = "default-%r.mhr";
+ HrtfEntry entry = { AL_STRING_INIT_STATIC(), *filename, NULL };
+ HrtfEntry *iter;
+ const char *name;
+ int i;
+
+ name = strrchr(al_string_get_cstr(entry.filename), '/');
+ if(!name) name = strrchr(al_string_get_cstr(entry.filename), '\\');
+ if(!name) name = al_string_get_cstr(entry.filename);
+ else ++name;
+
+ entry.hrtf = LoadedHrtfs;
+ while(entry.hrtf)
+ {
+ if(al_string_cmp(entry.filename, entry.hrtf->filename) == 0)
+ break;
+ entry.hrtf = entry.hrtf->next;
+ }
- ConfigValueStr(NULL, "hrtf_tables", &fnamelist);
- while(*fnamelist != '\0')
+ if(!entry.hrtf)
{
- struct Hrtf *Hrtf = NULL;
- char fname[PATH_MAX];
- const char *next;
+ struct Hrtf *hrtf = NULL;
ALchar magic[8];
- ALuint i;
FILE *f;
- i = 0;
- while(isspace(*fnamelist) || *fnamelist == ',')
- fnamelist++;
- next = fnamelist;
- while(*(fnamelist=next) != '\0' && *fnamelist != ',')
- {
- next = strpbrk(fnamelist, "%,");
- while(fnamelist != next && *fnamelist && i < sizeof(fname))
- fname[i++] = *(fnamelist++);
-
- if(!next || *next == ',')
- break;
-
- /* *next == '%' */
- next++;
- if(*next == 'r')
- {
- int wrote = snprintf(&fname[i], sizeof(fname)-i, "%u", deviceRate);
- i += minu(wrote, sizeof(fname)-i);
- next++;
- }
- else if(*next == '%')
- {
- if(i < sizeof(fname))
- fname[i++] = '%';
- next++;
- }
- else
- ERR("Invalid marker '%%%c'\n", *next);
- }
- i = minu(i, sizeof(fname)-1);
- fname[i] = '\0';
- while(i > 0 && isspace(fname[i-1]))
- i--;
- fname[i] = '\0';
-
- if(fname[0] == '\0')
- continue;
-
- TRACE("Loading %s...\n", fname);
- f = OpenDataFile(fname, "openal/hrtf");
+ TRACE("Loading %s...\n", al_string_get_cstr(entry.filename));
+ f = al_fopen(al_string_get_cstr(entry.filename), "rb");
if(f == NULL)
{
- ERR("Could not open %s\n", fname);
- continue;
+ ERR("Could not open %s\n", al_string_get_cstr(entry.filename));
+ goto error;
}
if(fread(magic, 1, sizeof(magic), f) != sizeof(magic))
- ERR("Failed to read header from %s\n", fname);
+ ERR("Failed to read header from %s\n", al_string_get_cstr(entry.filename));
else
{
if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0)
{
TRACE("Detected data set format v0\n");
- Hrtf = LoadHrtf00(f, deviceRate);
+ hrtf = LoadHrtf00(f);
}
else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0)
{
TRACE("Detected data set format v1\n");
- Hrtf = LoadHrtf01(f, deviceRate);
+ hrtf = LoadHrtf01(f);
}
else
- ERR("Invalid header in %s: \"%.8s\"\n", fname, magic);
+ ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(entry.filename), magic);
}
-
fclose(f);
- f = NULL;
- if(Hrtf)
+ if(!hrtf)
{
- Hrtf->next = LoadedHrtfs;
- LoadedHrtfs = Hrtf;
- TRACE("Loaded HRTF support for format: %s %uhz\n",
- DevFmtChannelsString(DevFmtStereo), Hrtf->sampleRate);
- return Hrtf;
+ ERR("Failed to load %s\n", al_string_get_cstr(entry.filename));
+ goto error;
}
- ERR("Failed to load %s\n", fname);
+ al_string_copy(&hrtf->filename, entry.filename);
+ hrtf->next = LoadedHrtfs;
+ LoadedHrtfs = hrtf;
+ TRACE("Loaded HRTF support for format: %s %uhz\n",
+ DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
+ entry.hrtf = hrtf;
}
- return NULL;
+ /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
+ * format update). */
+
+ i = 0;
+ do {
+ al_string_copy_cstr(&entry.name, name);
+ if(i != 0)
+ {
+ char str[64];
+ snprintf(str, sizeof(str), " #%d", i+1);
+ al_string_append_cstr(&entry.name, str);
+ }
+ ++i;
+
+#define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0)
+ VECTOR_FIND_IF(iter, HrtfEntry, *list, MATCH_NAME);
+#undef MATCH_NAME
+ } while(iter != VECTOR_ITER_END(*list));
+
+ TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name),
+ al_string_get_cstr(entry.filename));
+ VECTOR_PUSH_BACK(*list, entry);
+ return;
+
+error:
+ al_string_deinit(&entry.filename);
}
-const struct Hrtf *GetHrtf(ALCdevice *device)
+vector_HrtfEntry EnumerateHrtf(const_al_string devname)
{
- if(device->FmtChans == DevFmtStereo)
+ vector_HrtfEntry list = VECTOR_INIT_STATIC();
+ const char *fnamelist = "default-%r.mhr";
+
+ ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf_tables", &fnamelist);
+ while(fnamelist && *fnamelist)
{
- struct Hrtf *Hrtf = LoadedHrtfs;
- while(Hrtf != NULL)
+ while(isspace(*fnamelist) || *fnamelist == ',')
+ fnamelist++;
+ if(*fnamelist != '\0')
{
- if(device->Frequency == Hrtf->sampleRate)
- return Hrtf;
- Hrtf = Hrtf->next;
- }
+ const char *next, *end;
+
+ next = strchr(fnamelist, ',');
+ if(!next)
+ end = fnamelist + strlen(fnamelist);
+ else
+ end = next++;
- Hrtf = LoadHrtf(device->Frequency);
- if(Hrtf != NULL)
- return Hrtf;
+ while(end != fnamelist && isspace(*(end-1)))
+ --end;
+ if(end != fnamelist)
+ {
+ al_string fname = AL_STRING_INIT_STATIC();
+ vector_al_string flist;
+
+ al_string_append_range(&fname, fnamelist, end);
+
+ flist = SearchDataFiles(al_string_get_cstr(fname), "openal/hrtf");
+ VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list);
+ VECTOR_DEINIT(flist);
+
+ al_string_deinit(&fname);
+ }
+
+ fnamelist = next;
+ }
}
- ERR("Incompatible format: %s %uhz\n",
- DevFmtChannelsString(device->FmtChans), device->Frequency);
- return NULL;
+
+ return list;
}
-ALCboolean FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate)
+void FreeHrtfList(vector_HrtfEntry *list)
{
- const struct Hrtf *hrtf = LoadedHrtfs;
- while(hrtf != NULL)
- {
- if(device->Frequency == hrtf->sampleRate)
- break;
- hrtf = hrtf->next;
- }
+#define CLEAR_ENTRY(i) do { \
+ al_string_deinit(&(i)->name); \
+ al_string_deinit(&(i)->filename); \
+} while(0)
+ VECTOR_FOR_EACH(HrtfEntry, *list, CLEAR_ENTRY);
+ VECTOR_DEINIT(*list);
+#undef CLEAR_ENTRY
+}
- if(hrtf == NULL)
- {
- hrtf = LoadHrtf(device->Frequency);
- if(hrtf == NULL) return ALC_FALSE;
- }
- *chans = DevFmtStereo;
- *srate = hrtf->sampleRate;
- return ALC_TRUE;
+ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf)
+{
+ return Hrtf->sampleRate;
+}
+
+ALuint GetHrtfIrSize(const struct Hrtf *Hrtf)
+{
+ return Hrtf->irSize;
}
+
void FreeHrtfs(void)
{
struct Hrtf *Hrtf = NULL;
@@ -798,11 +894,7 @@ void FreeHrtfs(void)
free((void*)Hrtf->evOffset);
free((void*)Hrtf->coeffs);
free((void*)Hrtf->delays);
+ al_string_deinit(&Hrtf->filename);
free(Hrtf);
}
}
-
-ALuint GetHrtfIrSize (const struct Hrtf *Hrtf)
-{
- return Hrtf->irSize;
-}
diff --git a/Alc/hrtf.h b/Alc/hrtf.h
index d9022d02..6dcd6948 100644
--- a/Alc/hrtf.h
+++ b/Alc/hrtf.h
@@ -4,10 +4,20 @@
#include "AL/al.h"
#include "AL/alc.h"
+#include "alstring.h"
+
enum DevFmtChannels;
struct Hrtf;
+typedef struct HrtfEntry {
+ al_string name;
+ al_string filename;
+
+ const struct Hrtf *hrtf;
+} HrtfEntry;
+TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry)
+
#define HRIR_BITS (7)
#define HRIR_LENGTH (1<<HRIR_BITS)
#define HRIR_MASK (HRIR_LENGTH-1)
@@ -15,14 +25,16 @@ struct Hrtf;
#define HRTFDELAY_FRACONE (1<<HRTFDELAY_BITS)
#define HRTFDELAY_MASK (HRTFDELAY_FRACONE-1)
-const struct Hrtf *GetHrtf(ALCdevice *device);
-ALCboolean FindHrtfFormat(const ALCdevice *device, enum DevFmtChannels *chans, ALCuint *srate);
-
void FreeHrtfs(void);
+vector_HrtfEntry EnumerateHrtf(const_al_string devname);
+void FreeHrtfList(vector_HrtfEntry *list);
+
+ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf);
ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
-ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]);
-void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat 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);
+
+void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
+ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep);
+void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list);
#endif /* ALC_HRTF_H */
diff --git a/Alc/midi/base.c b/Alc/midi/base.c
deleted file mode 100644
index 1850a6c6..00000000
--- a/Alc/midi/base.c
+++ /dev/null
@@ -1,239 +0,0 @@
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include "midi/base.h"
-
-#include "alMidi.h"
-#include "alMain.h"
-#include "alError.h"
-#include "alThunk.h"
-#include "evtqueue.h"
-#include "rwlock.h"
-#include "alu.h"
-
-
-/* MIDI events */
-#define SYSEX_EVENT (0xF0)
-
-
-void InitEvtQueue(EvtQueue *queue)
-{
- queue->events = NULL;
- queue->maxsize = 0;
- queue->size = 0;
- queue->pos = 0;
-}
-
-void ResetEvtQueue(EvtQueue *queue)
-{
- ALsizei i;
- for(i = 0;i < queue->size;i++)
- {
- if(queue->events[i].event == SYSEX_EVENT)
- {
- free(queue->events[i].param.sysex.data);
- queue->events[i].param.sysex.data = NULL;
- }
- }
-
- free(queue->events);
- queue->events = NULL;
- queue->maxsize = 0;
- queue->size = 0;
- queue->pos = 0;
-}
-
-ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt)
-{
- ALsizei pos;
-
- if(queue->maxsize == queue->size)
- {
- if(queue->pos > 0)
- {
- /* Queue has some stale entries, remove them to make space for more
- * events. */
- for(pos = 0;pos < queue->pos;pos++)
- {
- if(queue->events[pos].event == SYSEX_EVENT)
- {
- free(queue->events[pos].param.sysex.data);
- queue->events[pos].param.sysex.data = NULL;
- }
- }
- memmove(&queue->events[0], &queue->events[queue->pos],
- (queue->size-queue->pos)*sizeof(queue->events[0]));
- queue->size -= queue->pos;
- queue->pos = 0;
- }
- else
- {
- /* Queue is full, double the allocated space. */
- void *temp = NULL;
- ALsizei newsize;
-
- newsize = (queue->maxsize ? (queue->maxsize<<1) : 16);
- if(newsize > queue->maxsize)
- temp = realloc(queue->events, newsize * sizeof(queue->events[0]));
- if(!temp)
- return AL_OUT_OF_MEMORY;
-
- queue->events = temp;
- queue->maxsize = newsize;
- }
- }
-
- pos = queue->pos;
- if(queue->size > 0)
- {
- ALsizei high = queue->size - 1;
- while(pos < high)
- {
- ALsizei mid = pos + (high-pos)/2;
- if(queue->events[mid].time < evt->time)
- pos = mid + 1;
- else
- high = mid;
- }
- while(pos < queue->size && queue->events[pos].time <= evt->time)
- pos++;
-
- if(pos < queue->size)
- memmove(&queue->events[pos+1], &queue->events[pos],
- (queue->size-pos)*sizeof(queue->events[0]));
- }
-
- queue->events[pos] = *evt;
- queue->size++;
-
- return AL_NO_ERROR;
-}
-
-
-void MidiSynth_Construct(MidiSynth *self, ALCdevice *device)
-{
- InitEvtQueue(&self->EventQueue);
-
- RWLockInit(&self->Lock);
-
- self->Soundfonts = NULL;
- self->NumSoundfonts = 0;
-
- self->Gain = 1.0f;
- self->State = AL_INITIAL;
-
- self->ClockBase = 0;
- self->SamplesDone = 0;
- self->SampleRate = device->Frequency;
-}
-
-void MidiSynth_Destruct(MidiSynth *self)
-{
- ALsizei i;
-
- for(i = 0;i < self->NumSoundfonts;i++)
- DecrementRef(&self->Soundfonts[i]->ref);
- free(self->Soundfonts);
- self->Soundfonts = NULL;
- self->NumSoundfonts = 0;
-
- ResetEvtQueue(&self->EventQueue);
-}
-
-
-ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
-{
- ALCdevice *device = context->Device;
- ALsoundfont **sfonts;
- ALsizei i;
-
- if(self->State != AL_INITIAL && self->State != AL_STOPPED)
- return AL_INVALID_OPERATION;
-
- sfonts = calloc(1, count * sizeof(sfonts[0]));
- if(!sfonts) return AL_OUT_OF_MEMORY;
-
- for(i = 0;i < count;i++)
- {
- if(ids[i] == 0)
- sfonts[i] = ALsoundfont_getDefSoundfont(context);
- else if(!(sfonts[i]=LookupSfont(device, ids[i])))
- {
- free(sfonts);
- return AL_INVALID_VALUE;
- }
- }
-
- for(i = 0;i < count;i++)
- IncrementRef(&sfonts[i]->ref);
- sfonts = ExchangePtr((XchgPtr*)&self->Soundfonts, sfonts);
- count = ExchangeInt(&self->NumSoundfonts, count);
-
- for(i = 0;i < count;i++)
- DecrementRef(&sfonts[i]->ref);
- free(sfonts);
-
- return AL_NO_ERROR;
-}
-
-extern inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain);
-extern inline ALfloat MidiSynth_getGain(const MidiSynth *self);
-extern inline void MidiSynth_setState(MidiSynth *self, ALenum state);
-extern inline ALenum MidiSynth_getState(const MidiSynth *self);
-
-void MidiSynth_stop(MidiSynth *self)
-{
- ResetEvtQueue(&self->EventQueue);
-
- self->ClockBase = 0;
- self->SamplesDone = 0;
-}
-
-extern inline void MidiSynth_reset(MidiSynth *self);
-extern inline ALuint64 MidiSynth_getTime(const MidiSynth *self);
-extern inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self);
-
-void MidiSynth_setSampleRate(MidiSynth *self, ALuint srate)
-{
- 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);
-
-ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2)
-{
- MidiEvent entry;
- entry.time = time;
- entry.event = event;
- entry.param.val[0] = param1;
- entry.param.val[1] = param2;
- return InsertEvtQueue(&self->EventQueue, &entry);
-}
-
-ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size)
-{
- MidiEvent entry;
- ALenum err;
-
- entry.time = time;
- entry.event = SYSEX_EVENT;
- entry.param.sysex.size = size;
- entry.param.sysex.data = malloc(size);
- if(!entry.param.sysex.data)
- return AL_OUT_OF_MEMORY;
- memcpy(entry.param.sysex.data, data, size);
-
- err = InsertEvtQueue(&self->EventQueue, &entry);
- if(err != AL_NO_ERROR)
- free(entry.param.sysex.data);
- return err;
-}
diff --git a/Alc/midi/base.h b/Alc/midi/base.h
deleted file mode 100644
index 42a4c279..00000000
--- a/Alc/midi/base.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef AL_MIDI_BASE_H
-#define AL_MIDI_BASE_H
-
-#include "alMain.h"
-#include "atomic.h"
-#include "evtqueue.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct ALsoundfont;
-
-typedef size_t (*ReaderCb)(void *ptr, size_t size, void *stream);
-typedef struct Reader {
- ReaderCb cb;
- void *ptr;
- int error;
-} Reader;
-#define READ(x_, buf_, len_) ((x_)->cb((buf_), (len_), (x_)->ptr))
-#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 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
- * thread.
- */
- RWLock Lock;
-
- struct ALsoundfont **Soundfonts;
- ALsizei NumSoundfonts;
-
- volatile ALfloat Gain;
- volatile ALenum State;
-
- const struct MidiSynthVtable *vtbl;
-} MidiSynth;
-
-void MidiSynth_Construct(MidiSynth *self, ALCdevice *device);
-void MidiSynth_Destruct(MidiSynth *self);
-ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
-inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain) { self->Gain = gain; }
-inline ALfloat MidiSynth_getGain(const MidiSynth *self) { return self->Gain; }
-inline void MidiSynth_setState(MidiSynth *self, ALenum state) { ExchangeInt(&self->State, state); }
-inline ALenum MidiSynth_getState(const MidiSynth *self) { return self->State; }
-void MidiSynth_stop(MidiSynth *self);
-inline void MidiSynth_reset(MidiSynth *self) { MidiSynth_stop(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, 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);
-ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size);
-
-
-struct MidiSynthVtable {
- void (*const Destruct)(MidiSynth *self);
-
- ALenum (*const selectSoundfonts)(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids);
-
- void (*const setGain)(MidiSynth *self, ALfloat gain);
-
- void (*const stop)(MidiSynth *self);
- void (*const reset)(MidiSynth *self);
-
- void (*const update)(MidiSynth *self, ALCdevice *device);
- void (*const process)(MidiSynth *self, ALuint samples, ALfloat (*restrict DryBuffer)[BUFFERSIZE]);
-
- 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_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) \
-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_stop, \
- T##_MidiSynth_reset, \
- T##_MidiSynth_update, \
- T##_MidiSynth_process, \
- \
- T##_MidiSynth_Delete, \
-}
-
-
-MidiSynth *SSynth_create(ALCdevice *device);
-MidiSynth *FSynth_create(ALCdevice *device);
-MidiSynth *DSynth_create(ALCdevice *device);
-
-MidiSynth *SynthCreate(ALCdevice *device);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* AL_MIDI_BASE_H */
diff --git a/Alc/midi/dummy.c b/Alc/midi/dummy.c
deleted file mode 100644
index d50b8fef..00000000
--- a/Alc/midi/dummy.c
+++ /dev/null
@@ -1,76 +0,0 @@
-
-#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 "rwlock.h"
-#include "alu.h"
-
-#include "midi/base.h"
-
-typedef struct DSynth {
- DERIVE_FROM_TYPE(MidiSynth);
-} DSynth;
-
-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_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]);
-DECLARE_DEFAULT_ALLOCATORS(DSynth)
-DEFINE_MIDISYNTH_VTABLE(DSynth);
-
-
-static void DSynth_Construct(DSynth *self, ALCdevice *device)
-{
- MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
- SET_VTABLE2(DSynth, MidiSynth, self);
-}
-
-
-static void DSynth_processQueue(DSynth *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 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->SamplesDone += SamplesToDo;
- synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES;
- synth->SamplesDone %= synth->SampleRate;
-
- curtime = MidiSynth_getTime(synth);
- DSynth_processQueue(self, maxi64(curtime-1, 0));
-}
-
-
-MidiSynth *DSynth_create(ALCdevice *device)
-{
- 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);
-}
diff --git a/Alc/midi/fluidsynth.c b/Alc/midi/fluidsynth.c
deleted file mode 100644
index b4788635..00000000
--- a/Alc/midi/fluidsynth.c
+++ /dev/null
@@ -1,822 +0,0 @@
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include "midi/base.h"
-
-#include "alMain.h"
-#include "alError.h"
-#include "alMidi.h"
-#include "evtqueue.h"
-#include "rwlock.h"
-#include "alu.h"
-
-#ifdef HAVE_FLUIDSYNTH
-
-#include <fluidsynth.h>
-
-
-/* MIDI events */
-#define SYSEX_EVENT (0xF0)
-
-/* MIDI controllers */
-#define CTRL_BANKSELECT_MSB (0)
-#define CTRL_BANKSELECT_LSB (32)
-#define CTRL_ALLNOTESOFF (123)
-
-
-static int getGenInput(ALenum input)
-{
- switch(input)
- {
- case AL_ONE_SOFT: return FLUID_MOD_NONE;
- case AL_NOTEON_VELOCITY_SOFT: return FLUID_MOD_VELOCITY;
- case AL_NOTEON_KEY_SOFT: return FLUID_MOD_KEY;
- case AL_KEYPRESSURE_SOFT: return FLUID_MOD_KEYPRESSURE;
- case AL_CHANNELPRESSURE_SOFT: return FLUID_MOD_CHANNELPRESSURE;
- case AL_PITCHBEND_SOFT: return FLUID_MOD_PITCHWHEEL;
- case AL_PITCHBEND_SENSITIVITY_SOFT: return FLUID_MOD_PITCHWHEELSENS;
- }
- return input&0x7F;
-}
-
-static int getGenFlags(ALenum input, ALenum type, ALenum form)
-{
- int ret = 0;
-
- switch(type)
- {
- case AL_UNORM_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE; break;
- case AL_UNORM_REV_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE; break;
- case AL_SNORM_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE; break;
- case AL_SNORM_REV_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE; break;
- }
- switch(form)
- {
- case AL_LINEAR_SOFT: ret |= FLUID_MOD_LINEAR; break;
- case AL_CONCAVE_SOFT: ret |= FLUID_MOD_CONCAVE; break;
- case AL_CONVEX_SOFT: ret |= FLUID_MOD_CONVEX; break;
- case AL_SWITCH_SOFT: ret |= FLUID_MOD_SWITCH; break;
- }
- /* Source input values less than 128 correspond to a MIDI continuous
- * controller. Otherwise, it's a general controller. */
- if(input < 128) ret |= FLUID_MOD_CC;
- else ret |= FLUID_MOD_GC;
-
- return ret;
-}
-
-static enum fluid_gen_type getSf2Gen(ALenum gen)
-{
- switch(gen)
- {
- case AL_MOD_LFO_TO_PITCH_SOFT: return GEN_MODLFOTOPITCH;
- case AL_VIBRATO_LFO_TO_PITCH_SOFT: return GEN_VIBLFOTOPITCH;
- case AL_MOD_ENV_TO_PITCH_SOFT: return GEN_MODENVTOPITCH;
- case AL_FILTER_CUTOFF_SOFT: return GEN_FILTERFC;
- case AL_FILTER_RESONANCE_SOFT: return GEN_FILTERQ;
- case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: return GEN_MODLFOTOFILTERFC;
- case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: return GEN_MODENVTOFILTERFC;
- case AL_MOD_LFO_TO_VOLUME_SOFT: return GEN_MODLFOTOVOL;
- case AL_CHORUS_SEND_SOFT: return GEN_CHORUSSEND;
- case AL_REVERB_SEND_SOFT: return GEN_REVERBSEND;
- case AL_PAN_SOFT: return GEN_PAN;
- case AL_MOD_LFO_DELAY_SOFT: return GEN_MODLFODELAY;
- case AL_MOD_LFO_FREQUENCY_SOFT: return GEN_MODLFOFREQ;
- case AL_VIBRATO_LFO_DELAY_SOFT: return GEN_VIBLFODELAY;
- case AL_VIBRATO_LFO_FREQUENCY_SOFT: return GEN_VIBLFOFREQ;
- case AL_MOD_ENV_DELAYTIME_SOFT: return GEN_MODENVDELAY;
- case AL_MOD_ENV_ATTACKTIME_SOFT: return GEN_MODENVATTACK;
- case AL_MOD_ENV_HOLDTIME_SOFT: return GEN_MODENVHOLD;
- case AL_MOD_ENV_DECAYTIME_SOFT: return GEN_MODENVDECAY;
- case AL_MOD_ENV_SUSTAINVOLUME_SOFT: return GEN_MODENVSUSTAIN;
- case AL_MOD_ENV_RELEASETIME_SOFT: return GEN_MODENVRELEASE;
- case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOMODENVHOLD;
- case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOMODENVDECAY;
- case AL_VOLUME_ENV_DELAYTIME_SOFT: return GEN_VOLENVDELAY;
- case AL_VOLUME_ENV_ATTACKTIME_SOFT: return GEN_VOLENVATTACK;
- case AL_VOLUME_ENV_HOLDTIME_SOFT: return GEN_VOLENVHOLD;
- case AL_VOLUME_ENV_DECAYTIME_SOFT: return GEN_VOLENVDECAY;
- case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: return GEN_VOLENVSUSTAIN;
- case AL_VOLUME_ENV_RELEASETIME_SOFT: return GEN_VOLENVRELEASE;
- case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOVOLENVHOLD;
- case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOVOLENVDECAY;
- case AL_ATTENUATION_SOFT: return GEN_ATTENUATION;
- case AL_TUNING_COARSE_SOFT: return GEN_COARSETUNE;
- case AL_TUNING_FINE_SOFT: return GEN_FINETUNE;
- case AL_TUNING_SCALE_SOFT: return GEN_SCALETUNE;
- }
- ERR("Unhandled generator: 0x%04x\n", gen);
- return 0;
-}
-
-static int getSf2LoopMode(ALenum mode)
-{
- switch(mode)
- {
- case AL_NONE: return 0;
- case AL_LOOP_CONTINUOUS_SOFT: return 1;
- case AL_LOOP_UNTIL_RELEASE_SOFT: return 3;
- }
- return 0;
-}
-
-static int getSampleType(ALenum type)
-{
- switch(type)
- {
- case AL_MONO_SOFT: return FLUID_SAMPLETYPE_MONO;
- case AL_RIGHT_SOFT: return FLUID_SAMPLETYPE_RIGHT;
- case AL_LEFT_SOFT: return FLUID_SAMPLETYPE_LEFT;
- }
- return FLUID_SAMPLETYPE_MONO;
-}
-
-typedef struct FSample {
- DERIVE_FROM_TYPE(fluid_sample_t);
-
- ALfontsound *Sound;
-
- fluid_mod_t *Mods;
- ALsizei NumMods;
-} FSample;
-
-static void FSample_Construct(FSample *self, ALfontsound *sound, ALsoundfont *sfont)
-{
- fluid_sample_t *sample = STATIC_CAST(fluid_sample_t, self);
- memset(sample->name, 0, sizeof(sample->name));
- sample->start = sound->Start;
- sample->end = sound->End;
- sample->loopstart = sound->LoopStart;
- sample->loopend = sound->LoopEnd;
- sample->samplerate = sound->SampleRate;
- sample->origpitch = sound->PitchKey;
- sample->pitchadj = sound->PitchCorrection;
- sample->sampletype = getSampleType(sound->SampleType);
- sample->valid = 1;
- sample->data = sfont->Samples;
-
- sample->amplitude_that_reaches_noise_floor_is_valid = 0;
- sample->amplitude_that_reaches_noise_floor = 0.0;
-
- sample->refcount = 0;
-
- sample->notify = NULL;
-
- sample->userdata = self;
-
- self->Sound = sound;
-
- self->NumMods = 0;
- self->Mods = calloc(sound->ModulatorMap.size, sizeof(self->Mods[0]));
- if(self->Mods)
- {
- ALsizei i;
-
- self->NumMods = sound->ModulatorMap.size;
- for(i = 0;i < self->NumMods;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;
- }
- }
-}
-
-static void FSample_Destruct(FSample *self)
-{
- free(self->Mods);
- self->Mods = NULL;
- self->NumMods = 0;
-}
-
-
-typedef struct FPreset {
- DERIVE_FROM_TYPE(fluid_preset_t);
-
- char Name[16];
-
- int Preset;
- int Bank;
-
- FSample *Samples;
- ALsizei NumSamples;
-} FPreset;
-
-static char* FPreset_getName(fluid_preset_t *preset);
-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_CAST(fluid_preset_t, self)->data = self;
- STATIC_CAST(fluid_preset_t, self)->sfont = parent;
- STATIC_CAST(fluid_preset_t, self)->free = NULL;
- STATIC_CAST(fluid_preset_t, self)->get_name = FPreset_getName;
- STATIC_CAST(fluid_preset_t, self)->get_banknum = FPreset_getBank;
- STATIC_CAST(fluid_preset_t, self)->get_num = FPreset_getPreset;
- STATIC_CAST(fluid_preset_t, self)->noteon = FPreset_noteOn;
- STATIC_CAST(fluid_preset_t, self)->notify = NULL;
-
- memset(self->Name, 0, sizeof(self->Name));
- self->Preset = preset->Preset;
- self->Bank = preset->Bank;
-
- self->NumSamples = 0;
- self->Samples = calloc(1, preset->NumSounds * sizeof(self->Samples[0]));
- if(self->Samples)
- {
- ALsizei i;
- self->NumSamples = preset->NumSounds;
- for(i = 0;i < self->NumSamples;i++)
- FSample_Construct(&self->Samples[i], preset->Sounds[i], sfont);
- }
-}
-
-static void FPreset_Destruct(FPreset *self)
-{
- ALsizei i;
-
- for(i = 0;i < self->NumSamples;i++)
- FSample_Destruct(&self->Samples[i]);
- free(self->Samples);
- self->Samples = NULL;
- self->NumSamples = 0;
-}
-
-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)
- return AL_FALSE;
- }
- return AL_TRUE;
-}
-
-static char* FPreset_getName(fluid_preset_t *preset)
-{
- return ((FPreset*)preset->data)->Name;
-}
-
-static int FPreset_getPreset(fluid_preset_t *preset)
-{
- return ((FPreset*)preset->data)->Preset;
-}
-
-static int FPreset_getBank(fluid_preset_t *preset)
-{
- return ((FPreset*)preset->data)->Bank;
-}
-
-static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int vel)
-{
- FPreset *self = ((FPreset*)preset->data);
- ALsizei i;
-
- for(i = 0;i < self->NumSamples;i++)
- {
- FSample *sample = &self->Samples[i];
- ALfontsound *sound = sample->Sound;
- fluid_voice_t *voice;
- ALsizei m;
-
- if(!(key >= sound->MinKey && key <= sound->MaxKey && vel >= sound->MinVelocity && vel <= sound->MaxVelocity))
- continue;
-
- voice = fluid_synth_alloc_voice(synth, STATIC_CAST(fluid_sample_t, sample), channel, key, vel);
- if(voice == NULL)
- return FLUID_FAILED;
-
- fluid_voice_gen_set(voice, GEN_MODLFOTOPITCH, sound->ModLfoToPitch);
- fluid_voice_gen_set(voice, GEN_VIBLFOTOPITCH, sound->VibratoLfoToPitch);
- fluid_voice_gen_set(voice, GEN_MODENVTOPITCH, sound->ModEnvToPitch);
- fluid_voice_gen_set(voice, GEN_FILTERFC, sound->FilterCutoff);
- fluid_voice_gen_set(voice, GEN_FILTERQ, sound->FilterQ);
- fluid_voice_gen_set(voice, GEN_MODLFOTOFILTERFC, sound->ModLfoToFilterCutoff);
- fluid_voice_gen_set(voice, GEN_MODENVTOFILTERFC, sound->ModEnvToFilterCutoff);
- fluid_voice_gen_set(voice, GEN_MODLFOTOVOL, sound->ModLfoToVolume);
- fluid_voice_gen_set(voice, GEN_CHORUSSEND, sound->ChorusSend);
- fluid_voice_gen_set(voice, GEN_REVERBSEND, sound->ReverbSend);
- fluid_voice_gen_set(voice, GEN_PAN, sound->Pan);
- fluid_voice_gen_set(voice, GEN_MODLFODELAY, sound->ModLfo.Delay);
- fluid_voice_gen_set(voice, GEN_MODLFOFREQ, sound->ModLfo.Frequency);
- fluid_voice_gen_set(voice, GEN_VIBLFODELAY, sound->VibratoLfo.Delay);
- fluid_voice_gen_set(voice, GEN_VIBLFOFREQ, sound->VibratoLfo.Frequency);
- fluid_voice_gen_set(voice, GEN_MODENVDELAY, sound->ModEnv.DelayTime);
- fluid_voice_gen_set(voice, GEN_MODENVATTACK, sound->ModEnv.AttackTime);
- fluid_voice_gen_set(voice, GEN_MODENVHOLD, sound->ModEnv.HoldTime);
- fluid_voice_gen_set(voice, GEN_MODENVDECAY, sound->ModEnv.DecayTime);
- fluid_voice_gen_set(voice, GEN_MODENVSUSTAIN, sound->ModEnv.SustainAttn);
- fluid_voice_gen_set(voice, GEN_MODENVRELEASE, sound->ModEnv.ReleaseTime);
- fluid_voice_gen_set(voice, GEN_KEYTOMODENVHOLD, sound->ModEnv.KeyToHoldTime);
- fluid_voice_gen_set(voice, GEN_KEYTOMODENVDECAY, sound->ModEnv.KeyToDecayTime);
- fluid_voice_gen_set(voice, GEN_VOLENVDELAY, sound->VolEnv.DelayTime);
- fluid_voice_gen_set(voice, GEN_VOLENVATTACK, sound->VolEnv.AttackTime);
- fluid_voice_gen_set(voice, GEN_VOLENVHOLD, sound->VolEnv.HoldTime);
- fluid_voice_gen_set(voice, GEN_VOLENVDECAY, sound->VolEnv.DecayTime);
- fluid_voice_gen_set(voice, GEN_VOLENVSUSTAIN, sound->VolEnv.SustainAttn);
- fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, sound->VolEnv.ReleaseTime);
- fluid_voice_gen_set(voice, GEN_KEYTOVOLENVHOLD, sound->VolEnv.KeyToHoldTime);
- fluid_voice_gen_set(voice, GEN_KEYTOVOLENVDECAY, sound->VolEnv.KeyToDecayTime);
- fluid_voice_gen_set(voice, GEN_ATTENUATION, sound->Attenuation);
- fluid_voice_gen_set(voice, GEN_COARSETUNE, sound->CoarseTuning);
- fluid_voice_gen_set(voice, GEN_FINETUNE, sound->FineTuning);
- fluid_voice_gen_set(voice, GEN_SAMPLEMODE, getSf2LoopMode(sound->LoopMode));
- fluid_voice_gen_set(voice, GEN_SCALETUNE, sound->TuningScale);
- fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, sound->ExclusiveClass);
- for(m = 0;m < sample->NumMods;m++)
- fluid_voice_add_mod(voice, &sample->Mods[m], FLUID_VOICE_OVERWRITE);
-
- fluid_synth_start_voice(synth, voice);
- }
-
- return FLUID_OK;
-}
-
-
-typedef struct FSfont {
- DERIVE_FROM_TYPE(fluid_sfont_t);
-
- char Name[16];
-
- FPreset *Presets;
- ALsizei NumPresets;
-
- ALsizei CurrentPos;
-} FSfont;
-
-static int FSfont_free(fluid_sfont_t *sfont);
-static char* FSfont_getName(fluid_sfont_t *sfont);
-static fluid_preset_t* FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum);
-static void FSfont_iterStart(fluid_sfont_t *sfont);
-static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset);
-
-static void FSfont_Construct(FSfont *self, ALsoundfont *sfont)
-{
- STATIC_CAST(fluid_sfont_t, self)->data = self;
- STATIC_CAST(fluid_sfont_t, self)->id = FLUID_FAILED;
- STATIC_CAST(fluid_sfont_t, self)->free = FSfont_free;
- STATIC_CAST(fluid_sfont_t, self)->get_name = FSfont_getName;
- STATIC_CAST(fluid_sfont_t, self)->get_preset = FSfont_getPreset;
- STATIC_CAST(fluid_sfont_t, self)->iteration_start = FSfont_iterStart;
- STATIC_CAST(fluid_sfont_t, self)->iteration_next = FSfont_iterNext;
-
- memset(self->Name, 0, sizeof(self->Name));
- self->CurrentPos = 0;
- self->NumPresets = 0;
- self->Presets = calloc(1, sfont->NumPresets * sizeof(self->Presets[0]));
- if(self->Presets)
- {
- 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);
- }
-}
-
-static void FSfont_Destruct(FSfont *self)
-{
- ALsizei i;
-
- for(i = 0;i < self->NumPresets;i++)
- FPreset_Destruct(&self->Presets[i]);
- free(self->Presets);
- self->Presets = NULL;
- self->NumPresets = 0;
- self->CurrentPos = 0;
-}
-
-static int FSfont_free(fluid_sfont_t *sfont)
-{
- FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
- ALsizei i;
-
- for(i = 0;i < self->NumPresets;i++)
- {
- if(!FPreset_canDelete(&self->Presets[i]))
- return 1;
- }
-
- FSfont_Destruct(self);
- free(self);
- return 0;
-}
-
-static char* FSfont_getName(fluid_sfont_t *sfont)
-{
- return STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->Name;
-}
-
-static fluid_preset_t *FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum)
-{
- FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
- ALsizei i;
-
- for(i = 0;i < self->NumPresets;i++)
- {
- FPreset *preset = &self->Presets[i];
- if(preset->Bank == (int)bank && preset->Preset == (int)prenum)
- return STATIC_CAST(fluid_preset_t, preset);
- }
-
- return NULL;
-}
-
-static void FSfont_iterStart(fluid_sfont_t *sfont)
-{
- STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->CurrentPos = 0;
-}
-
-static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset)
-{
- FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont);
- if(self->CurrentPos >= self->NumPresets)
- return 0;
- *preset = *STATIC_CAST(fluid_preset_t, &self->Presets[self->CurrentPos++]);
- preset->free = NULL;
- return 1;
-}
-
-
-typedef struct FSynth {
- DERIVE_FROM_TYPE(MidiSynth);
- DERIVE_FROM_TYPE(fluid_sfloader_t);
-
- fluid_settings_t *Settings;
- fluid_synth_t *Synth;
- int *FontIDs;
- ALsizei NumFontIDs;
-
- ALboolean ForceGM2BankSelect;
- ALfloat GainScale;
-} FSynth;
-
-static void FSynth_Construct(FSynth *self, ALCdevice *device);
-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_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]);
-DECLARE_DEFAULT_ALLOCATORS(FSynth)
-DEFINE_MIDISYNTH_VTABLE(FSynth);
-
-static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename);
-
-
-static void FSynth_Construct(FSynth *self, ALCdevice *device)
-{
- MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device);
- SET_VTABLE2(FSynth, MidiSynth, self);
-
- STATIC_CAST(fluid_sfloader_t, self)->data = self;
- STATIC_CAST(fluid_sfloader_t, self)->free = NULL;
- STATIC_CAST(fluid_sfloader_t, self)->load = FSynth_loadSfont;
-
- self->Settings = NULL;
- self->Synth = NULL;
- self->FontIDs = NULL;
- self->NumFontIDs = 0;
- self->ForceGM2BankSelect = AL_FALSE;
- self->GainScale = 0.2f;
-}
-
-static void FSynth_Destruct(FSynth *self)
-{
- ALsizei i;
-
- for(i = 0;i < self->NumFontIDs;i++)
- fluid_synth_sfunload(self->Synth, self->FontIDs[i], 0);
- free(self->FontIDs);
- self->FontIDs = NULL;
- self->NumFontIDs = 0;
-
- if(self->Synth != NULL)
- delete_fluid_synth(self->Synth);
- self->Synth = NULL;
-
- if(self->Settings != NULL)
- delete_fluid_settings(self->Settings);
- self->Settings = NULL;
-
- MidiSynth_Destruct(STATIC_CAST(MidiSynth, self));
-}
-
-static ALboolean FSynth_init(FSynth *self, ALCdevice *device)
-{
- ALfloat vol;
-
- if(ConfigValueFloat("midi", "volume", &vol))
- {
- if(!(vol <= 0.0f))
- {
- ERR("MIDI volume %f clamped to 0\n", vol);
- vol = 0.0f;
- }
- self->GainScale = powf(10.0f, vol / 20.0f);
- }
-
- self->Settings = new_fluid_settings();
- if(!self->Settings)
- {
- ERR("Failed to create FluidSettings\n");
- return AL_FALSE;
- }
-
- fluid_settings_setint(self->Settings, "synth.polyphony", 256);
- fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale);
- fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
-
- self->Synth = new_fluid_synth(self->Settings);
- if(!self->Synth)
- {
- ERR("Failed to create FluidSynth\n");
- return AL_FALSE;
- }
-
- fluid_synth_add_sfloader(self->Synth, STATIC_CAST(fluid_sfloader_t, self));
-
- return AL_TRUE;
-}
-
-
-static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename)
-{
- FSynth *self = STATIC_UPCAST(FSynth, fluid_sfloader_t, loader);
- FSfont *sfont;
- int idx;
-
- if(!filename || sscanf(filename, "_al_internal %d", &idx) != 1)
- return NULL;
- if(idx < 0 || idx >= STATIC_CAST(MidiSynth, self)->NumSoundfonts)
- {
- ERR("Received invalid soundfont index %d (max: %d)\n", idx, STATIC_CAST(MidiSynth, self)->NumSoundfonts);
- return NULL;
- }
-
- sfont = calloc(1, sizeof(sfont[0]));
- if(!sfont) return NULL;
-
- FSfont_Construct(sfont, STATIC_CAST(MidiSynth, self)->Soundfonts[idx]);
- return STATIC_CAST(fluid_sfont_t, sfont);
-}
-
-static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids)
-{
- int *fontid;
- ALenum ret;
- ALsizei i;
-
- ret = MidiSynth_selectSoundfonts(STATIC_CAST(MidiSynth, self), context, count, ids);
- if(ret != AL_NO_ERROR) return ret;
-
- ALCdevice_Lock(context->Device);
- for(i = 0;i < 16;i++)
- fluid_synth_all_sounds_off(self->Synth, i);
- ALCdevice_Unlock(context->Device);
-
- fontid = malloc(count * sizeof(fontid[0]));
- if(fontid)
- {
- for(i = 0;i < STATIC_CAST(MidiSynth, self)->NumSoundfonts;i++)
- {
- char name[16];
- snprintf(name, sizeof(name), "_al_internal %d", i);
-
- fontid[i] = fluid_synth_sfload(self->Synth, name, 0);
- if(fontid[i] == FLUID_FAILED)
- ERR("Failed to load selected soundfont %d\n", i);
- }
-
- fontid = ExchangePtr((XchgPtr*)&self->FontIDs, fontid);
- count = ExchangeInt(&self->NumFontIDs, count);
- }
- else
- {
- ERR("Failed to allocate space for %d font IDs!\n", count);
- fontid = ExchangePtr((XchgPtr*)&self->FontIDs, NULL);
- count = ExchangeInt(&self->NumFontIDs, 0);
- }
-
- for(i = 0;i < count;i++)
- fluid_synth_sfunload(self->Synth, fontid[i], 0);
- free(fontid);
-
- return ret;
-}
-
-
-static void FSynth_setGain(FSynth *self, ALfloat gain)
-{
- fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale * gain);
- fluid_synth_set_gain(self->Synth, self->GainScale * gain);
- MidiSynth_setGain(STATIC_CAST(MidiSynth, self), gain);
-}
-
-
-static void FSynth_stop(FSynth *self)
-{
- MidiSynth *synth = STATIC_CAST(MidiSynth, self);
- ALuint64 curtime;
- ALsizei chan;
-
- /* Make sure all pending events are processed. */
- curtime = MidiSynth_getTime(synth);
- FSynth_processQueue(self, curtime);
-
- /* All notes off */
- for(chan = 0;chan < 16;chan++)
- fluid_synth_cc(self->Synth, chan, CTRL_ALLNOTESOFF, 0);
-
- MidiSynth_stop(STATIC_CAST(MidiSynth, self));
-}
-
-static void FSynth_reset(FSynth *self)
-{
- /* Reset to power-up status. */
- fluid_synth_system_reset(self->Synth);
-
- MidiSynth_reset(STATIC_CAST(MidiSynth, self));
-}
-
-
-static void FSynth_update(FSynth *self, ALCdevice *device)
-{
- fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency);
- fluid_synth_set_sample_rate(self->Synth, device->Frequency);
- MidiSynth_update(STATIC_CAST(MidiSynth, self), device);
-}
-
-
-static void FSynth_processQueue(FSynth *self, ALuint64 time)
-{
- EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue;
-
- while(queue->pos < queue->size && queue->events[queue->pos].time <= time)
- {
- const MidiEvent *evt = &queue->events[queue->pos];
-
- if(evt->event == SYSEX_EVENT)
- {
- static const ALbyte gm2_on[] = { 0x7E, 0x7F, 0x09, 0x03 };
- static const ALbyte gm2_off[] = { 0x7E, 0x7F, 0x09, 0x02 };
- int handled = 0;
-
- fluid_synth_sysex(self->Synth, evt->param.sysex.data, evt->param.sysex.size, NULL, NULL, &handled, 0);
- if(!handled && evt->param.sysex.size >= (ALsizei)sizeof(gm2_on))
- {
- if(memcmp(evt->param.sysex.data, gm2_on, sizeof(gm2_on)) == 0)
- self->ForceGM2BankSelect = AL_TRUE;
- else if(memcmp(evt->param.sysex.data, gm2_off, sizeof(gm2_off)) == 0)
- self->ForceGM2BankSelect = AL_FALSE;
- }
- }
- else switch((evt->event&0xF0))
- {
- case AL_NOTEOFF_SOFT:
- fluid_synth_noteoff(self->Synth, (evt->event&0x0F), evt->param.val[0]);
- break;
- case AL_NOTEON_SOFT:
- fluid_synth_noteon(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
- break;
- case AL_KEYPRESSURE_SOFT:
- break;
-
- case AL_CONTROLLERCHANGE_SOFT:
- if(self->ForceGM2BankSelect)
- {
- int chan = (evt->event&0x0F);
- if(evt->param.val[0] == CTRL_BANKSELECT_MSB)
- {
- if(evt->param.val[1] == 120 && (chan == 9 || chan == 10))
- fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_DRUM);
- else if(evt->param.val[1] == 121)
- fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_MELODIC);
- break;
- }
- if(evt->param.val[0] == CTRL_BANKSELECT_LSB)
- {
- fluid_synth_bank_select(self->Synth, chan, evt->param.val[1]);
- break;
- }
- }
- fluid_synth_cc(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]);
- break;
- case AL_PROGRAMCHANGE_SOFT:
- fluid_synth_program_change(self->Synth, (evt->event&0x0F), evt->param.val[0]);
- break;
-
- case AL_CHANNELPRESSURE_SOFT:
- fluid_synth_channel_pressure(self->Synth, (evt->event&0x0F), evt->param.val[0]);
- break;
-
- case AL_PITCHBEND_SOFT:
- fluid_synth_pitch_bend(self->Synth, (evt->event&0x0F), (evt->param.val[0]&0x7F) |
- ((evt->param.val[1]&0x7F)<<7));
- break;
- }
-
- queue->pos++;
- }
-}
-
-static void FSynth_process(FSynth *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)
- {
- fluid_synth_write_float(self->Synth, SamplesToDo, DryBuffer[FrontLeft], 0, 1,
- DryBuffer[FrontRight], 0, 1);
- 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;
- }
-
- if(tonext > 0)
- {
- ALuint todo = mini(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);
- }
-
- synth->SamplesDone += SamplesToDo;
- synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES;
- synth->SamplesDone %= synth->SampleRate;
-}
-
-
-MidiSynth *FSynth_create(ALCdevice *device)
-{
- FSynth *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)
- {
- DELETE_OBJ(STATIC_CAST(MidiSynth, synth));
- return NULL;
- }
-
- return STATIC_CAST(MidiSynth, synth);
-}
-
-#else
-
-MidiSynth *FSynth_create(ALCdevice* UNUSED(device))
-{
- return NULL;
-}
-
-#endif
diff --git a/Alc/midi/sf2load.c b/Alc/midi/sf2load.c
deleted file mode 100644
index 2bc94133..00000000
--- a/Alc/midi/sf2load.c
+++ /dev/null
@@ -1,1364 +0,0 @@
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "alMain.h"
-#include "alMidi.h"
-#include "alError.h"
-#include "alu.h"
-
-#include "midi/base.h"
-
-
-static ALuint read_le32(Reader *stream)
-{
- ALubyte buf[4];
- if(READ(stream, buf, 4) != 4)
- {
- READERR(stream) = 1;
- 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;
- 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;
- return 0;
- }
- return buf[0];
-}
-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 || got > amt)
- READERR(stream) = 1;
-
- amt -= (ALuint)got;
- }
-}
-
-typedef struct Generator {
- ALushort mGenerator;
- ALushort mAmount;
-} Generator;
-static void Generator_read(Generator *self, Reader *stream)
-{
- self->mGenerator = read_le16(stream);
- self->mAmount = read_le16(stream);
-}
-
-static const ALint DefaultGenValue[60] = {
- 0, /* 0 - startAddrOffset */
- 0, /* 1 - endAddrOffset */
- 0, /* 2 - startloopAddrOffset */
- 0, /* 3 - endloopAddrOffset */
- 0, /* 4 - startAddrCoarseOffset */
- 0, /* 5 - modLfoToPitch */
- 0, /* 6 - vibLfoToPitch */
- 0, /* 7 - modEnvToPitch */
- 13500, /* 8 - initialFilterFc */
- 0, /* 9 - initialFilterQ */
- 0, /* 10 - modLfoToFilterFc */
- 0, /* 11 - modEnvToFilterFc */
- 0, /* 12 - endAddrCoarseOffset */
- 0, /* 13 - modLfoToVolume */
- 0, /* 14 - */
- 0, /* 15 - chorusEffectsSend */
- 0, /* 16 - reverbEffectsSend */
- 0, /* 17 - pan */
- 0, /* 18 - */
- 0, /* 19 - */
- 0, /* 20 - */
- -12000, /* 21 - delayModLFO */
- 0, /* 22 - freqModLFO */
- -12000, /* 23 - delayVibLFO */
- 0, /* 24 - freqVibLFO */
- -12000, /* 25 - delayModEnv */
- -12000, /* 26 - attackModEnv */
- -12000, /* 27 - holdModEnv */
- -12000, /* 28 - decayModEnv */
- 0, /* 29 - sustainModEnv */
- -12000, /* 30 - releaseModEnv */
- 0, /* 31 - keynumToModEnvHold */
- 0, /* 32 - keynumToModEnvDecay */
- -12000, /* 33 - delayVolEnv */
- -12000, /* 34 - attackVolEnv */
- -12000, /* 35 - holdVolEnv */
- -12000, /* 36 - decayVolEnv */
- 0, /* 37 - sustainVolEnv */
- -12000, /* 38 - releaseVolEnv */
- 0, /* 39 - keynumToVolEnvHold */
- 0, /* 40 - keynumToVolEnvDecay */
- 0, /* 41 - */
- 0, /* 42 - */
- 0, /* 43 - keyRange */
- 0, /* 44 - velRange */
- 0, /* 45 - startloopAddrCoarseOffset */
- 0, /* 46 - keynum */
- 0, /* 47 - velocity */
- 0, /* 48 - initialAttenuation */
- 0, /* 49 - */
- 0, /* 50 - endloopAddrCoarseOffset */
- 0, /* 51 - corseTune */
- 0, /* 52 - fineTune */
- 0, /* 53 - */
- 0, /* 54 - sampleModes */
- 0, /* 55 - */
- 100, /* 56 - scaleTuning */
- 0, /* 57 - exclusiveClass */
- 0, /* 58 - overridingRootKey */
- 0, /* 59 - */
-};
-
-typedef struct Modulator {
- ALushort mSrcOp;
- ALushort mDstOp;
- ALshort mAmount;
- ALushort mAmtSrcOp;
- ALushort mTransOp;
-} Modulator;
-static void Modulator_read(Modulator *self, Reader *stream)
-{
- self->mSrcOp = read_le16(stream);
- self->mDstOp = read_le16(stream);
- self->mAmount = read_le16(stream);
- self->mAmtSrcOp = read_le16(stream);
- self->mTransOp = read_le16(stream);
-}
-
-typedef struct Zone {
- ALushort mGenIdx;
- ALushort mModIdx;
-} Zone;
-static void Zone_read(Zone *self, Reader *stream)
-{
- self->mGenIdx = read_le16(stream);
- self->mModIdx = read_le16(stream);
-}
-
-typedef struct PresetHeader {
- ALchar mName[20];
- ALushort mPreset; /* MIDI program number */
- ALushort mBank;
- ALushort mZoneIdx;
- ALuint mLibrary;
- ALuint mGenre;
- ALuint mMorphology;
-} PresetHeader;
-static void PresetHeader_read(PresetHeader *self, Reader *stream)
-{
- if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
- READERR(stream) = 1;
- self->mPreset = read_le16(stream);
- self->mBank = read_le16(stream);
- self->mZoneIdx = read_le16(stream);
- self->mLibrary = read_le32(stream);
- self->mGenre = read_le32(stream);
- self->mMorphology = read_le32(stream);
-}
-
-typedef struct InstrumentHeader {
- ALchar mName[20];
- ALushort mZoneIdx;
-} InstrumentHeader;
-static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream)
-{
- if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
- READERR(stream) = 1;
- self->mZoneIdx = read_le16(stream);
-}
-
-typedef struct SampleHeader {
- ALchar mName[20]; // 20 bytes
- ALuint mStart;
- ALuint mEnd;
- ALuint mStartloop;
- ALuint mEndloop;
- ALuint mSampleRate;
- ALubyte mOriginalKey;
- ALbyte mCorrection;
- ALushort mSampleLink;
- ALushort mSampleType;
-} SampleHeader;
-static void SampleHeader_read(SampleHeader *self, Reader *stream)
-{
- if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
- READERR(stream) = 1;
- self->mStart = read_le32(stream);
- self->mEnd = read_le32(stream);
- self->mStartloop = read_le32(stream);
- self->mEndloop = read_le32(stream);
- self->mSampleRate = read_le32(stream);
- self->mOriginalKey = read_8(stream);
- self->mCorrection = read_8(stream);
- self->mSampleLink = read_le16(stream);
- self->mSampleType = read_le16(stream);
-}
-
-
-typedef struct Soundfont {
- ALuint ifil;
- ALchar *irom;
-
- PresetHeader *phdr;
- ALsizei phdr_size;
-
- Zone *pbag;
- ALsizei pbag_size;
- Modulator *pmod;
- ALsizei pmod_size;
- Generator *pgen;
- ALsizei pgen_size;
-
- InstrumentHeader *inst;
- ALsizei inst_size;
-
- Zone *ibag;
- ALsizei ibag_size;
- Modulator *imod;
- ALsizei imod_size;
- Generator *igen;
- ALsizei igen_size;
-
- SampleHeader *shdr;
- ALsizei shdr_size;
-} Soundfont;
-
-static void Soundfont_Construct(Soundfont *self)
-{
- self->ifil = 0;
- self->irom = NULL;
-
- self->phdr = NULL;
- self->phdr_size = 0;
-
- self->pbag = NULL;
- self->pbag_size = 0;
- self->pmod = NULL;
- self->pmod_size = 0;
- self->pgen = NULL;
- self->pgen_size = 0;
-
- self->inst = NULL;
- self->inst_size = 0;
-
- self->ibag = NULL;
- self->ibag_size = 0;
- self->imod = NULL;
- self->imod_size = 0;
- self->igen = NULL;
- self->igen_size = 0;
-
- self->shdr = NULL;
- self->shdr_size = 0;
-}
-
-static void Soundfont_Destruct(Soundfont *self)
-{
- free(self->irom);
- self->irom = NULL;
-
- free(self->phdr);
- self->phdr = NULL;
- self->phdr_size = 0;
-
- free(self->pbag);
- self->pbag = NULL;
- self->pbag_size = 0;
- free(self->pmod);
- self->pmod = NULL;
- self->pmod_size = 0;
- free(self->pgen);
- self->pgen = NULL;
- self->pgen_size = 0;
-
- free(self->inst);
- self->inst = NULL;
- self->inst_size = 0;
-
- free(self->ibag);
- self->ibag = NULL;
- self->ibag_size = 0;
- free(self->imod);
- self->imod = NULL;
- self->imod_size = 0;
- free(self->igen);
- self->igen = NULL;
- self->igen_size = 0;
-
- free(self->shdr);
- self->shdr = NULL;
- self->shdr_size = 0;
-}
-
-
-#define FOURCC(a,b,c,d) (((d)<<24) | ((c)<<16) | ((b)<<8) | (a))
-#define FOURCCARGS(x) (char)((x)&0xff), (char)(((x)>>8)&0xff), (char)(((x)>>16)&0xff), (char)(((x)>>24)&0xff)
-typedef struct RiffHdr {
- ALuint mCode;
- ALuint mSize;
-} RiffHdr;
-static void RiffHdr_read(RiffHdr *self, Reader *stream)
-{
- self->mCode = read_le32(stream);
- self->mSize = read_le32(stream);
-}
-
-
-DECL_VECTOR(Generator)
-DECL_VECTOR(Modulator)
-
-typedef struct GenModList {
- vector_Generator gens;
- vector_Modulator mods;
-} GenModList;
-
-static void GenModList_Construct(GenModList *self)
-{
- VECTOR_INIT(self->gens);
- VECTOR_INIT(self->mods);
-}
-
-static void GenModList_Destruct(GenModList *self)
-{
- VECTOR_DEINIT(self->mods);
- VECTOR_DEINIT(self->gens);
-}
-
-static GenModList GenModList_clone(const GenModList *self)
-{
- GenModList ret;
-
- GenModList_Construct(&ret);
-
- 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 = VECTOR_ITER_BEGIN(self->gens);
- Generator *end = VECTOR_ITER_END(self->gens);
- for(;i != end;i++)
- {
- if(i->mGenerator == gen->mGenerator)
- {
- i->mAmount = gen->mAmount;
- return;
- }
- }
-
- if(ispreset &&
- (gen->mGenerator == 0 || gen->mGenerator == 1 || gen->mGenerator == 2 ||
- gen->mGenerator == 3 || gen->mGenerator == 4 || gen->mGenerator == 12 ||
- gen->mGenerator == 45 || gen->mGenerator == 46 || gen->mGenerator == 47 ||
- gen->mGenerator == 50 || gen->mGenerator == 54 || gen->mGenerator == 57 ||
- gen->mGenerator == 58))
- return;
-
- if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE)
- {
- ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens));
- return;
- }
-}
-static void GenModList_accumGen(GenModList *self, const Generator *gen)
-{
- Generator *i = VECTOR_ITER_BEGIN(self->gens);
- Generator *end = VECTOR_ITER_END(self->gens);
- for(;i != end;i++)
- {
- if(i->mGenerator == gen->mGenerator)
- {
- if(gen->mGenerator == 43 || gen->mGenerator == 44)
- {
- /* Range generators accumulate by taking the intersection of
- * the two ranges.
- */
- ALushort low = maxu(i->mAmount&0x00ff, gen->mAmount&0x00ff);
- ALushort high = minu(i->mAmount&0xff00, gen->mAmount&0xff00);
- i->mAmount = low | high;
- }
- else
- i->mAmount += gen->mAmount;
- return;
- }
- }
-
- if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE)
- {
- ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens));
- return;
- }
- if(gen->mGenerator < 60)
- VECTOR_BACK(self->gens).mAmount += DefaultGenValue[gen->mGenerator];
-}
-
-static void GenModList_insertMod(GenModList *self, const Modulator *mod)
-{
- 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 &&
- i->mAmtSrcOp == mod->mAmtSrcOp && i->mTransOp == mod->mTransOp)
- {
- i->mAmount = mod->mAmount;
- return;
- }
- }
-
- if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE)
- {
- ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods));
- return;
- }
-}
-static void GenModList_accumMod(GenModList *self, const Modulator *mod)
-{
- 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 &&
- i->mAmtSrcOp == mod->mAmtSrcOp && i->mTransOp == mod->mTransOp)
- {
- i->mAmount += mod->mAmount;
- return;
- }
- }
-
- if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE)
- {
- ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods));
- return;
- }
-
- if(mod->mSrcOp == 0x0502 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 960;
- else if(mod->mSrcOp == 0x0102 && mod->mDstOp == 8 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += -2400;
- else if(mod->mSrcOp == 0x000D && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 50;
- else if(mod->mSrcOp == 0x0081 && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 50;
- else if(mod->mSrcOp == 0x0582 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 960;
- else if(mod->mSrcOp == 0x028A && mod->mDstOp == 17 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 1000;
- else if(mod->mSrcOp == 0x058B && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 960;
- else if(mod->mSrcOp == 0x00DB && mod->mDstOp == 16 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 200;
- else if(mod->mSrcOp == 0x00DD && mod->mDstOp == 15 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 200;
- /*else if(mod->mSrcOp == 0x020E && mod->mDstOp == ?initialpitch? && mod->mAmtSrcOp == 0x0010 && mod->mTransOp == 0)
- VECTOR_BACK(self->mods).mAmount += 12700;*/
-}
-
-
-#define ERROR_GOTO(lbl_, ...) do { \
- ERR(__VA_ARGS__); \
- goto lbl_; \
-} while(0)
-
-static ALboolean ensureFontSanity(const Soundfont *sfont)
-{
- ALsizei i;
-
- for(i = 0;i < sfont->phdr_size-1;i++)
- {
- 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;
- }
- if(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++)
- {
- 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+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);
- 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;
- }
- if(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++)
- {
- 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;
- }
- if(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++)
- {
- 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+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);
- 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;
- }
- if(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++)
- {
- if((sfont->shdr[i].mSampleType&0x8000) && sfont->irom == NULL)
- {
- WARN("Sample header %d has ROM sample type without an irom sub-chunk\n", i);
- return AL_FALSE;
- }
- }
-
-
- return AL_TRUE;
-}
-
-static ALboolean checkZone(const GenModList *zone, const PresetHeader *preset, const InstrumentHeader *inst, const SampleHeader *samp)
-{
- Generator *gen = VECTOR_ITER_BEGIN(zone->gens);
- Generator *gen_end = VECTOR_ITER_END(zone->gens);
- for(;gen != gen_end;gen++)
- {
- if(gen->mGenerator == 43 || gen->mGenerator == 44)
- {
- 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,
- (gen->mGenerator == 43) ? "key" :
- (gen->mGenerator == 44) ? "velocity" : "(unknown)",
- low, high);
- return AL_FALSE;
- }
- }
- }
-
- return AL_TRUE;
-}
-
-static ALenum getModSrcInput(int input)
-{
- if(input == 0) return AL_ONE_SOFT;
- if(input == 2) return AL_NOTEON_VELOCITY_SOFT;
- if(input == 3) return AL_NOTEON_KEY_SOFT;
- if(input == 10) return AL_KEYPRESSURE_SOFT;
- if(input == 13) return AL_CHANNELPRESSURE_SOFT;
- if(input == 14) return AL_PITCHBEND_SOFT;
- 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;
- }
- ERR("Unhandled modulator source input: 0x%02x\n", input);
- return AL_INVALID;
-}
-
-static ALenum getModSrcType(int type)
-{
- if(type == 0x0000) return AL_UNORM_SOFT;
- if(type == 0x0100) return AL_UNORM_REV_SOFT;
- if(type == 0x0200) return AL_SNORM_SOFT;
- if(type == 0x0300) return AL_SNORM_REV_SOFT;
- ERR("Unhandled modulator source type: 0x%04x\n", type);
- return AL_INVALID;
-}
-
-static ALenum getModSrcForm(int form)
-{
- if(form == 0x0000) return AL_LINEAR_SOFT;
- if(form == 0x0400) return AL_CONCAVE_SOFT;
- if(form == 0x0800) return AL_CONVEX_SOFT;
- if(form == 0x0C00) return AL_SWITCH_SOFT;
- ERR("Unhandled modulator source form: 0x%04x\n", form);
- return AL_INVALID;
-}
-
-static ALenum getModTransOp(int op)
-{
- if(op == 0) return AL_LINEAR_SOFT;
- if(op == 2) return AL_ABSOLUTE_SOFT;
- ERR("Unhandled modulator transform op: 0x%04x\n", op);
- return AL_INVALID;
-}
-
-static ALenum getLoopMode(int mode)
-{
- if(mode == 0) return AL_NONE;
- if(mode == 1) return AL_LOOP_CONTINUOUS_SOFT;
- if(mode == 3) return AL_LOOP_UNTIL_RELEASE_SOFT;
- ERR("Unhandled loop mode: %d\n", mode);
- return AL_NONE;
-}
-
-static ALenum getSampleType(int type)
-{
- if(type == 1) return AL_MONO_SOFT;
- if(type == 2) return AL_RIGHT_SOFT;
- if(type == 4) return AL_LEFT_SOFT;
- if(type == 8)
- {
- WARN("Sample type \"linked\" ignored; pretending mono\n");
- return AL_MONO_SOFT;
- }
- ERR("Unhandled sample type: 0x%04x\n", type);
- return AL_MONO_SOFT;
-}
-
-static void fillZone(ALfontsound *sound, ALCcontext *context, const GenModList *zone)
-{
- static const ALenum Gen2Param[60] = {
- 0, /* 0 - startAddrOffset */
- 0, /* 1 - endAddrOffset */
- 0, /* 2 - startloopAddrOffset */
- 0, /* 3 - endloopAddrOffset */
- 0, /* 4 - startAddrCoarseOffset */
- AL_MOD_LFO_TO_PITCH_SOFT, /* 5 - modLfoToPitch */
- AL_VIBRATO_LFO_TO_PITCH_SOFT, /* 6 - vibLfoToPitch */
- AL_MOD_ENV_TO_PITCH_SOFT, /* 7 - modEnvToPitch */
- AL_FILTER_CUTOFF_SOFT, /* 8 - initialFilterFc */
- AL_FILTER_RESONANCE_SOFT, /* 9 - initialFilterQ */
- AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT, /* 10 - modLfoToFilterFc */
- AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT, /* 11 - modEnvToFilterFc */
- 0, /* 12 - endAddrCoarseOffset */
- AL_MOD_LFO_TO_VOLUME_SOFT, /* 13 - modLfoToVolume */
- 0, /* 14 - */
- AL_CHORUS_SEND_SOFT, /* 15 - chorusEffectsSend */
- AL_REVERB_SEND_SOFT, /* 16 - reverbEffectsSend */
- AL_PAN_SOFT, /* 17 - pan */
- 0, /* 18 - */
- 0, /* 19 - */
- 0, /* 20 - */
- AL_MOD_LFO_DELAY_SOFT, /* 21 - delayModLFO */
- AL_MOD_LFO_FREQUENCY_SOFT, /* 22 - freqModLFO */
- AL_VIBRATO_LFO_DELAY_SOFT, /* 23 - delayVibLFO */
- AL_VIBRATO_LFO_FREQUENCY_SOFT, /* 24 - freqVibLFO */
- AL_MOD_ENV_DELAYTIME_SOFT, /* 25 - delayModEnv */
- AL_MOD_ENV_ATTACKTIME_SOFT, /* 26 - attackModEnv */
- AL_MOD_ENV_HOLDTIME_SOFT, /* 27 - holdModEnv */
- AL_MOD_ENV_DECAYTIME_SOFT, /* 28 - decayModEnv */
- AL_MOD_ENV_SUSTAINVOLUME_SOFT, /* 29 - sustainModEnv */
- AL_MOD_ENV_RELEASETIME_SOFT, /* 30 - releaseModEnv */
- AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT, /* 31 - keynumToModEnvHold */
- AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT, /* 32 - keynumToModEnvDecay */
- AL_VOLUME_ENV_DELAYTIME_SOFT, /* 33 - delayVolEnv */
- AL_VOLUME_ENV_ATTACKTIME_SOFT, /* 34 - attackVolEnv */
- AL_VOLUME_ENV_HOLDTIME_SOFT, /* 35 - holdVolEnv */
- AL_VOLUME_ENV_DECAYTIME_SOFT, /* 36 - decayVolEnv */
- AL_VOLUME_ENV_SUSTAINVOLUME_SOFT, /* 37 - sustainVolEnv */
- AL_VOLUME_ENV_RELEASETIME_SOFT, /* 38 - releaseVolEnv */
- AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT, /* 39 - keynumToVolEnvHold */
- AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT, /* 40 - keynumToVolEnvDecay */
- 0, /* 41 - */
- 0, /* 42 - */
- AL_KEY_RANGE_SOFT, /* 43 - keyRange */
- AL_VELOCITY_RANGE_SOFT, /* 44 - velRange */
- 0, /* 45 - startloopAddrCoarseOffset */
- 0, /* 46 - keynum */
- 0, /* 47 - velocity */
- AL_ATTENUATION_SOFT, /* 48 - initialAttenuation */
- 0, /* 49 - */
- 0, /* 50 - endloopAddrCoarseOffset */
- AL_TUNING_COARSE_SOFT, /* 51 - corseTune */
- AL_TUNING_FINE_SOFT, /* 52 - fineTune */
- 0, /* 53 - */
- AL_LOOP_MODE_SOFT, /* 54 - sampleModes */
- 0, /* 55 - */
- AL_TUNING_SCALE_SOFT, /* 56 - scaleTuning */
- AL_EXCLUSIVE_CLASS_SOFT, /* 57 - exclusiveClass */
- AL_BASE_KEY_SOFT, /* 58 - overridingRootKey */
- 0, /* 59 - */
- };
- const Generator *gen, *gen_end;
- const Modulator *mod, *mod_end;
-
- mod = VECTOR_ITER_BEGIN(zone->mods);
- mod_end = VECTOR_ITER_END(zone->mods);
- for(;mod != mod_end;mod++)
- {
- 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)
- {
- 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 = VECTOR_ITER_BEGIN(zone->gens);
- gen_end = VECTOR_ITER_END(zone->gens);
- for(;gen != gen_end;gen++)
- {
- ALint value = (ALshort)gen->mAmount;
- if(gen->mGenerator == 0)
- sound->Start += value;
- else if(gen->mGenerator == 1)
- sound->End += value;
- else if(gen->mGenerator == 2)
- sound->LoopStart += value;
- else if(gen->mGenerator == 3)
- sound->LoopEnd += value;
- else if(gen->mGenerator == 4)
- sound->Start += value<<15;
- else if(gen->mGenerator == 12)
- sound->End += value<<15;
- else if(gen->mGenerator == 45)
- sound->LoopStart += value<<15;
- else if(gen->mGenerator == 50)
- sound->LoopEnd += value<<15;
- else if(gen->mGenerator == 43)
- {
- sound->MinKey = mini((value&0xff), 127);
- sound->MaxKey = mini(((value>>8)&0xff), 127);
- }
- else if(gen->mGenerator == 44)
- {
- sound->MinVelocity = mini((value&0xff), 127);
- sound->MaxVelocity = mini(((value>>8)&0xff), 127);
- }
- else
- {
- ALenum param = 0;
- if(gen->mGenerator < 60)
- param = Gen2Param[gen->mGenerator];
- if(param)
- {
- if(param == AL_BASE_KEY_SOFT)
- {
- if(!(value >= 0 && value <= 127))
- {
- if(value != -1)
- WARN("Invalid overridingRootKey generator value %d\n", value);
- continue;
- }
- }
- if(param == AL_FILTER_RESONANCE_SOFT || param == AL_ATTENUATION_SOFT)
- value = maxi(0, value);
- else if(param == AL_CHORUS_SEND_SOFT || param == AL_REVERB_SEND_SOFT)
- value = clampi(value, 0, 1000);
- else if(param == AL_LOOP_MODE_SOFT)
- value = getLoopMode(value);
- ALfontsound_setPropi(sound, context, param, value);
- }
- else if(gen->mGenerator < 256)
- {
- static ALboolean warned[256];
- if(!warned[gen->mGenerator])
- {
- warned[gen->mGenerator] = AL_TRUE;
- ERR("Unhandled generator %d\n", gen->mGenerator);
- }
- }
- }
- }
-}
-
-static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCcontext *context, InstrumentHeader *inst, const PresetHeader *preset, const Soundfont *sfont, const GenModList *pzone)
-{
- const Generator *gen, *gen_end;
- const Modulator *mod, *mod_end;
- const Zone *zone, *zone_end;
- GenModList gzone;
- ALvoid *temp;
-
- if((inst+1)->mZoneIdx == inst->mZoneIdx)
- ERR("Instrument with no zones!");
-
- GenModList_Construct(&gzone);
- zone = sfont->ibag + inst->mZoneIdx;
- zone_end = sfont->ibag + (inst+1)->mZoneIdx;
- if(zone_end-zone > 1)
- {
- gen = sfont->igen + zone->mGenIdx;
- gen_end = sfont->igen + (zone+1)->mGenIdx;
-
- // If no generators, or last generator is not a sample, this is a global zone
- for(;gen != gen_end;gen++)
- {
- if(gen->mGenerator == 53)
- break;
- }
-
- if(gen == gen_end)
- {
- gen = sfont->igen + zone->mGenIdx;
- gen_end = sfont->igen + (zone+1)->mGenIdx;
- for(;gen != gen_end;gen++)
- GenModList_insertGen(&gzone, gen, AL_FALSE);
-
- mod = sfont->imod + zone->mModIdx;
- mod_end = sfont->imod + (zone+1)->mModIdx;
- for(;mod != mod_end;mod++)
- GenModList_insertMod(&gzone, mod);
-
- zone++;
- }
- }
-
- temp = realloc(*sounds, (zone_end-zone + *sounds_size)*sizeof((*sounds)[0]));
- if(!temp)
- {
- ERR("Failed reallocating fontsound storage to %d elements (from %d)\n",
- (ALsizei)(zone_end-zone) + *sounds_size, *sounds_size);
- return;
- }
- *sounds = temp;
- for(;zone != zone_end;zone++)
- {
- GenModList lzone = GenModList_clone(&gzone);
- mod = sfont->imod + zone->mModIdx;
- mod_end = sfont->imod + (zone+1)->mModIdx;
- for(;mod != mod_end;mod++)
- GenModList_insertMod(&lzone, mod);
-
- gen = sfont->igen + zone->mGenIdx;
- gen_end = sfont->igen + (zone+1)->mGenIdx;
- for(;gen != gen_end;gen++)
- {
- if(gen->mGenerator == 53)
- {
- const SampleHeader *samp;
- ALfontsound *sound;
-
- if(gen->mAmount >= sfont->shdr_size-1)
- {
- ERR("Generator %ld has invalid sample ID (%d of %d)\n",
- (long)(gen-sfont->igen), gen->mAmount, sfont->shdr_size-1);
- break;
- }
- samp = &sfont->shdr[gen->mAmount];
-
- gen = VECTOR_ITER_BEGIN(pzone->gens);
- gen_end = VECTOR_ITER_END(pzone->gens);
- for(;gen != gen_end;gen++)
- GenModList_accumGen(&lzone, gen);
-
- mod = VECTOR_ITER_BEGIN(pzone->mods);
- mod_end = VECTOR_ITER_END(pzone->mods);
- for(;mod != mod_end;mod++)
- GenModList_accumMod(&lzone, mod);
-
- if(!checkZone(&lzone, preset, inst, samp))
- break;
- /* Ignore ROM samples for now. */
- if((samp->mSampleType&0x8000))
- break;
-
- sound = NewFontsound(context);
- (*sounds)[(*sounds_size)++] = sound;
- 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);
- ALfontsound_setPropi(sound, context, AL_SAMPLE_LOOP_END_SOFT, samp->mEndloop);
- ALfontsound_setPropi(sound, context, AL_SAMPLE_RATE_SOFT, samp->mSampleRate);
- ALfontsound_setPropi(sound, context, AL_BASE_KEY_SOFT, (samp->mOriginalKey <= 127) ? samp->mOriginalKey : 60);
- ALfontsound_setPropi(sound, context, AL_KEY_CORRECTION_SOFT, samp->mCorrection);
- ALfontsound_setPropi(sound, context, AL_SAMPLE_TYPE_SOFT, getSampleType(samp->mSampleType&0x7fff));
- fillZone(sound, context, &lzone);
-
- break;
- }
- GenModList_insertGen(&lzone, gen, AL_FALSE);
- }
-
- GenModList_Destruct(&lzone);
- }
-
- GenModList_Destruct(&gzone);
-}
-
-ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
-{
- ALsfpreset **presets = NULL;
- ALsizei presets_size = 0;
- ALuint ltype;
- Soundfont sfont;
- RiffHdr riff;
- RiffHdr list;
- ALsizei i;
-
- Soundfont_Construct(&sfont);
-
- 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));
- 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));
-
- 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));
- 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));
- list.mSize -= 4;
- while(list.mSize > 0 && !READERR(stream))
- {
- RiffHdr info;
-
- RiffHdr_read(&info, stream);
- list.mSize -= 8;
- if(info.mCode == FOURCC('i','f','i','l'))
- {
- if(info.mSize != 4)
- ERR("Invalid ifil chunk size: %d\n", info.mSize);
- else
- {
- ALushort major = read_le16(stream);
- ALushort minor = read_le16(stream);
-
- list.mSize -= 4;
- info.mSize -= 4;
-
- if(major != 2)
- ERROR_GOTO(error, "Unsupported SF2 format version: %d.%02d\n", major, minor);
- TRACE("SF2 format version: %d.%02d\n", major, minor);
-
- sfont.ifil = (major<<16) | minor;
- }
- }
- else if(info.mCode == FOURCC('i','r','o','m'))
- {
- if(info.mSize == 0 || (info.mSize&1))
- ERR("Invalid irom size: %d\n", info.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;
-
- TRACE("SF2 ROM ID: %s\n", sfont.irom);
- }
- }
- else
- TRACE("Skipping INFO sub-chunk '%c%c%c%c' (%u bytes)\n", FOURCCARGS(info.mCode), info.mSize);
- list.mSize -= info.mSize;
- skip(stream, info.mSize);
- }
-
- if(READERR(stream) != 0)
- ERROR_GOTO(error, "Error reading INFO chunk\n");
- if(sfont.ifil == 0)
- ERROR_GOTO(error, "Missing ifil sub-chunk\n");
-
- 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));
- 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));
- list.mSize -= 4;
- {
- ALbyte *ptr;
- RiffHdr smpl;
-
- 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));
- list.mSize -= 8;
-
- if(smpl.mSize > list.mSize)
- ERROR_GOTO(error, "Invalid Format, sample chunk size mismatch\n");
-
- if(!(ptr=realloc(soundfont->Samples, smpl.mSize)))
- SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, error);
- soundfont->Samples = (ALshort*)ptr;
- soundfont->NumSamples = smpl.mSize/2;
-
- if(IS_LITTLE_ENDIAN)
- READ(stream, ptr, smpl.mSize);
- else
- {
- ALuint total = 0;
- while(total < smpl.mSize)
- {
- ALbyte buf[4096];
- ALuint todo = minu(smpl.mSize-total, sizeof(buf));
- ALuint i;
-
- READ(stream, buf, todo);
- for(i = 0;i < todo;i++)
- ptr[total+i] = buf[i^1];
-
- total += todo;
- }
- }
- list.mSize -= smpl.mSize;
-
- skip(stream, list.mSize);
- }
-
- if(READERR(stream) != 0)
- ERROR_GOTO(error, "Error reading sdta chunk\n");
-
- 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));
- 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));
-
- //
- 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));
- 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;
- sfont.phdr = calloc(sfont.phdr_size, sizeof(sfont.phdr[0]));
- for(i = 0;i < sfont.phdr_size;i++)
- PresetHeader_read(&sfont.phdr[i], stream);
-
- 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));
- 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;
- sfont.pbag = calloc(sfont.pbag_size, sizeof(sfont.pbag[0]));
- for(i = 0;i < sfont.pbag_size;i++)
- Zone_read(&sfont.pbag[i], stream);
-
- 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));
- 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;
- sfont.pmod = calloc(sfont.pmod_size, sizeof(sfont.pmod[0]));
- for(i = 0;i < sfont.pmod_size;i++)
- Modulator_read(&sfont.pmod[i], stream);
-
- 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));
- 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;
- sfont.pgen = calloc(sfont.pgen_size, sizeof(sfont.pgen[0]));
- for(i = 0;i < sfont.pgen_size;i++)
- Generator_read(&sfont.pgen[i], stream);
-
- //
- 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));
- 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;
- sfont.inst = calloc(sfont.inst_size, sizeof(sfont.inst[0]));
- for(i = 0;i < sfont.inst_size;i++)
- InstrumentHeader_read(&sfont.inst[i], stream);
-
- 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));
- 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;
- sfont.ibag = calloc(sfont.ibag_size, sizeof(sfont.ibag[0]));
- for(i = 0;i < sfont.ibag_size;i++)
- Zone_read(&sfont.ibag[i], stream);
-
- 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));
- 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;
- sfont.imod = calloc(sfont.imod_size, sizeof(sfont.imod[0]));
- for(i = 0;i < sfont.imod_size;i++)
- Modulator_read(&sfont.imod[i], stream);
-
- 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));
- 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;
- sfont.igen = calloc(sfont.igen_size, sizeof(sfont.igen[0]));
- for(i = 0;i < sfont.igen_size;i++)
- Generator_read(&sfont.igen[i], stream);
-
- //
- 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));
- 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;
- sfont.shdr = calloc(sfont.shdr_size, sizeof(sfont.shdr[0]));
- for(i = 0;i < sfont.shdr_size;i++)
- SampleHeader_read(&sfont.shdr[i], stream);
-
- if(READERR(stream) != 0)
- ERROR_GOTO(error, "Error reading pdta chunk\n");
-
- if(!ensureFontSanity(&sfont))
- goto error;
-
- presets = calloc(1, (sfont.phdr_size-1)*sizeof(presets[0]));
- if(!presets)
- ERROR_GOTO(error, "Error allocating presets\n");
-
- for(i = 0;i < sfont.phdr_size-1;i++)
- {
- const Generator *gen, *gen_end;
- const Modulator *mod, *mod_end;
- const Zone *zone, *zone_end;
- ALfontsound **sounds = NULL;
- ALsizei sounds_size = 0;
- GenModList gzone;
-
- if(sfont.phdr[i+1].mZoneIdx == sfont.phdr[i].mZoneIdx)
- continue;
-
- GenModList_Construct(&gzone);
- zone = sfont.pbag + sfont.phdr[i].mZoneIdx;
- zone_end = sfont.pbag + sfont.phdr[i+1].mZoneIdx;
- if(zone_end-zone > 1)
- {
- gen = sfont.pgen + zone->mGenIdx;
- gen_end = sfont.pgen + (zone+1)->mGenIdx;
-
- // If no generators, or last generator is not an instrument, this is a global zone
- for(;gen != gen_end;gen++)
- {
- if(gen->mGenerator == 41)
- break;
- }
-
- if(gen == gen_end)
- {
- gen = sfont.pgen + zone->mGenIdx;
- gen_end = sfont.pgen + (zone+1)->mGenIdx;
- for(;gen != gen_end;gen++)
- GenModList_insertGen(&gzone, gen, AL_TRUE);
-
- mod = sfont.pmod + zone->mModIdx;
- mod_end = sfont.pmod + (zone+1)->mModIdx;
- for(;mod != mod_end;mod++)
- GenModList_insertMod(&gzone, mod);
-
- zone++;
- }
- }
-
- for(;zone != zone_end;zone++)
- {
- GenModList lzone = GenModList_clone(&gzone);
-
- mod = sfont.pmod + zone->mModIdx;
- mod_end = sfont.pmod + (zone+1)->mModIdx;
- for(;mod != mod_end;mod++)
- GenModList_insertMod(&lzone, mod);
-
- gen = sfont.pgen + zone->mGenIdx;
- gen_end = sfont.pgen + (zone+1)->mGenIdx;
- for(;gen != gen_end;gen++)
- {
- if(gen->mGenerator == 41)
- {
- if(gen->mAmount >= sfont.inst_size-1)
- 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);
- break;
- }
- GenModList_insertGen(&lzone, gen, AL_TRUE);
- }
- GenModList_Destruct(&lzone);
- }
-
- if(sounds_size > 0)
- {
- ALsizei j;
-
- presets[presets_size] = NewPreset(context);
- presets[presets_size]->Preset = sfont.phdr[i].mPreset;
- presets[presets_size]->Bank = sfont.phdr[i].mBank;
-
- for(j = 0;j < sounds_size;j++)
- IncrementRef(&sounds[j]->ref);
- sounds = ExchangePtr((XchgPtr*)&presets[presets_size]->Sounds, sounds);
- ExchangeInt(&presets[presets_size]->NumSounds, sounds_size);
- presets_size++;
- }
- free(sounds);
-
- GenModList_Destruct(&gzone);
- }
-
- for(i = 0;i < presets_size;i++)
- IncrementRef(&presets[i]->ref);
- presets = ExchangePtr((XchgPtr*)&soundfont->Presets, presets);
- ExchangeInt(&soundfont->NumPresets, presets_size);
-
- free(presets);
-
- Soundfont_Destruct(&sfont);
-
- return AL_TRUE;
-
-error:
- if(presets)
- {
- ALCdevice *device = context->Device;
- for(i = 0;i < presets_size;i++)
- DeletePreset(presets[i], device);
- free(presets);
- }
-
- Soundfont_Destruct(&sfont);
-
- return AL_FALSE;
-}
diff --git a/Alc/midi/soft.c b/Alc/midi/soft.c
deleted file mode 100644
index 7102ff7a..00000000
--- a/Alc/midi/soft.c
+++ /dev/null
@@ -1,141 +0,0 @@
-
-#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), ALfloat (*restrict DryBuffer)[BUFFERSIZE])
-{
- (void)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);
-}
diff --git a/Alc/mixer.c b/Alc/mixer.c
index 6a4abfc6..712075f1 100644
--- a/Alc/mixer.c
+++ b/Alc/mixer.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -34,11 +34,255 @@
#include "alListener.h"
#include "alAuxEffectSlot.h"
#include "alu.h"
-#include "bs2b.h"
+#include "mixer_defs.h"
+
+
+static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
+ "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
+alignas(16) union ResamplerCoeffs ResampleCoeffs;
+
+
+enum Resampler {
+ PointResampler,
+ LinearResampler,
+ FIR4Resampler,
+ FIR8Resampler,
+ BSincResampler,
+
+ ResamplerDefault = LinearResampler
+};
+
+/* FIR8 requires 3 extra samples before the current position, and 4 after. */
+static_assert(MAX_PRE_SAMPLES >= 3, "MAX_PRE_SAMPLES must be at least 3!");
+static_assert(MAX_POST_SAMPLES >= 4, "MAX_POST_SAMPLES must be at least 4!");
+
+
+static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
+static MixerFunc MixSamples = Mix_C;
+static ResamplerFunc ResampleSamples = Resample_point32_C;
+
+static inline HrtfMixerFunc SelectHrtfMixer(void)
+{
+#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)
+{
+ 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 FIR4Resampler:
+#ifdef HAVE_SSE4_1
+ if((CPUCapFlags&CPU_CAP_SSE4_1))
+ return Resample_fir4_32_SSE41;
+#endif
+#ifdef HAVE_SSE3
+ if((CPUCapFlags&CPU_CAP_SSE3))
+ return Resample_fir4_32_SSE3;
+#endif
+ return Resample_fir4_32_C;
+ case FIR8Resampler:
+#ifdef HAVE_SSE4_1
+ if((CPUCapFlags&CPU_CAP_SSE4_1))
+ return Resample_fir8_32_SSE41;
+#endif
+#ifdef HAVE_SSE3
+ if((CPUCapFlags&CPU_CAP_SSE3))
+ return Resample_fir8_32_SSE3;
+#endif
+ return Resample_fir8_32_C;
+ case BSincResampler:
+#ifdef HAVE_SSE
+ if((CPUCapFlags&CPU_CAP_SSE))
+ return Resample_bsinc32_SSE;
+#endif
+ return Resample_bsinc32_C;
+ }
+
+ return Resample_point32_C;
+}
+
+
+/* The sinc resampler makes use of a Kaiser window to limit the needed sample
+ * points to 4 and 8, respectively.
+ */
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+static inline double Sinc(double x)
+{
+ if(x == 0.0) return 1.0;
+ return sin(x*M_PI) / (x*M_PI);
+}
+
+/* The zero-order modified Bessel function of the first kind, used for the
+ * Kaiser window.
+ *
+ * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
+ * = sum_{k=0}^inf ((x / 2)^k / k!)^2
+ */
+static double BesselI_0(double x)
+{
+ double term, sum, x2, y, last_sum;
+ int k;
+
+ /* Start at k=1 since k=0 is trivial. */
+ term = 1.0;
+ sum = 1.0;
+ x2 = x / 2.0;
+ k = 1;
+
+ /* Let the integration converge until the term of the sum is no longer
+ * significant.
+ */
+ do {
+ y = x2 / k;
+ k ++;
+ last_sum = sum;
+ term *= y * y;
+ sum += term;
+ } while(sum != last_sum);
+ return sum;
+}
+
+/* Calculate a Kaiser window from the given beta value and a normalized k
+ * [-1, 1].
+ *
+ * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
+ * { 0, elsewhere.
+ *
+ * Where k can be calculated as:
+ *
+ * k = i / l, where -l <= i <= l.
+ *
+ * or:
+ *
+ * k = 2 i / M - 1, where 0 <= i <= M.
+ */
+static inline double Kaiser(double b, double k)
+{
+ if(k <= -1.0 || k >= 1.0) return 0.0;
+ return BesselI_0(b * sqrt(1.0 - (k*k))) / BesselI_0(b);
+}
+
+static inline double CalcKaiserBeta(double rejection)
+{
+ if(rejection > 50.0)
+ return 0.1102 * (rejection - 8.7);
+ if(rejection >= 21.0)
+ return (0.5842 * pow(rejection - 21.0, 0.4)) +
+ (0.07886 * (rejection - 21.0));
+ return 0.0;
+}
+
+static float SincKaiser(double r, double x)
+{
+ /* Limit rippling to -60dB. */
+ return (float)(Kaiser(CalcKaiserBeta(60.0), x / r) * Sinc(x));
+}
+
+
+void aluInitMixer(void)
+{
+ enum Resampler resampler = ResamplerDefault;
+ const char *str;
+ ALuint i;
+
+ if(ConfigValueStr(NULL, NULL, "resampler", &str))
+ {
+ if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
+ resampler = PointResampler;
+ else if(strcasecmp(str, "linear") == 0)
+ resampler = LinearResampler;
+ else if(strcasecmp(str, "sinc4") == 0)
+ resampler = FIR4Resampler;
+ else if(strcasecmp(str, "sinc8") == 0)
+ resampler = FIR8Resampler;
+ else if(strcasecmp(str, "bsinc") == 0)
+ resampler = BSincResampler;
+ else if(strcasecmp(str, "cubic") == 0)
+ {
+ WARN("Resampler option \"cubic\" is deprecated, using sinc4\n");
+ resampler = FIR4Resampler;
+ }
+ else
+ {
+ char *end;
+ long n = strtol(str, &end, 0);
+ if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
+ resampler = n;
+ else
+ WARN("Invalid resampler: %s\n", str);
+ }
+ }
+
+ if(resampler == FIR8Resampler)
+ for(i = 0;i < FRACTIONONE;i++)
+ {
+ ALdouble mu = (ALdouble)i / FRACTIONONE;
+ ResampleCoeffs.FIR8[i][0] = SincKaiser(4.0, mu - -3.0);
+ ResampleCoeffs.FIR8[i][1] = SincKaiser(4.0, mu - -2.0);
+ ResampleCoeffs.FIR8[i][2] = SincKaiser(4.0, mu - -1.0);
+ ResampleCoeffs.FIR8[i][3] = SincKaiser(4.0, mu - 0.0);
+ ResampleCoeffs.FIR8[i][4] = SincKaiser(4.0, mu - 1.0);
+ ResampleCoeffs.FIR8[i][5] = SincKaiser(4.0, mu - 2.0);
+ ResampleCoeffs.FIR8[i][6] = SincKaiser(4.0, mu - 3.0);
+ ResampleCoeffs.FIR8[i][7] = SincKaiser(4.0, mu - 4.0);
+ }
+ else if(resampler == FIR4Resampler)
+ for(i = 0;i < FRACTIONONE;i++)
+ {
+ ALdouble mu = (ALdouble)i / FRACTIONONE;
+ ResampleCoeffs.FIR4[i][0] = SincKaiser(2.0, mu - -1.0);
+ ResampleCoeffs.FIR4[i][1] = SincKaiser(2.0, mu - 0.0);
+ ResampleCoeffs.FIR4[i][2] = SincKaiser(2.0, mu - 1.0);
+ ResampleCoeffs.FIR4[i][3] = SincKaiser(2.0, mu - 2.0);
+ }
+
+ MixHrtfSamples = SelectHrtfMixer();
+ MixSamples = SelectMixer();
+ ResampleSamples = SelectResampler(resampler);
+}
+
static inline ALfloat Sample_ALbyte(ALbyte val)
{ return val * (1.0f/127.0f); }
@@ -50,7 +294,7 @@ static inline ALfloat Sample_ALfloat(ALfloat val)
{ return val; }
#define DECL_TEMPLATE(T) \
-static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
+static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
{ \
ALuint i; \
for(i = 0;i < samples;i++) \
@@ -63,7 +307,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)
{
@@ -79,7 +323,7 @@ static void LoadData(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtTy
}
}
-static void SilenceData(ALfloat *dst, ALuint samples)
+static inline void SilenceSamples(ALfloat *dst, ALuint samples)
{
ALuint i;
for(i = 0;i < samples;i++)
@@ -95,20 +339,24 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter
switch(type)
{
case AF_None:
+ ALfilterState_processPassthru(lpfilter, src, numsamples);
+ ALfilterState_processPassthru(hpfilter, src, numsamples);
break;
case AF_LowPass:
ALfilterState_process(lpfilter, dst, src, numsamples);
+ ALfilterState_processPassthru(hpfilter, dst, numsamples);
return dst;
case AF_HighPass:
+ ALfilterState_processPassthru(lpfilter, src, numsamples);
ALfilterState_process(hpfilter, dst, src, numsamples);
return dst;
case AF_BandPass:
for(i = 0;i < numsamples;)
{
- ALfloat temp[64];
- ALuint todo = minu(64, numsamples-i);
+ ALfloat temp[256];
+ ALuint todo = minu(256, numsamples-i);
ALfilterState_process(lpfilter, temp, src+i, todo);
ALfilterState_process(hpfilter, dst+i, temp, todo);
@@ -120,38 +368,38 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter
}
-ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
+ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
{
- ALsource *Source = src->Source;
+ ResamplerFunc Resample;
ALbufferlistitem *BufferListItem;
ALuint DataPosInt, DataPosFrac;
ALboolean Looping;
ALuint increment;
- enum Resampler Resampler;
ALenum State;
ALuint OutPos;
ALuint NumChannels;
ALuint SampleSize;
ALint64 DataSize64;
+ ALuint IrSize;
ALuint chan, j;
/* Get source info */
State = Source->state;
- BufferListItem = Source->current_buffer;
+ 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;
+ increment = voice->Step;
- /* Get current buffer queue item */
+ IrSize = (Device->Hrtf ? GetHrtfIrSize(Device->Hrtf) : 0);
+
+ Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
+ Resample_copy32_C : ResampleSamples);
OutPos = 0;
do {
- const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
- const ALuint BufferPadding = ResamplerPadding[Resampler];
ALuint SrcBufferSize, DstBufferSize;
/* Figure out how many buffer samples will be needed */
@@ -159,13 +407,13 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
DataSize64 *= increment;
DataSize64 += DataPosFrac+FRACTIONMASK;
DataSize64 >>= FRACTIONBITS;
- DataSize64 += BufferPadding+BufferPrePadding;
+ DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
/* Figure out how many samples we can actually mix from this. */
DataSize64 = SrcBufferSize;
- DataSize64 -= BufferPadding+BufferPrePadding;
+ DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
DataSize64 <<= FRACTIONBITS;
DataSize64 -= DataPosFrac;
@@ -181,7 +429,11 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
{
const ALfloat *ResampledData;
ALfloat *SrcData = Device->SourceData;
- ALuint SrcDataSize = 0;
+ ALuint SrcDataSize;
+
+ /* Load the previous samples into the source data first. */
+ memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
+ SrcDataSize = MAX_PRE_SAMPLES;
if(Source->SourceType == AL_STATIC)
{
@@ -190,33 +442,24 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
ALuint DataSize;
ALuint pos;
+ /* Offset buffer data to current channel */
+ Data += chan*SampleSize;
+
/* If current pos is beyond the loop range, do not loop */
if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
{
Looping = AL_FALSE;
- if(DataPosInt >= BufferPrePadding)
- pos = DataPosInt - BufferPrePadding;
- else
- {
- DataSize = BufferPrePadding - DataPosInt;
- DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
-
- SilenceData(&SrcData[SrcDataSize], DataSize);
- SrcDataSize += DataSize;
-
- pos = 0;
- }
-
- /* Copy what's left to play in the source buffer, and clear the
- * rest of the temp buffer */
+ /* Load what's left to play from the source buffer, and
+ * clear the rest of the temp buffer */
+ pos = DataPosInt;
DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
- LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
- NumChannels, ALBuffer->FmtType, DataSize);
+ LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
+ NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
- SilenceData(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
+ SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
SrcDataSize += SrcBufferSize - SrcDataSize;
}
else
@@ -224,34 +467,14 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
ALuint LoopStart = ALBuffer->LoopStart;
ALuint LoopEnd = ALBuffer->LoopEnd;
- if(DataPosInt >= LoopStart)
- {
- pos = DataPosInt-LoopStart;
- while(pos < BufferPrePadding)
- pos += LoopEnd-LoopStart;
- pos -= BufferPrePadding;
- pos += LoopStart;
- }
- else if(DataPosInt >= BufferPrePadding)
- pos = DataPosInt - BufferPrePadding;
- else
- {
- DataSize = BufferPrePadding - DataPosInt;
- DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
-
- SilenceData(&SrcData[SrcDataSize], DataSize);
- SrcDataSize += DataSize;
-
- pos = 0;
- }
-
- /* Copy what's left of this loop iteration, then copy repeats
- * of the loop section */
+ /* Load what's left of this loop iteration, then load
+ * repeats of the loop section */
+ pos = DataPosInt;
DataSize = LoopEnd - pos;
DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
- LoadData(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
- NumChannels, ALBuffer->FmtType, DataSize);
+ LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
+ NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
DataSize = LoopEnd-LoopStart;
@@ -259,8 +482,8 @@ ALvoid MixSource(ALactivesource *src, 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*SampleSize],
+ NumChannels, ALBuffer->FmtType, DataSize);
SrcDataSize += DataSize;
}
}
@@ -269,45 +492,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
{
/* Crawl the buffer queue to fill in the temp buffer */
ALbufferlistitem *tmpiter = BufferListItem;
- ALuint pos;
-
- if(DataPosInt >= BufferPrePadding)
- pos = DataPosInt - BufferPrePadding;
- else
- {
- pos = BufferPrePadding - DataPosInt;
- while(pos > 0)
- {
- ALbufferlistitem *prev;
- if((prev=tmpiter->prev) != NULL)
- tmpiter = prev;
- else if(Looping)
- {
- while(tmpiter->next)
- tmpiter = tmpiter->next;
- }
- else
- {
- ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
-
- SilenceData(&SrcData[SrcDataSize], DataSize);
- SrcDataSize += DataSize;
-
- pos = 0;
- break;
- }
-
- if(tmpiter->buffer)
- {
- if((ALuint)tmpiter->buffer->SampleLen > pos)
- {
- pos = tmpiter->buffer->SampleLen - pos;
- break;
- }
- pos -= tmpiter->buffer->SampleLen;
- }
- }
- }
+ ALuint pos = DataPosInt;
while(tmpiter && SrcBufferSize > SrcDataSize)
{
@@ -327,29 +512,35 @@ ALvoid MixSource(ALactivesource *src, 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;
}
}
}
+ /* Store the last source samples used for next time. */
+ memcpy(voice->PrevSamples[chan],
+ &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
+ MAX_PRE_SAMPLES*sizeof(ALfloat)
+ );
+
/* Now resample, then filter and mix to the appropriate outputs. */
- ResampledData = src->Resample(
- &SrcData[BufferPrePadding], DataPosFrac, increment,
+ ResampledData = Resample(&voice->SincState,
+ &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
Device->ResampledData, DstBufferSize
);
{
- DirectParams *parms = &src->Direct;
+ DirectParams *parms = &voice->Direct;
const ALfloat *samples;
samples = DoFilters(
@@ -357,20 +548,18 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
Device->FilteredData, ResampledData, DstBufferSize,
parms->Filters[chan].ActiveType
);
- if(!src->IsHrtf)
- src->Dry.Mix(parms->OutBuffer, samples, &parms->Mix.Gains[chan],
- parms->Counter, OutPos, DstBufferSize);
+ if(!voice->IsHrtf)
+ MixSamples(samples, parms->OutChannels, parms->OutBuffer, parms->Gains[chan],
+ parms->Counter, OutPos, DstBufferSize);
else
- src->Dry.HrtfMix(
- parms->OutBuffer, samples, parms->Counter, src->Offset,
- OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan],
- &parms->Mix.Hrtf.State[chan], DstBufferSize
- );
+ MixHrtfSamples(parms->OutBuffer, samples, parms->Counter, voice->Offset,
+ OutPos, IrSize, &parms->Hrtf[chan].Params,
+ &parms->Hrtf[chan].State, DstBufferSize);
}
for(j = 0;j < Device->NumAuxSends;j++)
{
- SendParams *parms = &src->Send[j];
+ SendParams *parms = &voice->Send[j];
const ALfloat *samples;
if(!parms->OutBuffer)
@@ -381,8 +570,8 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
Device->FilteredData, ResampledData, DstBufferSize,
parms->Filters[chan].ActiveType
);
- src->WetMix(parms->OutBuffer, samples, &parms->Gain,
- parms->Counter, OutPos, DstBufferSize);
+ MixSamples(samples, 1, parms->OutBuffer, &parms->Gains[chan],
+ parms->Counter, OutPos, DstBufferSize);
}
}
/* Update positions */
@@ -391,10 +580,10 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
DataPosFrac &= FRACTIONMASK;
OutPos += DstBufferSize;
- src->Offset += DstBufferSize;
- src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize;
+ voice->Offset += DstBufferSize;
+ voice->Direct.Counter = maxu(voice->Direct.Counter, DstBufferSize) - DstBufferSize;
for(j = 0;j < Device->NumAuxSends;j++)
- src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize;
+ voice->Send[j].Counter = maxu(voice->Send[j].Counter, DstBufferSize) - DstBufferSize;
/* Handle looping sources */
while(1)
@@ -423,17 +612,18 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
if(DataSize > DataPosInt)
break;
- if(BufferListItem->next)
- BufferListItem = BufferListItem->next;
- else if(Looping)
- BufferListItem = Source->queue;
- else
+ if(!(BufferListItem=BufferListItem->next))
{
- State = AL_STOPPED;
- BufferListItem = NULL;
- 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;
@@ -442,7 +632,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
/* Update source info */
Source->state = State;
- Source->current_buffer = BufferListItem;
+ ATOMIC_STORE(&Source->current_buffer, BufferListItem);
Source->position = DataPosInt;
Source->position_fraction = DataPosFrac;
}
diff --git a/Alc/mixer_c.c b/Alc/mixer_c.c
index 6dd01e7d..ef37b730 100644
--- a/Alc/mixer_c.c
+++ b/Alc/mixer_c.c
@@ -12,13 +12,15 @@ static inline ALfloat point32(const ALfloat *vals, ALuint UNUSED(frac))
{ return vals[0]; }
static inline ALfloat lerp32(const ALfloat *vals, ALuint frac)
{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
-static inline ALfloat cubic32(const ALfloat *vals, ALuint frac)
-{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); }
+static inline ALfloat fir4_32(const ALfloat *vals, ALuint frac)
+{ return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); }
+static inline ALfloat fir8_32(const ALfloat *vals, ALuint frac)
+{ return resample_fir8(vals[-3], vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], vals[4], frac); }
-const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
- ALuint increment, ALfloat *restrict dst, ALuint numsamples)
+
+const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat *src, ALuint UNUSED(frac),
+ ALuint UNUSED(increment), ALfloat *restrict dst, ALuint numsamples)
{
- assert(increment==FRACTIONONE);
#if defined(HAVE_SSE) || defined(HAVE_NEON)
/* Avoid copying the source data if it's aligned like the destination. */
if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
@@ -29,8 +31,9 @@ const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
}
#define DECL_TEMPLATE(Sampler) \
-const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \
- ALuint increment, ALfloat *restrict dst, ALuint numsamples) \
+const ALfloat *Resample_##Sampler##_C(const BsincState* UNUSED(state), \
+ const ALfloat *src, ALuint frac, ALuint increment, \
+ ALfloat *restrict dst, ALuint numsamples) \
{ \
ALuint i; \
for(i = 0;i < numsamples;i++) \
@@ -46,10 +49,49 @@ const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \
DECL_TEMPLATE(point32)
DECL_TEMPLATE(lerp32)
-DECL_TEMPLATE(cubic32)
+DECL_TEMPLATE(fir4_32)
+DECL_TEMPLATE(fir8_32)
#undef DECL_TEMPLATE
+const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac,
+ ALuint increment, ALfloat *restrict dst, ALuint dstlen)
+{
+ const ALfloat *fil, *scd, *phd, *spd;
+ const ALfloat sf = state->sf;
+ const ALuint m = state->m;
+ const ALint l = state->l;
+ ALuint j_f, pi, i;
+ ALfloat pf, r;
+ ALint j_s;
+
+ for(i = 0;i < dstlen;i++)
+ {
+ // Calculate the phase index and factor.
+#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
+ pi = frac >> FRAC_PHASE_BITDIFF;
+ pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
+#undef FRAC_PHASE_BITDIFF
+
+ fil = state->coeffs[pi].filter;
+ scd = state->coeffs[pi].scDelta;
+ phd = state->coeffs[pi].phDelta;
+ spd = state->coeffs[pi].spDelta;
+
+ // Apply the scale and phase interpolated filter.
+ r = 0.0f;
+ for(j_f = 0,j_s = l;j_f < m;j_f++,j_s++)
+ r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) *
+ src[j_s];
+ dst[i] = r;
+
+ frac += increment;
+ src += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ }
+ return dst;
+}
+
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples)
{
@@ -59,6 +101,18 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const
}
+static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
+ const HrtfParams *hrtfparams,
+ ALuint IrSize, ALuint Counter)
+{
+ ALuint c;
+ for(c = 0;c < IrSize;c++)
+ {
+ OutCoeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter);
+ OutCoeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter);
+ }
+}
+
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
@@ -90,66 +144,38 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
}
}
-#define SUFFIX C
+#define MixHrtf MixHrtf_C
#include "mixer_inc.c"
-#undef SUFFIX
+#undef MixHrtf
-void MixDirect_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
+void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+ MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat DrySend, Step;
+ ALfloat gain, step;
ALuint c;
- for(c = 0;c < MaxChannels;c++)
+ for(c = 0;c < OutChans;c++)
{
ALuint pos = 0;
- DrySend = Gains->Current[c];
- Step = Gains->Step[c];
- if(Step != 1.0f && Counter > 0)
+ gain = Gains[c].Current;
+ step = Gains[c].Step;
+ if(step != 0.0f && Counter > 0)
{
- for(;pos < BufferSize && pos < Counter;pos++)
+ ALuint minsize = minu(BufferSize, Counter);
+ for(;pos < minsize;pos++)
{
- OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
- DrySend *= Step;
+ OutBuffer[c][OutPos+pos] += data[pos]*gain;
+ gain += step;
}
if(pos == Counter)
- DrySend = Gains->Target[c];
- Gains->Current[c] = DrySend;
+ gain = Gains[c].Target;
+ Gains[c].Current = gain;
}
- if(!(DrySend > GAIN_SILENCE_THRESHOLD))
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(;pos < BufferSize;pos++)
- OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
- }
-}
-
-
-void MixSend_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- MixGainMono *Gain, ALuint Counter, ALuint OutPos, ALuint BufferSize)
-{
- ALfloat WetSend, Step;
-
- {
- ALuint pos = 0;
- WetSend = Gain->Current;
- Step = Gain->Step;
- if(Step != 1.0f && Counter > 0)
- {
- for(;pos < BufferSize && pos < Counter;pos++)
- {
- OutBuffer[0][OutPos+pos] += data[pos]*WetSend;
- WetSend *= Step;
- }
- if(pos == Counter)
- WetSend = Gain->Target;
- Gain->Current = WetSend;
- }
-
- if(!(WetSend > GAIN_SILENCE_THRESHOLD))
- return;
- for(;pos < BufferSize;pos++)
- OutBuffer[0][OutPos+pos] += data[pos] * WetSend;
+ OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
diff --git a/Alc/mixer_defs.h b/Alc/mixer_defs.h
index caa06c25..3c32278b 100644
--- a/Alc/mixer_defs.h
+++ b/Alc/mixer_defs.h
@@ -7,41 +7,34 @@
#include "alu.h"
struct MixGains;
-struct MixGainMono;
struct HrtfParams;
struct HrtfState;
/* C resamplers */
-const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
/* C mixers */
-void MixDirect_Hrtf_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 MixDirect_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- struct MixGains *Gains, ALuint Counter, ALuint OutPos,
- ALuint BufferSize);
-void MixSend_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- struct MixGainMono *Gain, ALuint Counter, ALuint OutPos,
+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 MixDirect_Hrtf_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 MixDirect_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- struct MixGains *Gains, ALuint Counter, ALuint OutPos,
- ALuint BufferSize);
-void MixSend_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- struct MixGainMono *Gain, ALuint Counter, ALuint OutPos,
+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)
@@ -58,21 +51,30 @@ inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_a
}
}
-const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
+const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac,
+ ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+
+const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
-const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
+const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples);
+
+const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples);
+const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples);
+
+const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples);
+const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples);
/* Neon mixers */
-void MixDirect_Hrtf_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 MixDirect_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- struct MixGains *Gains, ALuint Counter, ALuint OutPos,
- ALuint BufferSize);
-void MixSend_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- struct MixGainMono *Gain, ALuint Counter, ALuint OutPos,
+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 */
diff --git a/Alc/mixer_inc.c b/Alc/mixer_inc.c
index 7c90ae9c..a82930cc 100644
--- a/Alc/mixer_inc.c
+++ b/Alc/mixer_inc.c
@@ -8,12 +8,9 @@
#include "align.h"
-#define REAL_MERGE2(a,b) a##b
-#define MERGE2(a,b) REAL_MERGE2(a,b)
-
-#define MixDirect_Hrtf MERGE2(MixDirect_Hrtf_,SUFFIX)
-
-
+static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
+ const HrtfParams *hrtfparams,
+ ALuint IrSize, ALuint Counter);
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint irSize,
ALfloat (*restrict Coeffs)[2],
@@ -25,32 +22,28 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
ALfloat left, ALfloat right);
-void MixDirect_Hrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize,
- const HrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize)
+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);
- }
+ SetupCoeffs(Coeffs, hrtfparams, IrSize, Counter);
Delay[0] = hrtfparams->Delay[0] - (hrtfparams->DelayStep[0]*Counter);
Delay[1] = hrtfparams->Delay[1] - (hrtfparams->DelayStep[1]*Counter);
- for(pos = 0;pos < BufferSize && pos < Counter;pos++)
+ pos = 0;
+ for(;pos < BufferSize && pos < Counter;pos++)
{
- hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
- left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
- hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
+ hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos];
+ left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK],
+ hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK],
(Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
- right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
- hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
+ right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK],
+ hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK],
(Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
Delay[0] += hrtfparams->DelayStep[0];
@@ -61,8 +54,8 @@ void MixDirect_Hrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *da
Offset++;
ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->CoeffStep, left, right);
- OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
- OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
+ OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
+ OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutPos++;
}
@@ -70,24 +63,17 @@ void MixDirect_Hrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *da
Delay[1] >>= HRTFDELAY_BITS;
for(;pos < BufferSize;pos++)
{
- hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
- left = hrtfstate->History[(Offset-Delay[0])&SRC_HISTORY_MASK];
- right = hrtfstate->History[(Offset-Delay[1])&SRC_HISTORY_MASK];
+ hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos];
+ left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK];
+ right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK];
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
Offset++;
ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
- OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
- OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
-
+ OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
+ OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
OutPos++;
}
}
-
-
-#undef MixDirect_Hrtf
-
-#undef MERGE2
-#undef REAL_MERGE2
diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c
index 6a0421a5..a89caeae 100644
--- a/Alc/mixer_neon.c
+++ b/Alc/mixer_neon.c
@@ -9,6 +9,25 @@
#include "hrtf.h"
+static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
+ const HrtfParams *hrtfparams,
+ ALuint IrSize, ALuint Counter)
+{
+ ALuint c;
+ float32x4_t counter4;
+ {
+ float32x2_t counter2 = vdup_n_f32(-(float)Counter);
+ counter4 = vcombine_f32(counter2, counter2);
+ }
+ for(c = 0;c < IrSize;c += 2)
+ {
+ float32x4_t step4 = vld1q_f32((float32_t*)hrtfparams->CoeffStep[c]);
+ float32x4_t coeffs = vld1q_f32((float32_t*)hrtfparams->Coeffs[c]);
+ coeffs = vmlaq_f32(coeffs, step4, counter4);
+ vst1q_f32((float32_t*)OutCoeffs[c], coeffs);
+ }
+}
+
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
@@ -69,90 +88,52 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
}
}
-
-#define SUFFIX Neon
+#define MixHrtf MixHrtf_Neon
#include "mixer_inc.c"
-#undef SUFFIX
+#undef MixHrtf
-void MixDirect_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
+void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+ MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat DrySend, Step;
- float32x4_t gain;
+ ALfloat gain, step;
+ float32x4_t gain4;
ALuint c;
- for(c = 0;c < MaxChannels;c++)
+ for(c = 0;c < OutChans;c++)
{
ALuint pos = 0;
- DrySend = Gains->Current[c];
- Step = Gains->Step[c];
- if(Step != 1.0f && Counter > 0)
+ gain = Gains[c].Current;
+ step = Gains[c].Step;
+ if(step != 0.0f && Counter > 0)
{
- for(;pos < BufferSize && pos < Counter;pos++)
+ ALuint minsize = minu(BufferSize, Counter);
+ for(;pos < minsize;pos++)
{
- OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
- DrySend *= Step;
+ OutBuffer[c][OutPos+pos] += data[pos]*gain;
+ gain += step;
}
if(pos == Counter)
- DrySend = Gains->Target[c];
- Gains->Current[c] = DrySend;
+ 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]*DrySend;
+ minsize = minu(BufferSize, (pos+3)&~3);
+ for(;pos < minsize;pos++)
+ OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
- if(!(DrySend > GAIN_SILENCE_THRESHOLD))
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
- gain = vdupq_n_f32(DrySend);
+ 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, gain));
+ dry4 = vmlaq_f32(dry4, val4, gain4);
vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
}
for(;pos < BufferSize;pos++)
- OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
- }
-}
-
-
-void MixSend_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- MixGainMono *Gain, ALuint Counter, ALuint OutPos, ALuint BufferSize)
-{
- ALfloat WetGain, Step;
- float32x4_t gain;
-
- {
- ALuint pos = 0;
- WetGain = Gain->Current;
- Step = Gain->Step;
- if(Step != 1.0f && Counter > 0)
- {
- for(;pos < BufferSize && pos < Counter;pos++)
- {
- OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
- WetGain *= Step;
- }
- if(pos == Counter)
- WetGain = Gain->Target;
- Gain->Current = WetGain;
- for(;pos < BufferSize && (pos&3) != 0;pos++)
- OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
- }
-
- if(!(WetGain > GAIN_SILENCE_THRESHOLD))
- return;
- gain = vdupq_n_f32(WetGain);
- for(;BufferSize-pos > 3;pos += 4)
- {
- const float32x4_t val4 = vld1q_f32(&data[pos]);
- float32x4_t wet4 = vld1q_f32(&OutBuffer[0][OutPos+pos]);
- wet4 = vaddq_f32(wet4, vmulq_f32(val4, gain));
- vst1q_f32(&OutBuffer[0][OutPos+pos], wet4);
- }
- for(;pos < BufferSize;pos++)
- OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
+ OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
diff --git a/Alc/mixer_sse.c b/Alc/mixer_sse.c
index c4e1fdf5..090b7a5a 100644
--- a/Alc/mixer_sse.c
+++ b/Alc/mixer_sse.c
@@ -1,12 +1,5 @@
#include "config.h"
-#ifdef IN_IDE_PARSER
-/* KDevelop's parser won't recognize these defines that get added by the -msse
- * switch used to compile this source. Without them, xmmintrin.h fails to
- * declare anything. */
-#define __MMX__
-#define __SSE__
-#endif
#include <xmmintrin.h>
#include "AL/al.h"
@@ -19,6 +12,82 @@
#include "mixer_defs.h"
+const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac,
+ ALuint increment, ALfloat *restrict dst, ALuint dstlen)
+{
+ const __m128 sf4 = _mm_set1_ps(state->sf);
+ const ALuint m = state->m;
+ const ALint l = state->l;
+ const ALfloat *fil, *scd, *phd, *spd;
+ ALuint pi, j_f, i;
+ ALfloat pf;
+ ALint j_s;
+ __m128 r4;
+
+ for(i = 0;i < dstlen;i++)
+ {
+ // Calculate the phase index and factor.
+#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
+ pi = frac >> FRAC_PHASE_BITDIFF;
+ pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
+#undef FRAC_PHASE_BITDIFF
+
+ fil = state->coeffs[pi].filter;
+ scd = state->coeffs[pi].scDelta;
+ phd = state->coeffs[pi].phDelta;
+ spd = state->coeffs[pi].spDelta;
+
+ // Apply the scale and phase interpolated filter.
+ r4 = _mm_setzero_ps();
+ {
+ const __m128 pf4 = _mm_set1_ps(pf);
+ for(j_f = 0,j_s = l;j_f < m;j_f+=4,j_s+=4)
+ {
+ const __m128 f4 = _mm_add_ps(
+ _mm_add_ps(
+ _mm_load_ps(&fil[j_f]),
+ _mm_mul_ps(sf4, _mm_load_ps(&scd[j_f]))
+ ),
+ _mm_mul_ps(
+ pf4,
+ _mm_add_ps(
+ _mm_load_ps(&phd[j_f]),
+ _mm_mul_ps(sf4, _mm_load_ps(&spd[j_f]))
+ )
+ )
+ );
+ r4 = _mm_add_ps(r4, _mm_mul_ps(f4, _mm_loadu_ps(&src[j_s])));
+ }
+ }
+ r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3)));
+ r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4));
+ dst[i] = _mm_cvtss_f32(r4);
+
+ frac += increment;
+ src += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ }
+ return dst;
+}
+
+
+static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
+ const HrtfParams *hrtfparams,
+ ALuint IrSize, ALuint Counter)
+{
+ const __m128 counter4 = _mm_set1_ps((float)Counter);
+ __m128 coeffs, step4;
+ ALuint i;
+
+ for(i = 0;i < IrSize;i += 2)
+ {
+ step4 = _mm_load_ps(&hrtfparams->CoeffStep[i][0]);
+ coeffs = _mm_load_ps(&hrtfparams->Coeffs[i][0]);
+ coeffs = _mm_sub_ps(coeffs, _mm_mul_ps(step4, counter4));
+ _mm_store_ps(&OutCoeffs[i][0], coeffs);
+ }
+}
+
static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
const ALuint IrSize,
ALfloat (*restrict Coeffs)[2],
@@ -133,129 +202,78 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
}
}
-#define SUFFIX SSE
+#define MixHrtf MixHrtf_SSE
#include "mixer_inc.c"
-#undef SUFFIX
+#undef MixHrtf
-void MixDirect_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
+void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+ MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
{
- ALfloat DrySend, Step;
- __m128 gain, step;
+ ALfloat gain, step;
+ __m128 gain4;
ALuint c;
- for(c = 0;c < MaxChannels;c++)
+ for(c = 0;c < OutChans;c++)
{
ALuint pos = 0;
- DrySend = Gains->Current[c];
- Step = Gains->Step[c];
- if(Step != 1.0f && Counter > 0)
+ gain = Gains[c].Current;
+ step = Gains[c].Step;
+ if(step != 0.0f && Counter > 0)
{
+ ALuint minsize = minu(BufferSize, Counter);
/* Mix with applying gain steps in aligned multiples of 4. */
- if(BufferSize-pos > 3 && Counter-pos > 3)
+ if(minsize-pos > 3)
{
- gain = _mm_setr_ps(
- DrySend,
- DrySend * Step,
- DrySend * Step * Step,
- DrySend * Step * Step * Step
+ __m128 step4;
+ gain4 = _mm_setr_ps(
+ gain,
+ gain + step,
+ gain + step + step,
+ gain + step + step + step
);
- step = _mm_set1_ps(Step * Step * Step * Step);
+ step4 = _mm_set1_ps(step + step + step + step);
do {
const __m128 val4 = _mm_load_ps(&data[pos]);
__m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
- dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain));
- gain = _mm_mul_ps(gain, step);
+ dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
+ gain4 = _mm_add_ps(gain4, step4);
_mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
pos += 4;
- } while(BufferSize-pos > 3 && Counter-pos > 3);
- DrySend = _mm_cvtss_f32(gain);
+ } while(minsize-pos > 3);
+ /* NOTE: gain4 now represents the next four gains after the
+ * last four mixed samples, so the lowest element represents
+ * the next gain to apply.
+ */
+ gain = _mm_cvtss_f32(gain4);
}
/* Mix with applying left over gain steps that aren't aligned multiples of 4. */
- for(;pos < BufferSize && pos < Counter;pos++)
+ for(;pos < minsize;pos++)
{
- OutBuffer[c][OutPos+pos] += data[pos]*DrySend;
- DrySend *= Step;
+ OutBuffer[c][OutPos+pos] += data[pos]*gain;
+ gain += step;
}
if(pos == Counter)
- DrySend = Gains->Target[c];
- Gains->Current[c] = DrySend;
+ 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]*DrySend;
+ minsize = minu(BufferSize, (pos+3)&~3);
+ for(;pos < minsize;pos++)
+ OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
- if(!(DrySend > GAIN_SILENCE_THRESHOLD))
+ if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
- gain = _mm_set1_ps(DrySend);
+ 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, gain));
+ 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]*DrySend;
- }
-}
-
-
-void MixSend_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- MixGainMono *Gain, ALuint Counter, ALuint OutPos, ALuint BufferSize)
-{
- ALfloat WetGain, Step;
- __m128 gain, step;
-
- {
- ALuint pos = 0;
- WetGain = Gain->Current;
- Step = Gain->Step;
- if(Step != 1.0f && Counter > 0)
- {
- if(BufferSize-pos > 3 && Counter-pos > 3)
- {
- gain = _mm_setr_ps(
- WetGain,
- WetGain * Step,
- WetGain * Step * Step,
- WetGain * Step * Step * Step
- );
- step = _mm_set1_ps(Step * Step * Step * Step);
- do {
- const __m128 val4 = _mm_load_ps(&data[pos]);
- __m128 dry4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
- dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain));
- gain = _mm_mul_ps(gain, step);
- _mm_store_ps(&OutBuffer[0][OutPos+pos], dry4);
- pos += 4;
- } while(BufferSize-pos > 3 && Counter-pos > 3);
- WetGain = _mm_cvtss_f32(gain);
- }
- for(;pos < BufferSize && pos < Counter;pos++)
- {
- OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
- WetGain *= Step;
- }
- if(pos == Counter)
- WetGain = Gain->Target;
- Gain->Current = WetGain;
- for(;pos < BufferSize && (pos&3) != 0;pos++)
- OutBuffer[0][OutPos+pos] += data[pos]*WetGain;
- }
-
- if(!(WetGain > GAIN_SILENCE_THRESHOLD))
- return;
- gain = _mm_set1_ps(WetGain);
- for(;BufferSize-pos > 3;pos += 4)
- {
- const __m128 val4 = _mm_load_ps(&data[pos]);
- __m128 wet4 = _mm_load_ps(&OutBuffer[0][OutPos+pos]);
- wet4 = _mm_add_ps(wet4, _mm_mul_ps(val4, gain));
- _mm_store_ps(&OutBuffer[0][OutPos+pos], wet4);
- }
- for(;pos < BufferSize;pos++)
- OutBuffer[0][OutPos+pos] += data[pos] * WetGain;
+ OutBuffer[c][OutPos+pos] += data[pos]*gain;
}
}
diff --git a/Alc/mixer_sse2.c b/Alc/mixer_sse2.c
index 7670add3..32f29227 100644
--- a/Alc/mixer_sse2.c
+++ b/Alc/mixer_sse2.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -27,7 +27,7 @@
#include "mixer_defs.h"
-const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
+const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
@@ -63,6 +63,9 @@ const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint incr
_mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
}
+ /* NOTE: These four elements represent the position *after* the last four
+ * samples, so the lowest element is the next position to resample.
+ */
pos = pos_.i[0];
frac = _mm_cvtsi128_si32(frac4);
diff --git a/Alc/mixer_sse3.c b/Alc/mixer_sse3.c
new file mode 100644
index 00000000..7085c537
--- /dev/null
+++ b/Alc/mixer_sse3.c
@@ -0,0 +1,162 @@
+/**
+ * OpenAL cross platform audio library, SSE3 mixer functions
+ *
+ * Copyright (C) 2014 by Timothy Arceri <[email protected]>.
+ * Copyright (C) 2015 by Chris Robinson <[email protected]>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <pmmintrin.h>
+
+#include "alu.h"
+#include "mixer_defs.h"
+
+
+const ALfloat *Resample_fir4_32_SSE3(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples)
+{
+ const __m128i increment4 = _mm_set1_epi32(increment*4);
+ const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+ alignas(16) union { ALuint i[4]; float f[4]; } pos_;
+ alignas(16) union { ALuint i[4]; float f[4]; } frac_;
+ __m128i frac4, pos4;
+ ALuint pos;
+ ALuint i;
+
+ InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+ frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+ pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+ --src;
+ for(i = 0;numsamples-i > 3;i += 4)
+ {
+ const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]]);
+ const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]);
+ const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]);
+ const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]);
+ __m128 k0 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[0]]);
+ __m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]);
+ __m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]);
+ __m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]);
+ __m128 out;
+
+ k0 = _mm_mul_ps(k0, val0);
+ k1 = _mm_mul_ps(k1, val1);
+ k2 = _mm_mul_ps(k2, val2);
+ k3 = _mm_mul_ps(k3, val3);
+ k0 = _mm_hadd_ps(k0, k1);
+ k2 = _mm_hadd_ps(k2, k3);
+ out = _mm_hadd_ps(k0, k2);
+
+ _mm_store_ps(&dst[i], out);
+
+ frac4 = _mm_add_epi32(frac4, increment4);
+ pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+ frac4 = _mm_and_si128(frac4, fracMask4);
+
+ _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
+ _mm_store_ps(frac_.f, _mm_castsi128_ps(frac4));
+ }
+
+ /* NOTE: These four elements represent the position *after* the last four
+ * samples, so the lowest element is the next position to resample.
+ */
+ pos = pos_.i[0];
+ frac = frac_.i[0];
+
+ for(;i < numsamples;i++)
+ {
+ dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac);
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ }
+ return dst;
+}
+
+const ALfloat *Resample_fir8_32_SSE3(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples)
+{
+ const __m128i increment4 = _mm_set1_epi32(increment*4);
+ const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+ alignas(16) union { ALuint i[4]; float f[4]; } pos_;
+ alignas(16) union { ALuint i[4]; float f[4]; } frac_;
+ __m128i frac4, pos4;
+ ALuint pos;
+ ALuint i, j;
+
+ InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+ frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+ pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+ src -= 3;
+ for(i = 0;numsamples-i > 3;i += 4)
+ {
+ __m128 out[2];
+ for(j = 0;j < 8;j+=4)
+ {
+ const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]+j]);
+ const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]+j]);
+ const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]+j]);
+ const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]+j]);
+ __m128 k0 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[0]][j]);
+ __m128 k1 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[1]][j]);
+ __m128 k2 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[2]][j]);
+ __m128 k3 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[3]][j]);
+
+ k0 = _mm_mul_ps(k0, val0);
+ k1 = _mm_mul_ps(k1, val1);
+ k2 = _mm_mul_ps(k2, val2);
+ k3 = _mm_mul_ps(k3, val3);
+ k0 = _mm_hadd_ps(k0, k1);
+ k2 = _mm_hadd_ps(k2, k3);
+ out[j>>2] = _mm_hadd_ps(k0, k2);
+ }
+
+ out[0] = _mm_add_ps(out[0], out[1]);
+ _mm_store_ps(&dst[i], out[0]);
+
+ frac4 = _mm_add_epi32(frac4, increment4);
+ pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+ frac4 = _mm_and_si128(frac4, fracMask4);
+
+ _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
+ _mm_store_ps(frac_.f, _mm_castsi128_ps(frac4));
+ }
+
+ pos = pos_.i[0];
+ frac = frac_.i[0];
+
+ for(;i < numsamples;i++)
+ {
+ dst[i] = resample_fir8(src[pos ], src[pos+1], src[pos+2], src[pos+3],
+ src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac);
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ }
+ return dst;
+}
diff --git a/Alc/mixer_sse41.c b/Alc/mixer_sse41.c
index 8ce8cd90..e832e5df 100644
--- a/Alc/mixer_sse41.c
+++ b/Alc/mixer_sse41.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -28,7 +28,7 @@
#include "mixer_defs.h"
-const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
+const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
ALfloat *restrict dst, ALuint numsamples)
{
const __m128i increment4 = _mm_set1_epi32(increment*4);
@@ -67,6 +67,9 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc
pos_.i[3] = _mm_extract_epi32(pos4, 3);
}
+ /* NOTE: These four elements represent the position *after* the last four
+ * samples, so the lowest element is the next position to resample.
+ */
pos = pos_.i[0];
frac = _mm_cvtsi128_si32(frac4);
@@ -80,3 +83,142 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc
}
return dst;
}
+
+const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples)
+{
+ const __m128i increment4 = _mm_set1_epi32(increment*4);
+ const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+ alignas(16) union { ALuint i[4]; float f[4]; } pos_;
+ alignas(16) union { ALuint i[4]; float f[4]; } frac_;
+ __m128i frac4, pos4;
+ ALuint pos;
+ ALuint i;
+
+ InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+ frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+ pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+ --src;
+ for(i = 0;numsamples-i > 3;i += 4)
+ {
+ const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]]);
+ const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]);
+ const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]);
+ const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]);
+ __m128 k0 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[0]]);
+ __m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]);
+ __m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]);
+ __m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]);
+ __m128 out;
+
+ k0 = _mm_mul_ps(k0, val0);
+ k1 = _mm_mul_ps(k1, val1);
+ k2 = _mm_mul_ps(k2, val2);
+ k3 = _mm_mul_ps(k3, val3);
+ k0 = _mm_hadd_ps(k0, k1);
+ k2 = _mm_hadd_ps(k2, k3);
+ out = _mm_hadd_ps(k0, k2);
+
+ _mm_store_ps(&dst[i], out);
+
+ frac4 = _mm_add_epi32(frac4, increment4);
+ pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+ frac4 = _mm_and_si128(frac4, fracMask4);
+
+ pos_.i[0] = _mm_extract_epi32(pos4, 0);
+ pos_.i[1] = _mm_extract_epi32(pos4, 1);
+ pos_.i[2] = _mm_extract_epi32(pos4, 2);
+ pos_.i[3] = _mm_extract_epi32(pos4, 3);
+ frac_.i[0] = _mm_extract_epi32(frac4, 0);
+ frac_.i[1] = _mm_extract_epi32(frac4, 1);
+ frac_.i[2] = _mm_extract_epi32(frac4, 2);
+ frac_.i[3] = _mm_extract_epi32(frac4, 3);
+ }
+
+ pos = pos_.i[0];
+ frac = frac_.i[0];
+
+ for(;i < numsamples;i++)
+ {
+ dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac);
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ }
+ return dst;
+}
+
+const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
+ ALfloat *restrict dst, ALuint numsamples)
+{
+ const __m128i increment4 = _mm_set1_epi32(increment*4);
+ const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+ alignas(16) union { ALuint i[4]; float f[4]; } pos_;
+ alignas(16) union { ALuint i[4]; float f[4]; } frac_;
+ __m128i frac4, pos4;
+ ALuint pos;
+ ALuint i, j;
+
+ InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+ frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+ pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+ src -= 3;
+ for(i = 0;numsamples-i > 3;i += 4)
+ {
+ __m128 out[2];
+ for(j = 0;j < 8;j+=4)
+ {
+ const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]+j]);
+ const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]+j]);
+ const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]+j]);
+ const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]+j]);
+ __m128 k0 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[0]][j]);
+ __m128 k1 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[1]][j]);
+ __m128 k2 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[2]][j]);
+ __m128 k3 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[3]][j]);
+
+ k0 = _mm_mul_ps(k0, val0);
+ k1 = _mm_mul_ps(k1, val1);
+ k2 = _mm_mul_ps(k2, val2);
+ k3 = _mm_mul_ps(k3, val3);
+ k0 = _mm_hadd_ps(k0, k1);
+ k2 = _mm_hadd_ps(k2, k3);
+ out[j>>2] = _mm_hadd_ps(k0, k2);
+ }
+
+ out[0] = _mm_add_ps(out[0], out[1]);
+ _mm_store_ps(&dst[i], out[0]);
+
+ frac4 = _mm_add_epi32(frac4, increment4);
+ pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+ frac4 = _mm_and_si128(frac4, fracMask4);
+
+ pos_.i[0] = _mm_extract_epi32(pos4, 0);
+ pos_.i[1] = _mm_extract_epi32(pos4, 1);
+ pos_.i[2] = _mm_extract_epi32(pos4, 2);
+ pos_.i[3] = _mm_extract_epi32(pos4, 3);
+ frac_.i[0] = _mm_extract_epi32(frac4, 0);
+ frac_.i[1] = _mm_extract_epi32(frac4, 1);
+ frac_.i[2] = _mm_extract_epi32(frac4, 2);
+ frac_.i[3] = _mm_extract_epi32(frac4, 3);
+ }
+
+ pos = pos_.i[0];
+ frac = frac_.i[0];
+
+ for(;i < numsamples;i++)
+ {
+ dst[i] = resample_fir8(src[pos ], src[pos+1], src[pos+2], src[pos+3],
+ src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac);
+
+ frac += increment;
+ pos += frac>>FRACTIONBITS;
+ frac &= FRACTIONMASK;
+ }
+ return dst;
+}
diff --git a/Alc/panning.c b/Alc/panning.c
index 30a1e571..6305bff7 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -30,421 +30,528 @@
#include "AL/al.h"
#include "AL/alc.h"
#include "alu.h"
-
-extern inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels]);
-
-static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChannels],
- enum Channel Speaker2Chan[MaxChannels], ALint chans)
+#include "bool.h"
+
+
+#define ZERO_ORDER_SCALE 0.0f
+#define FIRST_ORDER_SCALE 1.0f
+#define SECOND_ORDER_SCALE (1.0f / 1.22474f)
+#define THIRD_ORDER_SCALE (1.0f / 1.30657f)
+
+
+static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = {
+ 0, /* W */
+ 3, /* X */
+ 1, /* Y */
+ 2, /* Z */
+ 6, /* R */
+ 7, /* S */
+ 5, /* T */
+ 8, /* U */
+ 4, /* V */
+ 12, /* K */
+ 13, /* L */
+ 11, /* M */
+ 14, /* N */
+ 10, /* O */
+ 15, /* P */
+ 9, /* Q */
+};
+
+/* NOTE: These are scale factors as applied to Ambisonics content. FuMa
+ * decoder coefficients should be divided by these values to get N3D decoder
+ * coefficients.
+ */
+static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
+ 1.414213562f, /* ACN 0 (W), sqrt(2) */
+ 1.732050808f, /* ACN 1 (Y), sqrt(3) */
+ 1.732050808f, /* ACN 2 (Z), sqrt(3) */
+ 1.732050808f, /* ACN 3 (X), sqrt(3) */
+ 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
+ 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
+ 2.236067978f, /* ACN 6 (R), sqrt(5) */
+ 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
+ 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
+ 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
+ 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
+ 2.231093404f, /* ACN 11 (M), sqrt(224/45) */
+ 2.645751311f, /* ACN 12 (K), sqrt(7) */
+ 2.231093404f, /* ACN 13 (L), sqrt(224/45) */
+ 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
+ 2.091650066f, /* ACN 15 (P), sqrt(35/8) */
+};
+
+
+void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
{
- char *confkey, *next;
- char *layout_str;
- char *sep, *end;
- enum Channel val;
- const char *str;
- int i;
-
- if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str))
- return;
+ ALuint i;
- layout_str = strdup(str);
- next = confkey = layout_str;
- while(next && *next)
+ for(i = 0;i < device->NumChannels;i++)
{
- confkey = next;
- next = strchr(confkey, ',');
- if(next)
- {
- *next = 0;
- do {
- next++;
- } while(isspace(*next) || *next == ',');
- }
-
- sep = strchr(confkey, '=');
- if(!sep || confkey == sep)
- {
- ERR("Malformed speaker key: %s\n", confkey);
- continue;
- }
-
- end = sep - 1;
- while(isspace(*end) && end != confkey)
- end--;
- *(++end) = 0;
-
- if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
- val = FrontLeft;
- else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
- val = FrontRight;
- else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
- val = FrontCenter;
- else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
- val = BackLeft;
- else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
- val = BackRight;
- else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
- val = BackCenter;
- else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
- val = SideLeft;
- else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
- val = SideRight;
- else
- {
- ERR("Unknown speaker for %s: \"%s\"\n", name, confkey);
- continue;
- }
-
- *(sep++) = 0;
- while(isspace(*sep))
- sep++;
-
- for(i = 0;i < chans;i++)
- {
- if(Speaker2Chan[i] == val)
- {
- long angle = strtol(sep, NULL, 10);
- if(angle >= -180 && angle <= 180)
- SpeakerAngle[i] = DEG2RAD(angle);
- else
- ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
- break;
- }
- }
+ // The W coefficients are based on a mathematical average of the
+ // output. The square root of the base average provides for a more
+ // perceptual average volume, better suited to non-directional gains.
+ gains[i] = sqrtf(device->AmbiCoeffs[i][0]) * ingain;
}
- free(layout_str);
- layout_str = NULL;
+ for(;i < MAX_OUTPUT_CHANNELS;i++)
+ gains[i] = 0.0f;
+}
- for(i = 0;i < chans;i++)
+void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
+{
+ ALfloat dir[3] = {
+ sinf(angle) * cosf(elevation),
+ sinf(elevation),
+ -cosf(angle) * cosf(elevation)
+ };
+ ComputeDirectionalGains(device, dir, ingain, gains);
+}
+
+void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
+{
+ ALfloat coeffs[MAX_AMBI_COEFFS];
+ ALuint i, j;
+ /* Convert from OpenAL coords to Ambisonics. */
+ ALfloat x = -dir[2];
+ ALfloat y = -dir[0];
+ ALfloat z = dir[1];
+
+ /* Zeroth-order */
+ coeffs[0] = 1.0f; /* ACN 0 = 1 */
+ /* First-order */
+ coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */
+ coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */
+ coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */
+ /* Second-order */
+ coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */
+ coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */
+ coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
+ coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */
+ coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
+ /* Third-order */
+ coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
+ coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */
+ coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
+ coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
+ coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
+ coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
+ coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
+
+ for(i = 0;i < device->NumChannels;i++)
{
- int min = i;
- int i2;
+ float gain = 0.0f;
+ for(j = 0;j < MAX_AMBI_COEFFS;j++)
+ gain += device->AmbiCoeffs[i][j]*coeffs[j];
+ gains[i] = gain * ingain;
+ }
+ for(;i < MAX_OUTPUT_CHANNELS;i++)
+ gains[i] = 0.0f;
+}
- for(i2 = i+1;i2 < chans;i2++)
- {
- if(SpeakerAngle[i2] < SpeakerAngle[min])
- min = i2;
- }
+void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
+{
+ ALuint i, j;
- if(min != i)
- {
- ALfloat tmpf;
- enum Channel tmpc;
+ for(i = 0;i < device->NumChannels;i++)
+ {
+ float gain = 0.0f;
+ for(j = 0;j < 4;j++)
+ gain += device->AmbiCoeffs[i][j] * mtx[j];
+ gains[i] = gain * ingain;
+ }
+ for(;i < MAX_OUTPUT_CHANNELS;i++)
+ gains[i] = 0.0f;
+}
- tmpf = SpeakerAngle[i];
- SpeakerAngle[i] = SpeakerAngle[min];
- SpeakerAngle[min] = tmpf;
- tmpc = Speaker2Chan[i];
- Speaker2Chan[i] = Speaker2Chan[min];
- Speaker2Chan[min] = tmpc;
- }
+DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel)
+{
+ switch(channel)
+ {
+ case FrontLeft: return "front-left";
+ case FrontRight: return "front-right";
+ case FrontCenter: return "front-center";
+ case LFE: return "lfe";
+ case BackLeft: return "back-left";
+ case BackRight: return "back-right";
+ case BackCenter: return "back-center";
+ case SideLeft: return "side-left";
+ case SideRight: return "side-right";
+
+ case BFormatW: return "bformat-w";
+ case BFormatX: return "bformat-x";
+ case BFormatY: return "bformat-y";
+ case BFormatZ: return "bformat-z";
+
+ case InvalidChannel: break;
}
+ return "(unknown)";
}
-void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels])
+typedef struct ChannelMap {
+ enum Channel ChanName;
+ ChannelConfig Config;
+} ChannelMap;
+
+static void SetChannelMap(ALCdevice *device, const ChannelMap *chanmap, size_t count, ALfloat ambiscale, ALboolean isfuma)
{
- ALfloat tmpgains[MaxChannels] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
- enum Channel Speaker2Chan[MaxChannels];
- ALfloat SpeakerAngle[MaxChannels];
- ALfloat langle, rangle;
- ALfloat a;
+ size_t j, k;
ALuint i;
- for(i = 0;i < device->NumChan;i++)
- Speaker2Chan[i] = device->Speaker2Chan[i];
- for(i = 0;i < device->NumChan;i++)
- SpeakerAngle[i] = device->SpeakerAngle[i];
-
- /* Some easy special-cases first... */
- if(device->NumChan <= 1 || hwidth >= F_PI)
+ device->AmbiScale = ambiscale;
+ for(i = 0;i < MAX_OUTPUT_CHANNELS && device->ChannelName[i] != InvalidChannel;i++)
{
- /* Full coverage for all speakers. */
- for(i = 0;i < MaxChannels;i++)
- gains[i] = 0.0f;
- for(i = 0;i < device->NumChan;i++)
+ if(device->ChannelName[i] == LFE)
{
- enum Channel chan = Speaker2Chan[i];
- gains[chan] = ingain;
+ for(j = 0;j < MAX_AMBI_COEFFS;j++)
+ device->AmbiCoeffs[i][j] = 0.0f;
+ continue;
}
- return;
- }
- if(hwidth <= 0.0f)
- {
- /* Infinitely small sound point. */
- for(i = 0;i < MaxChannels;i++)
- gains[i] = 0.0f;
- for(i = 0;i < device->NumChan-1;i++)
+
+ for(j = 0;j < count;j++)
{
- if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1])
+ if(device->ChannelName[i] == chanmap[j].ChanName)
{
- /* Sound is between speakers i and i+1 */
- a = (angle-SpeakerAngle[i]) /
- (SpeakerAngle[i+1]-SpeakerAngle[i]);
- gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain;
- gains[Speaker2Chan[i+1]] = sqrtf( a) * ingain;
- return;
+ if(isfuma)
+ {
+ /* Reformat FuMa -> ACN/N3D */
+ for(k = 0;k < MAX_AMBI_COEFFS;++k)
+ {
+ ALuint acn = FuMa2ACN[k];
+ device->AmbiCoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn];
+ }
+ }
+ else
+ {
+ for(k = 0;k < MAX_AMBI_COEFFS;++k)
+ device->AmbiCoeffs[i][k] = chanmap[j].Config[k];
+ }
+ break;
}
}
- /* Sound is between last and first speakers */
- if(angle < SpeakerAngle[0])
- angle += F_2PI;
- a = (angle-SpeakerAngle[i]) /
- (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
- gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain;
- gains[Speaker2Chan[0]] = sqrtf( a) * ingain;
- return;
+ if(j == count)
+ ERR("Failed to match %s channel (%u) in config\n", GetLabelFromChannel(device->ChannelName[i]), i);
}
+ device->NumChannels = i;
+}
- if(fabsf(angle)+hwidth > F_PI)
+static bool LoadChannelSetup(ALCdevice *device)
+{
+ static const enum Channel mono_chans[1] = {
+ FrontCenter
+ }, stereo_chans[2] = {
+ FrontLeft, FrontRight
+ }, quad_chans[4] = {
+ FrontLeft, FrontRight,
+ BackLeft, BackRight
+ }, surround51_chans[5] = {
+ FrontLeft, FrontRight, FrontCenter,
+ SideLeft, SideRight
+ }, surround51rear_chans[5] = {
+ FrontLeft, FrontRight, FrontCenter,
+ BackLeft, BackRight
+ }, surround61_chans[6] = {
+ FrontLeft, FrontRight,
+ FrontCenter, BackCenter,
+ SideLeft, SideRight
+ }, surround71_chans[7] = {
+ FrontLeft, FrontRight, FrontCenter,
+ BackLeft, BackRight,
+ SideLeft, SideRight
+ };
+ ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
+ const enum Channel *channels = NULL;
+ const char *layout = NULL;
+ ALfloat ambiscale = 1.0f;
+ size_t count = 0;
+ int isfuma;
+ int order;
+ size_t i;
+
+ switch(device->FmtChans)
{
- /* The coverage area would go outside of -pi...+pi. Instead, rotate the
- * speaker angles so it would be as if angle=0, and keep them wrapped
- * within -pi...+pi. */
- if(angle > 0.0f)
- {
- ALuint done;
- ALuint i = 0;
- while(i < device->NumChan && device->SpeakerAngle[i]-angle < -F_PI)
- i++;
- for(done = 0;i < device->NumChan;done++)
- {
- SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
- Speaker2Chan[done] = device->Speaker2Chan[i];
- i++;
- }
- for(i = 0;done < device->NumChan;i++)
- {
- SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_2PI;
- Speaker2Chan[done] = device->Speaker2Chan[i];
- done++;
- }
- }
- else
- {
- /* NOTE: '< device->NumChan' on the iterators is correct here since
- * we need to handle index 0. Because the iterators are unsigned,
- * they'll underflow and wrap to become 0xFFFFFFFF, which will
- * break as expected. */
- ALuint done;
- ALuint i = device->NumChan-1;
- while(i < device->NumChan && device->SpeakerAngle[i]-angle > F_PI)
- i--;
- for(done = device->NumChan-1;i < device->NumChan;done--)
- {
- SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
- Speaker2Chan[done] = device->Speaker2Chan[i];
- i--;
- }
- for(i = device->NumChan-1;done < device->NumChan;i--)
- {
- SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_2PI;
- Speaker2Chan[done] = device->Speaker2Chan[i];
- done--;
- }
- }
- angle = 0.0f;
+ case DevFmtMono:
+ layout = "mono";
+ channels = mono_chans;
+ count = COUNTOF(mono_chans);
+ break;
+ case DevFmtStereo:
+ layout = "stereo";
+ channels = stereo_chans;
+ count = COUNTOF(stereo_chans);
+ break;
+ case DevFmtQuad:
+ layout = "quad";
+ channels = quad_chans;
+ count = COUNTOF(quad_chans);
+ break;
+ case DevFmtX51:
+ layout = "surround51";
+ channels = surround51_chans;
+ count = COUNTOF(surround51_chans);
+ break;
+ case DevFmtX51Rear:
+ layout = "surround51rear";
+ channels = surround51rear_chans;
+ count = COUNTOF(surround51rear_chans);
+ break;
+ case DevFmtX61:
+ layout = "surround61";
+ channels = surround61_chans;
+ count = COUNTOF(surround61_chans);
+ break;
+ case DevFmtX71:
+ layout = "surround71";
+ channels = surround71_chans;
+ count = COUNTOF(surround71_chans);
+ break;
+ case DevFmtBFormat3D:
+ break;
}
- langle = angle - hwidth;
- rangle = angle + hwidth;
- /* First speaker */
- i = 0;
- do {
- ALuint last = device->NumChan-1;
- enum Channel chan = Speaker2Chan[i];
+ if(!layout)
+ return false;
+ else
+ {
+ char name[32] = {0};
+ const char *type;
+ char eol;
- if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
- {
- tmpgains[chan] = 1.0f;
- continue;
- }
+ snprintf(name, sizeof(name), "%s/type", layout);
+ if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", name, &type))
+ return false;
- if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
+ if(sscanf(type, " %31[^: ] : %d%c", name, &order, &eol) != 2)
{
- a = (langle-SpeakerAngle[i]) /
- (SpeakerAngle[i+1]-SpeakerAngle[i]);
- tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
+ ERR("Invalid type value '%s' (expected name:order) for layout %s\n", type, layout);
+ return false;
}
- if(SpeakerAngle[i] > rangle)
- {
- a = (F_2PI + rangle-SpeakerAngle[last]) /
- (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
- tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
- }
- else if(SpeakerAngle[last] < rangle)
- {
- a = (rangle-SpeakerAngle[last]) /
- (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
- tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
- }
- } while(0);
- for(i = 1;i < device->NumChan-1;i++)
- {
- enum Channel chan = Speaker2Chan[i];
- if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
+ if(strcasecmp(name, "fuma") == 0)
+ isfuma = 1;
+ else if(strcasecmp(name, "n3d") == 0)
+ isfuma = 0;
+ else
{
- tmpgains[chan] = 1.0f;
- continue;
+ ERR("Unhandled type name '%s' (expected FuMa or N3D) for layout %s\n", name, layout);
+ return false;
}
- if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
- {
- a = (langle-SpeakerAngle[i]) /
- (SpeakerAngle[i+1]-SpeakerAngle[i]);
- tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
- }
- if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
+ if(order == 3)
+ ambiscale = THIRD_ORDER_SCALE;
+ else if(order == 2)
+ ambiscale = SECOND_ORDER_SCALE;
+ else if(order == 1)
+ ambiscale = FIRST_ORDER_SCALE;
+ else if(order == 0)
+ ambiscale = ZERO_ORDER_SCALE;
+ else
{
- a = (rangle-SpeakerAngle[i-1]) /
- (SpeakerAngle[i]-SpeakerAngle[i-1]);
- tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
+ ERR("Unhandled type order %d (expected 0, 1, 2, or 3) for layout %s\n", order, layout);
+ return false;
}
}
- /* Last speaker */
- i = device->NumChan-1;
- do {
- enum Channel chan = Speaker2Chan[i];
- if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
- {
- tmpgains[Speaker2Chan[i]] = 1.0f;
- continue;
- }
- if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
+ for(i = 0;i < count;i++)
+ {
+ float coeffs[MAX_AMBI_COEFFS] = {0.0f};
+ const char *channame;
+ char chanlayout[32];
+ const char *value;
+ int props = 0;
+ char eol = 0;
+ int j;
+
+ chanmap[i].ChanName = channels[i];
+ channame = GetLabelFromChannel(channels[i]);
+
+ snprintf(chanlayout, sizeof(chanlayout), "%s/%s", layout, channame);
+ if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", chanlayout, &value))
{
- a = (rangle-SpeakerAngle[i-1]) /
- (SpeakerAngle[i]-SpeakerAngle[i-1]);
- tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
+ ERR("Missing channel %s\n", channame);
+ return false;
}
- if(SpeakerAngle[i] < langle)
+ if(order == 3)
+ props = sscanf(value, " %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %c",
+ &coeffs[0], &coeffs[1], &coeffs[2], &coeffs[3],
+ &coeffs[4], &coeffs[5], &coeffs[6], &coeffs[7],
+ &coeffs[8], &coeffs[9], &coeffs[10], &coeffs[11],
+ &coeffs[12], &coeffs[13], &coeffs[14], &coeffs[15],
+ &eol
+ );
+ else if(order == 2)
+ props = sscanf(value, " %f %f %f %f %f %f %f %f %f %c",
+ &coeffs[0], &coeffs[1], &coeffs[2],
+ &coeffs[3], &coeffs[4], &coeffs[5],
+ &coeffs[6], &coeffs[7], &coeffs[8],
+ &eol
+ );
+ else if(order == 1)
+ props = sscanf(value, " %f %f %f %f %c",
+ &coeffs[0], &coeffs[1],
+ &coeffs[2], &coeffs[3],
+ &eol
+ );
+ else if(order == 0)
+ props = sscanf(value, " %f %c", &coeffs[0], &eol);
+ if(props == 0)
{
- a = (langle-SpeakerAngle[i]) /
- (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
- tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
+ ERR("Failed to parse option %s properties\n", chanlayout);
+ return false;
}
- else if(SpeakerAngle[0] > langle)
+
+ if(props > (order+1)*(order+1))
{
- a = (F_2PI + langle-SpeakerAngle[i]) /
- (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
- tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
+ ERR("Excess elements in option %s (expected %d)\n", chanlayout, (order+1)*(order+1));
+ return false;
}
- } while(0);
- for(i = 0;i < device->NumChan;i++)
- {
- enum Channel chan = device->Speaker2Chan[i];
- gains[chan] = sqrtf(tmpgains[chan]) * ingain;
+ for(j = 0;j < MAX_AMBI_COEFFS;++j)
+ chanmap[i].Config[j] = coeffs[j];
}
+ SetChannelMap(device, chanmap, count, ambiscale, isfuma);
+ return true;
}
-
-ALvoid aluInitPanning(ALCdevice *Device)
+ALvoid aluInitPanning(ALCdevice *device)
{
- const char *layoutname = NULL;
- enum Channel *Speaker2Chan;
- ALfloat *SpeakerAngle;
+ /* NOTE: These decoder coefficients are using FuMa channel ordering and
+ * normalization, since that's what was produced by the Ambisonic Decoder
+ * Toolbox. SetChannelMap will convert them to N3D.
+ */
+ static const ChannelMap MonoCfg[1] = {
+ { FrontCenter, { 1.414213562f } },
+ }, StereoCfg[2] = {
+ { FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } },
+ { FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } },
+ }, QuadCfg[4] = {
+ { FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } },
+ { FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } },
+ { BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } },
+ { BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } },
+ }, X51SideCfg[5] = {
+ { FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } },
+ { FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } },
+ { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
+ { SideLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } },
+ { SideRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } },
+ }, X51RearCfg[5] = {
+ { FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } },
+ { FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } },
+ { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
+ { BackLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } },
+ { BackRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } },
+ }, X61Cfg[6] = {
+ { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } },
+ { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } },
+ { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
+ { BackCenter, { 0.353556f, -0.461940f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.165723f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.000000f } },
+ { SideLeft, { 0.289151f, -0.081301f, 0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, -0.032897f } },
+ { SideRight, { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, 0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, 0.032897f } },
+ }, X71Cfg[7] = {
+ { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } },
+ { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } },
+ { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
+ { BackLeft, { 0.224752f, -0.295009f, 0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, -0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065799f } },
+ { BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } },
+ { SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } },
+ { SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } },
+ }, BFormat3D[4] = {
+ { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
+ { BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } },
+ { BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } },
+ { BFormatZ, { 0.0f, 0.0f, 0.0f, 1.0f } },
+ };
+ const ChannelMap *chanmap = NULL;
+ ALfloat ambiscale = 1.0f;
+ size_t count = 0;
+
+ device->AmbiScale = 1.0f;
+ memset(device->AmbiCoeffs, 0, sizeof(device->AmbiCoeffs));
+ device->NumChannels = 0;
+
+ if(device->Hrtf)
+ {
+ ALfloat (*coeffs_list[4])[2];
+ ALuint *delay_list[4];
+ ALuint i;
+
+ count = COUNTOF(BFormat3D);
+ chanmap = BFormat3D;
+ ambiscale = 1.0f;
+
+ for(i = 0;i < count;i++)
+ device->ChannelName[i] = chanmap[i].ChanName;
+ for(;i < MAX_OUTPUT_CHANNELS;i++)
+ device->ChannelName[i] = InvalidChannel;
+ SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE);
+
+ for(i = 0;i < 4;++i)
+ {
+ static const enum Channel inputs[4] = { BFormatW, BFormatX, BFormatY, BFormatZ };
+ int chan = GetChannelIdxByName(device, inputs[i]);
+ coeffs_list[i] = device->Hrtf_Params[chan].Coeffs;
+ delay_list[i] = device->Hrtf_Params[chan].Delay;
+ }
+ GetBFormatHrtfCoeffs(device->Hrtf, 4, coeffs_list, delay_list);
+
+ return;
+ }
+
+ if(LoadChannelSetup(device))
+ return;
- Speaker2Chan = Device->Speaker2Chan;
- SpeakerAngle = Device->SpeakerAngle;
- switch(Device->FmtChans)
+ switch(device->FmtChans)
{
case DevFmtMono:
- Device->NumChan = 1;
- Speaker2Chan[0] = FrontCenter;
- SpeakerAngle[0] = DEG2RAD(0.0f);
- layoutname = NULL;
+ count = COUNTOF(MonoCfg);
+ chanmap = MonoCfg;
+ ambiscale = ZERO_ORDER_SCALE;
break;
case DevFmtStereo:
- Device->NumChan = 2;
- Speaker2Chan[0] = FrontLeft;
- Speaker2Chan[1] = FrontRight;
- SpeakerAngle[0] = DEG2RAD(-90.0f);
- SpeakerAngle[1] = DEG2RAD( 90.0f);
- layoutname = "layout_stereo";
+ count = COUNTOF(StereoCfg);
+ chanmap = StereoCfg;
+ ambiscale = FIRST_ORDER_SCALE;
break;
case DevFmtQuad:
- Device->NumChan = 4;
- Speaker2Chan[0] = BackLeft;
- Speaker2Chan[1] = FrontLeft;
- Speaker2Chan[2] = FrontRight;
- Speaker2Chan[3] = BackRight;
- SpeakerAngle[0] = DEG2RAD(-135.0f);
- SpeakerAngle[1] = DEG2RAD( -45.0f);
- SpeakerAngle[2] = DEG2RAD( 45.0f);
- SpeakerAngle[3] = DEG2RAD( 135.0f);
- layoutname = "layout_quad";
+ count = COUNTOF(QuadCfg);
+ chanmap = QuadCfg;
+ ambiscale = SECOND_ORDER_SCALE;
break;
case DevFmtX51:
- Device->NumChan = 5;
- Speaker2Chan[0] = BackLeft;
- Speaker2Chan[1] = FrontLeft;
- Speaker2Chan[2] = FrontCenter;
- Speaker2Chan[3] = FrontRight;
- Speaker2Chan[4] = BackRight;
- SpeakerAngle[0] = DEG2RAD(-110.0f);
- SpeakerAngle[1] = DEG2RAD( -30.0f);
- SpeakerAngle[2] = DEG2RAD( 0.0f);
- SpeakerAngle[3] = DEG2RAD( 30.0f);
- SpeakerAngle[4] = DEG2RAD( 110.0f);
- layoutname = "layout_surround51";
+ count = COUNTOF(X51SideCfg);
+ chanmap = X51SideCfg;
+ ambiscale = THIRD_ORDER_SCALE;
break;
- case DevFmtX51Side:
- Device->NumChan = 5;
- Speaker2Chan[0] = SideLeft;
- Speaker2Chan[1] = FrontLeft;
- Speaker2Chan[2] = FrontCenter;
- Speaker2Chan[3] = FrontRight;
- Speaker2Chan[4] = SideRight;
- SpeakerAngle[0] = DEG2RAD(-90.0f);
- SpeakerAngle[1] = DEG2RAD(-30.0f);
- SpeakerAngle[2] = DEG2RAD( 0.0f);
- SpeakerAngle[3] = DEG2RAD( 30.0f);
- SpeakerAngle[4] = DEG2RAD( 90.0f);
- layoutname = "layout_side51";
+ case DevFmtX51Rear:
+ count = COUNTOF(X51RearCfg);
+ chanmap = X51RearCfg;
+ ambiscale = THIRD_ORDER_SCALE;
break;
case DevFmtX61:
- Device->NumChan = 6;
- Speaker2Chan[0] = SideLeft;
- Speaker2Chan[1] = FrontLeft;
- Speaker2Chan[2] = FrontCenter;
- Speaker2Chan[3] = FrontRight;
- Speaker2Chan[4] = SideRight;
- Speaker2Chan[5] = BackCenter;
- SpeakerAngle[0] = DEG2RAD(-90.0f);
- SpeakerAngle[1] = DEG2RAD(-30.0f);
- SpeakerAngle[2] = DEG2RAD( 0.0f);
- SpeakerAngle[3] = DEG2RAD( 30.0f);
- SpeakerAngle[4] = DEG2RAD( 90.0f);
- SpeakerAngle[5] = DEG2RAD(180.0f);
- layoutname = "layout_surround61";
+ count = COUNTOF(X61Cfg);
+ chanmap = X61Cfg;
+ ambiscale = THIRD_ORDER_SCALE;
break;
case DevFmtX71:
- Device->NumChan = 7;
- Speaker2Chan[0] = BackLeft;
- Speaker2Chan[1] = SideLeft;
- Speaker2Chan[2] = FrontLeft;
- Speaker2Chan[3] = FrontCenter;
- Speaker2Chan[4] = FrontRight;
- Speaker2Chan[5] = SideRight;
- Speaker2Chan[6] = BackRight;
- SpeakerAngle[0] = DEG2RAD(-150.0f);
- SpeakerAngle[1] = DEG2RAD( -90.0f);
- SpeakerAngle[2] = DEG2RAD( -30.0f);
- SpeakerAngle[3] = DEG2RAD( 0.0f);
- SpeakerAngle[4] = DEG2RAD( 30.0f);
- SpeakerAngle[5] = DEG2RAD( 90.0f);
- SpeakerAngle[6] = DEG2RAD( 150.0f);
- layoutname = "layout_surround71";
+ count = COUNTOF(X71Cfg);
+ chanmap = X71Cfg;
+ ambiscale = THIRD_ORDER_SCALE;
+ break;
+
+ case DevFmtBFormat3D:
+ count = COUNTOF(BFormat3D);
+ chanmap = BFormat3D;
+ ambiscale = 1.0f;
break;
}
- if(layoutname && Device->Type != Loopback)
- SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan);
+
+ SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE);
}
diff --git a/Alc/vector.h b/Alc/vector.h
index 5c094bee..c1fc925d 100644
--- a/Alc/vector.h
+++ b/Alc/vector.h
@@ -7,35 +7,42 @@
/* "Base" vector type, designed to alias with the actual vector types. */
typedef struct vector__s {
- ALsizei Capacity;
- ALsizei Size;
+ size_t Capacity;
+ size_t Size;
} *vector_;
-#define DECL_VECTOR(T) typedef struct vector_##T##_s { \
- ALsizei Capacity; \
- ALsizei Size; \
+#define TYPEDEF_VECTOR(T, N) typedef struct { \
+ size_t Capacity; \
+ size_t Size; \
T Data[]; \
-} *vector_##T; \
-typedef const struct vector_##T##_s *const_vector_##T;
+} _##N; \
+typedef _##N* N; \
+typedef const _##N* const_##N;
-#define VECTOR_INIT(_x) do { (_x) = NULL; } while(0)
-#define VECTOR_DEINIT(_x) do { free((_x)); (_x) = NULL; } while(0)
+#define VECTOR(T) struct { \
+ size_t Capacity; \
+ size_t 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(void *ptr, size_t base_size, size_t obj_count, size_t obj_size, ALboolean exact);
-#define VECTOR_RESERVE(_x, _c) (vector_reserve(&(_x), sizeof(*(_x)), (_c), sizeof((_x)->Data[0]), AL_TRUE))
+ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact);
+#define VECTOR_RESERVE(_x, _c) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c), AL_TRUE))
-/* Helper to change a vector's size. Do not call directly. */
-ALboolean vector_resize(void *ptr, size_t base_size, size_t obj_count, size_t obj_size);
-#define VECTOR_RESIZE(_x, _c) (vector_resize(&(_x), sizeof(*(_x)), (_c), sizeof((_x)->Data[0])))
+ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count);
+#define VECTOR_RESIZE(_x, _c) (vector_resize((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c)))
-#define VECTOR_CAPACITY(_x) ((const ALsizei)((_x) ? (_x)->Capacity : 0))
-#define VECTOR_SIZE(_x) ((const ALsizei)((_x) ? (_x)->Size : 0))
+#define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0)
+#define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0)
-#define VECTOR_ITER_BEGIN(_x) ((_x)->Data + 0)
-#define VECTOR_ITER_END(_x) ((_x)->Data + VECTOR_SIZE(_x))
+#define VECTOR_ITER_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL)
+#define VECTOR_ITER_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL)
-ALboolean vector_insert(void *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend);
+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__({ \
@@ -43,14 +50,14 @@ ALboolean vector_insert(void *ptr, size_t base_size, size_t obj_size, void *ins_
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(&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e)); \
+ _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(&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e)))
+#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(&(_x), sizeof(*(_x)), VECTOR_SIZE(_x)+1, sizeof((_x)->Data[0]), AL_FALSE) && \
+#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--))
@@ -63,7 +70,36 @@ ALboolean vector_insert(void *ptr, size_t base_size, size_t obj_size, void *ins_
_t *_iter = VECTOR_ITER_BEGIN((_x)); \
_t *_end = VECTOR_ITER_END((_x)); \
for(;_iter != _end;++_iter) \
- (_f)(_iter); \
+ _f(_iter); \
+} while(0)
+
+#define VECTOR_FOR_EACH_PARAMS(_t, _x, _f, ...) do { \
+ _t *_iter = VECTOR_ITER_BEGIN((_x)); \
+ _t *_end = VECTOR_ITER_END((_x)); \
+ for(;_iter != _end;++_iter) \
+ _f(__VA_ARGS__, _iter); \
+} while(0)
+
+#define VECTOR_FIND_IF(_i, _t, _x, _f) do { \
+ _t *_iter = VECTOR_ITER_BEGIN((_x)); \
+ _t *_end = VECTOR_ITER_END((_x)); \
+ for(;_iter != _end;++_iter) \
+ { \
+ if(_f(_iter)) \
+ break; \
+ } \
+ (_i) = _iter; \
+} while(0)
+
+#define VECTOR_FIND_IF_PARMS(_i, _t, _x, _f, ...) do { \
+ _t *_iter = VECTOR_ITER_BEGIN((_x)); \
+ _t *_end = VECTOR_ITER_END((_x)); \
+ for(;_iter != _end;++_iter) \
+ { \
+ if(_f(__VA_ARGS__, _iter)) \
+ break; \
+ } \
+ (_i) = _iter; \
} while(0)
#endif /* AL_VECTOR_H */
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cfbe30c9..5596d2fa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,23 +20,12 @@ INCLUDE(CheckSymbolExists)
INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckCSourceCompiles)
INCLUDE(CheckTypeSize)
+include(CheckFileOffsetBits)
SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
-IF(WIN32)
- # This option is mainly for static linking OpenAL Soft into another project
- # that already defines the IDs. It is up to that project to ensure all
- # required IDs are defined.
- OPTION(ALSOFT_NO_UID_DEFS "Do not define GUIDs, IIDs, CLSIDs, or PropertyKeys" OFF)
-ELSE()
- # These are needed on non-Windows systems for extra features
- ADD_DEFINITIONS(-D_GNU_SOURCE=1 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700)
- SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_GNU_SOURCE=1 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700")
-ENDIF()
-
-
OPTION(ALSOFT_DLOPEN "Check for the dlopen API for loading optional libs" ON)
OPTION(ALSOFT_WERROR "Treat compile warnings as errors" OFF)
@@ -45,18 +34,50 @@ OPTION(ALSOFT_UTILS "Build and install utility programs" ON)
OPTION(ALSOFT_NO_CONFIG_UTIL "Disable building the alsoft-config utility" OFF)
OPTION(ALSOFT_EXAMPLES "Build and install example programs" ON)
+OPTION(ALSOFT_TESTS "Build and install test programs" ON)
OPTION(ALSOFT_CONFIG "Install alsoft.conf sample configuration file" ON)
OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" ON)
+OPTION(ALSOFT_INSTALL "Install headers and libraries" ON)
IF(WIN32)
SET(LIBNAME OpenAL32)
ADD_DEFINITIONS("-D_WIN32 -D_WIN32_WINNT=0x0502")
+
+ # This option is mainly for static linking OpenAL Soft into another project
+ # that already defines the IDs. It is up to that project to ensure all
+ # required IDs are defined.
+ OPTION(ALSOFT_NO_UID_DEFS "Do not define GUIDs, IIDs, CLSIDs, or PropertyKeys" OFF)
+
+ IF(MINGW)
+ OPTION(ALSOFT_BUILD_IMPORT_LIB "Build an import .lib using dlltool (requires sed)" ON)
+ IF(NOT DLLTOOL)
+ IF(HOST)
+ SET(DLLTOOL "${HOST}-dlltool")
+ ELSE()
+ SET(DLLTOOL "dlltool")
+ ENDIF()
+ ENDIF()
+ ENDIF()
ELSE()
SET(LIBNAME openal)
+
+ # These are needed on non-Windows systems for extra features
+ ADD_DEFINITIONS(-D_GNU_SOURCE=1 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700)
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_GNU_SOURCE=1 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700")
ENDIF()
+# Set defines for large file support
+CHECK_FILE_OFFSET_BITS()
+IF(_FILE_OFFSET_BITS)
+ ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS})
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_FILE_OFFSET_BITS=${_FILE_OFFSET_BITS}")
+ENDIF()
+ADD_DEFINITIONS(-D_LARGEFILE_SOURCE -D_LARGE_FILES)
+SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_LARGEFILE_SOURCE -D_LARGE_FILES")
+
+
# QNX's gcc do not uses /usr/include and /usr/lib pathes by default
IF ("${CMAKE_C_PLATFORM_ID}" STREQUAL "QNX")
ADD_DEFINITIONS("-I/usr/include")
@@ -68,8 +89,8 @@ IF(NOT LIBTYPE)
ENDIF()
SET(LIB_MAJOR_VERSION "1")
-SET(LIB_MINOR_VERSION "15")
-SET(LIB_REVISION "1")
+SET(LIB_MINOR_VERSION "16")
+SET(LIB_REVISION "0")
SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}")
SET(EXPORT_DECL "")
@@ -83,9 +104,14 @@ CHECK_TYPE_SIZE("long" SIZEOF_LONG)
CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
-CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99)
-IF(HAVE_STD_C99)
- SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
+CHECK_C_COMPILER_FLAG(-std=c11 HAVE_STD_C11)
+IF(HAVE_STD_C11)
+ SET(CMAKE_C_FLAGS "-std=c11 ${CMAKE_C_FLAGS}")
+ELSE()
+ CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99)
+ IF(HAVE_STD_C99)
+ SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
+ ENDIF()
ENDIF()
# MSVC may need workarounds for C99 restrict and inline
@@ -167,6 +193,16 @@ CHECK_C_SOURCE_COMPILES(
}"
HAVE_C11_ALIGNAS)
+# Check if we have C11 _Atomic
+CHECK_C_SOURCE_COMPILES(
+"#include <stdatomic.h>
+ const int _Atomic foo = ATOMIC_VAR_INIT(~0);
+ int main()
+ {
+ return atomic_load(&foo);
+ }"
+HAVE_C11_ATOMIC)
+
# Add definitions, compiler switches, etc.
INCLUDE_DIRECTORIES("${OpenAL_SOURCE_DIR}/include" "${OpenAL_BINARY_DIR}")
IF(CMAKE_VERSION VERSION_LESS "2.8.8")
@@ -188,11 +224,6 @@ IF(NOT CMAKE_DEBUG_POSTFIX)
ENDIF()
IF(MSVC)
- # ???
- SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEBUG")
- SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -DNDEBUG")
- SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
- SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
ADD_DEFINITIONS("/wd4098")
@@ -204,9 +235,6 @@ IF(MSVC)
ENDIF()
IF(DXSDK_DIR)
MESSAGE(STATUS "Using DirectX SDK directory: ${DXSDK_DIR}")
- SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} "${DXSDK_DIR}/Include")
- INCLUDE_DIRECTORIES("${DXSDK_DIR}/Include")
- LINK_DIRECTORIES("${DXSDK_DIR}/Lib")
ENDIF()
OPTION(FORCE_STATIC_VCRT "Force /MT for static VC runtimes" OFF)
@@ -230,27 +258,24 @@ ELSE()
ADD_DEFINITIONS(-Werror)
ENDIF()
- # Force enable PIC if available. The static common library will be linked
- # into the dynamic openal library, which requires all its code to be
- # position-independent, and CMake doesn't automatically enable PIC for
- # static library targets (Windows code is always position-independent).
- CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH)
- IF(HAVE_FPIC_SWITCH AND NOT WIN32)
- ADD_DEFINITIONS(-fPIC)
+ # Force enable -fPIC for CMake versions before 2.8.9 (later versions have
+ # the POSITION_INDEPENDENT_CODE target property). The static common library
+ # will be linked into the dynamic openal library, which requires all its
+ # code to be position-independent.
+ IF(CMAKE_VERSION VERSION_LESS "2.8.9" AND NOT WIN32)
+ CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH)
+ IF(HAVE_FPIC_SWITCH)
+ ADD_DEFINITIONS(-fPIC)
+ ENDIF()
ENDIF()
- SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O2 -D_DEBUG" CACHE STRING
- "Flags used by the compiler during Release with Debug Info builds."
- FORCE)
- SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" CACHE STRING
- "Flags used by the compiler during release minsize builds."
- FORCE)
- SET(CMAKE_C_FLAGS_RELEASE "-O2 -fomit-frame-pointer -DNDEBUG" CACHE STRING
- "Flags used by the compiler during release builds"
- FORCE)
- SET(CMAKE_C_FLAGS_DEBUG "-g3 -D_DEBUG" CACHE STRING
- "Flags used by the compiler during debug builds."
- FORCE)
+ # We want RelWithDebInfo to actually include debug stuff (define _DEBUG
+ # instead of NDEBUG)
+ FOREACH(flag_var CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ IF(${flag_var} MATCHES "-DNDEBUG")
+ STRING(REGEX REPLACE "-DNDEBUG" "-D_DEBUG" ${flag_var} "${${flag_var}}")
+ ENDIF()
+ ENDFOREACH()
CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
@@ -282,14 +307,9 @@ ELSE()
ENDIF()
IF(HAVE_GCC_PROTECTED_VISIBILITY OR HAVE_GCC_DEFAULT_VISIBILITY)
- CHECK_C_COMPILER_FLAG(-fvisibility=internal HAVE_VISIBILITY_INTERNAL_SWITCH)
- IF(HAVE_VISIBILITY_INTERNAL_SWITCH)
- ADD_DEFINITIONS(-fvisibility=internal)
- ELSE()
- CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN_SWITCH)
- IF(HAVE_VISIBILITY_HIDDEN_SWITCH)
- ADD_DEFINITIONS(-fvisibility=hidden)
- ENDIF()
+ CHECK_C_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN_SWITCH)
+ IF(HAVE_VISIBILITY_HIDDEN_SWITCH)
+ ADD_DEFINITIONS(-fvisibility=hidden)
ENDIF()
ENDIF()
@@ -314,6 +334,10 @@ IF(NOT MSVC)
IF(HAVE_MSSE2_SWITCH)
SET(SSE2_SWITCH "-msse2")
ENDIF()
+ CHECK_C_COMPILER_FLAG(-msse3 HAVE_MSSE3_SWITCH)
+ IF(HAVE_MSSE3_SWITCH)
+ SET(SSE3_SWITCH "-msse3")
+ ENDIF()
CHECK_C_COMPILER_FLAG(-msse4.1 HAVE_MSSE4_1_SWITCH)
IF(HAVE_MSSE4_1_SWITCH)
SET(SSE4_1_SWITCH "-msse4.1")
@@ -326,10 +350,11 @@ CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(pri
CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H)
CHECK_INCLUDE_FILE(stdalign.h HAVE_STDALIGN_H)
CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H)
-CHECK_INCLUDE_FILE(ftw.h HAVE_FTW_H)
+CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H)
CHECK_INCLUDE_FILE(io.h HAVE_IO_H)
CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H)
CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H)
+CHECK_INCLUDE_FILE(intrin.h HAVE_INTRIN_H)
CHECK_INCLUDE_FILE(sys/sysconf.h HAVE_SYS_SYSCONF_H)
CHECK_INCLUDE_FILE(fenv.h HAVE_FENV_H)
CHECK_INCLUDE_FILE(float.h HAVE_FLOAT_H)
@@ -339,6 +364,25 @@ IF(NOT HAVE_GUIDDEF_H)
CHECK_INCLUDE_FILE(initguid.h HAVE_INITGUID_H)
ENDIF()
+IF(HAVE_CPUID_H)
+ CHECK_C_SOURCE_COMPILES("#include <cpuid.h>
+ int main()
+ {
+ unsigned int eax, ebx, ecx, edx;
+ return __get_cpuid(0, &eax, &ebx, &ecx, &edx);
+ }" HAVE_GCC_GET_CPUID)
+ENDIF()
+
+IF(HAVE_INTRIN_H)
+ CHECK_C_SOURCE_COMPILES("#include <intrin.h>
+ int main()
+ {
+ int regs[4];
+ __cpuid(regs, 0);
+ return regs[0];
+ }" HAVE_CPUID_INTRINSIC)
+ENDIF()
+
# Some systems need libm for some of the following math functions to work
CHECK_LIBRARY_EXISTS(m pow "" HAVE_LIBM)
IF(HAVE_LIBM)
@@ -351,6 +395,7 @@ CHECK_SYMBOL_EXISTS(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC)
CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN)
CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC)
CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF)
+CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF)
IF(NOT HAVE_C99_VLA)
CHECK_SYMBOL_EXISTS(alloca malloc.h HAVE_ALLOCA)
IF(NOT HAVE_ALLOCA)
@@ -362,12 +407,6 @@ IF(HAVE_FLOAT_H)
CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP)
CHECK_SYMBOL_EXISTS(__control87_2 float.h HAVE___CONTROL87_2)
ENDIF()
-IF(HAVE_FTW_H)
- CHECK_SYMBOL_EXISTS(ftw ftw.h HAVE_FTW)
-ENDIF()
-IF(HAVE_IO_H)
- CHECK_SYMBOL_EXISTS(_wfindfirst io.h HAVE__WFINDFIRST)
-ENDIF()
CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF)
CHECK_FUNCTION_EXISTS(stat HAVE_STAT)
@@ -391,7 +430,7 @@ IF(NOT HAVE_STRNCASECMP)
ADD_DEFINITIONS(-Dstrncasecmp=_strnicmp)
ENDIF()
-CHECK_FUNCTION_EXISTS(snprintf HAVE_SNPRINTF)
+CHECK_SYMBOL_EXISTS(snprintf stdio.h HAVE_SNPRINTF)
IF(NOT HAVE_SNPRINTF)
CHECK_FUNCTION_EXISTS(_snprintf HAVE__SNPRINTF)
IF(NOT HAVE__SNPRINTF)
@@ -480,12 +519,18 @@ IF(NOT HAVE_WINDOWS_H)
CHECK_SYMBOL_EXISTS(pthread_setschedparam pthread.h HAVE_PTHREAD_SETSCHEDPARAM)
- CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
- IF(NOT HAVE_PTHREAD_SETNAME_NP)
- CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP)
- ENDIF()
IF(HAVE_PTHREAD_NP_H)
+ CHECK_SYMBOL_EXISTS(pthread_setname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SETNAME_NP)
+ IF(NOT HAVE_PTHREAD_SETNAME_NP)
+ CHECK_SYMBOL_EXISTS(pthread_set_name_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SET_NAME_NP)
+ ENDIF()
CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np "pthread.h;pthread_np.h" HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
+ ELSE()
+ CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
+ IF(NOT HAVE_PTHREAD_SETNAME_NP)
+ CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP)
+ ENDIF()
+ CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np pthread.h HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
ENDIF()
CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK)
@@ -526,11 +571,7 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c
OpenAL32/alError.c
OpenAL32/alExtension.c
OpenAL32/alFilter.c
- OpenAL32/alFontsound.c
OpenAL32/alListener.c
- OpenAL32/alMidi.c
- OpenAL32/alPreset.c
- OpenAL32/alSoundfont.c
OpenAL32/alSource.c
OpenAL32/alState.c
OpenAL32/alThunk.c
@@ -553,6 +594,7 @@ SET(ALC_OBJS Alc/ALc.c
Alc/effects/null.c
Alc/effects/reverb.c
Alc/helpers.c
+ Alc/bsinc.c
Alc/hrtf.c
Alc/panning.c
Alc/mixer.c
@@ -561,10 +603,25 @@ SET(ALC_OBJS Alc/ALc.c
SET(CPU_EXTS "Default")
-SET(HAVE_SSE 0)
-SET(HAVE_SSE2 0)
-SET(HAVE_SSE4_1 0)
-SET(HAVE_NEON 0)
+SET(HAVE_SSE 0)
+SET(HAVE_SSE2 0)
+SET(HAVE_SSE3 0)
+SET(HAVE_SSE4_1 0)
+SET(HAVE_NEON 0)
+
+SET(HAVE_ALSA 0)
+SET(HAVE_OSS 0)
+SET(HAVE_SOLARIS 0)
+SET(HAVE_SNDIO 0)
+SET(HAVE_QSA 0)
+SET(HAVE_DSOUND 0)
+SET(HAVE_MMDEVAPI 0)
+SET(HAVE_WINMM 0)
+SET(HAVE_PORTAUDIO 0)
+SET(HAVE_PULSEAUDIO 0)
+SET(HAVE_COREAUDIO 0)
+SET(HAVE_OPENSL 0)
+SET(HAVE_WAVE 0)
# Check for SSE support
OPTION(ALSOFT_REQUIRE_SSE "Require SSE support" OFF)
@@ -607,6 +664,26 @@ IF(ALSOFT_REQUIRE_SSE2 AND NOT HAVE_SSE2)
MESSAGE(FATAL_ERROR "Failed to enable required SSE2 CPU extensions")
ENDIF()
+OPTION(ALSOFT_REQUIRE_SSE2 "Require SSE3 support" OFF)
+CHECK_INCLUDE_FILE(pmmintrin.h HAVE_PMMINTRIN_H "${SSE3_SWITCH}")
+IF(HAVE_EMMINTRIN_H)
+ OPTION(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON)
+ IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE3)
+ IF(ALIGN_DECL OR HAVE_C11_ALIGNAS)
+ SET(HAVE_SSE3 1)
+ SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_sse3.c)
+ IF(SSE2_SWITCH)
+ SET_SOURCE_FILES_PROPERTIES(Alc/mixer_sse3.c PROPERTIES
+ COMPILE_FLAGS "${SSE3_SWITCH}")
+ ENDIF()
+ SET(CPU_EXTS "${CPU_EXTS}, SSE3")
+ ENDIF()
+ ENDIF()
+ENDIF()
+IF(ALSOFT_REQUIRE_SSE3 AND NOT HAVE_SSE3)
+ MESSAGE(FATAL_ERROR "Failed to enable required SSE3 CPU extensions")
+ENDIF()
+
OPTION(ALSOFT_REQUIRE_SSE4_1 "Require SSE4.1 support" OFF)
CHECK_INCLUDE_FILE(smmintrin.h HAVE_SMMINTRIN_H "${SSE4_1_SWITCH}")
IF(HAVE_SMMINTRIN_H)
@@ -643,55 +720,6 @@ IF(ALSOFT_REQUIRE_NEON AND NOT HAVE_NEON)
ENDIF()
-SET(ALC_OBJS ${ALC_OBJS}
- Alc/midi/base.c
- Alc/midi/sf2load.c
- Alc/midi/dummy.c
- Alc/midi/fluidsynth.c
- Alc/midi/soft.c
-)
-
-SET(HAVE_FLUIDSYNTH 0)
-
-# Check for FluidSynth support
-OPTION(ALSOFT_REQUIRE_FLUIDSYNTH "Require FluidSynth MIDI" OFF)
-FIND_PACKAGE(FluidSynth)
-IF(FLUIDSYNTH_FOUND)
- OPTION(ALSOFT_MIDI_FLUIDSYNTH "Enable FluidSynth MIDI" ON)
- IF(ALSOFT_MIDI_FLUIDSYNTH)
- SET(HAVE_FLUIDSYNTH 1)
- IF(CMAKE_VERSION VERSION_LESS "2.8.8")
- INCLUDE_DIRECTORIES(${FLUIDSYNTH_INCLUDE_DIR})
- ENDIF()
- SET(EXTRA_LIBS ${FLUIDSYNTH_LIBRARIES} ${EXTRA_LIBS})
- ENDIF()
-ENDIF()
-IF(ALSOFT_REQUIRE_FLUIDSYNTH AND NOT HAVE_FLUIDSYNTH)
- MESSAGE(FATAL_ERROR "Failed to enabled required FluidSynth support")
-ENDIF()
-
-
-SET(ALC_OBJS ${ALC_OBJS}
- Alc/backends/base.c
- # Default backends, always available
- Alc/backends/loopback.c
- Alc/backends/null.c
-)
-
-SET(BACKENDS "")
-SET(HAVE_ALSA 0)
-SET(HAVE_OSS 0)
-SET(HAVE_SOLARIS 0)
-SET(HAVE_SNDIO 0)
-SET(HAVE_QSA 0)
-SET(HAVE_DSOUND 0)
-SET(HAVE_MMDEVAPI 0)
-SET(HAVE_WINMM 0)
-SET(HAVE_PORTAUDIO 0)
-SET(HAVE_PULSEAUDIO 0)
-SET(HAVE_COREAUDIO 0)
-SET(HAVE_OPENSL 0)
-SET(HAVE_WAVE 0)
IF(WIN32 OR HAVE_DLFCN_H)
SET(IS_LINKED "")
MACRO(ADD_BACKEND_LIBS _LIBS)
@@ -703,6 +731,14 @@ ELSE()
ENDMACRO()
ENDIF()
+SET(BACKENDS "")
+SET(ALC_OBJS ${ALC_OBJS}
+ Alc/backends/base.c
+ # Default backends, always available
+ Alc/backends/loopback.c
+ Alc/backends/null.c
+)
+
# Check ALSA backend
OPTION(ALSOFT_REQUIRE_ALSA "Require ALSA backend" OFF)
FIND_PACKAGE(ALSA)
@@ -796,45 +832,12 @@ IF(ALSOFT_REQUIRE_QSA AND NOT HAVE_QSA)
MESSAGE(FATAL_ERROR "Failed to enabled required QSA backend")
ENDIF()
-# Check DSound backend
+# Check Windows-only backends
+OPTION(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF)
OPTION(ALSOFT_REQUIRE_DSOUND "Require DirectSound backend" OFF)
-FIND_PACKAGE(DSound)
-IF(DSOUND_FOUND)
- OPTION(ALSOFT_BACKEND_DSOUND "Enable DirectSound backend" ON)
- IF(ALSOFT_BACKEND_DSOUND)
- SET(HAVE_DSOUND 1)
- SET(BACKENDS "${BACKENDS} DirectSound${IS_LINKED},")
- SET(ALC_OBJS ${ALC_OBJS} Alc/backends/dsound.c)
- ADD_BACKEND_LIBS(${DSOUND_LIBRARIES})
- IF(CMAKE_VERSION VERSION_LESS "2.8.8")
- INCLUDE_DIRECTORIES(${DSOUND_INCLUDE_DIRS})
- ENDIF()
- ENDIF()
-ENDIF()
-IF(ALSOFT_REQUIRE_DSOUND AND NOT HAVE_DSOUND)
- MESSAGE(FATAL_ERROR "Failed to enabled required DSound backend")
-ENDIF()
-
-# Check for MMDevApi backend
OPTION(ALSOFT_REQUIRE_MMDEVAPI "Require MMDevApi backend" OFF)
IF(HAVE_WINDOWS_H)
- CHECK_INCLUDE_FILE(mmdeviceapi.h HAVE_MMDEVICEAPI_H)
- IF(HAVE_MMDEVICEAPI_H)
- OPTION(ALSOFT_BACKEND_MMDEVAPI "Enable MMDevApi backend" ON)
- IF(ALSOFT_BACKEND_MMDEVAPI)
- SET(HAVE_MMDEVAPI 1)
- SET(BACKENDS "${BACKENDS} MMDevApi,")
- SET(ALC_OBJS ${ALC_OBJS} Alc/backends/mmdevapi.c)
- ENDIF()
- ENDIF()
-ENDIF()
-IF(ALSOFT_REQUIRE_MMDEVAPI AND NOT HAVE_MMDEVAPI)
- MESSAGE(FATAL_ERROR "Failed to enabled required MMDevApi backend")
-ENDIF()
-
-# Check MMSystem backend
-OPTION(ALSOFT_REQUIRE_WINMM "Require Windows Multimedia backend" OFF)
-IF(HAVE_WINDOWS_H)
+ # Check MMSystem backend
CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0502)
IF(HAVE_MMSYSTEM_H)
CHECK_SHARED_FUNCTION_EXISTS(waveOutOpen "windows.h;mmsystem.h" winmm "" HAVE_LIBWINMM)
@@ -848,10 +851,42 @@ IF(HAVE_WINDOWS_H)
ENDIF()
ENDIF()
ENDIF()
+
+ # Check DSound backend
+ FIND_PACKAGE(DSound)
+ IF(DSOUND_FOUND)
+ OPTION(ALSOFT_BACKEND_DSOUND "Enable DirectSound backend" ON)
+ IF(ALSOFT_BACKEND_DSOUND)
+ SET(HAVE_DSOUND 1)
+ SET(BACKENDS "${BACKENDS} DirectSound${IS_LINKED},")
+ SET(ALC_OBJS ${ALC_OBJS} Alc/backends/dsound.c)
+ ADD_BACKEND_LIBS(${DSOUND_LIBRARIES})
+ IF(CMAKE_VERSION VERSION_LESS "2.8.8")
+ INCLUDE_DIRECTORIES(${DSOUND_INCLUDE_DIRS})
+ ENDIF()
+ ENDIF()
+ ENDIF()
+
+ # Check for MMDevApi backend
+ CHECK_INCLUDE_FILE(mmdeviceapi.h HAVE_MMDEVICEAPI_H)
+ IF(HAVE_MMDEVICEAPI_H)
+ OPTION(ALSOFT_BACKEND_MMDEVAPI "Enable MMDevApi backend" ON)
+ IF(ALSOFT_BACKEND_MMDEVAPI)
+ SET(HAVE_MMDEVAPI 1)
+ SET(BACKENDS "${BACKENDS} MMDevApi,")
+ SET(ALC_OBJS ${ALC_OBJS} Alc/backends/mmdevapi.c)
+ ENDIF()
+ ENDIF()
ENDIF()
IF(ALSOFT_REQUIRE_WINMM AND NOT HAVE_WINMM)
MESSAGE(FATAL_ERROR "Failed to enabled required WinMM backend")
ENDIF()
+IF(ALSOFT_REQUIRE_DSOUND AND NOT HAVE_DSOUND)
+ MESSAGE(FATAL_ERROR "Failed to enabled required DSound backend")
+ENDIF()
+IF(ALSOFT_REQUIRE_MMDEVAPI AND NOT HAVE_MMDEVAPI)
+ MESSAGE(FATAL_ERROR "Failed to enabled required MMDevApi backend")
+ENDIF()
# Check PortAudio backend
OPTION(ALSOFT_REQUIRE_PORTAUDIO "Require PortAudio backend" OFF)
@@ -891,6 +926,25 @@ IF(ALSOFT_REQUIRE_PULSEAUDIO AND NOT HAVE_PULSEAUDIO)
MESSAGE(FATAL_ERROR "Failed to enabled required PulseAudio backend")
ENDIF()
+# Check JACK backend
+OPTION(ALSOFT_REQUIRE_JACK "Require JACK backend" OFF)
+FIND_PACKAGE(JACK)
+IF(JACK_FOUND)
+ OPTION(ALSOFT_BACKEND_JACK "Enable JACK backend" ON)
+ IF(ALSOFT_BACKEND_JACK)
+ SET(HAVE_JACK 1)
+ SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},")
+ SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.c)
+ ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES})
+ IF(CMAKE_VERSION VERSION_LESS "2.8.8")
+ INCLUDE_DIRECTORIES(${JACK_INCLUDE_DIRS})
+ ENDIF()
+ ENDIF()
+ENDIF()
+IF(ALSOFT_REQUIRE_JACK AND NOT HAVE_JACK)
+ MESSAGE(FATAL_ERROR "Failed to enabled required JACK backend")
+ENDIF()
+
# Check CoreAudio backend
OPTION(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" OFF)
FIND_LIBRARY(COREAUDIO_FRAMEWORK
@@ -995,17 +1049,21 @@ CONFIGURE_FILE(
# Build a common library with reusable helpers
ADD_LIBRARY(common STATIC ${COMMON_OBJS})
+IF(NOT LIBTYPE STREQUAL "STATIC")
+ SET_PROPERTY(TARGET common PROPERTY POSITION_INDEPENDENT_CODE TRUE)
+ENDIF()
# Build main library
-ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
+IF(LIBTYPE STREQUAL "STATIC")
+ ADD_LIBRARY(${LIBNAME} STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS})
+ELSE()
+ ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS})
+ENDIF()
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES)
IF(WIN32 AND ALSOFT_NO_UID_DEFS)
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS)
ENDIF()
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc")
-IF(FLUIDSYNTH_FOUND)
- SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${FLUIDSYNTH_INCLUDE_DIR})
-ENDIF()
IF(HAVE_ALSA)
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS})
ENDIF()
@@ -1030,30 +1088,57 @@ ENDIF()
IF(HAVE_PULSEAUDIO)
SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS})
ENDIF()
+IF(HAVE_JACK)
+ SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS})
+ENDIF()
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION}
SOVERSION ${LIB_MAJOR_VERSION})
IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
+
+ IF(MINGW AND ALSOFT_BUILD_IMPORT_LIB)
+ FIND_PROGRAM(SED_EXECUTABLE NAMES sed DOC "sed executable")
+ FIND_PROGRAM(DLLTOOL_EXECUTABLE NAMES "${DLLTOOL}" DOC "dlltool executable")
+ IF(NOT SED_EXECUTABLE OR NOT DLLTOOL_EXECUTABLE)
+ MESSAGE(STATUS "")
+ IF(NOT SED_EXECUTABLE)
+ MESSAGE(STATUS "WARNING: Cannot find sed, disabling .def/.lib generation")
+ ENDIF()
+ IF(NOT DLLTOOL_EXECUTABLE)
+ MESSAGE(STATUS "WARNING: Cannot find dlltool, disabling .def/.lib generation")
+ ENDIF()
+ ELSE()
+ SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES LINK_FLAGS "-Wl,--output-def,${LIBNAME}.def")
+ ADD_CUSTOM_COMMAND(TARGET ${LIBNAME} POST_BUILD
+ COMMAND "${SED_EXECUTABLE}" -i -e "s/ @[^ ]*//" ${LIBNAME}.def
+ COMMAND "${DLLTOOL_EXECUTABLE}" -d ${LIBNAME}.def -l ${LIBNAME}.lib -D ${LIBNAME}.dll
+ COMMENT "Stripping ordinals from ${LIBNAME}.def and generating ${LIBNAME}.lib..."
+ VERBATIM
+ )
+ ENDIF()
+ ENDIF()
ENDIF()
TARGET_LINK_LIBRARIES(${LIBNAME} common ${EXTRA_LIBS})
-# Add an install target here
-INSTALL(TARGETS ${LIBNAME}
- RUNTIME DESTINATION bin
- LIBRARY DESTINATION "lib${LIB_SUFFIX}"
- ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
-)
-INSTALL(FILES include/AL/al.h
- include/AL/alc.h
- include/AL/alext.h
- include/AL/efx.h
- include/AL/efx-creative.h
- include/AL/efx-presets.h
- DESTINATION include/AL
-)
-INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
- DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
+IF(ALSOFT_INSTALL)
+ # Add an install target here
+ INSTALL(TARGETS ${LIBNAME}
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+ ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+ )
+ INSTALL(FILES include/AL/al.h
+ include/AL/alc.h
+ include/AL/alext.h
+ include/AL/efx.h
+ include/AL/efx-creative.h
+ include/AL/efx-presets.h
+ DESTINATION include/AL
+ )
+ INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
+ DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
+ENDIF()
MESSAGE(STATUS "")
@@ -1063,10 +1148,6 @@ MESSAGE(STATUS "")
MESSAGE(STATUS "Building with support for CPU extensions:")
MESSAGE(STATUS " ${CPU_EXTS}")
MESSAGE(STATUS "")
-IF(HAVE_FLUIDSYNTH)
- MESSAGE(STATUS "FluidSynth support for ALC_SOFT_midi_interface enabled")
- MESSAGE(STATUS "")
-ENDIF()
IF(WIN32)
IF(NOT HAVE_DSOUND)
@@ -1088,6 +1169,7 @@ ENDIF()
# Install HRTF definitions
IF(ALSOFT_HRTF_DEFS)
INSTALL(FILES hrtf/default-44100.mhr
+ hrtf/default-48000.mhr
DESTINATION share/openal/hrtf
)
MESSAGE(STATUS "Installing HRTF definitions")
@@ -1103,11 +1185,18 @@ IF(ALSOFT_UTILS)
TARGET_LINK_LIBRARIES(makehrtf m)
ENDIF()
- INSTALL(TARGETS openal-info makehrtf
- RUNTIME DESTINATION bin
- LIBRARY DESTINATION "lib${LIB_SUFFIX}"
- ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
- )
+ ADD_EXECUTABLE(bsincgen utils/bsincgen.c)
+ IF(HAVE_LIBM)
+ TARGET_LINK_LIBRARIES(bsincgen m)
+ ENDIF()
+
+ IF(ALSOFT_INSTALL)
+ INSTALL(TARGETS openal-info makehrtf bsincgen
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+ ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+ )
+ ENDIF()
MESSAGE(STATUS "Building utility programs")
IF(TARGET alsoft-config)
@@ -1116,6 +1205,24 @@ IF(ALSOFT_UTILS)
MESSAGE(STATUS "")
ENDIF()
+IF(ALSOFT_TESTS)
+ ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c)
+
+ ADD_EXECUTABLE(altonegen examples/altonegen.c)
+ TARGET_LINK_LIBRARIES(altonegen test-common ${LIBNAME})
+
+ IF(ALSOFT_INSTALL)
+ INSTALL(TARGETS altonegen
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+ ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+ )
+ ENDIF()
+
+ MESSAGE(STATUS "Building test programs")
+ MESSAGE(STATUS "")
+ENDIF()
+
IF(ALSOFT_EXAMPLES)
IF(SDL2_FOUND AND SDL_SOUND_FOUND)
ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c
@@ -1143,11 +1250,18 @@ IF(ALSOFT_EXAMPLES)
SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
${SDL_SOUND_INCLUDE_DIR})
- INSTALL(TARGETS alstream alreverb allatency alloopback
- RUNTIME DESTINATION bin
- LIBRARY DESTINATION "lib${LIB_SUFFIX}"
- ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
- )
+ ADD_EXECUTABLE(alhrtf examples/alhrtf.c)
+ TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME})
+ SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
+ ${SDL_SOUND_INCLUDE_DIR})
+
+ IF(ALSOFT_INSTALL)
+ INSTALL(TARGETS alstream alreverb allatency alloopback
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+ ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+ )
+ ENDIF()
SET(FFVER_OK FALSE)
IF(FFMPEG_FOUND)
@@ -1179,11 +1293,13 @@ IF(ALSOFT_EXAMPLES)
SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
${FFMPEG_INCLUDE_DIRS})
- INSTALL(TARGETS alffplay
- RUNTIME DESTINATION bin
- LIBRARY DESTINATION "lib${LIB_SUFFIX}"
- ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
- )
+ IF(ALSOFT_INSTALL)
+ INSTALL(TARGETS alffplay
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+ ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+ )
+ ENDIF()
MESSAGE(STATUS "Building SDL and FFmpeg example programs")
ELSE()
MESSAGE(STATUS "Building SDL example programs")
diff --git a/COPYING b/COPYING
index d0c89786..5bc8fb2c 100644
--- a/COPYING
+++ b/COPYING
@@ -1,17 +1,15 @@
-
- GNU LIBRARY GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
- Preamble
+ Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -101,7 +99,7 @@ works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
- GNU LIBRARY GENERAL PUBLIC LICENSE
+ GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
@@ -413,7 +411,7 @@ decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
- NO WARRANTY
+ NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
@@ -436,9 +434,9 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
- END OF TERMS AND CONDITIONS
+ END OF TERMS AND CONDITIONS
- Appendix: How to Apply These Terms to Your New Libraries
+ How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
@@ -465,8 +463,8 @@ convey the exclusion of warranty; and each file should have at least the
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
@@ -481,4 +479,3 @@ necessary. Here is a sample; alter the names:
Ty Coon, President of Vice
That's all there is to it!
-
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..2f037254
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,158 @@
+openal-soft-1.17.0:
+
+ Implemented a JACK playback backend.
+
+ Implemented the AL_EXT_BFORMAT and AL_EXT_MULAW_BFORMAT extensions.
+
+ Implemented the ALC_SOFT_HRTF extension.
+
+ Implemented C, SSE3, and SSE4.1 based 4- and 8-point Sinc resamplers.
+
+ Implemented a C and SSE based band-limited Sinc resampler. This does 12- to
+ 24-point Sinc resampling, and performs anti-aliasing.
+
+ Implemented B-Format output support for the wave file writer. This creates
+ FuMa-style first-order Ambisonics wave files (AMB format).
+
+ Implemented a stereo-mode config option for treating stereo modes as either
+ speakers or headphones.
+
+ Implemented per-device configuration options.
+
+ Fixed handling of PulseAudio and MMDevAPI devices that have identical
+ descriptions.
+
+ Fixed a potential lockup when stopping playback of suspended PulseAudio devices.
+
+ Fixed logging of Unicode characters on Windows.
+
+ Fixed 5.1 surround sound channels. By default it will now use the side
+ channels for the surround output. A configuration using rear channels is
+ still available.
+
+ Fixed the QSA backend potentially altering the capture format.
+
+ Fixed detecting MMDevAPI's default device.
+
+ Fixed returning the default capture device name.
+
+ Fixed mixing property calculations when deferring context updates.
+
+ Altered the behavior of alcSuspendContext and alcProcessContext to better
+ match certain Windows drivers.
+
+ Altered the panning algorithm, utilizing Ambisonics for better side and
+ back positioning cues with surround sound output.
+
+ Improved support for certain older Windows apps.
+
+ Improved the alffplay example to support surround sound streams.
+
+ Improved support for building as a sub-project.
+
+ Added an HRTF playback example.
+
+ Added a tone generator output test.
+
+ Added a toolchain to help with cross-compiling to Android.
+
+openal-soft-1.16.0:
+
+ Implemented EFX Chorus, Flanger, Distortion, Equalizer, and Compressor
+ effects.
+
+ Implemented high-pass and band-pass EFX filters.
+
+ Implemented the high-pass filter for the EAXReverb effect.
+
+ Implemented SSE2 and SSE4.1 linear resamplers.
+
+ Implemented Neon-enhanced non-HRTF mixers.
+
+ Implemented a QSA backend, for QNX.
+
+ Implemented the ALC_SOFT_pause_device, AL_SOFT_deferred_updates,
+ AL_SOFT_block_alignment, AL_SOFT_MSADPCM, and AL_SOFT_source_length
+ extensions.
+
+ Fixed resetting mmdevapi backend devices.
+
+ Fixed clamping when converting 32-bit float samples to integer.
+
+ Fixed modulation range in the Modulator effect.
+
+ Several fixes for the OpenSL playback backend.
+
+ Fixed device specifier names that have Unicode characters on Windows.
+
+ Added support for filenames and paths with Unicode (UTF-8) characters on
+ Windows.
+
+ Added support for alsoft.conf config files found in XDG Base Directory
+ Specification locations (XDG_CONFIG_DIRS and XDG_CONFIG_HOME, or their
+ defaults) on non-Windows systems.
+
+ Added a GUI configuration utility (requires Qt 4.8).
+
+ Added support for environment variable expansion in config options (not
+ keys or section names).
+
+ Added an example that uses SDL2 and ffmpeg.
+
+ Modified examples to use SDL_sound.
+
+ Modified CMake config option names for better sorting.
+
+ HRTF data sets specified in the hrtf_tables config option may now be
+ relative or absolute filenames.
+
+ Made the default HRTF data set an external file, and added a data set for
+ 48khz playback in addition to 44.1khz.
+
+ Added support for C11 atomic methods.
+
+ Improved support for some non-GNU build systems.
+
+openal-soft-1.15.1:
+
+ Fixed a regression with retrieving the source's AL_GAIN property.
+
+openal-soft-1.15:
+
+ Fixed device enumeration with the OSS backend.
+
+ Reorganized internal mixing logic, so unneeded steps can potentially be
+ skipped for better performance.
+
+ Removed the lookup table for calculating the mixing pans. The panning is
+ now calculated directly for better precision.
+
+ Improved the panning of stereo source channels when using stereo output.
+
+ Improved source filter quality on send paths.
+
+ Added a config option to allow PulseAudio to move streams between devices.
+
+ The PulseAudio backend will now attempt to spawn a server by default.
+
+ Added a workaround for a DirectSound bug relating to float32 output.
+
+ Added SSE-based mixers, for HRTF and non-HRTF mixing.
+
+ Added support for the new AL_SOFT_source_latency extension.
+
+ Improved ALSA capture by avoiding an extra buffer when using sizes
+ supported by the underlying device.
+
+ Improved the makehrtf utility to support new options and input formats.
+
+ Modified the CFLAGS declared in the pkg-config file so the "AL/" portion of
+ the header includes can optionally be omitted.
+
+ Added a couple example code programs to show how to apply reverb, and
+ retrieve latency.
+
+ The configuration sample is now installed into the share/openal/ directory
+ instead of /etc/openal.
+
+ The configuration sample now gets installed by default.
diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h
index bc871111..0f0d3ef8 100644
--- a/OpenAL32/Include/alAuxEffectSlot.h
+++ b/OpenAL32/Include/alAuxEffectSlot.h
@@ -22,7 +22,7 @@ struct ALeffectStateVtable {
ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
void (*const update)(ALeffectState *state, ALCdevice *device, const struct ALeffectslot *slot);
- void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE]);
+ void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels);
void (*const Delete)(void *ptr);
};
@@ -31,7 +31,7 @@ struct ALeffectStateVtable {
DECLARE_THUNK(T, ALeffectState, void, Destruct) \
DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \
DECLARE_THUNK2(T, ALeffectState, void, update, ALCdevice*, const ALeffectslot*) \
-DECLARE_THUNK3(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict) \
+DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \
static void T##_ALeffectState_Delete(void *ptr) \
{ return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \
\
@@ -71,7 +71,7 @@ typedef struct ALeffectslot {
volatile ALfloat Gain;
volatile ALboolean AuxSendAuto;
- volatile ALenum NeedsUpdate;
+ ATOMIC(ALenum) NeedsUpdate;
ALeffectState *EffectState;
alignas(16) ALfloat WetBuffer[1][BUFFERSIZE];
diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h
index 12a682f4..dd046da8 100644
--- a/OpenAL32/Include/alBuffer.h
+++ b/OpenAL32/Include/alBuffer.h
@@ -32,6 +32,8 @@ enum UserFmtChannels {
UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */
UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */
UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */
+ UserFmtBFormat2D = 0x10000000, /* WXY */
+ UserFmtBFormat3D, /* WXYZ */
};
ALuint BytesFromUserFmt(enum UserFmtType type) DECL_CONST;
@@ -56,6 +58,8 @@ enum FmtChannels {
FmtX51 = UserFmtX51,
FmtX61 = UserFmtX61,
FmtX71 = UserFmtX71,
+ FmtBFormat2D = UserFmtBFormat2D,
+ FmtBFormat3D = UserFmtBFormat3D,
};
#define MAX_INPUT_CHANNELS (8)
@@ -85,8 +89,8 @@ typedef struct ALbuffer {
ALsizei LoopStart;
ALsizei LoopEnd;
- ALsizei UnpackAlign;
- ALsizei PackAlign;
+ ATOMIC(ALsizei) UnpackAlign;
+ ATOMIC(ALsizei) PackAlign;
/* Number of times buffer was attached to a source (deletion can only occur when 0) */
RefCount ref;
@@ -97,6 +101,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)
diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h
index f656c56a..91ee782f 100644
--- a/OpenAL32/Include/alEffect.h
+++ b/OpenAL32/Include/alEffect.h
@@ -132,7 +132,6 @@ typedef union ALeffectProps {
} Echo;
struct {
- ALfloat Delay;
ALfloat LowCutoff;
ALfloat LowGain;
ALfloat Mid1Center;
diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h
index 62b5fda8..3c65fd9f 100644
--- a/OpenAL32/Include/alFilter.h
+++ b/OpenAL32/Include/alFilter.h
@@ -3,6 +3,8 @@
#include "alMain.h"
+#include "math_defs.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -11,23 +13,29 @@ extern "C" {
#define HIGHPASSFREQREF (250.0f)
-/* Filters implementation is based on the "Cookbook formulae for audio *
- * EQ biquad filter coefficients" by Robert Bristow-Johnson *
- * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */
+/* Filters implementation is based on the "Cookbook formulae for audio
+ * EQ biquad filter coefficients" by Robert Bristow-Johnson
+ * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+ */
+/* Implementation note: For the shelf filters, the specified gain is for the
+ * reference frequency, which is the centerpoint of the transition band. This
+ * better matches EFX filter design. To set the gain for the shelf itself, use
+ * the square root of the desired linear gain (or halve the dB gain).
+ */
typedef enum ALfilterType {
/** EFX-style low-pass filter, specifying a gain and reference frequency. */
ALfilterType_HighShelf,
/** EFX-style high-pass filter, specifying a gain and reference frequency. */
ALfilterType_LowShelf,
- /** Peaking filter, specifying a gain, reference frequency, and bandwidth. */
+ /** Peaking filter, specifying a gain and reference frequency. */
ALfilterType_Peaking,
- /** Low-pass cut-off filter, specifying a cut-off frequency and bandwidth. */
+ /** Low-pass cut-off filter, specifying a cut-off frequency. */
ALfilterType_LowPass,
- /** High-pass cut-off filter, specifying a cut-off frequency and bandwidth. */
+ /** High-pass cut-off filter, specifying a cut-off frequency. */
ALfilterType_HighPass,
- /** Band-pass filter, specifying a center frequency and bandwidth. */
+ /** Band-pass filter, specifying a center frequency. */
ALfilterType_BandPass,
} ALfilterType;
@@ -41,8 +49,27 @@ typedef struct ALfilterState {
} ALfilterState;
#define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__))
+/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the
+ * reference gain and shelf slope parameter.
+ * 0 < gain
+ * 0 < slope <= 1
+ */
+inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope)
+{
+ return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f);
+}
+/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency
+ * multiple (i.e. ref_freq / sampling_freq) and bandwidth.
+ * 0 < freq_mult < 0.5.
+ */
+inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth)
+{
+ ALfloat w0 = F_TAU * freq_mult;
+ return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0));
+}
+
void ALfilterState_clear(ALfilterState *filter);
-void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth);
+void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample)
{
@@ -63,6 +90,8 @@ inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample
void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples);
+void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples);
+
typedef struct ALfilter {
// Filter type (AL_FILTER_NULL, ...)
diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h
index ee07d87c..c9bd9be0 100644
--- a/OpenAL32/Include/alListener.h
+++ b/OpenAL32/Include/alListener.h
@@ -2,22 +2,23 @@
#define _AL_LISTENER_H_
#include "alMain.h"
+#include "alu.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ALlistener {
- volatile ALfloat Position[3];
- volatile ALfloat Velocity[3];
+ aluVector Position;
+ aluVector Velocity;
volatile ALfloat Forward[3];
volatile ALfloat Up[3];
volatile ALfloat Gain;
volatile ALfloat MetersPerUnit;
struct {
- ALfloat Matrix[4][4];
- ALfloat Velocity[3];
+ aluMatrixd Matrix;
+ aluVector Velocity;
} Params;
} ALlistener;
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 232c438c..8f1fd956 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -37,211 +37,7 @@
#include "vector.h"
#include "alstring.h"
-#ifndef ALC_SOFT_HRTF
-#define ALC_SOFT_HRTF 1
-#define ALC_HRTF_SOFT 0x1992
-#endif
-
-#ifndef ALC_SOFT_midi_interface
-#define ALC_SOFT_midi_interface 1
-#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
-#define AL_PRESETS_SIZE_SOFT 0x9993
-#define AL_PRESETS_SOFT 0x9992
-#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
-
-#define AL_SAMPLE_START_SOFT 0x2000
-#define AL_SAMPLE_END_SOFT 0x2001
-#define AL_SAMPLE_LOOP_START_SOFT 0x2002
-#define AL_SAMPLE_LOOP_END_SOFT 0x2003
-#define AL_SAMPLE_RATE_SOFT 0x2004
-#define AL_BASE_KEY_SOFT 0x2005
-#define AL_KEY_CORRECTION_SOFT 0x2006
-#define AL_SAMPLE_TYPE_SOFT 0x2007
-#define AL_FONTSOUND_LINK_SOFT 0x2008
-#define AL_MOD_LFO_TO_PITCH_SOFT 0x0005
-#define AL_VIBRATO_LFO_TO_PITCH_SOFT 0x0006
-#define AL_MOD_ENV_TO_PITCH_SOFT 0x0007
-#define AL_FILTER_CUTOFF_SOFT 0x0008
-#define AL_FILTER_RESONANCE_SOFT 0x0009
-#define AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT 0x000A
-#define AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT 0x000B
-#define AL_MOD_LFO_TO_VOLUME_SOFT 0x000D
-#define AL_CHORUS_SEND_SOFT 0x000F
-#define AL_REVERB_SEND_SOFT 0x0010
-#define AL_PAN_SOFT 0x0011
-#define AL_MOD_LFO_DELAY_SOFT 0x0015
-#define AL_MOD_LFO_FREQUENCY_SOFT 0x0016
-#define AL_VIBRATO_LFO_DELAY_SOFT 0x0017
-#define AL_VIBRATO_LFO_FREQUENCY_SOFT 0x0018
-#define AL_MOD_ENV_DELAYTIME_SOFT 0x0019
-#define AL_MOD_ENV_ATTACKTIME_SOFT 0x001A
-#define AL_MOD_ENV_HOLDTIME_SOFT 0x001B
-#define AL_MOD_ENV_DECAYTIME_SOFT 0x001C
-#define AL_MOD_ENV_SUSTAINVOLUME_SOFT 0x001D
-#define AL_MOD_ENV_RELEASETIME_SOFT 0x002E
-#define AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT 0x001F
-#define AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT 0x0020
-#define AL_VOLUME_ENV_DELAYTIME_SOFT 0x0021
-#define AL_VOLUME_ENV_ATTACKTIME_SOFT 0x0022
-#define AL_VOLUME_ENV_HOLDTIME_SOFT 0x0023
-#define AL_VOLUME_ENV_DECAYTIME_SOFT 0x0024
-#define AL_VOLUME_ENV_SUSTAINVOLUME_SOFT 0x0025
-#define AL_VOLUME_ENV_RELEASETIME_SOFT 0x0026
-#define AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT 0x0027
-#define AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT 0x0028
-#define AL_KEY_RANGE_SOFT 0x002B
-#define AL_VELOCITY_RANGE_SOFT 0x002C
-#define AL_ATTENUATION_SOFT 0x0030
-#define AL_TUNING_COARSE_SOFT 0x0033
-#define AL_TUNING_FINE_SOFT 0x0034
-#define AL_LOOP_MODE_SOFT 0x0036
-#define AL_TUNING_SCALE_SOFT 0x0038
-#define AL_EXCLUSIVE_CLASS_SOFT 0x0039
-#define AL_LOOP_CONTINUOUS_SOFT 0x0001
-#define AL_LOOP_UNTIL_RELEASE_SOFT 0x0003
-#define AL_RIGHT_SOFT 0x0002
-#define AL_LEFT_SOFT 0x0004
-#define AL_FORMAT_TYPE_SOFT 0x1991
-#define AL_NOTEOFF_SOFT 0x0080
-#define AL_NOTEON_SOFT 0x0090
-#define AL_KEYPRESSURE_SOFT 0x00A0
-#define AL_CONTROLLERCHANGE_SOFT 0x00B0
-#define AL_PROGRAMCHANGE_SOFT 0x00C0
-#define AL_CHANNELPRESSURE_SOFT 0x00D0
-#define AL_PITCHBEND_SOFT 0x00E0
-typedef void (AL_APIENTRY*LPALGENSOUNDFONTSSOFT)(ALsizei n, ALuint *ids);
-typedef void (AL_APIENTRY*LPALDELETESOUNDFONTSSOFT)(ALsizei n, const ALuint *ids);
-typedef ALboolean (AL_APIENTRY*LPALISSOUNDFONTSOFT)(ALuint id);
-typedef void (AL_APIENTRY*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);
-typedef void (AL_APIENTRY*LPALDELETEPRESETSSOFT)(ALsizei n, const ALuint *ids);
-typedef ALboolean (AL_APIENTRY*LPALISPRESETSOFT)(ALuint id);
-typedef void (AL_APIENTRY*LPALPRESETISOFT)(ALuint id, ALenum param, ALint value);
-typedef void (AL_APIENTRY*LPALPRESETIVSOFT)(ALuint id, ALenum param, const ALint *values);
-typedef void (AL_APIENTRY*LPALPRESETFONTSOUNDSSOFT)(ALuint id, ALsizei count, const ALuint *fsids);
-typedef void (AL_APIENTRY*LPALGETPRESETIVSOFT)(ALuint id, ALenum param, ALint *values);
-typedef void (AL_APIENTRY*LPALGENFONTSOUNDSSOFT)(ALsizei n, ALuint *ids);
-typedef void (AL_APIENTRY*LPALDELETEFONTSOUNDSSOFT)(ALsizei n, const ALuint *ids);
-typedef ALboolean (AL_APIENTRY*LPALISFONTSOUNDSOFT)(ALuint id);
-typedef void (AL_APIENTRY*LPALFONTSOUNDISOFT)(ALuint id, ALenum param, ALint value);
-typedef void (AL_APIENTRY*LPALFONTSOUND2ISOFT)(ALuint id, ALenum param, ALint value1, ALint value2);
-typedef void (AL_APIENTRY*LPALFONTSOUNDIVSOFT)(ALuint id, ALenum param, const ALint *values);
-typedef void (AL_APIENTRY*LPALGETFONTSOUNDIVSOFT)(ALuint id, ALenum param, ALint *values);
-typedef void (AL_APIENTRY*LPALFONTSOUNDMOFULATORISOFT)(ALuint id, ALsizei stage, ALenum param, ALint value);
-typedef void (AL_APIENTRY*LPALGETFONTSOUNDMODULATORIVSOFT)(ALuint id, ALsizei stage, ALenum param, ALint *values);
-typedef void (AL_APIENTRY*LPALMIDISOUNDFONTSOFT)(ALuint id);
-typedef void (AL_APIENTRY*LPALMIDISOUNDFONTVSOFT)(ALsizei count, const ALuint *ids);
-typedef void (AL_APIENTRY*LPALMIDIEVENTSOFT)(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2);
-typedef void (AL_APIENTRY*LPALMIDISYSEXSOFT)(ALuint64SOFT time, const ALbyte *data, ALsizei size);
-typedef void (AL_APIENTRY*LPALMIDIPLAYSOFT)(void);
-typedef void (AL_APIENTRY*LPALMIDIPAUSESOFT)(void);
-typedef void (AL_APIENTRY*LPALMIDISTOPSOFT)(void);
-typedef void (AL_APIENTRY*LPALMIDIRESETSOFT)(void);
-typedef void (AL_APIENTRY*LPALMIDIGAINSOFT)(ALfloat value);
-typedef ALint64SOFT (AL_APIENTRY*LPALGETINTEGER64SOFT)(ALenum pname);
-typedef void (AL_APIENTRY*LPALGETINTEGER64VSOFT)(ALenum pname, ALint64SOFT *values);
-typedef void (AL_APIENTRY*LPALLOADSOUNDFONTSOFT)(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user);
-#ifdef AL_ALEXT_PROTOTYPES
-AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids);
-AL_API void AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids);
-AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id);
-AL_API void AL_APIENTRY 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);
-
-AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids);
-AL_API void AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids);
-AL_API ALboolean AL_APIENTRY alIsPresetSOFT(ALuint id);
-AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value);
-AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *values);
-AL_API void AL_APIENTRY alGetPresetivSOFT(ALuint id, ALenum param, ALint *values);
-AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids);
-
-AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids);
-AL_API void AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids);
-AL_API ALboolean AL_APIENTRY alIsFontsoundSOFT(ALuint id);
-AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value);
-AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1, ALint value2);
-AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *values);
-AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *values);
-AL_API void AL_APIENTRY alFontsoundModulatoriSOFT(ALuint id, ALsizei stage, ALenum param, ALint value);
-AL_API void AL_APIENTRY alGetFontsoundModulatorivSOFT(ALuint id, ALsizei stage, ALenum param, ALint *values);
-
-AL_API void AL_APIENTRY alMidiSoundfontSOFT(ALuint id);
-AL_API void AL_APIENTRY alMidiSoundfontvSOFT(ALsizei count, const ALuint *ids);
-AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2);
-AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, ALsizei size);
-AL_API void AL_APIENTRY alMidiPlaySOFT(void);
-AL_API void AL_APIENTRY alMidiPauseSOFT(void);
-AL_API void AL_APIENTRY alMidiStopSOFT(void);
-AL_API void AL_APIENTRY alMidiResetSOFT(void);
-AL_API void AL_APIENTRY alMidiGainSOFT(ALfloat value);
-AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname);
-AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values);
-AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user);
-#endif
-#endif
-
-#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);
-#ifdef AL_ALEXT_PROTOTYPES
-ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device);
-ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device);
-#endif
-#endif
+#include "hrtf.h"
#ifndef ALC_SOFT_device_clock
#define ALC_SOFT_device_clock 1
@@ -254,26 +50,10 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
#endif
#endif
-#ifndef AL_SOFT_MSADPCM
-#define AL_SOFT_MSADPCM 1
-#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302
-#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303
-#endif
-
-
-#ifdef IN_IDE_PARSER
-/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
- * recent versions (at least 4.5.1) do recognize GCC's __restrict. */
-#define restrict __restrict
-#endif
-
typedef ALint64SOFT ALint64;
typedef ALuint64SOFT ALuint64;
-typedef ptrdiff_t ALintptrEXT;
-typedef ptrdiff_t ALsizeiptrEXT;
-
#ifndef U64
#if defined(_MSC_VER)
#define U64(x) ((ALuint64)(x##ui64))
@@ -393,9 +173,13 @@ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
+#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); }
+
#define DECLARE_DEFAULT_ALLOCATORS(T) \
-static void* T##_New(size_t size) { return malloc(size); } \
-static void T##_Delete(void *ptr) { free(ptr); }
+static void* T##_New(size_t size) { return al_malloc(16, size); } \
+static void T##_Delete(void *ptr) { al_free(ptr); }
/* Helper to extract an argument list for VCALL. Not used directly. */
#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
@@ -414,6 +198,18 @@ static void T##_Delete(void *ptr) { free(ptr); }
} while(0)
+#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \
+ } \
+} while(0)
+
+#define NEW_OBJ(_res, T) do { \
+ _res = T##_New(sizeof(T)); \
+ if(_res) \
+ { \
+ memset(_res, 0, sizeof(T)); \
+ T##_Construct(_res, EXTRACT_NEW_ARGS
+
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -480,25 +276,11 @@ typedef struct {
void (*StopCapture)(ALCdevice*);
ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint);
ALCuint (*AvailableSamples)(ALCdevice*);
-
- ALint64 (*GetLatency)(ALCdevice*);
} BackendFuncs;
-ALCboolean alc_solaris_init(BackendFuncs *func_list);
-void alc_solaris_deinit(void);
-void alc_solaris_probe(enum DevProbe type);
ALCboolean alc_sndio_init(BackendFuncs *func_list);
void alc_sndio_deinit(void);
void alc_sndio_probe(enum DevProbe type);
-ALCboolean alcWinMMInit(BackendFuncs *FuncList);
-void alcWinMMDeinit(void);
-void alcWinMMProbe(enum DevProbe type);
-ALCboolean alc_pa_init(BackendFuncs *func_list);
-void alc_pa_deinit(void);
-void alc_pa_probe(enum DevProbe type);
-ALCboolean alc_wave_init(BackendFuncs *func_list);
-void alc_wave_deinit(void);
-void alc_wave_probe(enum DevProbe type);
ALCboolean alc_ca_init(BackendFuncs *func_list);
void alc_ca_deinit(void);
void alc_ca_probe(enum DevProbe type);
@@ -524,14 +306,6 @@ enum DistanceModel {
DefaultDistanceModel = InverseDistanceClamped
};
-enum Resampler {
- PointResampler,
- LinearResampler,
- CubicResampler,
-
- ResamplerMax,
-};
-
enum Channel {
FrontLeft = 0,
FrontRight,
@@ -543,7 +317,12 @@ enum Channel {
SideLeft,
SideRight,
- MaxChannels,
+ BFormatW,
+ BFormatX,
+ BFormatY,
+ BFormatZ,
+
+ InvalidChannel
};
@@ -567,11 +346,14 @@ enum DevFmtChannels {
DevFmtX61 = ALC_6POINT1_SOFT,
DevFmtX71 = ALC_7POINT1_SOFT,
- /* Similar to 5.1, except using the side channels instead of back */
- DevFmtX51Side = 0x80000000,
+ /* Similar to 5.1, except using rear channels instead of sides */
+ DevFmtX51Rear = 0x80000000,
+
+ DevFmtBFormat3D,
DevFmtChannelsDefault = DevFmtStereo
};
+#define MAX_OUTPUT_CHANNELS (8)
ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST;
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST;
@@ -596,6 +378,38 @@ enum DeviceType {
};
+enum HrtfMode {
+ DisabledHrtf,
+ BasicHrtf,
+ FullHrtf
+};
+
+
+/* The maximum number of Ambisonics coefficients. For a given order (o), the
+ * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4,
+ * second-order has 9, and third-order has 16. */
+#define MAX_AMBI_COEFFS 16
+
+typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS];
+
+
+#define HRTF_HISTORY_BITS (6)
+#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
+#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
+
+typedef struct HrtfState {
+ alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
+ alignas(16) ALfloat Values[HRIR_LENGTH][2];
+} HrtfState;
+
+typedef struct HrtfParams {
+ alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
+ alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
+ ALuint Delay[2];
+ ALint DelayStep[2];
+} HrtfParams;
+
+
/* Size for temporary storage of buffer data, in ALfloats. Larger values need
* more memory, while smaller values may need more iterations. The value needs
* to be a sensible size, however, as it constrains the max stepping value used
@@ -603,7 +417,6 @@ enum DeviceType {
*/
#define BUFFERSIZE (2048u)
-
struct ALCdevice_struct
{
RefCount ref;
@@ -616,10 +429,11 @@ struct ALCdevice_struct
ALuint NumUpdates;
enum DevFmtChannels FmtChans;
enum DevFmtType FmtType;
+ ALboolean IsHeadphones;
al_string DeviceName;
- volatile ALCenum LastError;
+ ATOMIC(ALCenum) LastError;
// Maximum number of sources that can be created
ALuint MaxNoOfSources;
@@ -639,36 +453,26 @@ struct ALCdevice_struct
// Map of Filters for this device
UIntMap FilterMap;
- // Map of Soundfonts for this device
- UIntMap SfontMap;
-
- // Map of Presets for this device
- UIntMap PresetMap;
-
- // Map of Fontsounds for this device
- UIntMap FontsoundMap;
-
- /* Default soundfont (accessible as ID 0) */
- struct ALsoundfont *DefaultSfont;
-
- /* MIDI synth engine */
- struct MidiSynth *Synth;
-
/* HRTF filter tables */
+ vector_HrtfEntry Hrtf_List;
+ al_string Hrtf_Name;
const struct Hrtf *Hrtf;
+ ALCenum Hrtf_Status;
+ enum HrtfMode Hrtf_Mode;
+ HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS];
+ HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS];
+ ALuint Hrtf_Offset;
// Stereo-to-binaural filter
struct bs2b *Bs2b;
- ALCint Bs2bLevel;
// Device flags
- ALuint Flags;
+ ALuint Flags;
- ALuint ChannelOffsets[MaxChannels];
-
- enum Channel Speaker2Chan[MaxChannels];
- ALfloat SpeakerAngle[MaxChannels];
- ALuint NumChan;
+ enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
+ ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS];
+ ALfloat AmbiScale; /* Scale for first-order XYZ inputs using AmbCoeffs. */
+ ALuint NumChannels;
ALuint64 ClockBase;
ALuint SamplesDone;
@@ -678,8 +482,8 @@ struct ALCdevice_struct
alignas(16) ALfloat ResampledData[BUFFERSIZE];
alignas(16) ALfloat FilteredData[BUFFERSIZE];
- // Dry path buffer mix
- alignas(16) ALfloat DryBuffer[MaxChannels][BUFFERSIZE];
+ /* Dry path buffer mix. */
+ alignas(16) ALfloat (*DryBuffer)[BUFFERSIZE];
/* Running count of the mixer invocations, in 31.1 fixed point. This
* actually increments *twice* when mixing, first at the start and then at
@@ -692,11 +496,11 @@ struct ALCdevice_struct
struct ALeffectslot *DefaultSlot;
// Contexts created on this device
- ALCcontext *volatile ContextList;
+ ATOMIC(ALCcontext*) ContextList;
struct ALCbackend *Backend;
- void *ExtraData; // For the backend's use
+ void *ExtraData; // For the backend's use
ALCdevice *volatile next;
@@ -710,11 +514,6 @@ struct ALCdevice_struct
#define DEVICE_CHANNELS_REQUEST (1<<2)
// Sample type was requested by the config file
#define DEVICE_SAMPLE_TYPE_REQUEST (1<<3)
-// HRTF was requested by the app
-#define DEVICE_HRTF_REQUEST (1<<4)
-
-// Stereo sources cover 120-degree angles around +/-90
-#define DEVICE_WIDE_STEREO (1<<16)
// Specifies if the DSP is paused at user request
#define DEVICE_PAUSED (1<<30)
@@ -722,9 +521,6 @@ struct ALCdevice_struct
// Specifies if the device is currently running
#define DEVICE_RUNNING (1<<31)
-/* Invalid channel offset */
-#define INVALID_OFFSET (~0u)
-
/* Nanosecond resolution for the device clock time. */
#define DEVICE_CLOCK_RES U64(1000000000)
@@ -734,9 +530,7 @@ struct ALCdevice_struct
* compatibility with pthread_setname_np limitations. */
#define MIXER_THREAD_NAME "alsoft-mixer"
-
-typedef struct ALeffectslot *ALeffectslotPtr;
-DECL_VECTOR(ALeffectslotPtr)
+#define RECORD_THREAD_NAME "alsoft-record"
struct ALCcontext_struct
@@ -748,9 +542,9 @@ struct ALCcontext_struct
UIntMap SourceMap;
UIntMap EffectSlotMap;
- volatile ALenum LastError;
+ ATOMIC(ALenum) LastError;
- volatile ALenum UpdateSources;
+ ATOMIC(ALenum) UpdateSources;
volatile enum DistanceModel DistanceModel;
volatile ALboolean SourceDistanceModel;
@@ -760,11 +554,11 @@ struct ALCcontext_struct
volatile ALfloat SpeedOfSound;
volatile ALenum DeferUpdates;
- struct ALactivesource **ActiveSources;
- ALsizei ActiveSourceCount;
- ALsizei MaxActiveSources;
+ struct ALvoice *Voices;
+ ALsizei VoiceCount;
+ ALsizei MaxVoices;
- vector_ALeffectslotPtr ActiveAuxSlots;
+ VECTOR(struct ALeffectslot*) ActiveAuxSlots;
ALCdevice *Device;
const ALCchar *ExtensionList;
@@ -783,11 +577,11 @@ void ALCcontext_DecRef(ALCcontext *context);
void AppendAllDevicesList(const ALCchar *name);
void AppendCaptureDeviceList(const ALCchar *name);
-ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device);
-
void ALCdevice_Lock(ALCdevice *device);
void ALCdevice_Unlock(ALCdevice *device);
-ALint64 ALCdevice_GetLatency(ALCdevice *device);
+
+void ALCcontext_DeferUpdates(ALCcontext *context);
+void ALCcontext_ProcessUpdates(ALCcontext *context);
inline void LockContext(ALCcontext *context)
{ ALCdevice_Lock(context->Device); }
@@ -822,15 +616,35 @@ ALsizei RingBufferSize(RingBuffer *ring);
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len);
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len);
+typedef struct ll_ringbuffer ll_ringbuffer_t;
+typedef struct ll_ringbuffer_data {
+ char *buf;
+ size_t len;
+} ll_ringbuffer_data_t;
+ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz);
+void ll_ringbuffer_free(ll_ringbuffer_t *rb);
+void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
+void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
+size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt);
+size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt);
+void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt);
+size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb);
+int ll_ringbuffer_mlock(ll_ringbuffer_t *rb);
+void ll_ringbuffer_reset(ll_ringbuffer_t *rb);
+size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt);
+void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt);
+size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb);
+
void ReadALConfig(void);
void FreeALConfig(void);
-int ConfigValueExists(const char *blockName, const char *keyName);
-const char *GetConfigValue(const char *blockName, const char *keyName, const char *def);
-int GetConfigValueBool(const char *blockName, const char *keyName, int def);
-int ConfigValueStr(const char *blockName, const char *keyName, const char **ret);
-int ConfigValueInt(const char *blockName, const char *keyName, int *ret);
-int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret);
-int ConfigValueFloat(const char *blockName, const char *keyName, float *ret);
+int ConfigValueExists(const char *devName, const char *blockName, const char *keyName);
+const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def);
+int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def);
+int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret);
+int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret);
+int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret);
+int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret);
+int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret);
void SetRTPriority(void);
@@ -840,10 +654,27 @@ void SetDefaultWFXChannelOrder(ALCdevice *device);
const ALCchar *DevFmtTypeString(enum DevFmtType type) DECL_CONST;
const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST;
+/**
+ * GetChannelIdxByName
+ *
+ * Returns the device's channel index given a channel name (e.g. FrontCenter),
+ * or -1 if it doesn't exist.
+ */
+inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan)
+{
+ ALint i = 0;
+ for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+ {
+ if(device->ChannelName[i] == chan)
+ return i;
+ }
+ return -1;
+}
+
extern FILE *LogFile;
-#if defined(__GNUC__) && !defined(IN_IDE_PARSER)
+#if defined(__GNUC__) && !defined(_WIN32) && !defined(IN_IDE_PARSER)
#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__)
#else
void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4);
@@ -887,14 +718,17 @@ extern ALuint CPUCapFlags;
enum {
CPU_CAP_SSE = 1<<0,
CPU_CAP_SSE2 = 1<<1,
- CPU_CAP_SSE4_1 = 1<<2,
- CPU_CAP_NEON = 1<<3,
+ CPU_CAP_SSE3 = 1<<2,
+ CPU_CAP_SSE4_1 = 1<<3,
+ CPU_CAP_NEON = 1<<4,
};
void FillCPUCaps(ALuint capfilter);
FILE *OpenDataFile(const char *fname, const char *subdir);
+vector_al_string SearchDataFiles(const char *match, const char *subdir);
+
/* Small hack to use a pointer-to-array type as a normal argument type.
* Shouldn't be used directly. */
typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
diff --git a/OpenAL32/Include/alMidi.h b/OpenAL32/Include/alMidi.h
deleted file mode 100644
index d18c165e..00000000
--- a/OpenAL32/Include/alMidi.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef ALMIDI_H
-#define ALMIDI_H
-
-#include "alMain.h"
-#include "atomic.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct ALsfmodulator {
- struct {
- ALenum Input;
- ALenum Type;
- ALenum Form;
- } Source[2];
- ALint Amount;
- ALenum TransformOp;
- ALenum Dest;
-} ALsfmodulator;
-
-typedef struct ALenvelope {
- ALint DelayTime;
- ALint AttackTime;
- ALint HoldTime;
- ALint DecayTime;
- ALint SustainAttn;
- ALint ReleaseTime;
- ALint KeyToHoldTime;
- ALint KeyToDecayTime;
-} ALenvelope;
-
-
-typedef struct ALfontsound {
- RefCount ref;
-
- ALint MinKey, MaxKey;
- ALint MinVelocity, MaxVelocity;
-
- ALint ModLfoToPitch;
- ALint VibratoLfoToPitch;
- ALint ModEnvToPitch;
-
- ALint FilterCutoff;
- ALint FilterQ;
- ALint ModLfoToFilterCutoff;
- ALint ModEnvToFilterCutoff;
- ALint ModLfoToVolume;
-
- ALint ChorusSend;
- ALint ReverbSend;
-
- ALint Pan;
-
- struct {
- ALint Delay;
- ALint Frequency;
- } ModLfo;
- struct {
- ALint Delay;
- ALint Frequency;
- } VibratoLfo;
-
- ALenvelope ModEnv;
- ALenvelope VolEnv;
-
- ALint Attenuation;
-
- ALint CoarseTuning;
- ALint FineTuning;
-
- ALenum LoopMode;
-
- ALint TuningScale;
-
- ALint ExclusiveClass;
-
- ALuint Start;
- ALuint End;
- ALuint LoopStart;
- ALuint LoopEnd;
- ALuint SampleRate;
- ALubyte PitchKey;
- ALbyte PitchCorrection;
- ALenum SampleType;
- struct ALfontsound *Link;
-
- 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);
-
-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 {
- RefCount ref;
-
- ALint Preset; /* a.k.a. MIDI program number */
- ALint Bank; /* MIDI bank 0...127, or percussion (bank 128) */
-
- ALfontsound **Sounds;
- ALsizei NumSounds;
-
- ALuint id;
-} ALsfpreset;
-
-ALsfpreset *NewPreset(ALCcontext *context);
-void DeletePreset(ALsfpreset *preset, ALCdevice *device);
-
-inline struct ALsfpreset *LookupPreset(ALCdevice *device, ALuint id)
-{ return (struct ALsfpreset*)LookupUIntMapKey(&device->PresetMap, id); }
-inline struct ALsfpreset *RemovePreset(ALCdevice *device, ALuint id)
-{ return (struct ALsfpreset*)RemoveUIntMapKey(&device->PresetMap, id); }
-
-void ReleaseALPresets(ALCdevice *device);
-
-
-typedef struct ALsoundfont {
- 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);
-
-inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id)
-{ return (struct ALsoundfont*)LookupUIntMapKey(&device->SfontMap, id); }
-inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id)
-{ return (struct ALsoundfont*)RemoveUIntMapKey(&device->SfontMap, id); }
-
-void ReleaseALSoundfonts(ALCdevice *device);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ALMIDI_H */
diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h
index f87f1672..13596161 100644
--- a/OpenAL32/Include/alSource.h
+++ b/OpenAL32/Include/alSource.h
@@ -11,41 +11,37 @@
extern "C" {
#endif
-extern enum Resampler DefaultResampler;
-
-extern const ALsizei ResamplerPadding[ResamplerMax];
-extern const ALsizei ResamplerPrePadding[ResamplerMax];
+struct ALbuffer;
+struct ALsource;
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 ALactivesource {
- struct ALsource *Source;
+typedef struct ALvoice {
+ struct ALsource *volatile Source;
/** Method to update mixing parameters. */
- ALvoid (*Update)(struct ALactivesource *self, const ALCcontext *context);
+ ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const ALCcontext *context);
/** Current target parameters used for mixing. */
- ResamplerFunc Resample;
- union {
- DryMixerFunc Mix;
- HrtfMixerFunc HrtfMix;
- } Dry;
- WetMixerFunc WetMix;
+ ALint Step;
ALboolean IsHrtf;
- ALint Step;
ALuint Offset; /* Number of output samples mixed since starting. */
+ alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
+
+ BsincState SincState;
+
DirectParams Direct;
SendParams Send[MAX_SENDS];
-} ALactivesource;
+} ALvoice;
typedef struct ALsource {
@@ -60,9 +56,10 @@ typedef struct ALsource {
volatile ALfloat RefDistance;
volatile ALfloat MaxDistance;
volatile ALfloat RollOffFactor;
- volatile ALfloat Position[3];
- volatile ALfloat Velocity[3];
- volatile ALfloat Orientation[3];
+ aluVector Position;
+ aluVector Velocity;
+ aluVector Direction;
+ volatile ALfloat Orientation[2][3];
volatile ALboolean HeadRelative;
volatile ALboolean Looping;
volatile enum DistanceModel DistanceModel;
@@ -77,7 +74,7 @@ typedef struct ALsource {
volatile ALfloat RoomRolloffFactor;
volatile ALfloat DopplerFactor;
- enum Resampler Resampler;
+ volatile ALfloat Radius;
/**
* Last user-specified offset, and the offset type (bytes, samples, or
@@ -102,8 +99,8 @@ typedef struct ALsource {
ALuint position_fraction;
/** Source Buffer Queue info. */
- ALbufferlistitem *volatile queue;
- ALbufferlistitem *volatile current_buffer;
+ ATOMIC(ALbufferlistitem*) queue;
+ ATOMIC(ALbufferlistitem*) current_buffer;
RWLock queue_lock;
/** Current buffer sample info. */
@@ -128,7 +125,7 @@ typedef struct ALsource {
} Send[MAX_SENDS];
/** Source needs to update its mixing parameters. */
- volatile ALenum NeedsUpdate;
+ ATOMIC(ALenum) NeedsUpdate;
/** Self ID */
ALuint id;
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
index c4b4d674..a309c4ab 100644
--- a/OpenAL32/Include/alu.h
+++ b/OpenAL32/Include/alu.h
@@ -16,30 +16,111 @@
#include "hrtf.h"
#include "align.h"
+#include "math_defs.h"
-#define F_PI (3.14159265358979323846f)
-#define F_PI_2 (1.57079632679489661923f)
-#define F_2PI (6.28318530717958647692f)
+#define MAX_PITCH (255)
-#ifndef FLT_EPSILON
-#define FLT_EPSILON (1.19209290e-07f)
+/* Maximum number of buffer samples before the current pos needed for resampling. */
+#define MAX_PRE_SAMPLES 12
+
+/* Maximum number of buffer samples after the current pos needed for resampling. */
+#define MAX_POST_SAMPLES 12
+
+
+#ifdef __cplusplus
+extern "C" {
#endif
-#define DEG2RAD(x) ((ALfloat)(x) * (F_PI/180.0f))
-#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI))
+struct ALsource;
+struct ALvoice;
-#define SRC_HISTORY_BITS (6)
-#define SRC_HISTORY_LENGTH (1<<SRC_HISTORY_BITS)
-#define SRC_HISTORY_MASK (SRC_HISTORY_LENGTH-1)
+/* The number of distinct scale and phase intervals within the filter table. */
+#define BSINC_SCALE_BITS 4
+#define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
+#define BSINC_PHASE_BITS 4
+#define BSINC_PHASE_COUNT (1<<BSINC_PHASE_BITS)
-#define MAX_PITCH (10)
+/* Interpolator state. Kind of a misnomer since the interpolator itself is
+ * stateless. This just keeps it from having to recompute scale-related
+ * mappings for every sample.
+ */
+typedef struct BsincState {
+ ALfloat sf; /* Scale interpolation factor. */
+ ALuint m; /* Coefficient count. */
+ ALint l; /* Left coefficient offset. */
+ struct {
+ const ALfloat *filter; /* Filter coefficients. */
+ const ALfloat *scDelta; /* Scale deltas. */
+ const ALfloat *phDelta; /* Phase deltas. */
+ const ALfloat *spDelta; /* Scale-phase deltas. */
+ } coeffs[BSINC_PHASE_COUNT];
+} BsincState;
-#ifdef __cplusplus
-extern "C" {
-#endif
+typedef union aluVector {
+ alignas(16) ALfloat v[4];
+} aluVector;
+
+inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w)
+{
+ vector->v[0] = x;
+ vector->v[1] = y;
+ vector->v[2] = z;
+ vector->v[3] = w;
+}
+
+
+typedef union aluMatrixf {
+ alignas(16) ALfloat m[4][4];
+} aluMatrixf;
+
+inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
+ ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3)
+{
+ matrix->m[row][0] = m0;
+ matrix->m[row][1] = m1;
+ matrix->m[row][2] = m2;
+ matrix->m[row][3] = m3;
+}
+
+inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
+ ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
+ ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
+ ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33)
+{
+ aluMatrixfSetRow(matrix, 0, m00, m01, m02, m03);
+ aluMatrixfSetRow(matrix, 1, m10, m11, m12, m13);
+ aluMatrixfSetRow(matrix, 2, m20, m21, m22, m23);
+ aluMatrixfSetRow(matrix, 3, m30, m31, m32, m33);
+}
+
+
+typedef union aluMatrixd {
+ alignas(16) ALdouble m[4][4];
+} aluMatrixd;
+
+inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
+ ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3)
+{
+ matrix->m[row][0] = m0;
+ matrix->m[row][1] = m1;
+ matrix->m[row][2] = m2;
+ matrix->m[row][3] = m3;
+}
+
+inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
+ ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
+ ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
+ ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33)
+{
+ aluMatrixdSetRow(matrix, 0, m00, m01, m02, m03);
+ aluMatrixdSetRow(matrix, 1, m10, m11, m12, m13);
+ aluMatrixdSetRow(matrix, 2, m20, m21, m22, m23);
+ aluMatrixdSetRow(matrix, 3, m30, m31, m32, m33);
+}
+
enum ActiveFilters {
AF_None = 0,
@@ -49,39 +130,24 @@ enum ActiveFilters {
};
-typedef struct HrtfState {
- alignas(16) ALfloat History[SRC_HISTORY_LENGTH];
- alignas(16) ALfloat Values[HRIR_LENGTH][2];
-} HrtfState;
-
-typedef struct HrtfParams {
- alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
- alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
- ALuint Delay[2];
- ALint DelayStep[2];
-} HrtfParams;
-
-
typedef struct MixGains {
- ALfloat Current[MaxChannels];
- ALfloat Step[MaxChannels];
- ALfloat Target[MaxChannels];
-} MixGains;
-
-typedef struct MixGainMono {
ALfloat Current;
ALfloat Step;
ALfloat Target;
-} MixGainMono;
+} MixGains;
typedef struct DirectParams {
ALfloat (*OutBuffer)[BUFFERSIZE];
+ ALuint OutChannels;
/* If not 'moving', gain/coefficients are set directly without fading. */
ALboolean Moving;
/* Stepping counter for gain/coefficient fading. */
ALuint Counter;
+ /* Last direction (relative to listener) and gain of a moving source. */
+ aluVector LastDir;
+ ALfloat LastGain;
struct {
enum ActiveFilters ActiveType;
@@ -89,17 +155,11 @@ typedef struct DirectParams {
ALfilterState HighPass;
} Filters[MAX_INPUT_CHANNELS];
- union {
- struct {
- HrtfParams Params[MAX_INPUT_CHANNELS];
- HrtfState State[MAX_INPUT_CHANNELS];
- ALuint IrSize;
- ALfloat Gain;
- ALfloat Dir[3];
- } Hrtf;
-
- MixGains Gains[MAX_INPUT_CHANNELS];
- } Mix;
+ struct {
+ HrtfParams Params;
+ HrtfState State;
+ } Hrtf[MAX_INPUT_CHANNELS];
+ MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
} DirectParams;
typedef struct SendParams {
@@ -114,25 +174,23 @@ typedef struct SendParams {
ALfilterState HighPass;
} Filters[MAX_INPUT_CHANNELS];
- /* Gain control, which applies to all input channels to a single (mono)
+ /* Gain control, which applies to each input channel to a single (mono)
* output buffer. */
- MixGainMono Gain;
+ MixGains Gains[MAX_INPUT_CHANNELS];
} SendParams;
-typedef const ALfloat* (*ResamplerFunc)(const ALfloat *src, ALuint frac, ALuint increment,
- ALfloat *restrict dst, ALuint dstlen);
+typedef const ALfloat* (*ResamplerFunc)(const BsincState *state,
+ const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen
+);
-typedef void (*DryMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- MixGains *Gains, ALuint Counter, ALuint OutPos,
- ALuint BufferSize);
+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);
-typedef void (*WetMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
- MixGainMono *Gain, ALuint Counter, ALuint OutPos,
- ALuint BufferSize);
#define GAIN_SILENCE_THRESHOLD (0.00001f) /* -100dB */
@@ -140,7 +198,7 @@ typedef void (*WetMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const AL
#define SPEEDOFSOUNDMETRESPERSEC (343.3f)
#define AIRABSORBGAINHF (0.99426f) /* -0.05dB */
-#define FRACTIONBITS (14)
+#define FRACTIONBITS (12)
#define FRACTIONONE (1<<FRACTIONBITS)
#define FRACTIONMASK (FRACTIONONE-1)
@@ -188,47 +246,75 @@ inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
{ return minu64(max, maxu64(min, val)); }
+union ResamplerCoeffs {
+ ALfloat FIR4[FRACTIONONE][4];
+ ALfloat FIR8[FRACTIONONE][8];
+};
+extern alignas(16) union ResamplerCoeffs ResampleCoeffs;
+
+extern alignas(16) const ALfloat bsincTab[18840];
+
+
inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
{
return val1 + (val2-val1)*mu;
}
-inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu)
+inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac)
{
- ALfloat mu2 = mu*mu;
- ALfloat a0 = -0.5f*val0 + 1.5f*val1 + -1.5f*val2 + 0.5f*val3;
- ALfloat a1 = val0 + -2.5f*val1 + 2.0f*val2 + -0.5f*val3;
- ALfloat a2 = -0.5f*val0 + 0.5f*val2;
- ALfloat a3 = val1;
-
- return a0*mu*mu2 + a1*mu2 + a2*mu + a3;
+ const ALfloat *k = ResampleCoeffs.FIR4[frac];
+ return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3;
+}
+inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac)
+{
+ const ALfloat *k = ResampleCoeffs.FIR8[frac];
+ return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3 +
+ k[4]*val4 + k[5]*val5 + k[6]*val6 + k[7]*val7;
}
+void aluInitMixer(void);
+
ALvoid aluInitPanning(ALCdevice *Device);
/**
+ * ComputeDirectionalGains
+ *
+ * Sets channel gains based on a direction. The direction must be a 3-component
+ * vector no longer than 1 unit.
+ */
+void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+
+/**
* ComputeAngleGains
*
- * Sets channel gains based on a given source's angle and its half-width. The
- * angle and hwidth parameters are in radians.
+ * Sets channel gains based on angle and elevation. The angle and elevation
+ * parameters are in radians, going right and up respectively.
*/
-void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels]);
+void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
/**
- * SetGains
+ * ComputeAmbientGains
*
- * Helper to set the appropriate channels to the specified gain.
+ * Sets channel gains for ambient, omni-directional sounds.
*/
-inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels])
-{
- ComputeAngleGains(device, 0.0f, F_PI, ingain, gains);
-}
+void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+/**
+ * ComputeBFormatGains
+ *
+ * Sets channel gains for a given (first-order) B-Format channel. The matrix is
+ * a 1x4 'slice' of the rotation matrix for a given channel used to orient the
+ * coefficients.
+ */
+void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
-ALvoid CalcSourceParams(struct ALactivesource *src, const ALCcontext *ALContext);
-ALvoid CalcNonAttnSourceParams(struct ALactivesource *src, const ALCcontext *ALContext);
-ALvoid MixSource(struct ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo);
+ALvoid UpdateContextSources(ALCcontext *context);
+
+ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext);
+ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext);
+
+ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo);
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
/* Caller must lock the device. */
@@ -242,4 +328,3 @@ extern ALfloat ZScale;
#endif
#endif
-
diff --git a/OpenAL32/Include/bs2b.h b/OpenAL32/Include/bs2b.h
index 0f06b1ca..903c6bc5 100644
--- a/OpenAL32/Include/bs2b.h
+++ b/OpenAL32/Include/bs2b.h
@@ -51,40 +51,34 @@ 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;
};
-/* Clear buffers and set new coefficients with new crossfeed level value.
+/* Clear buffers and set new coefficients with new crossfeed level and sample
+ * rate values.
* level - crossfeed level of *LEVEL values.
+ * srate - sample rate by Hz.
*/
-void bs2b_set_level(struct bs2b *bs2b, int level);
+void bs2b_set_params(struct bs2b *bs2b, int level, int srate);
/* Return current crossfeed level value */
int bs2b_get_level(struct bs2b *bs2b);
-/* Clear buffers and set new coefficients with new sample rate value.
- * srate - sample rate by Hz.
- */
-void bs2b_set_srate(struct bs2b *bs2b, int srate);
-
/* Return current sample rate value */
int bs2b_get_srate(struct bs2b *bs2b);
@@ -93,11 +87,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]
+ */
+
+/* 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];
-/* sample poits to floats */
-void bs2b_cross_feed(struct bs2b *bs2b, float *sample);
+ /* 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" */
diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c
index 9f554cb0..c1314301 100644
--- a/OpenAL32/alAuxEffectSlot.c
+++ b/OpenAL32/alAuxEffectSlot.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -35,7 +35,7 @@
extern inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id);
extern inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id);
-static ALenum AddEffectSlotArray(ALCcontext *Context, const_vector_ALeffectslotPtr slots);
+static ALenum AddEffectSlotArray(ALCcontext *Context, ALeffectslot **start, ALsizei count);
static void RemoveEffectSlotArray(ALCcontext *Context, const ALeffectslot *slot);
@@ -52,7 +52,7 @@ static inline ALeffectStateFactory *getFactoryByType(ALenum type)
AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
{
ALCcontext *context;
- vector_ALeffectslotPtr slotvec;
+ VECTOR(ALeffectslot*) slotvec;
ALsizei cur;
ALenum err;
@@ -94,7 +94,7 @@ AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslo
effectslots[cur] = slot->id;
}
- err = AddEffectSlotArray(context, slotvec);
+ err = AddEffectSlotArray(context, VECTOR_ITER_BEGIN(slotvec), n);
if(err != AL_NO_ERROR)
{
alDeleteAuxiliaryEffectSlots(cur, effectslots);
@@ -183,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:
@@ -191,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:
@@ -246,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:
@@ -385,13 +385,12 @@ done:
}
-static ALenum AddEffectSlotArray(ALCcontext *context, const_vector_ALeffectslotPtr slots)
+static ALenum AddEffectSlotArray(ALCcontext *context, ALeffectslot **start, ALsizei count)
{
ALenum err = AL_NO_ERROR;
LockContext(context);
- if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_ITER_END(context->ActiveAuxSlots),
- VECTOR_ITER_BEGIN(slots), VECTOR_ITER_END(slots)))
+ if(!VECTOR_INSERT(context->ActiveAuxSlots, VECTOR_ITER_END(context->ActiveAuxSlots), start, start+count))
err = AL_OUT_OF_MEMORY;
UnlockContext(context);
@@ -400,21 +399,17 @@ static ALenum AddEffectSlotArray(ALCcontext *context, const_vector_ALeffectslotP
static void RemoveEffectSlotArray(ALCcontext *context, const ALeffectslot *slot)
{
- ALeffectslot **slotlist, **slotlistend;
+ ALeffectslot **iter;
LockContext(context);
- slotlist = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
- slotlistend = VECTOR_ITER_END(context->ActiveAuxSlots);
- while(slotlist != slotlistend)
+#define MATCH_SLOT(_i) (slot == *(_i))
+ VECTOR_FIND_IF(iter, ALeffectslot*, context->ActiveAuxSlots, MATCH_SLOT);
+ if(iter != VECTOR_ITER_END(context->ActiveAuxSlots))
{
- if(*slotlist == slot)
- {
- *slotlist = VECTOR_BACK(context->ActiveAuxSlots);
- VECTOR_POP_BACK(context->ActiveAuxSlots);
- break;
- }
- slotlist++;
+ *iter = VECTOR_BACK(context->ActiveAuxSlots);
+ VECTOR_POP_BACK(context->ActiveAuxSlots);
}
+#undef MATCH_SLOT
UnlockContext(context);
}
@@ -490,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);
@@ -506,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);
}
}
@@ -527,7 +522,7 @@ 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++)
diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c
index 2b2528f6..904fd61d 100644
--- a/OpenAL32/alBuffer.c
+++ b/OpenAL32/alBuffer.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -41,7 +41,6 @@ extern inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id);
extern inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type);
extern inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type);
-static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels chans, enum UserFmtType type, const ALvoid *data, ALsizei align, ALboolean storesrc);
static ALboolean IsValidType(ALenum type) DECL_CONST;
static ALboolean IsValidChannels(ALenum channels) DECL_CONST;
static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, enum UserFmtType *type) DECL_CONST;
@@ -51,10 +50,8 @@ static ALboolean SanitizeAlignment(enum UserFmtType type, ALsizei *align);
AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
{
- ALCdevice *device;
ALCcontext *context;
ALsizei cur = 0;
- ALenum err;
context = GetContextRef();
if(!context) return;
@@ -62,28 +59,13 @@ AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
if(!(n >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- device = context->Device;
for(cur = 0;cur < n;cur++)
{
- ALbuffer *buffer = calloc(1, sizeof(ALbuffer));
+ ALbuffer *buffer = NewBuffer(context);
if(!buffer)
{
alDeleteBuffers(cur, buffers);
- SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
- }
- RWLockInit(&buffer->lock);
-
- err = NewThunkEntry(&buffer->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
- if(err != AL_NO_ERROR)
- {
- FreeThunkEntry(buffer->id);
- memset(buffer, 0, sizeof(ALbuffer));
- free(buffer);
-
- alDeleteBuffers(cur, buffers);
- SET_ERROR_AND_GOTO(context, err, done);
+ break;
}
buffers[cur] = buffer->id;
@@ -121,14 +103,8 @@ AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
for(i = 0;i < n;i++)
{
- if((ALBuf=RemoveBuffer(device, buffers[i])) == NULL)
- continue;
- FreeThunkEntry(ALBuf->id);
-
- free(ALBuf->data);
-
- memset(ALBuf, 0, sizeof(*ALBuf));
- free(ALBuf);
+ if((ALBuf=LookupBuffer(device, buffers[i])) != NULL)
+ DeleteBuffer(device, ALBuf);
}
done:
@@ -175,7 +151,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- align = albuf->UnpackAlign;
+ align = ATOMIC_LOAD(&albuf->UnpackAlign);
if(SanitizeAlignment(srctype, &align) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
switch(srctype)
@@ -213,6 +189,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
+ case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_FLOAT32; break;
+ case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_FLOAT32; break;
}
err = LoadData(albuf, freq, newformat, size/framesize*align,
srcchannels, srctype, data, align, AL_TRUE);
@@ -235,6 +213,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+ case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
+ case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
}
err = LoadData(albuf, freq, newformat, size/framesize*align,
srcchannels, srctype, data, align, AL_TRUE);
@@ -257,6 +237,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+ case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
+ case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
}
err = LoadData(albuf, freq, newformat, size/framesize*align,
srcchannels, srctype, data, align, AL_TRUE);
@@ -279,6 +261,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+ case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
+ case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
}
err = LoadData(albuf, freq, newformat, size/framesize*align,
srcchannels, srctype, data, align, AL_TRUE);
@@ -315,7 +299,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
WriteLock(&albuf->lock);
- align = albuf->UnpackAlign;
+ align = ATOMIC_LOAD(&albuf->UnpackAlign);
if(SanitizeAlignment(srctype, &align) == AL_FALSE)
{
WriteUnlock(&albuf->lock);
@@ -392,7 +376,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- align = albuf->UnpackAlign;
+ align = ATOMIC_LOAD(&albuf->UnpackAlign);
if(SanitizeAlignment(type, &align) == AL_FALSE)
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
if((samples%align) != 0)
@@ -428,7 +412,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
WriteLock(&albuf->lock);
- align = albuf->UnpackAlign;
+ align = ATOMIC_LOAD(&albuf->UnpackAlign);
if(SanitizeAlignment(type, &align) == AL_FALSE)
{
WriteUnlock(&albuf->lock);
@@ -481,7 +465,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
ReadLock(&albuf->lock);
- align = albuf->PackAlign;
+ align = ATOMIC_LOAD(&albuf->PackAlign);
if(SanitizeAlignment(type, &align) == AL_FALSE)
{
ReadUnlock(&albuf->lock);
@@ -620,13 +604,13 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
if(!(value >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- ExchangeInt(&albuf->UnpackAlign, value);
+ ATOMIC_STORE(&albuf->UnpackAlign, value);
break;
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
if(!(value >= 0))
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- ExchangeInt(&albuf->PackAlign, value);
+ ATOMIC_STORE(&albuf->PackAlign, value);
break;
default:
@@ -858,11 +842,11 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value
break;
case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
- *value = albuf->UnpackAlign;
+ *value = ATOMIC_LOAD(&albuf->UnpackAlign);
break;
case AL_PACK_BLOCK_ALIGNMENT_SOFT:
- *value = albuf->PackAlign;
+ *value = ATOMIC_LOAD(&albuf->PackAlign);
break;
default:
@@ -954,7 +938,7 @@ done:
* Currently, the new format must have the same channel configuration as the
* original format.
*/
-static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc)
+ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc)
{
ALuint NewChannels, NewBytes;
enum FmtChannels DstChannels;
@@ -1069,6 +1053,8 @@ ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
case UserFmtX51: return 6;
case UserFmtX61: return 7;
case UserFmtX71: return 8;
+ case UserFmtBFormat2D: return 3;
+ case UserFmtBFormat3D: return 4;
}
return 0;
}
@@ -1125,6 +1111,16 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
{ AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort },
{ AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat },
{ AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
+
+ { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte },
+ { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort },
+ { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat },
+ { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw },
+
+ { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte },
+ { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort },
+ { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat },
+ { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw },
};
ALuint i;
@@ -1162,6 +1158,8 @@ ALuint ChannelsFromFmt(enum FmtChannels chans)
case FmtX51: return 6;
case FmtX61: return 7;
case FmtX71: return 8;
+ case FmtBFormat2D: return 3;
+ case FmtBFormat3D: return 4;
}
return 0;
}
@@ -1202,6 +1200,14 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm
{ AL_7POINT1_8_SOFT, FmtX71, FmtByte },
{ AL_7POINT1_16_SOFT, FmtX71, FmtShort },
{ AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
+
+ { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtByte },
+ { AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort },
+ { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat },
+
+ { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtByte },
+ { AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort },
+ { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat },
};
ALuint i;
@@ -1293,6 +1299,44 @@ static ALboolean IsValidChannels(ALenum channels)
}
+ALbuffer *NewBuffer(ALCcontext *context)
+{
+ ALCdevice *device = context->Device;
+ ALbuffer *buffer;
+ ALenum err;
+
+ buffer = calloc(1, sizeof(ALbuffer));
+ if(!buffer)
+ SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
+ RWLockInit(&buffer->lock);
+
+ err = NewThunkEntry(&buffer->id);
+ if(err == AL_NO_ERROR)
+ err = InsertUIntMapEntry(&device->BufferMap, buffer->id, buffer);
+ if(err != AL_NO_ERROR)
+ {
+ FreeThunkEntry(buffer->id);
+ memset(buffer, 0, sizeof(ALbuffer));
+ free(buffer);
+
+ SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
+ }
+
+ return buffer;
+}
+
+void DeleteBuffer(ALCdevice *device, ALbuffer *buffer)
+{
+ RemoveBuffer(device, buffer->id);
+ FreeThunkEntry(buffer->id);
+
+ free(buffer->data);
+
+ memset(buffer, 0, sizeof(*buffer));
+ free(buffer);
+}
+
+
/*
* ReleaseALBuffers()
*
diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c
index c9e5928f..0bfe11b9 100644
--- a/OpenAL32/alEffect.c
+++ b/OpenAL32/alEffect.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -402,13 +402,27 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN;
effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
+ effect->Props.Reverb.GainLF = 1.0f;
effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME;
effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
+ effect->Props.Reverb.DecayLFRatio = 1.0f;
effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
+ effect->Props.Reverb.ReflectionsPan[0] = 0.0f;
+ effect->Props.Reverb.ReflectionsPan[1] = 0.0f;
+ effect->Props.Reverb.ReflectionsPan[2] = 0.0f;
effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
+ effect->Props.Reverb.LateReverbPan[0] = 0.0f;
+ effect->Props.Reverb.LateReverbPan[1] = 0.0f;
+ effect->Props.Reverb.LateReverbPan[2] = 0.0f;
+ effect->Props.Reverb.EchoTime = 0.25f;
+ effect->Props.Reverb.EchoDepth = 0.0f;
+ effect->Props.Reverb.ModulationTime = 0.25f;
+ effect->Props.Reverb.ModulationDepth = 0.0f;
effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
+ effect->Props.Reverb.HFReference = 5000.0f;
+ effect->Props.Reverb.LFReference = 250.0f;
effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
SET_VTABLE1(ALreverb, effect);
diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c
index b557532e..b38d8dfe 100644
--- a/OpenAL32/alError.c
+++ b/OpenAL32/alError.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -35,6 +35,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);
diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c
index fc23a932..609cc969 100644
--- a/OpenAL32/alExtension.c
+++ b/OpenAL32/alExtension.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -38,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 },
diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c
index acfae8a6..3cf82c32 100644
--- a/OpenAL32/alFilter.c
+++ b/OpenAL32/alFilter.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -32,6 +32,8 @@
extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample);
+extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
+extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth);
static void InitFilterParams(ALfilter *filter, ALenum type);
@@ -336,72 +338,72 @@ void ALfilterState_clear(ALfilterState *filter)
filter->y[1] = 0.0f;
}
-void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth)
+void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ)
{
- ALfloat alpha;
- ALfloat w0;
+ ALfloat alpha, sqrtgain_alpha_2;
+ ALfloat w0, sin_w0, cos_w0;
// Limit gain to -100dB
gain = maxf(gain, 0.00001f);
- w0 = F_2PI * freq_mult;
+ w0 = F_TAU * freq_mult;
+ sin_w0 = sinf(w0);
+ cos_w0 = cosf(w0);
+ alpha = sin_w0/2.0f * rcpQ;
/* Calculate filter coefficients depending on filter type */
switch(type)
{
case ALfilterType_HighShelf:
- alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f);
- filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha);
- filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cosf(w0) );
- filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha);
- filter->a[0] = (gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha;
- filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cosf(w0) );
- filter->a[2] = (gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha;
+ sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
+ filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
+ filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
+ filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
+ filter->a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
+ filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
+ filter->a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
break;
case ALfilterType_LowShelf:
- alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f);
- filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha);
- filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cosf(w0) );
- filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha);
- filter->a[0] = (gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha;
- filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cosf(w0) );
- filter->a[2] = (gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha;
+ sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
+ filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
+ filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
+ filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
+ filter->a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
+ filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
+ filter->a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
break;
case ALfilterType_Peaking:
- alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
+ gain = sqrtf(gain);
filter->b[0] = 1.0f + alpha * gain;
- filter->b[1] = -2.0f * cosf(w0);
+ filter->b[1] = -2.0f * cos_w0;
filter->b[2] = 1.0f - alpha * gain;
filter->a[0] = 1.0f + alpha / gain;
- filter->a[1] = -2.0f * cosf(w0);
+ filter->a[1] = -2.0f * cos_w0;
filter->a[2] = 1.0f - alpha / gain;
break;
case ALfilterType_LowPass:
- alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
- filter->b[0] = (1.0f - cosf(w0)) / 2.0f;
- filter->b[1] = 1.0f - cosf(w0);
- filter->b[2] = (1.0f - cosf(w0)) / 2.0f;
+ filter->b[0] = (1.0f - cos_w0) / 2.0f;
+ filter->b[1] = 1.0f - cos_w0;
+ filter->b[2] = (1.0f - cos_w0) / 2.0f;
filter->a[0] = 1.0f + alpha;
- filter->a[1] = -2.0f * cosf(w0);
+ filter->a[1] = -2.0f * cos_w0;
filter->a[2] = 1.0f - alpha;
break;
case ALfilterType_HighPass:
- alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
- filter->b[0] = (1.0f + cosf(w0)) / 2.0f;
- filter->b[1] = 1.0f + cosf(w0);
- filter->b[2] = (1.0f + cosf(w0)) / 2.0f;
- filter->a[0] = 1.0f + alpha;
- filter->a[1] = -2.0f * cosf(w0);
- filter->a[2] = 1.0f - alpha;
+ filter->b[0] = (1.0f + cos_w0) / 2.0f;
+ filter->b[1] = -(1.0f + cos_w0);
+ filter->b[2] = (1.0f + cos_w0) / 2.0f;
+ filter->a[0] = 1.0f + alpha;
+ filter->a[1] = -2.0f * cos_w0;
+ filter->a[2] = 1.0f - alpha;
break;
case ALfilterType_BandPass:
- alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
filter->b[0] = alpha;
filter->b[1] = 0;
filter->b[2] = -alpha;
filter->a[0] = 1.0f + alpha;
- filter->a[1] = -2.0f * cosf(w0);
+ filter->a[1] = -2.0f * cos_w0;
filter->a[2] = 1.0f - alpha;
break;
}
@@ -416,6 +418,24 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g
filter->process = ALfilterState_processC;
}
+void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples)
+{
+ if(numsamples >= 2)
+ {
+ filter->x[1] = src[numsamples-2];
+ filter->x[0] = src[numsamples-1];
+ filter->y[1] = src[numsamples-2];
+ filter->y[0] = src[numsamples-1];
+ }
+ else if(numsamples == 1)
+ {
+ filter->x[1] = filter->x[0];
+ filter->x[0] = src[0];
+ filter->y[1] = filter->y[0];
+ filter->y[0] = src[0];
+ }
+}
+
static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
diff --git a/OpenAL32/alFontsound.c b/OpenAL32/alFontsound.c
deleted file mode 100644
index c4d49e92..00000000
--- a/OpenAL32/alFontsound.c
+++ /dev/null
@@ -1,972 +0,0 @@
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "alMain.h"
-#include "alMidi.h"
-#include "alError.h"
-#include "alThunk.h"
-
-#include "midi/base.h"
-
-
-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);
-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);
-
-
-AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids)
-{
- ALCcontext *context;
- ALsizei cur = 0;
-
- context = GetContextRef();
- if(!context) return;
-
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- for(cur = 0;cur < n;cur++)
- {
- ALfontsound *sound = NewFontsound(context);
- if(!sound)
- {
- alDeleteFontsoundsSOFT(cur, ids);
- break;
- }
-
- ids[cur] = sound->id;
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API ALvoid AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALfontsound *inst;
- ALsizei i;
-
- context = GetContextRef();
- if(!context) return;
-
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- device = context->Device;
- for(i = 0;i < n;i++)
- {
- /* Check for valid ID */
- if((inst=LookupFontsound(device, ids[i])) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- 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);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API ALboolean AL_APIENTRY alIsFontsoundSOFT(ALuint id)
-{
- ALCcontext *context;
- ALboolean ret;
-
- context = GetContextRef();
- if(!context) return AL_FALSE;
-
- ret = LookupFontsound(context->Device, id) ? AL_TRUE : AL_FALSE;
-
- ALCcontext_DecRef(context);
-
- return ret;
-}
-
-AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALfontsound *sound;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if(!(sound=LookupFontsound(device, id)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(ReadRef(&sound->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
-
- ALfontsound_setPropi(sound, context, param, value);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1, ALint value2)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALfontsound *sound;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if(!(sound=LookupFontsound(device, id)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(ReadRef(&sound->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- switch(param)
- {
- case AL_KEY_RANGE_SOFT:
- if(!(value1 >= 0 && value1 <= 127 && value2 >= 0 && value2 <= 127 && value2 >= value1))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- sound->MinKey = value1;
- sound->MaxKey = value2;
- break;
-
- case AL_VELOCITY_RANGE_SOFT:
- if(!(value1 >= 0 && value1 <= 127 && value2 >= 0 && value2 <= 127 && value2 >= value1))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- sound->MinVelocity = value1;
- sound->MaxVelocity = value2;
- break;
-
- default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *values)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALfontsound *sound;
-
- switch(param)
- {
- case AL_KEY_RANGE_SOFT:
- case AL_VELOCITY_RANGE_SOFT:
- alFontsound2iSOFT(id, param, values[0], values[1]);
- return;
-
- case AL_MOD_LFO_TO_PITCH_SOFT:
- case AL_VIBRATO_LFO_TO_PITCH_SOFT:
- case AL_MOD_ENV_TO_PITCH_SOFT:
- case AL_FILTER_CUTOFF_SOFT:
- case AL_FILTER_RESONANCE_SOFT:
- case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT:
- case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT:
- case AL_MOD_LFO_TO_VOLUME_SOFT:
- case AL_CHORUS_SEND_SOFT:
- case AL_REVERB_SEND_SOFT:
- case AL_PAN_SOFT:
- case AL_MOD_LFO_DELAY_SOFT:
- case AL_MOD_LFO_FREQUENCY_SOFT:
- case AL_VIBRATO_LFO_DELAY_SOFT:
- case AL_VIBRATO_LFO_FREQUENCY_SOFT:
- case AL_MOD_ENV_DELAYTIME_SOFT:
- case AL_MOD_ENV_ATTACKTIME_SOFT:
- case AL_MOD_ENV_HOLDTIME_SOFT:
- case AL_MOD_ENV_DECAYTIME_SOFT:
- case AL_MOD_ENV_SUSTAINVOLUME_SOFT:
- case AL_MOD_ENV_RELEASETIME_SOFT:
- case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT:
- case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT:
- case AL_VOLUME_ENV_DELAYTIME_SOFT:
- case AL_VOLUME_ENV_ATTACKTIME_SOFT:
- case AL_VOLUME_ENV_HOLDTIME_SOFT:
- case AL_VOLUME_ENV_DECAYTIME_SOFT:
- case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT:
- case AL_VOLUME_ENV_RELEASETIME_SOFT:
- case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT:
- case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT:
- case AL_ATTENUATION_SOFT:
- case AL_TUNING_COARSE_SOFT:
- case AL_TUNING_FINE_SOFT:
- case AL_LOOP_MODE_SOFT:
- case AL_TUNING_SCALE_SOFT:
- case AL_EXCLUSIVE_CLASS_SOFT:
- case AL_SAMPLE_START_SOFT:
- case AL_SAMPLE_END_SOFT:
- case AL_SAMPLE_LOOP_START_SOFT:
- case AL_SAMPLE_LOOP_END_SOFT:
- case AL_SAMPLE_RATE_SOFT:
- case AL_BASE_KEY_SOFT:
- case AL_KEY_CORRECTION_SOFT:
- case AL_SAMPLE_TYPE_SOFT:
- case AL_FONTSOUND_LINK_SOFT:
- alFontsoundiSOFT(id, param, values[0]);
- return;
- }
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if(!(sound=LookupFontsound(device, id)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(ReadRef(&sound->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- switch(param)
- {
- default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *values)
-{
- ALCdevice *device;
- ALCcontext *context;
- const ALfontsound *sound;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if(!(sound=LookupFontsound(device, id)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- switch(param)
- {
- case AL_MOD_LFO_TO_PITCH_SOFT:
- values[0] = sound->ModLfoToPitch;
- break;
-
- case AL_VIBRATO_LFO_TO_PITCH_SOFT:
- values[0] = sound->VibratoLfoToPitch;
- break;
-
- case AL_MOD_ENV_TO_PITCH_SOFT:
- values[0] = sound->ModEnvToPitch;
- break;
-
- case AL_FILTER_CUTOFF_SOFT:
- values[0] = sound->FilterCutoff;
- break;
-
- case AL_FILTER_RESONANCE_SOFT:
- values[0] = sound->FilterQ;
- break;
-
- case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT:
- values[0] = sound->ModLfoToFilterCutoff;
- break;
-
- case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT:
- values[0] = sound->ModEnvToFilterCutoff;
- break;
-
- case AL_MOD_LFO_TO_VOLUME_SOFT:
- values[0] = sound->ModLfoToVolume;
- break;
-
- case AL_CHORUS_SEND_SOFT:
- values[0] = sound->ChorusSend;
- break;
-
- case AL_REVERB_SEND_SOFT:
- values[0] = sound->ReverbSend;
- break;
-
- case AL_PAN_SOFT:
- values[0] = sound->Pan;
- break;
-
- case AL_MOD_LFO_DELAY_SOFT:
- values[0] = sound->ModLfo.Delay;
- break;
- case AL_MOD_LFO_FREQUENCY_SOFT:
- values[0] = sound->ModLfo.Frequency;
- break;
-
- case AL_VIBRATO_LFO_DELAY_SOFT:
- values[0] = sound->VibratoLfo.Delay;
- break;
- case AL_VIBRATO_LFO_FREQUENCY_SOFT:
- values[0] = sound->VibratoLfo.Frequency;
- break;
-
- case AL_MOD_ENV_DELAYTIME_SOFT:
- values[0] = sound->ModEnv.DelayTime;
- break;
- case AL_MOD_ENV_ATTACKTIME_SOFT:
- values[0] = sound->ModEnv.AttackTime;
- break;
- case AL_MOD_ENV_HOLDTIME_SOFT:
- values[0] = sound->ModEnv.HoldTime;
- break;
- case AL_MOD_ENV_DECAYTIME_SOFT:
- values[0] = sound->ModEnv.DecayTime;
- break;
- case AL_MOD_ENV_SUSTAINVOLUME_SOFT:
- values[0] = sound->ModEnv.SustainAttn;
- break;
- case AL_MOD_ENV_RELEASETIME_SOFT:
- values[0] = sound->ModEnv.ReleaseTime;
- break;
- case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT:
- values[0] = sound->ModEnv.KeyToHoldTime;
- break;
- case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT:
- values[0] = sound->ModEnv.KeyToDecayTime;
- break;
-
- case AL_VOLUME_ENV_DELAYTIME_SOFT:
- values[0] = sound->VolEnv.DelayTime;
- break;
- case AL_VOLUME_ENV_ATTACKTIME_SOFT:
- values[0] = sound->VolEnv.AttackTime;
- break;
- case AL_VOLUME_ENV_HOLDTIME_SOFT:
- values[0] = sound->VolEnv.HoldTime;
- break;
- case AL_VOLUME_ENV_DECAYTIME_SOFT:
- values[0] = sound->VolEnv.DecayTime;
- break;
- case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT:
- values[0] = sound->VolEnv.SustainAttn;
- break;
- case AL_VOLUME_ENV_RELEASETIME_SOFT:
- values[0] = sound->VolEnv.ReleaseTime;
- break;
- case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT:
- values[0] = sound->VolEnv.KeyToHoldTime;
- break;
- case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT:
- values[0] = sound->VolEnv.KeyToDecayTime;
- break;
-
- case AL_KEY_RANGE_SOFT:
- values[0] = sound->MinKey;
- values[1] = sound->MaxKey;
- break;
-
- case AL_VELOCITY_RANGE_SOFT:
- values[0] = sound->MinVelocity;
- values[1] = sound->MaxVelocity;
- break;
-
- case AL_ATTENUATION_SOFT:
- values[0] = sound->Attenuation;
- break;
-
- case AL_TUNING_COARSE_SOFT:
- values[0] = sound->CoarseTuning;
- break;
- case AL_TUNING_FINE_SOFT:
- values[0] = sound->FineTuning;
- break;
-
- case AL_LOOP_MODE_SOFT:
- values[0] = sound->LoopMode;
- break;
-
- case AL_TUNING_SCALE_SOFT:
- values[0] = sound->TuningScale;
- break;
-
- case AL_EXCLUSIVE_CLASS_SOFT:
- values[0] = sound->ExclusiveClass;
- break;
-
- case AL_SAMPLE_START_SOFT:
- values[0] = sound->Start;
- break;
-
- case AL_SAMPLE_END_SOFT:
- values[0] = sound->End;
- break;
-
- case AL_SAMPLE_LOOP_START_SOFT:
- values[0] = sound->LoopStart;
- break;
-
- case AL_SAMPLE_LOOP_END_SOFT:
- values[0] = sound->LoopEnd;
- break;
-
- case AL_SAMPLE_RATE_SOFT:
- values[0] = sound->SampleRate;
- break;
-
- case AL_BASE_KEY_SOFT:
- values[0] = sound->PitchKey;
- break;
-
- case AL_KEY_CORRECTION_SOFT:
- values[0] = sound->PitchCorrection;
- break;
-
- case AL_SAMPLE_TYPE_SOFT:
- values[0] = sound->SampleType;
- break;
-
- case AL_FONTSOUND_LINK_SOFT:
- values[0] = (sound->Link ? sound->Link->id : 0);
- break;
-
- default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alFontsoundModulatoriSOFT(ALuint id, ALsizei stage, ALenum param, ALint value)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALfontsound *sound;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if(!(sound=LookupFontsound(device, id)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- ALfontsound_setModStagei(sound, context, stage, param, value);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alGetFontsoundModulatorivSOFT(ALuint id, ALsizei stage, ALenum param, ALint *values)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALfontsound *sound;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if(!(sound=LookupFontsound(device, id)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- ALfontsound_getModStagei(sound, context, stage, param, values);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-
-ALfontsound *NewFontsound(ALCcontext *context)
-{
- ALCdevice *device = context->Device;
- ALfontsound *sound;
- ALenum err;
-
- sound = calloc(1, sizeof(*sound));
- if(!sound)
- SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
- ALfontsound_Construct(sound);
-
- err = NewThunkEntry(&sound->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->FontsoundMap, sound->id, sound);
- if(err != AL_NO_ERROR)
- {
- ALfontsound_Destruct(sound);
- memset(sound, 0, sizeof(*sound));
- free(sound);
-
- SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
- }
-
- return sound;
-}
-
-
-static void ALfontsound_Construct(ALfontsound *self)
-{
- InitRef(&self->ref, 0);
-
- self->MinKey = 0;
- self->MaxKey = 127;
- self->MinVelocity = 0;
- self->MaxVelocity = 127;
-
- self->ModLfoToPitch = 0;
- self->VibratoLfoToPitch = 0;
- self->ModEnvToPitch = 0;
-
- self->FilterCutoff = 13500;
- self->FilterQ = 0;
- self->ModLfoToFilterCutoff = 0;
- self->ModEnvToFilterCutoff = 0;
- self->ModLfoToVolume = 0;
-
- self->ChorusSend = 0;
- self->ReverbSend = 0;
-
- self->Pan = 0;
-
- self->ModLfo.Delay = 0;
- self->ModLfo.Frequency = 0;
-
- self->VibratoLfo.Delay = 0;
- self->VibratoLfo.Frequency = 0;
-
- self->ModEnv.DelayTime = -12000;
- self->ModEnv.AttackTime = -12000;
- self->ModEnv.HoldTime = -12000;
- self->ModEnv.DecayTime = -12000;
- self->ModEnv.SustainAttn = 0;
- self->ModEnv.ReleaseTime = -12000;
- self->ModEnv.KeyToHoldTime = 0;
- self->ModEnv.KeyToDecayTime = 0;
-
- self->VolEnv.DelayTime = -12000;
- self->VolEnv.AttackTime = -12000;
- self->VolEnv.HoldTime = -12000;
- self->VolEnv.DecayTime = -12000;
- self->VolEnv.SustainAttn = 0;
- self->VolEnv.ReleaseTime = -12000;
- self->VolEnv.KeyToHoldTime = 0;
- self->VolEnv.KeyToDecayTime = 0;
-
- self->Attenuation = 0;
-
- self->CoarseTuning = 0;
- self->FineTuning = 0;
-
- self->LoopMode = AL_NONE;
-
- self->TuningScale = 100;
-
- self->ExclusiveClass = 0;
-
- self->Start = 0;
- self->End = 0;
- self->LoopStart = 0;
- self->LoopEnd = 0;
- self->SampleRate = 0;
- self->PitchKey = 0;
- self->PitchCorrection = 0;
- self->SampleType = AL_MONO_SOFT;
- self->Link = NULL;
-
- InitUIntMap(&self->ModulatorMap, ~0);
-
- self->id = 0;
-}
-
-void ALfontsound_Destruct(ALfontsound *self)
-{
- ALsizei i;
-
- FreeThunkEntry(self->id);
- self->id = 0;
-
- if(self->Link)
- DecrementRef(&self->Link->ref);
- self->Link = NULL;
-
- for(i = 0;i < self->ModulatorMap.size;i++)
- {
- free(self->ModulatorMap.array[i].value);
- self->ModulatorMap.array[i].value = NULL;
- }
- ResetUIntMap(&self->ModulatorMap);
-}
-
-void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value)
-{
- ALfontsound *link;
-
- switch(param)
- {
- case AL_MOD_LFO_TO_PITCH_SOFT:
- self->ModLfoToPitch = value;
- break;
-
- case AL_VIBRATO_LFO_TO_PITCH_SOFT:
- self->VibratoLfoToPitch = value;
- break;
-
- case AL_MOD_ENV_TO_PITCH_SOFT:
- self->ModEnvToPitch = value;
- break;
-
- case AL_FILTER_CUTOFF_SOFT:
- self->FilterCutoff = value;
- break;
-
- case AL_FILTER_RESONANCE_SOFT:
- if(!(value >= 0))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->FilterQ = value;
- break;
-
- case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT:
- self->ModLfoToFilterCutoff = value;
- break;
-
- case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT:
- self->ModEnvToFilterCutoff = value;
- break;
-
- case AL_MOD_LFO_TO_VOLUME_SOFT:
- self->ModLfoToVolume = value;
- break;
-
- case AL_CHORUS_SEND_SOFT:
- if(!(value >= 0 && value <= 1000))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->ChorusSend = value;
- break;
- case AL_REVERB_SEND_SOFT:
- if(!(value >= 0 && value <= 1000))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->ReverbSend = value;
- break;
-
- case AL_PAN_SOFT:
- self->Pan = value;
- break;
-
- case AL_MOD_LFO_DELAY_SOFT:
- self->ModLfo.Delay = value;
- break;
- case AL_MOD_LFO_FREQUENCY_SOFT:
- self->ModLfo.Frequency = value;
- break;
-
- case AL_VIBRATO_LFO_DELAY_SOFT:
- self->VibratoLfo.Delay = value;
- break;
- case AL_VIBRATO_LFO_FREQUENCY_SOFT:
- self->VibratoLfo.Frequency = value;
- break;
-
- case AL_MOD_ENV_DELAYTIME_SOFT:
- self->ModEnv.DelayTime = value;
- break;
- case AL_MOD_ENV_ATTACKTIME_SOFT:
- self->ModEnv.AttackTime = value;
- break;
- case AL_MOD_ENV_HOLDTIME_SOFT:
- self->ModEnv.HoldTime = value;
- break;
- case AL_MOD_ENV_DECAYTIME_SOFT:
- self->ModEnv.DecayTime = value;
- break;
- case AL_MOD_ENV_SUSTAINVOLUME_SOFT:
- self->ModEnv.SustainAttn = value;
- break;
- case AL_MOD_ENV_RELEASETIME_SOFT:
- self->ModEnv.ReleaseTime = value;
- break;
- case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT:
- self->ModEnv.KeyToHoldTime = value;
- break;
- case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT:
- self->ModEnv.KeyToDecayTime = value;
- break;
-
- case AL_VOLUME_ENV_DELAYTIME_SOFT:
- self->VolEnv.DelayTime = value;
- break;
- case AL_VOLUME_ENV_ATTACKTIME_SOFT:
- self->VolEnv.AttackTime = value;
- break;
- case AL_VOLUME_ENV_HOLDTIME_SOFT:
- self->VolEnv.HoldTime = value;
- break;
- case AL_VOLUME_ENV_DECAYTIME_SOFT:
- self->VolEnv.DecayTime = value;
- break;
- case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT:
- self->VolEnv.SustainAttn = value;
- break;
- case AL_VOLUME_ENV_RELEASETIME_SOFT:
- self->VolEnv.ReleaseTime = value;
- break;
- case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT:
- self->VolEnv.KeyToHoldTime = value;
- break;
- case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT:
- self->VolEnv.KeyToDecayTime = value;
- break;
-
- case AL_ATTENUATION_SOFT:
- if(!(value >= 0))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->Attenuation = value;
- break;
-
- case AL_TUNING_COARSE_SOFT:
- self->CoarseTuning = value;
- break;
- case AL_TUNING_FINE_SOFT:
- self->FineTuning = value;
- break;
-
- case AL_LOOP_MODE_SOFT:
- if(!(value == AL_NONE || value == AL_LOOP_CONTINUOUS_SOFT ||
- value == AL_LOOP_UNTIL_RELEASE_SOFT))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->LoopMode = value;
- break;
-
- case AL_TUNING_SCALE_SOFT:
- self->TuningScale = value;
- break;
-
- case AL_EXCLUSIVE_CLASS_SOFT:
- self->ExclusiveClass = value;
- break;
-
- case AL_SAMPLE_START_SOFT:
- self->Start = value;
- break;
-
- case AL_SAMPLE_END_SOFT:
- self->End = value;
- break;
-
- case AL_SAMPLE_LOOP_START_SOFT:
- self->LoopStart = value;
- break;
-
- case AL_SAMPLE_LOOP_END_SOFT:
- self->LoopEnd = value;
- break;
-
- case AL_SAMPLE_RATE_SOFT:
- if(!(value > 0))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->SampleRate = value;
- break;
-
- case AL_BASE_KEY_SOFT:
- if(!((value >= 0 && value <= 127) || value == 255))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->PitchKey = value;
- break;
-
- case AL_KEY_CORRECTION_SOFT:
- if(!(value >= -99 && value <= 99))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->PitchCorrection = value;
- break;
-
- case AL_SAMPLE_TYPE_SOFT:
- if(!(value == AL_MONO_SOFT || value == AL_RIGHT_SOFT || value == AL_LEFT_SOFT))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- self->SampleType = value;
- 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);
- }
- if(link) IncrementRef(&link->ref);
- link = ExchangePtr((XchgPtr*)&self->Link, link);
- if(link) DecrementRef(&link->ref);
- break;
-
- default:
- SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
- }
-}
-
-static ALsfmodulator *ALfontsound_getModStage(ALfontsound *self, ALsizei stage)
-{
- ALsfmodulator *ret = LookupModulator(self, stage);
- if(!ret)
- {
- static const ALsfmodulator moddef = {
- { { 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);
- }
- return ret;
-}
-
-void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value)
-{
- ALint srcidx = 0;
-
- if(ReadRef(&self->ref) != 0)
- SET_ERROR_AND_RETURN(context, AL_INVALID_OPERATION);
- switch(param)
- {
- case AL_SOURCE1_INPUT_SOFT:
- srcidx++;
- /* fall-through */
- case AL_SOURCE0_INPUT_SOFT:
- if(!(value == AL_ONE_SOFT || value == AL_NOTEON_VELOCITY_SOFT ||
- 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))
- )
- ))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- ALfontsound_getModStage(self, stage)->Source[srcidx].Input = value;
- break;
-
- case AL_SOURCE1_TYPE_SOFT:
- srcidx++;
- /* fall-through */
- case AL_SOURCE0_TYPE_SOFT:
- if(!(value == AL_UNORM_SOFT || value == AL_UNORM_REV_SOFT ||
- value == AL_SNORM_SOFT || value == AL_SNORM_REV_SOFT))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- ALfontsound_getModStage(self, stage)->Source[srcidx].Type = value;
- break;
-
- case AL_SOURCE1_FORM_SOFT:
- srcidx++;
- /* fall-through */
- case AL_SOURCE0_FORM_SOFT:
- if(!(value == AL_LINEAR_SOFT || value == AL_CONCAVE_SOFT ||
- value == AL_CONVEX_SOFT || value == AL_SWITCH_SOFT))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- ALfontsound_getModStage(self, stage)->Source[srcidx].Form = value;
- break;
-
- case AL_AMOUNT_SOFT:
- ALfontsound_getModStage(self, stage)->Amount = value;
- break;
-
- case AL_TRANSFORM_OP_SOFT:
- if(!(value == AL_LINEAR_SOFT || value == AL_ABSOLUTE_SOFT))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- ALfontsound_getModStage(self, stage)->TransformOp = value;
- break;
-
- case AL_DESTINATION_SOFT:
- if(!(value == AL_MOD_LFO_TO_PITCH_SOFT || value == AL_VIBRATO_LFO_TO_PITCH_SOFT ||
- value == AL_MOD_ENV_TO_PITCH_SOFT || value == AL_FILTER_CUTOFF_SOFT ||
- value == AL_FILTER_RESONANCE_SOFT || value == AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT ||
- value == AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT || value == AL_MOD_LFO_TO_VOLUME_SOFT ||
- value == AL_CHORUS_SEND_SOFT || value == AL_REVERB_SEND_SOFT || value == AL_PAN_SOFT ||
- value == AL_MOD_LFO_DELAY_SOFT || value == AL_MOD_LFO_FREQUENCY_SOFT ||
- value == AL_VIBRATO_LFO_DELAY_SOFT || value == AL_VIBRATO_LFO_FREQUENCY_SOFT ||
- value == AL_MOD_ENV_DELAYTIME_SOFT || value == AL_MOD_ENV_ATTACKTIME_SOFT ||
- value == AL_MOD_ENV_HOLDTIME_SOFT || value == AL_MOD_ENV_DECAYTIME_SOFT ||
- value == AL_MOD_ENV_SUSTAINVOLUME_SOFT || value == AL_MOD_ENV_RELEASETIME_SOFT ||
- value == AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT || value == AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT ||
- value == AL_VOLUME_ENV_DELAYTIME_SOFT || value == AL_VOLUME_ENV_ATTACKTIME_SOFT ||
- value == AL_VOLUME_ENV_HOLDTIME_SOFT || value == AL_VOLUME_ENV_DECAYTIME_SOFT ||
- value == AL_VOLUME_ENV_SUSTAINVOLUME_SOFT || value == AL_VOLUME_ENV_RELEASETIME_SOFT ||
- value == AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT || value == AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT ||
- value == AL_ATTENUATION_SOFT || value == AL_TUNING_COARSE_SOFT ||
- value == AL_TUNING_FINE_SOFT || value == AL_TUNING_SCALE_SOFT))
- SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
- ALfontsound_getModStage(self, stage)->Dest = value;
- break;
-
- default:
- SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
- }
-}
-
-static void ALfontsound_getModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint *values)
-{
- ALsfmodulator *mod = LookupModulator(self, stage);
- ALint srcidx = 0;
-
- switch(param)
- {
- case AL_SOURCE1_INPUT_SOFT:
- srcidx++;
- /* fall-through */
- case AL_SOURCE0_INPUT_SOFT:
- values[0] = mod ? mod->Source[srcidx].Input : AL_ONE_SOFT;
- break;
-
- case AL_SOURCE1_TYPE_SOFT:
- srcidx++;
- /* fall-through */
- case AL_SOURCE0_TYPE_SOFT:
- values[0] = mod ? mod->Source[srcidx].Type : AL_UNORM_SOFT;
- break;
-
- case AL_SOURCE1_FORM_SOFT:
- srcidx++;
- /* fall-through */
- case AL_SOURCE0_FORM_SOFT:
- values[0] = mod ? mod->Source[srcidx].Form : AL_LINEAR_SOFT;
- break;
-
- case AL_AMOUNT_SOFT:
- values[0] = mod ? mod->Amount : 0;
- break;
-
- case AL_TRANSFORM_OP_SOFT:
- values[0] = mod ? mod->TransformOp : AL_LINEAR_SOFT;
- break;
-
- case AL_DESTINATION_SOFT:
- values[0] = mod ? mod->Dest : AL_NONE;
- break;
-
- default:
- SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
- }
-}
-
-
-/* ReleaseALFontsounds
- *
- * Called to destroy any fontsounds that still exist on the device
- */
-void ReleaseALFontsounds(ALCdevice *device)
-{
- ALsizei i;
- for(i = 0;i < device->FontsoundMap.size;i++)
- {
- ALfontsound *temp = device->FontsoundMap.array[i].value;
- device->FontsoundMap.array[i].value = NULL;
-
- ALfontsound_Destruct(temp);
-
- memset(temp, 0, sizeof(*temp));
- free(temp);
- }
-}
diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c
index 87cd3c61..66865473 100644
--- a/OpenAL32/alListener.c
+++ b/OpenAL32/alListener.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -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:
@@ -74,10 +74,8 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
LockContext(context);
- context->Listener->Position[0] = value1;
- context->Listener->Position[1] = value2;
- context->Listener->Position[2] = value3;
- context->UpdateSources = AL_TRUE;
+ aluVectorSet(&context->Listener->Position, value1, value2, value3, 1.0f);
+ ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
UnlockContext(context);
break;
@@ -86,10 +84,8 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
LockContext(context);
- context->Listener->Velocity[0] = value1;
- context->Listener->Velocity[1] = value2;
- context->Listener->Velocity[2] = value3;
- context->UpdateSources = AL_TRUE;
+ aluVectorSet(&context->Listener->Velocity, value1, value2, value3, 0.0f);
+ ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
UnlockContext(context);
break;
@@ -142,7 +138,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;
@@ -282,17 +278,17 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
{
case AL_POSITION:
LockContext(context);
- *value1 = context->Listener->Position[0];
- *value2 = context->Listener->Position[1];
- *value3 = context->Listener->Position[2];
+ *value1 = context->Listener->Position.v[0];
+ *value2 = context->Listener->Position.v[1];
+ *value3 = context->Listener->Position.v[2];
UnlockContext(context);
break;
case AL_VELOCITY:
LockContext(context);
- *value1 = context->Listener->Velocity[0];
- *value2 = context->Listener->Velocity[1];
- *value3 = context->Listener->Velocity[2];
+ *value1 = context->Listener->Velocity.v[0];
+ *value2 = context->Listener->Velocity.v[1];
+ *value3 = context->Listener->Velocity.v[2];
UnlockContext(context);
break;
@@ -383,17 +379,17 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
{
case AL_POSITION:
LockContext(context);
- *value1 = (ALint)context->Listener->Position[0];
- *value2 = (ALint)context->Listener->Position[1];
- *value3 = (ALint)context->Listener->Position[2];
+ *value1 = (ALint)context->Listener->Position.v[0];
+ *value2 = (ALint)context->Listener->Position.v[1];
+ *value3 = (ALint)context->Listener->Position.v[2];
UnlockContext(context);
break;
case AL_VELOCITY:
LockContext(context);
- *value1 = (ALint)context->Listener->Velocity[0];
- *value2 = (ALint)context->Listener->Velocity[1];
- *value3 = (ALint)context->Listener->Velocity[2];
+ *value1 = (ALint)context->Listener->Velocity.v[0];
+ *value2 = (ALint)context->Listener->Velocity.v[1];
+ *value3 = (ALint)context->Listener->Velocity.v[2];
UnlockContext(context);
break;
diff --git a/OpenAL32/alMidi.c b/OpenAL32/alMidi.c
deleted file mode 100644
index 6313523e..00000000
--- a/OpenAL32/alMidi.c
+++ /dev/null
@@ -1,223 +0,0 @@
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include "alMain.h"
-#include "alMidi.h"
-#include "alError.h"
-#include "alThunk.h"
-#include "evtqueue.h"
-#include "rwlock.h"
-#include "alu.h"
-
-#include "midi/base.h"
-
-
-MidiSynth *SynthCreate(ALCdevice *device)
-{
- MidiSynth *synth = NULL;
- if(!synth) synth = SSynth_create(device);
- if(!synth) synth = FSynth_create(device);
- if(!synth) synth = DSynth_create(device);
- return synth;
-}
-
-
-AL_API void AL_APIENTRY alMidiSoundfontSOFT(ALuint id)
-{
- alMidiSoundfontvSOFT(1, &id);
-}
-
-AL_API void AL_APIENTRY alMidiSoundfontvSOFT(ALsizei count, const ALuint *ids)
-{
- ALCdevice *device;
- ALCcontext *context;
- MidiSynth *synth;
- ALenum err;
-
- context = GetContextRef();
- if(!context) return;
-
- if(count < 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- device = context->Device;
- synth = device->Synth;
-
- WriteLock(&synth->Lock);
- if(synth->State == AL_PLAYING || synth->State == AL_PAUSED)
- alSetError(context, AL_INVALID_OPERATION);
- else
- {
- err = V(synth,selectSoundfonts)(context, count, ids);
- if(err != AL_NO_ERROR)
- alSetError(context, err);
- }
- WriteUnlock(&synth->Lock);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-
-AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALenum err;
-
- context = GetContextRef();
- if(!context) return;
-
- if(!(event == AL_NOTEOFF_SOFT || event == AL_NOTEON_SOFT ||
- event == AL_KEYPRESSURE_SOFT || event == AL_CONTROLLERCHANGE_SOFT ||
- event == AL_PROGRAMCHANGE_SOFT || event == AL_CHANNELPRESSURE_SOFT ||
- event == AL_PITCHBEND_SOFT))
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- if(!(channel >= 0 && channel <= 15))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if(!(param1 >= 0 && param1 <= 127))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- if(!(param2 >= 0 && param2 <= 127))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- device = context->Device;
- ALCdevice_Lock(device);
- err = MidiSynth_insertEvent(device->Synth, time, event|channel, param1, param2);
- ALCdevice_Unlock(device);
- if(err != AL_NO_ERROR)
- alSetError(context, err);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, ALsizei size)
-{
- 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);
- err = MidiSynth_insertSysExEvent(device->Synth, time, data, size);
- ALCdevice_Unlock(device);
- if(err != AL_NO_ERROR)
- alSetError(context, err);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alMidiPlaySOFT(void)
-{
- ALCcontext *context;
- MidiSynth *synth;
-
- context = GetContextRef();
- if(!context) return;
-
- synth = context->Device->Synth;
- WriteLock(&synth->Lock);
- MidiSynth_setState(synth, AL_PLAYING);
- WriteUnlock(&synth->Lock);
-
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alMidiPauseSOFT(void)
-{
- ALCcontext *context;
- MidiSynth *synth;
-
- context = GetContextRef();
- if(!context) return;
-
- synth = context->Device->Synth;
- WriteLock(&synth->Lock);
- MidiSynth_setState(synth, AL_PAUSED);
- WriteUnlock(&synth->Lock);
-
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alMidiStopSOFT(void)
-{
- ALCdevice *device;
- ALCcontext *context;
- MidiSynth *synth;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- synth = device->Synth;
-
- WriteLock(&synth->Lock);
- MidiSynth_setState(synth, AL_STOPPED);
-
- ALCdevice_Lock(device);
- V0(synth,stop)();
- ALCdevice_Unlock(device);
- WriteUnlock(&synth->Lock);
-
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alMidiResetSOFT(void)
-{
- ALCdevice *device;
- ALCcontext *context;
- MidiSynth *synth;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- synth = device->Synth;
-
- WriteLock(&synth->Lock);
- MidiSynth_setState(synth, AL_INITIAL);
-
- ALCdevice_Lock(device);
- V0(synth,reset)();
- ALCdevice_Unlock(device);
- WriteUnlock(&synth->Lock);
-
- ALCcontext_DecRef(context);
-}
-
-
-AL_API void AL_APIENTRY alMidiGainSOFT(ALfloat value)
-{
- ALCdevice *device;
- ALCcontext *context;
-
- context = GetContextRef();
- if(!context) return;
-
- if(!(value >= 0.0f && isfinite(value)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- device = context->Device;
- V(device->Synth,setGain)(value);
-
-done:
- ALCcontext_DecRef(context);
-}
diff --git a/OpenAL32/alPreset.c b/OpenAL32/alPreset.c
deleted file mode 100644
index c7167d6b..00000000
--- a/OpenAL32/alPreset.c
+++ /dev/null
@@ -1,340 +0,0 @@
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "alMain.h"
-#include "alMidi.h"
-#include "alError.h"
-#include "alThunk.h"
-
-#include "midi/base.h"
-
-
-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);
-
-
-AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids)
-{
- ALCcontext *context;
- ALsizei cur = 0;
-
- context = GetContextRef();
- if(!context) return;
-
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- for(cur = 0;cur < n;cur++)
- {
- ALsfpreset *preset = NewPreset(context);
- if(!preset)
- {
- alDeletePresetsSOFT(cur, ids);
- break;
- }
-
- ids[cur] = preset->id;
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API ALvoid AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsfpreset *preset;
- ALsizei i;
-
- context = GetContextRef();
- if(!context) return;
-
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- device = context->Device;
- for(i = 0;i < n;i++)
- {
- /* Check for valid ID */
- if((preset=LookupPreset(device, ids[i])) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- 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);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API ALboolean AL_APIENTRY alIsPresetSOFT(ALuint id)
-{
- ALCcontext *context;
- ALboolean ret;
-
- context = GetContextRef();
- if(!context) return AL_FALSE;
-
- ret = LookupPreset(context->Device, id) ? AL_TRUE : AL_FALSE;
-
- ALCcontext_DecRef(context);
-
- return ret;
-}
-
-AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsfpreset *preset;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if((preset=LookupPreset(device, id)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(ReadRef(&preset->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- switch(param)
- {
- case AL_MIDI_PRESET_SOFT:
- if(!(value >= 0 && value <= 127))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- preset->Preset = value;
- break;
-
- case AL_MIDI_BANK_SOFT:
- if(!(value >= 0 && value <= 128))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- preset->Bank = value;
- break;
-
- default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *values)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsfpreset *preset;
-
- switch(param)
- {
- case AL_MIDI_PRESET_SOFT:
- case AL_MIDI_BANK_SOFT:
- alPresetiSOFT(id, param, values[0]);
- return;
- }
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if((preset=LookupPreset(device, id)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(ReadRef(&preset->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- switch(param)
- {
- default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alGetPresetivSOFT(ALuint id, ALenum param, ALint *values)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsfpreset *preset;
- ALsizei i;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if((preset=LookupPreset(device, id)) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- switch(param)
- {
- case AL_MIDI_PRESET_SOFT:
- values[0] = preset->Preset;
- break;
-
- case AL_MIDI_BANK_SOFT:
- values[0] = preset->Bank;
- break;
-
- case AL_FONTSOUNDS_SIZE_SOFT:
- values[0] = preset->NumSounds;
- break;
-
- case AL_FONTSOUNDS_SOFT:
- for(i = 0;i < preset->NumSounds;i++)
- values[i] = preset->Sounds[i]->id;
- break;
-
- default:
- SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsfpreset *preset;
- ALfontsound **sounds;
- ALsizei i;
-
- context = GetContextRef();
- if(!context) return;
-
- device = context->Device;
- if(!(preset=LookupPreset(device, id)))
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(count < 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- if(ReadRef(&preset->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
-
- if(count == 0)
- sounds = NULL;
- else
- {
- sounds = calloc(count, sizeof(sounds[0]));
- if(!sounds)
- SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
-
- for(i = 0;i < count;i++)
- {
- if(!(sounds[i]=LookupFontsound(device, fsids[i])))
- {
- free(sounds);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- }
- }
- }
-
- for(i = 0;i < count;i++)
- IncrementRef(&sounds[i]->ref);
-
- sounds = ExchangePtr((XchgPtr*)&preset->Sounds, sounds);
- count = ExchangeInt(&preset->NumSounds, count);
-
- for(i = 0;i < count;i++)
- DecrementRef(&sounds[i]->ref);
- free(sounds);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-
-ALsfpreset *NewPreset(ALCcontext *context)
-{
- ALCdevice *device = context->Device;
- ALsfpreset *preset;
- ALenum err;
-
- preset = calloc(1, sizeof(*preset));
- if(!preset)
- SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL);
- ALsfpreset_Construct(preset);
-
- err = NewThunkEntry(&preset->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->PresetMap, preset->id, preset);
- if(err != AL_NO_ERROR)
- {
- ALsfpreset_Destruct(preset);
- memset(preset, 0, sizeof(*preset));
- free(preset);
-
- SET_ERROR_AND_RETURN_VALUE(context, err, NULL);
- }
-
- return preset;
-}
-
-void DeletePreset(ALsfpreset *preset, ALCdevice *device)
-{
- RemovePreset(device, preset->id);
-
- ALsfpreset_Destruct(preset);
- memset(preset, 0, sizeof(*preset));
- free(preset);
-}
-
-
-static void ALsfpreset_Construct(ALsfpreset *self)
-{
- InitRef(&self->ref, 0);
-
- self->Preset = 0;
- self->Bank = 0;
-
- self->Sounds = NULL;
- self->NumSounds = 0;
-
- self->id = 0;
-}
-
-void ALsfpreset_Destruct(ALsfpreset *self)
-{
- ALsizei i;
-
- FreeThunkEntry(self->id);
- self->id = 0;
-
- for(i = 0;i < self->NumSounds;i++)
- DecrementRef(&self->Sounds[i]->ref);
- free(self->Sounds);
- self->Sounds = NULL;
- self->NumSounds = 0;
-}
-
-
-/* ReleaseALPresets
- *
- * Called to destroy any presets that still exist on the device
- */
-void ReleaseALPresets(ALCdevice *device)
-{
- ALsizei i;
- for(i = 0;i < device->PresetMap.size;i++)
- {
- ALsfpreset *temp = device->PresetMap.array[i].value;
- device->PresetMap.array[i].value = NULL;
-
- ALsfpreset_Destruct(temp);
-
- memset(temp, 0, sizeof(*temp));
- free(temp);
- }
-}
diff --git a/OpenAL32/alSoundfont.c b/OpenAL32/alSoundfont.c
deleted file mode 100644
index 357e13e7..00000000
--- a/OpenAL32/alSoundfont.c
+++ /dev/null
@@ -1,564 +0,0 @@
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "alMain.h"
-#include "alMidi.h"
-#include "alThunk.h"
-#include "alError.h"
-
-#include "midi/base.h"
-
-
-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);
-void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device);
-ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context);
-static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr);
-
-
-AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsizei cur = 0;
- ALenum err;
-
- context = GetContextRef();
- if(!context) return;
-
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- device = context->Device;
- for(cur = 0;cur < n;cur++)
- {
- ALsoundfont *sfont = calloc(1, sizeof(ALsoundfont));
- if(!sfont)
- {
- alDeleteSoundfontsSOFT(cur, ids);
- SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
- }
- ALsoundfont_Construct(sfont);
-
- err = NewThunkEntry(&sfont->id);
- if(err == AL_NO_ERROR)
- err = InsertUIntMapEntry(&device->SfontMap, sfont->id, sfont);
- if(err != AL_NO_ERROR)
- {
- ALsoundfont_Destruct(sfont);
- memset(sfont, 0, sizeof(ALsoundfont));
- free(sfont);
-
- alDeleteSoundfontsSOFT(cur, ids);
- SET_ERROR_AND_GOTO(context, err, done);
- }
-
- ids[cur] = sfont->id;
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsoundfont *sfont;
- ALsizei i;
-
- context = GetContextRef();
- if(!context) return;
-
- if(!(n >= 0))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- device = context->Device;
- for(i = 0;i < n;i++)
- {
- /* Check for valid soundfont ID */
- if(ids[i] == 0)
- {
- if(!(sfont=device->DefaultSfont))
- continue;
- }
- else if((sfont=LookupSfont(device, ids[i])) == NULL)
- SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done);
- if(sfont->Mapped != AL_FALSE || ReadRef(&sfont->ref) != 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- }
-
- for(i = 0;i < n;i++)
- {
- if(ids[i] == 0)
- {
- MidiSynth *synth = device->Synth;
- WriteLock(&synth->Lock);
- if(device->DefaultSfont != NULL)
- ALsoundfont_deleteSoundfont(device->DefaultSfont, device);
- device->DefaultSfont = NULL;
- WriteUnlock(&synth->Lock);
- continue;
- }
- else if((sfont=RemoveSfont(device, ids[i])) == NULL)
- continue;
-
- ALsoundfont_Destruct(sfont);
-
- memset(sfont, 0, sizeof(*sfont));
- free(sfont);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id)
-{
- ALCcontext *context;
- ALboolean ret;
-
- context = GetContextRef();
- if(!context) return AL_FALSE;
-
- ret = ((!id || LookupSfont(context->Device, id)) ?
- AL_TRUE : AL_FALSE);
-
- ALCcontext_DecRef(context);
-
- 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(ReadRef(&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(ReadRef(&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;
- ALCcontext *context;
- ALsoundfont *sfont;
- ALsizei i;
-
- 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);
- switch(param)
- {
- case AL_PRESETS_SIZE_SOFT:
- values[0] = sfont->NumPresets;
- break;
-
- case AL_PRESETS_SOFT:
- for(i = 0;i < sfont->NumPresets;i++)
- 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);
- }
-
-done:
- ALCcontext_DecRef(context);
-}
-
-AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsoundfont *sfont;
- ALsfpreset **presets;
- ALsizei i;
-
- 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(count < 0)
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-
- WriteLock(&sfont->Lock);
- if(ReadRef(&sfont->ref) != 0)
- {
- WriteUnlock(&sfont->Lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- }
-
- if(count == 0)
- presets = NULL;
- else
- {
- presets = calloc(count, sizeof(presets[0]));
- if(!presets)
- {
- WriteUnlock(&sfont->Lock);
- SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
- }
-
- for(i = 0;i < count;i++)
- {
- if(!(presets[i]=LookupPreset(device, pids[i])))
- {
- free(presets);
- WriteUnlock(&sfont->Lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- }
- }
- }
-
- for(i = 0;i < count;i++)
- IncrementRef(&presets[i]->ref);
-
- presets = ExchangePtr((XchgPtr*)&sfont->Presets, presets);
- count = ExchangeInt(&sfont->NumPresets, count);
- WriteUnlock(&sfont->Lock);
-
- for(i = 0;i < count;i++)
- DecrementRef(&presets[i]->ref);
- free(presets);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-
-AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user)
-{
- ALCdevice *device;
- ALCcontext *context;
- ALsoundfont *sfont;
- Reader reader;
-
- 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);
-
- WriteLock(&sfont->Lock);
- if(ReadRef(&sfont->ref) != 0)
- {
- WriteUnlock(&sfont->Lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- }
- if(sfont->Mapped)
- {
- WriteUnlock(&sfont->Lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- }
- if(sfont->NumPresets > 0)
- {
- WriteUnlock(&sfont->Lock);
- SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done);
- }
-
- reader.cb = cb;
- reader.ptr = user;
- reader.error = 0;
- loadSf2(&reader, sfont, context);
- WriteUnlock(&sfont->Lock);
-
-done:
- ALCcontext_DecRef(context);
-}
-
-
-void ALsoundfont_Construct(ALsoundfont *self)
-{
- 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)
-{
- ALsizei i;
-
- FreeThunkEntry(self->id);
- self->id = 0;
-
- for(i = 0;i < self->NumPresets;i++)
- {
- DecrementRef(&self->Presets[i]->ref);
- self->Presets[i] = NULL;
- }
- 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;
-
- if(device->DefaultSfont)
- return device->DefaultSfont;
-
- device->DefaultSfont = calloc(1, sizeof(device->DefaultSfont[0]));
- ALsoundfont_Construct(device->DefaultSfont);
-
- fname = getenv("ALSOFT_SOUNDFONT");
- if((fname && fname[0]) || ConfigValueStr("midi", "soundfont", &fname))
- {
- FILE *f;
-
- f = OpenDataFile(fname, "openal/soundfonts");
- if(f == NULL)
- ERR("Failed to open %s\n", fname);
- else
- {
- Reader reader;
- reader.cb = ALsoundfont_read;
- reader.ptr = f;
- reader.error = 0;
- TRACE("Loading %s\n", fname);
- loadSf2(&reader, device->DefaultSfont, context);
- fclose(f);
- }
- }
-
- return device->DefaultSfont;
-}
-
-void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device)
-{
- ALsfpreset **presets;
- ALsizei num_presets;
- ALsizei i;
-
- presets = ExchangePtr((XchgPtr*)&self->Presets, NULL);
- num_presets = ExchangeInt(&self->NumPresets, 0);
-
- for(i = 0;i < num_presets;i++)
- {
- ALsfpreset *preset = presets[i];
- ALfontsound **sounds;
- ALsizei num_sounds;
- ALboolean deleting;
- ALsizei j;
-
- sounds = ExchangePtr((XchgPtr*)&preset->Sounds, NULL);
- num_sounds = ExchangeInt(&preset->NumSounds, 0);
- DeletePreset(preset, device);
- preset = NULL;
-
- for(j = 0;j < num_sounds;j++)
- DecrementRef(&sounds[j]->ref);
- /* Some fontsounds may not be immediately deletable because they're
- * linked to another fontsound. When those fontsounds are deleted
- * they should become deletable, so use a loop until all fontsounds
- * are deleted. */
- do {
- deleting = AL_FALSE;
- for(j = 0;j < num_sounds;j++)
- {
- if(sounds[j] && ReadRef(&sounds[j]->ref) == 0)
- {
- deleting = AL_TRUE;
- RemoveFontsound(device, sounds[j]->id);
- ALfontsound_Destruct(sounds[j]);
- free(sounds[j]);
- sounds[j] = NULL;
- }
- }
- } while(deleting);
- free(sounds);
- }
-
- ALsoundfont_Destruct(self);
- free(self);
-}
-
-
-static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr)
-{
- return fread(buf, 1, bytes, (FILE*)ptr);
-}
-
-
-/* ReleaseALSoundfonts
- *
- * Called to destroy any soundfonts that still exist on the device
- */
-void ReleaseALSoundfonts(ALCdevice *device)
-{
- ALsizei i;
- for(i = 0;i < device->SfontMap.size;i++)
- {
- ALsoundfont *temp = device->SfontMap.array[i].value;
- device->SfontMap.array[i].value = NULL;
-
- ALsoundfont_Destruct(temp);
-
- memset(temp, 0, sizeof(*temp));
- free(temp);
- }
-}
diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c
index a580c45c..0d454882 100644
--- a/OpenAL32/alSource.c
+++ b/OpenAL32/alSource.c
@@ -13,14 +13,15 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
#include "config.h"
#include <stdlib.h>
+#include <limits.h>
#include <math.h>
#include <float.h>
@@ -33,328 +34,331 @@
#include "alThunk.h"
#include "alAuxEffectSlot.h"
-#include "threads.h"
-
+#include "backends/base.h"
-enum Resampler DefaultResampler = LinearResampler;
-const ALsizei ResamplerPadding[ResamplerMax] = {
- 0, /* Point */
- 1, /* Linear */
- 2, /* Cubic */
-};
-const ALsizei ResamplerPrePadding[ResamplerMax] = {
- 0, /* Point */
- 0, /* Linear */
- 1, /* Cubic */
-};
+#include "threads.h"
extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id);
extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id);
static ALvoid InitSourceParams(ALsource *Source);
-static ALint64 GetSourceOffset(const ALsource *Source);
-static ALdouble GetSourceSecOffset(const ALsource *Source);
-static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
-static ALint GetSampleOffset(ALsource *Source);
-
-typedef enum SrcFloatProp {
- sfPitch = AL_PITCH,
- sfGain = AL_GAIN,
- sfMinGain = AL_MIN_GAIN,
- sfMaxGain = AL_MAX_GAIN,
- sfMaxDistance = AL_MAX_DISTANCE,
- sfRolloffFactor = AL_ROLLOFF_FACTOR,
- sfDopplerFactor = AL_DOPPLER_FACTOR,
- sfConeOuterGain = AL_CONE_OUTER_GAIN,
- sfSecOffset = AL_SEC_OFFSET,
- sfSampleOffset = AL_SAMPLE_OFFSET,
- sfByteOffset = AL_BYTE_OFFSET,
- sfConeInnerAngle = AL_CONE_INNER_ANGLE,
- sfConeOuterAngle = AL_CONE_OUTER_ANGLE,
- sfRefDistance = AL_REFERENCE_DISTANCE,
-
- sfPosition = AL_POSITION,
- sfVelocity = AL_VELOCITY,
- sfDirection = AL_DIRECTION,
-
- sfSourceRelative = AL_SOURCE_RELATIVE,
- sfLooping = AL_LOOPING,
- sfBuffer = AL_BUFFER,
- sfSourceState = AL_SOURCE_STATE,
- sfBuffersQueued = AL_BUFFERS_QUEUED,
- sfBuffersProcessed = AL_BUFFERS_PROCESSED,
- sfSourceType = AL_SOURCE_TYPE,
+static ALint64 GetSourceSampleOffset(ALsource *Source);
+static ALdouble GetSourceSecOffset(ALsource *Source);
+static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen);
+static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac);
+
+typedef enum SourceProp {
+ srcPitch = AL_PITCH,
+ srcGain = AL_GAIN,
+ srcMinGain = AL_MIN_GAIN,
+ srcMaxGain = AL_MAX_GAIN,
+ srcMaxDistance = AL_MAX_DISTANCE,
+ srcRolloffFactor = AL_ROLLOFF_FACTOR,
+ srcDopplerFactor = AL_DOPPLER_FACTOR,
+ srcConeOuterGain = AL_CONE_OUTER_GAIN,
+ srcSecOffset = AL_SEC_OFFSET,
+ srcSampleOffset = AL_SAMPLE_OFFSET,
+ srcByteOffset = AL_BYTE_OFFSET,
+ srcConeInnerAngle = AL_CONE_INNER_ANGLE,
+ srcConeOuterAngle = AL_CONE_OUTER_ANGLE,
+ srcRefDistance = AL_REFERENCE_DISTANCE,
+
+ srcPosition = AL_POSITION,
+ srcVelocity = AL_VELOCITY,
+ srcDirection = AL_DIRECTION,
+
+ srcSourceRelative = AL_SOURCE_RELATIVE,
+ srcLooping = AL_LOOPING,
+ srcBuffer = AL_BUFFER,
+ srcSourceState = AL_SOURCE_STATE,
+ srcBuffersQueued = AL_BUFFERS_QUEUED,
+ srcBuffersProcessed = AL_BUFFERS_PROCESSED,
+ srcSourceType = AL_SOURCE_TYPE,
/* ALC_EXT_EFX */
- sfConeOuterGainHF = AL_CONE_OUTER_GAINHF,
- sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
- sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
- sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
- sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
- sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
+ srcConeOuterGainHF = AL_CONE_OUTER_GAINHF,
+ srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR,
+ srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR,
+ srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
+ srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
+ srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
+ srcDirectFilter = AL_DIRECT_FILTER,
+ srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
/* AL_SOFT_direct_channels */
- sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
+ srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
/* AL_EXT_source_distance_model */
- sfDistanceModel = AL_DISTANCE_MODEL,
+ srcDistanceModel = AL_DISTANCE_MODEL,
- sfSecLength = AL_SEC_LENGTH_SOFT,
+ srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT,
+ srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT,
+ srcSecLengthSOFT = AL_SEC_LENGTH_SOFT,
/* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
- sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
- sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
+ srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
+ srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
/* AL_SOFT_source_latency */
- sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
-} SrcFloatProp;
-
-typedef enum SrcIntProp {
- siMaxDistance = AL_MAX_DISTANCE,
- siRolloffFactor = AL_ROLLOFF_FACTOR,
- siRefDistance = AL_REFERENCE_DISTANCE,
- siSourceRelative = AL_SOURCE_RELATIVE,
- siConeInnerAngle = AL_CONE_INNER_ANGLE,
- siConeOuterAngle = AL_CONE_OUTER_ANGLE,
- siLooping = AL_LOOPING,
- siBuffer = AL_BUFFER,
- siSourceState = AL_SOURCE_STATE,
- siBuffersQueued = AL_BUFFERS_QUEUED,
- siBuffersProcessed = AL_BUFFERS_PROCESSED,
- siSourceType = AL_SOURCE_TYPE,
- siSecOffset = AL_SEC_OFFSET,
- siSampleOffset = AL_SAMPLE_OFFSET,
- siByteOffset = AL_BYTE_OFFSET,
- siDopplerFactor = AL_DOPPLER_FACTOR,
- siPosition = AL_POSITION,
- siVelocity = AL_VELOCITY,
- siDirection = AL_DIRECTION,
-
- /* ALC_EXT_EFX */
- siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO,
- siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO,
- siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO,
- siDirectFilter = AL_DIRECT_FILTER,
- siAuxSendFilter = AL_AUXILIARY_SEND_FILTER,
-
- /* AL_SOFT_direct_channels */
- siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT,
+ srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
+ srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT,
- /* AL_EXT_source_distance_model */
- siDistanceModel = AL_DISTANCE_MODEL,
-
- siByteLength = AL_BYTE_LENGTH_SOFT,
- siSampleLength = AL_SAMPLE_LENGTH_SOFT,
+ /* AL_EXT_BFORMAT */
+ srcOrientation = AL_ORIENTATION,
+} SourceProp;
- /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */
- siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT,
- siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT,
+static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values);
+static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values);
+static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values);
- /* AL_SOFT_source_latency */
- siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT,
-} SrcIntProp;
-
-static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values);
-static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values);
-static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values);
-
-static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values);
-static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values);
-static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values);
+static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values);
+static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values);
+static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values);
static ALint FloatValsByProp(ALenum prop)
{
- if(prop != (ALenum)((SrcFloatProp)prop))
+ if(prop != (ALenum)((SourceProp)prop))
return 0;
- switch((SrcFloatProp)prop)
+ switch((SourceProp)prop)
{
- case sfPitch:
- case sfGain:
- case sfMinGain:
- case sfMaxGain:
- case sfMaxDistance:
- case sfRolloffFactor:
- case sfDopplerFactor:
- case sfConeOuterGain:
- case sfSecOffset:
- case sfSampleOffset:
- case sfByteOffset:
- case sfConeInnerAngle:
- case sfConeOuterAngle:
- case sfRefDistance:
- case sfConeOuterGainHF:
- case sfAirAbsorptionFactor:
- case sfRoomRolloffFactor:
- case sfDirectFilterGainHFAuto:
- case sfAuxSendFilterGainAuto:
- case sfAuxSendFilterGainHFAuto:
- case sfDirectChannelsSOFT:
- case sfDistanceModel:
- case sfSourceRelative:
- case sfLooping:
- case sfBuffer:
- case sfSourceState:
- case sfBuffersQueued:
- case sfBuffersProcessed:
- case sfSourceType:
- case sfSecLength:
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_DOPPLER_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_REFERENCE_DISTANCE:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ case AL_DIRECT_CHANNELS_SOFT:
+ case AL_DISTANCE_MODEL:
+ case AL_SOURCE_RELATIVE:
+ case AL_LOOPING:
+ case AL_SOURCE_STATE:
+ case AL_BUFFERS_QUEUED:
+ case AL_BUFFERS_PROCESSED:
+ case AL_SOURCE_TYPE:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
+ case AL_SEC_LENGTH_SOFT:
return 1;
- case sfSampleRWOffsetsSOFT:
- case sfByteRWOffsetsSOFT:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_RW_OFFSETS_SOFT:
return 2;
- case sfPosition:
- case sfVelocity:
- case sfDirection:
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
return 3;
- case sfSecOffsetLatencySOFT:
+ case AL_ORIENTATION:
+ return 6;
+
+ case AL_SEC_OFFSET_LATENCY_SOFT:
break; /* Double only */
+
+ case AL_BUFFER:
+ case AL_DIRECT_FILTER:
+ case AL_AUXILIARY_SEND_FILTER:
+ break; /* i/i64 only */
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ break; /* i64 only */
}
return 0;
}
static ALint DoubleValsByProp(ALenum prop)
{
- if(prop != (ALenum)((SrcFloatProp)prop))
+ if(prop != (ALenum)((SourceProp)prop))
return 0;
- switch((SrcFloatProp)prop)
+ switch((SourceProp)prop)
{
- case sfPitch:
- case sfGain:
- case sfMinGain:
- case sfMaxGain:
- case sfMaxDistance:
- case sfRolloffFactor:
- case sfDopplerFactor:
- case sfConeOuterGain:
- case sfSecOffset:
- case sfSampleOffset:
- case sfByteOffset:
- case sfConeInnerAngle:
- case sfConeOuterAngle:
- case sfRefDistance:
- case sfConeOuterGainHF:
- case sfAirAbsorptionFactor:
- case sfRoomRolloffFactor:
- case sfDirectFilterGainHFAuto:
- case sfAuxSendFilterGainAuto:
- case sfAuxSendFilterGainHFAuto:
- case sfDirectChannelsSOFT:
- case sfDistanceModel:
- case sfSourceRelative:
- case sfLooping:
- case sfBuffer:
- case sfSourceState:
- case sfBuffersQueued:
- case sfBuffersProcessed:
- case sfSourceType:
- case sfSecLength:
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_DOPPLER_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_REFERENCE_DISTANCE:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ case AL_DIRECT_CHANNELS_SOFT:
+ case AL_DISTANCE_MODEL:
+ case AL_SOURCE_RELATIVE:
+ case AL_LOOPING:
+ case AL_SOURCE_STATE:
+ case AL_BUFFERS_QUEUED:
+ case AL_BUFFERS_PROCESSED:
+ case AL_SOURCE_TYPE:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
+ case AL_SEC_LENGTH_SOFT:
return 1;
- case sfSampleRWOffsetsSOFT:
- case sfByteRWOffsetsSOFT:
- case sfSecOffsetLatencySOFT:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_RW_OFFSETS_SOFT:
+ case AL_SEC_OFFSET_LATENCY_SOFT:
return 2;
- case sfPosition:
- case sfVelocity:
- case sfDirection:
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
return 3;
+
+ case AL_ORIENTATION:
+ return 6;
+
+ case AL_BUFFER:
+ case AL_DIRECT_FILTER:
+ case AL_AUXILIARY_SEND_FILTER:
+ break; /* i/i64 only */
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ break; /* i64 only */
}
return 0;
}
static ALint IntValsByProp(ALenum prop)
{
- if(prop != (ALenum)((SrcIntProp)prop))
+ if(prop != (ALenum)((SourceProp)prop))
return 0;
- switch((SrcIntProp)prop)
+ switch((SourceProp)prop)
{
- case siMaxDistance:
- case siRolloffFactor:
- case siRefDistance:
- case siSourceRelative:
- case siConeInnerAngle:
- case siConeOuterAngle:
- case siLooping:
- case siBuffer:
- case siSourceState:
- case siBuffersQueued:
- case siBuffersProcessed:
- case siSourceType:
- case siSecOffset:
- case siSampleOffset:
- case siByteOffset:
- case siDopplerFactor:
- case siDirectFilterGainHFAuto:
- case siAuxSendFilterGainAutio:
- case siAuxSendFilterGainHFAuto:
- case siDirectFilter:
- case siDirectChannelsSOFT:
- case siDistanceModel:
- case siByteLength:
- case siSampleLength:
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_DOPPLER_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_REFERENCE_DISTANCE:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ case AL_DIRECT_CHANNELS_SOFT:
+ case AL_DISTANCE_MODEL:
+ case AL_SOURCE_RELATIVE:
+ case AL_LOOPING:
+ case AL_BUFFER:
+ case AL_SOURCE_STATE:
+ case AL_BUFFERS_QUEUED:
+ case AL_BUFFERS_PROCESSED:
+ case AL_SOURCE_TYPE:
+ case AL_DIRECT_FILTER:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
+ case AL_SEC_LENGTH_SOFT:
return 1;
- case siSampleRWOffsetsSOFT:
- case siByteRWOffsetsSOFT:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_RW_OFFSETS_SOFT:
return 2;
- case siPosition:
- case siVelocity:
- case siDirection:
- case siAuxSendFilter:
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
+ case AL_AUXILIARY_SEND_FILTER:
return 3;
- case siSampleOffsetLatencySOFT:
+ case AL_ORIENTATION:
+ return 6;
+
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
break; /* i64 only */
+ case AL_SEC_OFFSET_LATENCY_SOFT:
+ break; /* Double only */
}
return 0;
}
static ALint Int64ValsByProp(ALenum prop)
{
- if(prop != (ALenum)((SrcIntProp)prop))
+ if(prop != (ALenum)((SourceProp)prop))
return 0;
- switch((SrcIntProp)prop)
+ switch((SourceProp)prop)
{
- case siMaxDistance:
- case siRolloffFactor:
- case siRefDistance:
- case siSourceRelative:
- case siConeInnerAngle:
- case siConeOuterAngle:
- case siLooping:
- case siBuffer:
- case siSourceState:
- case siBuffersQueued:
- case siBuffersProcessed:
- case siSourceType:
- case siSecOffset:
- case siSampleOffset:
- case siByteOffset:
- case siDopplerFactor:
- case siDirectFilterGainHFAuto:
- case siAuxSendFilterGainAutio:
- case siAuxSendFilterGainHFAuto:
- case siDirectFilter:
- case siDirectChannelsSOFT:
- case siDistanceModel:
- case siByteLength:
- case siSampleLength:
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
+ case AL_MAX_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_DOPPLER_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_SEC_OFFSET:
+ case AL_SAMPLE_OFFSET:
+ case AL_BYTE_OFFSET:
+ case AL_CONE_INNER_ANGLE:
+ case AL_CONE_OUTER_ANGLE:
+ case AL_REFERENCE_DISTANCE:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ case AL_DIRECT_CHANNELS_SOFT:
+ case AL_DISTANCE_MODEL:
+ case AL_SOURCE_RELATIVE:
+ case AL_LOOPING:
+ case AL_BUFFER:
+ case AL_SOURCE_STATE:
+ case AL_BUFFERS_QUEUED:
+ case AL_BUFFERS_PROCESSED:
+ case AL_SOURCE_TYPE:
+ case AL_DIRECT_FILTER:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
+ case AL_SEC_LENGTH_SOFT:
return 1;
- case siSampleRWOffsetsSOFT:
- case siByteRWOffsetsSOFT:
- case siSampleOffsetLatencySOFT:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_RW_OFFSETS_SOFT:
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
return 2;
- case siPosition:
- case siVelocity:
- case siDirection:
- case siAuxSendFilter:
+ case AL_POSITION:
+ case AL_VELOCITY:
+ case AL_DIRECTION:
+ case AL_AUXILIARY_SEND_FILTER:
return 3;
+
+ case AL_ORIENTATION:
+ return 6;
+
+ case AL_SEC_OFFSET_LATENCY_SOFT:
+ break; /* Double only */
}
return 0;
}
@@ -365,108 +369,117 @@ static ALint Int64ValsByProp(ALenum prop)
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \
} while(0)
-static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values)
+static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values)
{
ALint ival;
switch(prop)
{
+ case AL_BYTE_RW_OFFSETS_SOFT:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
+ case AL_SEC_LENGTH_SOFT:
+ case AL_SEC_OFFSET_LATENCY_SOFT:
+ /* Query only */
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
+
case AL_PITCH:
CHECKVAL(*values >= 0.0f);
Source->Pitch = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_CONE_INNER_ANGLE:
CHECKVAL(*values >= 0.0f && *values <= 360.0f);
Source->InnerAngle = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_CONE_OUTER_ANGLE:
CHECKVAL(*values >= 0.0f && *values <= 360.0f);
Source->OuterAngle = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_GAIN:
CHECKVAL(*values >= 0.0f);
Source->Gain = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_MAX_DISTANCE:
CHECKVAL(*values >= 0.0f);
Source->MaxDistance = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_ROLLOFF_FACTOR:
CHECKVAL(*values >= 0.0f);
Source->RollOffFactor = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_REFERENCE_DISTANCE:
CHECKVAL(*values >= 0.0f);
Source->RefDistance = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_MIN_GAIN:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->MinGain = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_MAX_GAIN:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->MaxGain = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_CONE_OUTER_GAIN:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->OuterGain = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_CONE_OUTER_GAINHF:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->OuterGainHF = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_AIR_ABSORPTION_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 10.0f);
Source->AirAbsorptionFactor = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_ROOM_ROLLOFF_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 10.0f);
Source->RoomRolloffFactor = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_DOPPLER_FACTOR:
CHECKVAL(*values >= 0.0f && *values <= 1.0f);
Source->DopplerFactor = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_SEC_OFFSET:
@@ -481,100 +494,119 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp
if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
!Context->DeferUpdates)
{
+ WriteLock(&Source->queue_lock);
if(ApplyOffset(Source) == AL_FALSE)
{
+ WriteUnlock(&Source->queue_lock);
UnlockContext(Context);
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
}
+ WriteUnlock(&Source->queue_lock);
}
UnlockContext(Context);
return AL_TRUE;
- case sfSecLength:
- case AL_SEC_OFFSET_LATENCY_SOFT:
- /* Query only */
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
-
-
case AL_POSITION:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
LockContext(Context);
- Source->Position[0] = values[0];
- Source->Position[1] = values[1];
- Source->Position[2] = values[2];
+ aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f);
UnlockContext(Context);
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_VELOCITY:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
LockContext(Context);
- Source->Velocity[0] = values[0];
- Source->Velocity[1] = values[1];
- Source->Velocity[2] = values[2];
+ aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f);
UnlockContext(Context);
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_DIRECTION:
CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]));
LockContext(Context);
- Source->Orientation[0] = values[0];
- Source->Orientation[1] = values[1];
- Source->Orientation[2] = values[2];
+ aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f);
UnlockContext(Context);
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
+ case AL_ORIENTATION:
+ CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) &&
+ isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5]));
- case sfSampleRWOffsetsSOFT:
- case sfByteRWOffsetsSOFT:
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
+ LockContext(Context);
+ Source->Orientation[0][0] = values[0];
+ Source->Orientation[0][1] = values[1];
+ Source->Orientation[0][2] = values[2];
+ Source->Orientation[1][0] = values[3];
+ Source->Orientation[1][1] = values[4];
+ Source->Orientation[1][2] = values[5];
+ UnlockContext(Context);
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
+ return AL_TRUE;
- case sfSourceRelative:
- case sfLooping:
- case sfSourceState:
- case sfSourceType:
- case sfDistanceModel:
- case sfDirectFilterGainHFAuto:
- case sfAuxSendFilterGainAuto:
- case sfAuxSendFilterGainHFAuto:
- case sfDirectChannelsSOFT:
+ case AL_SOURCE_RELATIVE:
+ case AL_LOOPING:
+ case AL_SOURCE_STATE:
+ case AL_SOURCE_TYPE:
+ case AL_DISTANCE_MODEL:
+ case AL_DIRECT_FILTER_GAINHF_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+ case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+ case AL_DIRECT_CHANNELS_SOFT:
ival = (ALint)values[0];
- return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
+ return SetSourceiv(Source, Context, prop, &ival);
- case sfBuffer:
- case sfBuffersQueued:
- case sfBuffersProcessed:
+ case AL_BUFFERS_QUEUED:
+ case AL_BUFFERS_PROCESSED:
ival = (ALint)((ALuint)values[0]);
- return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival);
+ return SetSourceiv(Source, Context, prop, &ival);
+
+ case AL_BUFFER:
+ case AL_DIRECT_FILTER:
+ case AL_AUXILIARY_SEND_FILTER:
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ break;
}
ERR("Unexpected property: 0x%04x\n", prop);
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values)
+static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values)
{
ALCdevice *device = Context->Device;
ALbuffer *buffer = NULL;
ALfilter *filter = NULL;
ALeffectslot *slot = NULL;
ALbufferlistitem *oldlist;
- ALfloat fvals[3];
+ ALbufferlistitem *newlist;
+ ALfloat fvals[6];
switch(prop)
{
+ case AL_SOURCE_STATE:
+ case AL_SOURCE_TYPE:
+ case AL_BUFFERS_QUEUED:
+ case AL_BUFFERS_PROCESSED:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_RW_OFFSETS_SOFT:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
+ case AL_SEC_LENGTH_SOFT:
+ /* Query only */
+ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
+
case AL_SOURCE_RELATIVE:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->HeadRelative = (ALboolean)*values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_LOOPING:
@@ -595,18 +627,15 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
if(buffer != NULL)
{
- ALbufferlistitem *BufferListItem;
-
/* Add the selected buffer to a one-item queue */
- BufferListItem = malloc(sizeof(ALbufferlistitem));
- BufferListItem->buffer = buffer;
- BufferListItem->next = NULL;
- BufferListItem->prev = NULL;
+ newlist = malloc(sizeof(ALbufferlistitem));
+ newlist->buffer = buffer;
+ newlist->next = NULL;
+ newlist->prev = NULL;
IncrementRef(&buffer->ref);
/* Source is now Static */
Source->SourceType = AL_STATIC;
- oldlist = ExchangePtr((XchgPtr*)&Source->queue, BufferListItem);
ReadLock(&buffer->lock);
Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels);
@@ -617,9 +646,10 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
{
/* Source is now Undetermined */
Source->SourceType = AL_UNDETERMINED;
- oldlist = ExchangePtr((XchgPtr*)&Source->queue, NULL);
+ newlist = NULL;
}
- Source->current_buffer = Source->queue;
+ oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist);
+ ATOMIC_STORE(&Source->current_buffer, newlist);
WriteUnlock(&Source->queue_lock);
/* Delete all elements in the previous queue */
@@ -634,13 +664,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
}
return AL_TRUE;
- case siSourceState:
- case siSourceType:
- case siBuffersQueued:
- case siBuffersProcessed:
- /* Query only */
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
-
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
@@ -653,24 +676,18 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
!Context->DeferUpdates)
{
+ WriteLock(&Source->queue_lock);
if(ApplyOffset(Source) == AL_FALSE)
{
+ WriteUnlock(&Source->queue_lock);
UnlockContext(Context);
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE);
}
+ WriteUnlock(&Source->queue_lock);
}
UnlockContext(Context);
return AL_TRUE;
-
- case siByteLength:
- case siSampleLength:
- case siSampleRWOffsetsSOFT:
- case siByteRWOffsetsSOFT:
- /* Query only */
- SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
-
-
case AL_DIRECT_FILTER:
CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL);
@@ -692,35 +709,35 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
Source->Direct.LFReference = filter->LFReference;
}
UnlockContext(Context);
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_DIRECT_FILTER_GAINHF_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->DryGainHFAuto = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->WetGainAuto = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->WetGainHFAuto = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_DIRECT_CHANNELS_SOFT:
CHECKVAL(*values == AL_FALSE || *values == AL_TRUE);
Source->DirectChannels = *values;
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
case AL_DISTANCE_MODEL:
@@ -734,7 +751,7 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
Source->DistanceModel = *values;
if(Context->SourceDistanceModel)
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
@@ -770,20 +787,30 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
Source->Send[values[1]].GainLF = filter->GainLF;
Source->Send[values[1]].LFReference = filter->LFReference;
}
- Source->NeedsUpdate = AL_TRUE;
UnlockContext(Context);
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
return AL_TRUE;
- case AL_MAX_DISTANCE:
- case AL_ROLLOFF_FACTOR:
+ /* 1x float */
case AL_CONE_INNER_ANGLE:
case AL_CONE_OUTER_ANGLE:
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
case AL_REFERENCE_DISTANCE:
- case siDopplerFactor:
+ case AL_ROLLOFF_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_MAX_DISTANCE:
+ case AL_DOPPLER_FACTOR:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
fvals[0] = (ALfloat)*values;
return SetSourcefv(Source, Context, (int)prop, fvals);
+ /* 3x float */
case AL_POSITION:
case AL_VELOCITY:
case AL_DIRECTION:
@@ -792,8 +819,18 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
fvals[2] = (ALfloat)values[2];
return SetSourcefv(Source, Context, (int)prop, fvals);
- case siSampleOffsetLatencySOFT:
- /* i64 only */
+ /* 6x float */
+ case AL_ORIENTATION:
+ fvals[0] = (ALfloat)values[0];
+ fvals[1] = (ALfloat)values[1];
+ fvals[2] = (ALfloat)values[2];
+ fvals[3] = (ALfloat)values[3];
+ fvals[4] = (ALfloat)values[4];
+ fvals[5] = (ALfloat)values[5];
+ return SetSourcefv(Source, Context, (int)prop, fvals);
+
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_SEC_OFFSET_LATENCY_SOFT:
break;
}
@@ -801,16 +838,23 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values)
+static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values)
{
- ALfloat fvals[3];
+ ALfloat fvals[6];
ALint ivals[3];
switch(prop)
{
- case siSampleRWOffsetsSOFT:
- case siByteRWOffsetsSOFT:
- case siSampleOffsetLatencySOFT:
+ case AL_SOURCE_TYPE:
+ case AL_BUFFERS_QUEUED:
+ case AL_BUFFERS_PROCESSED:
+ case AL_SOURCE_STATE:
+ case AL_SAMPLE_RW_OFFSETS_SOFT:
+ case AL_BYTE_RW_OFFSETS_SOFT:
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
+ case AL_SEC_LENGTH_SOFT:
/* Query only */
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE);
@@ -818,14 +862,9 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp
/* 1x int */
case AL_SOURCE_RELATIVE:
case AL_LOOPING:
- case AL_SOURCE_STATE:
- case AL_BYTE_OFFSET:
+ case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
- case siByteLength:
- case siSampleLength:
- case siSourceType:
- case siBuffersQueued:
- case siBuffersProcessed:
+ case AL_BYTE_OFFSET:
case AL_DIRECT_FILTER_GAINHF_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
@@ -856,13 +895,20 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp
return SetSourceiv(Source, Context, (int)prop, ivals);
/* 1x float */
- case AL_MAX_DISTANCE:
- case AL_ROLLOFF_FACTOR:
case AL_CONE_INNER_ANGLE:
case AL_CONE_OUTER_ANGLE:
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
case AL_REFERENCE_DISTANCE:
- case AL_SEC_OFFSET:
- case siDopplerFactor:
+ case AL_ROLLOFF_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_MAX_DISTANCE:
+ case AL_DOPPLER_FACTOR:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
fvals[0] = (ALfloat)*values;
return SetSourcefv(Source, Context, (int)prop, fvals);
@@ -874,6 +920,19 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp
fvals[1] = (ALfloat)values[1];
fvals[2] = (ALfloat)values[2];
return SetSourcefv(Source, Context, (int)prop, fvals);
+
+ /* 6x float */
+ case AL_ORIENTATION:
+ fvals[0] = (ALfloat)values[0];
+ fvals[1] = (ALfloat)values[1];
+ fvals[2] = (ALfloat)values[2];
+ fvals[3] = (ALfloat)values[3];
+ fvals[4] = (ALfloat)values[4];
+ fvals[5] = (ALfloat)values[5];
+ return SetSourcefv(Source, Context, (int)prop, fvals);
+
+ case AL_SEC_OFFSET_LATENCY_SOFT:
+ break;
}
ERR("Unexpected property: 0x%04x\n", prop);
@@ -883,8 +942,9 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp
#undef CHECKVAL
-static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values)
+static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values)
{
+ ALCdevice *device = Context->Device;
ALbufferlistitem *BufferList;
ALdouble offsets[2];
ALdouble updateLen;
@@ -936,11 +996,9 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
- ReadLock(&Source->queue_lock);
LockContext(Context);
GetSourceOffsets(Source, prop, offsets, 0.0);
UnlockContext(Context);
- ReadUnlock(&Source->queue_lock);
*values = offsets[0];
return AL_TRUE;
@@ -960,9 +1018,9 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp
*values = Source->DopplerFactor;
return AL_TRUE;
- case sfSecLength:
+ case AL_SEC_LENGTH_SOFT:
ReadLock(&Source->queue_lock);
- if(!(BufferList=Source->queue))
+ if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
*values = 0;
else
{
@@ -983,52 +1041,58 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp
case AL_SAMPLE_RW_OFFSETS_SOFT:
case AL_BYTE_RW_OFFSETS_SOFT:
- ReadLock(&Source->queue_lock);
LockContext(Context);
- updateLen = (ALdouble)Context->Device->UpdateSize /
- Context->Device->Frequency;
+ updateLen = (ALdouble)device->UpdateSize / device->Frequency;
GetSourceOffsets(Source, prop, values, updateLen);
UnlockContext(Context);
- ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_SEC_OFFSET_LATENCY_SOFT:
- ReadLock(&Source->queue_lock);
LockContext(Context);
values[0] = GetSourceSecOffset(Source);
- values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) /
+ values[1] = (ALdouble)(V0(device->Backend,getLatency)()) /
1000000000.0;
UnlockContext(Context);
- ReadUnlock(&Source->queue_lock);
return AL_TRUE;
case AL_POSITION:
LockContext(Context);
- values[0] = Source->Position[0];
- values[1] = Source->Position[1];
- values[2] = Source->Position[2];
+ values[0] = Source->Position.v[0];
+ values[1] = Source->Position.v[1];
+ values[2] = Source->Position.v[2];
UnlockContext(Context);
return AL_TRUE;
case AL_VELOCITY:
LockContext(Context);
- values[0] = Source->Velocity[0];
- values[1] = Source->Velocity[1];
- values[2] = Source->Velocity[2];
+ values[0] = Source->Velocity.v[0];
+ values[1] = Source->Velocity.v[1];
+ values[2] = Source->Velocity.v[2];
UnlockContext(Context);
return AL_TRUE;
case AL_DIRECTION:
LockContext(Context);
- values[0] = Source->Orientation[0];
- values[1] = Source->Orientation[1];
- values[2] = Source->Orientation[2];
+ values[0] = Source->Direction.v[0];
+ values[1] = Source->Direction.v[1];
+ values[2] = Source->Direction.v[2];
UnlockContext(Context);
return AL_TRUE;
+ case AL_ORIENTATION:
+ LockContext(Context);
+ values[0] = Source->Orientation[0][0];
+ values[1] = Source->Orientation[0][1];
+ values[2] = Source->Orientation[0][2];
+ values[3] = Source->Orientation[1][0];
+ values[4] = Source->Orientation[1][1];
+ values[5] = Source->Orientation[1][2];
+ UnlockContext(Context);
+ return AL_TRUE;
+
+ /* 1x int */
case AL_SOURCE_RELATIVE:
case AL_LOOPING:
- case AL_BUFFER:
case AL_SOURCE_STATE:
case AL_BUFFERS_QUEUED:
case AL_BUFFERS_PROCESSED:
@@ -1037,20 +1101,28 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DIRECT_CHANNELS_SOFT:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
case AL_DISTANCE_MODEL:
if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
*values = (ALdouble)ivals[0];
return err;
+
+ case AL_BUFFER:
+ case AL_DIRECT_FILTER:
+ case AL_AUXILIARY_SEND_FILTER:
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ break;
}
ERR("Unexpected property: 0x%04x\n", prop);
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values)
+static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values)
{
ALbufferlistitem *BufferList;
- ALdouble dvals[3];
+ ALdouble dvals[6];
ALboolean err;
switch(prop)
@@ -1065,8 +1137,8 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
case AL_BUFFER:
ReadLock(&Source->queue_lock);
- BufferList = (Source->SourceType == AL_STATIC) ? Source->queue :
- Source->current_buffer;
+ BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) :
+ ATOMIC_LOAD(&Source->current_buffer);
*values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0;
ReadUnlock(&Source->queue_lock);
return AL_TRUE;
@@ -1075,9 +1147,9 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
*values = Source->state;
return AL_TRUE;
- case siByteLength:
+ case AL_BYTE_LENGTH_SOFT:
ReadLock(&Source->queue_lock);
- if(!(BufferList=Source->queue))
+ if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
*values = 0;
else
{
@@ -1114,9 +1186,9 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
ReadUnlock(&Source->queue_lock);
return AL_TRUE;
- case siSampleLength:
+ case AL_SAMPLE_LENGTH_SOFT:
ReadLock(&Source->queue_lock);
- if(!(BufferList=Source->queue))
+ if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
*values = 0;
else
{
@@ -1132,7 +1204,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
case AL_BUFFERS_QUEUED:
ReadLock(&Source->queue_lock);
- if(!(BufferList=Source->queue))
+ if(!(BufferList=ATOMIC_LOAD(&Source->queue)))
*values = 0;
else
{
@@ -1155,9 +1227,10 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
}
else
{
- const ALbufferlistitem *BufferList = Source->queue;
+ const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue);
+ const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer);
ALsizei played = 0;
- while(BufferList && BufferList != Source->current_buffer)
+ while(BufferList && BufferList != Current)
{
played++;
BufferList = BufferList->next;
@@ -1191,32 +1264,44 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
*values = Source->DistanceModel;
return AL_TRUE;
- case AL_MAX_DISTANCE:
- case AL_ROLLOFF_FACTOR:
- case AL_REFERENCE_DISTANCE:
+ /* 1x float/double */
case AL_CONE_INNER_ANGLE:
case AL_CONE_OUTER_ANGLE:
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
+ case AL_REFERENCE_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_MAX_DISTANCE:
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
case AL_DOPPLER_FACTOR:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_SEC_LENGTH_SOFT:
+ if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
*values = (ALint)dvals[0];
return err;
+ /* 2x float/double */
case AL_SAMPLE_RW_OFFSETS_SOFT:
case AL_BYTE_RW_OFFSETS_SOFT:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
+ if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
{
values[0] = (ALint)dvals[0];
values[1] = (ALint)dvals[1];
}
return err;
+ /* 3x float/double */
case AL_POSITION:
case AL_VELOCITY:
case AL_DIRECTION:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
+ if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
{
values[0] = (ALint)dvals[0];
values[1] = (ALint)dvals[1];
@@ -1224,101 +1309,144 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p
}
return err;
- case siSampleOffsetLatencySOFT:
- /* i64 only */
- break;
+ /* 6x float/double */
+ case AL_ORIENTATION:
+ if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
+ {
+ values[0] = (ALint)dvals[0];
+ values[1] = (ALint)dvals[1];
+ values[2] = (ALint)dvals[2];
+ values[3] = (ALint)dvals[3];
+ values[4] = (ALint)dvals[4];
+ values[5] = (ALint)dvals[5];
+ }
+ return err;
- case siDirectFilter:
- case siAuxSendFilter:
- /* ??? */
- break;
+ case AL_SAMPLE_OFFSET_LATENCY_SOFT:
+ break; /* i64 only */
+ case AL_SEC_OFFSET_LATENCY_SOFT:
+ break; /* Double only */
+
+ case AL_DIRECT_FILTER:
+ case AL_AUXILIARY_SEND_FILTER:
+ break; /* ??? */
}
ERR("Unexpected property: 0x%04x\n", prop);
SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE);
}
-static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values)
+static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values)
{
- ALdouble dvals[3];
+ ALCdevice *device = Context->Device;
+ ALdouble dvals[6];
ALint ivals[3];
ALboolean err;
switch(prop)
{
case AL_SAMPLE_OFFSET_LATENCY_SOFT:
- ReadLock(&Source->queue_lock);
LockContext(Context);
- values[0] = GetSourceOffset(Source);
- values[1] = ALCdevice_GetLatency(Context->Device);
+ values[0] = GetSourceSampleOffset(Source);
+ values[1] = V0(device->Backend,getLatency)();
UnlockContext(Context);
- ReadUnlock(&Source->queue_lock);
return AL_TRUE;
- case AL_MAX_DISTANCE:
- case AL_ROLLOFF_FACTOR:
- case AL_REFERENCE_DISTANCE:
+ /* 1x float/double */
case AL_CONE_INNER_ANGLE:
case AL_CONE_OUTER_ANGLE:
+ case AL_PITCH:
+ case AL_GAIN:
+ case AL_MIN_GAIN:
+ case AL_MAX_GAIN:
+ case AL_REFERENCE_DISTANCE:
+ case AL_ROLLOFF_FACTOR:
+ case AL_CONE_OUTER_GAIN:
+ case AL_MAX_DISTANCE:
case AL_SEC_OFFSET:
case AL_SAMPLE_OFFSET:
case AL_BYTE_OFFSET:
case AL_DOPPLER_FACTOR:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
+ case AL_AIR_ABSORPTION_FACTOR:
+ case AL_ROOM_ROLLOFF_FACTOR:
+ case AL_CONE_OUTER_GAINHF:
+ case AL_SEC_LENGTH_SOFT:
+ if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
*values = (ALint64)dvals[0];
return err;
+ /* 2x float/double */
case AL_SAMPLE_RW_OFFSETS_SOFT:
case AL_BYTE_RW_OFFSETS_SOFT:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
+ if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
{
values[0] = (ALint64)dvals[0];
values[1] = (ALint64)dvals[1];
}
return err;
+ /* 3x float/double */
case AL_POSITION:
case AL_VELOCITY:
case AL_DIRECTION:
- if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE)
+ if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
+ {
+ values[0] = (ALint64)dvals[0];
+ values[1] = (ALint64)dvals[1];
+ values[2] = (ALint64)dvals[2];
+ }
+ return err;
+
+ /* 6x float/double */
+ case AL_ORIENTATION:
+ if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE)
{
values[0] = (ALint64)dvals[0];
values[1] = (ALint64)dvals[1];
values[2] = (ALint64)dvals[2];
+ values[3] = (ALint64)dvals[3];
+ values[4] = (ALint64)dvals[4];
+ values[5] = (ALint64)dvals[5];
}
return err;
+ /* 1x int */
case AL_SOURCE_RELATIVE:
case AL_LOOPING:
case AL_SOURCE_STATE:
case AL_BUFFERS_QUEUED:
case AL_BUFFERS_PROCESSED:
- case siByteLength:
- case siSampleLength:
+ case AL_BYTE_LENGTH_SOFT:
+ case AL_SAMPLE_LENGTH_SOFT:
case AL_SOURCE_TYPE:
case AL_DIRECT_FILTER_GAINHF_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
case AL_DIRECT_CHANNELS_SOFT:
case AL_DISTANCE_MODEL:
- if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
+ if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
*values = ivals[0];
return err;
- case siBuffer:
- case siDirectFilter:
- if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
- *values = ((ALuint*)ivals)[0];
+ /* 1x uint */
+ case AL_BUFFER:
+ case AL_DIRECT_FILTER:
+ if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
+ *values = (ALuint)ivals[0];
return err;
- case siAuxSendFilter:
- if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE)
+ /* 3x uint */
+ case AL_AUXILIARY_SEND_FILTER:
+ if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE)
{
- values[0] = ((ALuint*)ivals)[0];
- values[1] = ((ALuint*)ivals)[1];
- values[2] = ((ALuint*)ivals)[2];
+ values[0] = (ALuint)ivals[0];
+ values[1] = (ALuint)ivals[1];
+ values[2] = (ALuint)ivals[2];
}
return err;
+
+ case AL_SEC_OFFSET_LATENCY_SOFT:
+ break; /* Double only */
}
ERR("Unexpected property: 0x%04x\n", prop);
@@ -1389,37 +1517,32 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
}
for(i = 0;i < n;i++)
{
- ALactivesource **srclist, **srclistend;
+ ALvoice *voice, *voice_end;
if((Source=RemoveSource(context, sources[i])) == NULL)
continue;
FreeThunkEntry(Source->id);
LockContext(context);
- srclist = context->ActiveSources;
- srclistend = srclist + context->ActiveSourceCount;
- while(srclist != srclistend)
+ voice = context->Voices;
+ voice_end = voice + context->VoiceCount;
+ while(voice != voice_end)
{
- if((*srclist)->Source == Source)
- {
- ALactivesource *temp = *(--srclistend);
- *srclistend = *srclist;
- *srclist = temp;
- --(context->ActiveSourceCount);
+ ALsource *old = Source;
+ if(COMPARE_EXCHANGE(&voice->Source, &old, NULL))
break;
- }
- srclist++;
+ voice++;
}
UnlockContext(context);
- while(Source->queue != NULL)
+ BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL);
+ while(BufferList != NULL)
{
- BufferList = Source->queue;
- Source->queue = BufferList->next;
-
+ ALbufferlistitem *next = BufferList->next;
if(BufferList->buffer != NULL)
DecrementRef(&BufferList->buffer->ref);
free(BufferList);
+ BufferList = next;
}
for(j = 0;j < MAX_SENDS;++j)
@@ -1569,11 +1692,11 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo
alSetError(Context, AL_INVALID_NAME);
else if(!values)
alSetError(Context, AL_INVALID_VALUE);
- else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3))
+ else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6))
alSetError(Context, AL_INVALID_ENUM);
else
{
- ALfloat fvals[3];
+ ALfloat fvals[6];
ALint i;
for(i = 0;i < count;i++)
@@ -1772,11 +1895,11 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va
alSetError(Context, AL_INVALID_NAME);
else if(!values)
alSetError(Context, AL_INVALID_VALUE);
- else if(!((count=FloatValsByProp(param)) > 0 && count <= 3))
+ else if(!((count=FloatValsByProp(param)) > 0 && count <= 6))
alSetError(Context, AL_INVALID_ENUM);
else
{
- ALdouble dvals[3];
+ ALdouble dvals[6];
if(GetSourcedv(Source, Context, param, dvals))
{
ALint i;
@@ -2020,25 +2143,23 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
}
LockContext(context);
- while(n > context->MaxActiveSources-context->ActiveSourceCount)
+ while(n > context->MaxVoices-context->VoiceCount)
{
- ALactivesource **temp = NULL;
+ ALvoice *temp = NULL;
ALsizei newcount;
- newcount = context->MaxActiveSources << 1;
+ newcount = context->MaxVoices << 1;
if(newcount > 0)
- temp = realloc(context->ActiveSources,
- newcount * sizeof(context->ActiveSources[0]));
+ temp = realloc(context->Voices, newcount * sizeof(context->Voices[0]));
if(!temp)
{
UnlockContext(context);
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done);
}
- for(i = context->MaxActiveSources;i < newcount;i++)
- temp[i] = NULL;
+ memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0]));
- context->ActiveSources = temp;
- context->MaxActiveSources = newcount;
+ context->Voices = temp;
+ context->MaxVoices = newcount;
}
for(i = 0;i < n;i++)
@@ -2188,7 +2309,7 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu
}
/* Check for a valid Buffer, for its frequency and format */
- BufferList = source->queue;
+ BufferList = ATOMIC_LOAD(&source->queue);
while(BufferList)
{
if(BufferList->buffer)
@@ -2276,7 +2397,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu
/* Source is now streaming */
source->SourceType = AL_STREAMING;
- if((BufferList=CompExchangePtr((XchgPtr*)&source->queue, NULL, BufferListStart)) != NULL)
+ BufferList = NULL;
+ if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart))
{
/* Queue head is not NULL, append to the end of the queue */
while(BufferList->next != NULL)
@@ -2285,7 +2407,8 @@ AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALu
BufferListStart->prev = BufferList;
BufferList->next = BufferListStart;
}
- CompExchangePtr((XchgPtr*)&source->current_buffer, NULL, BufferListStart);
+ BufferList = NULL;
+ ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart);
WriteUnlock(&source->queue_lock);
done:
@@ -2296,8 +2419,9 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint
{
ALCcontext *context;
ALsource *source;
- ALbufferlistitem *BufferList;
+ ALbufferlistitem *NewHead;
ALbufferlistitem *OldHead;
+ ALbufferlistitem *Current;
ALsizei i;
if(nb == 0)
@@ -2314,12 +2438,13 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint
WriteLock(&source->queue_lock);
/* Find the new buffer queue head */
- BufferList = source->queue;
- for(i = 0;i < nb && BufferList;i++)
+ NewHead = ATOMIC_LOAD(&source->queue);
+ Current = ATOMIC_LOAD(&source->current_buffer);
+ for(i = 0;i < nb && NewHead;i++)
{
- if(BufferList == source->current_buffer)
+ if(NewHead == Current)
break;
- BufferList = BufferList->next;
+ NewHead = NewHead->next;
}
if(source->Looping || source->SourceType != AL_STREAMING || i != nb)
{
@@ -2329,23 +2454,24 @@ AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint
}
/* Swap it, and cut the new head from the old. */
- OldHead = ExchangePtr((XchgPtr*)&source->queue, BufferList);
- if(BufferList)
+ OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead);
+ if(NewHead)
{
ALCdevice *device = context->Device;
+ ALbufferlistitem *OldTail = NewHead->prev;
uint count;
/* Cut the new head's link back to the old body. The mixer is robust
* enough to handle the link back going away. Once the active mix (if
* any) is complete, it's safe to finish cutting the old tail from the
* new head. */
- BufferList = ExchangePtr((XchgPtr*)&BufferList->prev, NULL);
+ NewHead->prev = NULL;
if(((count=ReadRef(&device->MixCount))&1) != 0)
{
while(count == ReadRef(&device->MixCount))
althrd_yield();
}
- BufferList->next = NULL;
+ OldTail->next = NULL;
}
WriteUnlock(&source->queue_lock);
@@ -2380,15 +2506,15 @@ static ALvoid InitSourceParams(ALsource *Source)
Source->InnerAngle = 360.0f;
Source->OuterAngle = 360.0f;
Source->Pitch = 1.0f;
- Source->Position[0] = 0.0f;
- Source->Position[1] = 0.0f;
- Source->Position[2] = 0.0f;
- Source->Orientation[0] = 0.0f;
- Source->Orientation[1] = 0.0f;
- Source->Orientation[2] = 0.0f;
- Source->Velocity[0] = 0.0f;
- Source->Velocity[1] = 0.0f;
- Source->Velocity[2] = 0.0f;
+ aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f);
+ aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f);
+ aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f);
+ Source->Orientation[0][0] = 0.0f;
+ Source->Orientation[0][1] = 0.0f;
+ Source->Orientation[0][2] = -1.0f;
+ Source->Orientation[1][0] = 0.0f;
+ Source->Orientation[1][1] = 1.0f;
+ Source->Orientation[1][2] = 0.0f;
Source->RefDistance = 1.0f;
Source->MaxDistance = FLT_MAX;
Source->RollOffFactor = 1.0f;
@@ -2407,17 +2533,17 @@ static ALvoid InitSourceParams(ALsource *Source)
Source->DopplerFactor = 1.0f;
Source->DirectChannels = AL_FALSE;
- Source->DistanceModel = DefaultDistanceModel;
+ Source->Radius = 0.0f;
- Source->Resampler = DefaultResampler;
+ Source->DistanceModel = DefaultDistanceModel;
Source->state = AL_INITIAL;
Source->new_state = AL_NONE;
Source->SourceType = AL_UNDETERMINED;
Source->Offset = -1.0;
- Source->queue = NULL;
- Source->current_buffer = NULL;
+ ATOMIC_INIT(&Source->queue, NULL);
+ ATOMIC_INIT(&Source->current_buffer, NULL);
Source->Direct.Gain = 1.0f;
Source->Direct.GainHF = 1.0f;
@@ -2433,7 +2559,7 @@ static ALvoid InitSourceParams(ALsource *Source)
Source->Send[i].LFReference = HIGHPASSFREQREF;
}
- Source->NeedsUpdate = AL_TRUE;
+ ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE);
}
@@ -2443,17 +2569,18 @@ static ALvoid InitSourceParams(ALsource *Source)
*/
ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
{
- ReadLock(&Source->queue_lock);
+ WriteLock(&Source->queue_lock);
if(state == AL_PLAYING)
{
ALCdevice *device = Context->Device;
ALbufferlistitem *BufferList;
- ALactivesource *src = NULL;
- ALsizei j, k;
+ ALboolean discontinuity;
+ ALvoice *voice = NULL;
+ ALsizei i;
/* Check that there is a queue containing at least one valid, non zero
* length Buffer. */
- BufferList = Source->queue;
+ BufferList = ATOMIC_LOAD(&Source->queue);
while(BufferList)
{
ALbuffer *buffer;
@@ -2467,68 +2594,80 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
Source->state = AL_PLAYING;
Source->position = 0;
Source->position_fraction = 0;
- Source->current_buffer = BufferList;
+ ATOMIC_STORE(&Source->current_buffer, BufferList);
+ discontinuity = AL_TRUE;
}
else
+ {
Source->state = AL_PLAYING;
+ discontinuity = AL_FALSE;
+ }
// Check if an Offset has been set
if(Source->Offset >= 0.0)
+ {
ApplyOffset(Source);
+ /* discontinuity = AL_TRUE;??? */
+ }
/* If there's nothing to play, or device is disconnected, go right to
* stopped */
if(!BufferList || !device->Connected)
goto do_stop;
- for(j = 0;j < Context->ActiveSourceCount;j++)
+ /* Make sure this source isn't already active, while looking for an
+ * unused active source slot to put it in. */
+ for(i = 0;i < Context->VoiceCount;i++)
{
- if(Context->ActiveSources[j]->Source == Source)
+ ALsource *old = Source;
+ if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL))
{
- src = Context->ActiveSources[j];
+ if(voice == NULL)
+ {
+ voice = &Context->Voices[i];
+ voice->Source = Source;
+ }
break;
}
+ old = NULL;
+ if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source))
+ voice = &Context->Voices[i];
}
- if(src == NULL)
+ if(voice == NULL)
{
- src = Context->ActiveSources[Context->ActiveSourceCount];
- if(src == NULL)
- {
- src = al_malloc(16, sizeof(src[0]));
- Context->ActiveSources[Context->ActiveSourceCount] = src;
- }
- memset(src, 0, sizeof(*src));
-
- src->Source = Source;
- if(BufferList->buffer->FmtChannels == FmtMono)
- src->Update = CalcSourceParams;
- else
- src->Update = CalcNonAttnSourceParams;
- Context->ActiveSourceCount++;
+ voice = &Context->Voices[Context->VoiceCount++];
+ voice->Source = Source;
}
- else
- {
- ALuint i;
- src->Direct.Moving = AL_FALSE;
- src->Direct.Counter = 0;
- for(j = 0;j < MAX_INPUT_CHANNELS;j++)
- {
- for(k = 0;k < SRC_HISTORY_LENGTH;k++)
- src->Direct.Mix.Hrtf.State[j].History[k] = 0.0f;
- for(k = 0;k < HRIR_LENGTH;k++)
- {
- src->Direct.Mix.Hrtf.State[j].Values[k][0] = 0.0f;
- src->Direct.Mix.Hrtf.State[j].Values[k][1] = 0.0f;
- }
- }
- for(i = 0;i < device->NumAuxSends;i++)
+ /* Clear previous samples if playback is discontinuous. */
+ if(discontinuity)
+ memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples));
+
+ voice->Direct.Moving = AL_FALSE;
+ voice->Direct.Counter = 0;
+ for(i = 0;i < MAX_INPUT_CHANNELS;i++)
+ {
+ ALsizei j;
+ for(j = 0;j < HRTF_HISTORY_LENGTH;j++)
+ voice->Direct.Hrtf[i].State.History[j] = 0.0f;
+ for(j = 0;j < HRIR_LENGTH;j++)
{
- src->Send[i].Counter = 0;
- src->Send[i].Moving = AL_FALSE;
+ voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f;
+ voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f;
}
}
- Source->NeedsUpdate = AL_TRUE;
+ for(i = 0;i < (ALsizei)device->NumAuxSends;i++)
+ {
+ voice->Send[i].Moving = AL_FALSE;
+ voice->Send[i].Counter = 0;
+ }
+
+ if(BufferList->buffer->FmtChannels == FmtMono)
+ voice->Update = CalcSourceParams;
+ else
+ voice->Update = CalcNonAttnSourceParams;
+
+ ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE);
}
else if(state == AL_PAUSED)
{
@@ -2541,7 +2680,7 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
if(Source->state != AL_INITIAL)
{
Source->state = AL_STOPPED;
- Source->current_buffer = NULL;
+ ATOMIC_STORE(&Source->current_buffer, NULL);
}
Source->Offset = -1.0;
}
@@ -2552,39 +2691,46 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state)
Source->state = AL_INITIAL;
Source->position = 0;
Source->position_fraction = 0;
- Source->current_buffer = Source->queue;
+ ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue));
}
Source->Offset = -1.0;
}
- ReadUnlock(&Source->queue_lock);
+ WriteUnlock(&Source->queue_lock);
}
-/* GetSourceOffset
+/* GetSourceSampleOffset
*
* Gets the current read offset for the given Source, in 32.32 fixed-point
* samples. The offset is relative to the start of the queue (not the start of
* the current buffer).
*/
-static ALint64 GetSourceOffset(const ALsource *Source)
+ALint64 GetSourceSampleOffset(ALsource *Source)
{
const ALbufferlistitem *BufferList;
+ const ALbufferlistitem *Current;
ALuint64 readPos;
+ ReadLock(&Source->queue_lock);
if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
+ {
+ ReadUnlock(&Source->queue_lock);
return 0;
+ }
/* NOTE: This is the offset into the *current* buffer, so add the length of
* any played buffers */
readPos = (ALuint64)Source->position << 32;
readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS);
- BufferList = Source->queue;
- while(BufferList && BufferList != Source->current_buffer)
+ BufferList = ATOMIC_LOAD(&Source->queue);
+ Current = ATOMIC_LOAD(&Source->current_buffer);
+ while(BufferList && BufferList != Current)
{
if(BufferList->buffer)
readPos += (ALuint64)BufferList->buffer->SampleLen << 32;
BufferList = BufferList->next;
}
+ ReadUnlock(&Source->queue_lock);
return (ALint64)minu64(readPos, U64(0x7fffffffffffffff));
}
@@ -2593,21 +2739,27 @@ static ALint64 GetSourceOffset(const ALsource *Source)
* Gets the current read offset for the given Source, in seconds. The offset is
* relative to the start of the queue (not the start of the current buffer).
*/
-static ALdouble GetSourceSecOffset(const ALsource *Source)
+static ALdouble GetSourceSecOffset(ALsource *Source)
{
const ALbufferlistitem *BufferList;
+ const ALbufferlistitem *Current;
const ALbuffer *Buffer = NULL;
ALuint64 readPos;
+ ReadLock(&Source->queue_lock);
if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
+ {
+ ReadUnlock(&Source->queue_lock);
return 0.0;
+ }
/* NOTE: This is the offset into the *current* buffer, so add the length of
* any played buffers */
readPos = (ALuint64)Source->position << FRACTIONBITS;
readPos |= (ALuint64)Source->position_fraction;
- BufferList = Source->queue;
- while(BufferList && BufferList != Source->current_buffer)
+ BufferList = ATOMIC_LOAD(&Source->queue);
+ Current = ATOMIC_LOAD(&Source->current_buffer);
+ while(BufferList && BufferList != Current)
{
const ALbuffer *buffer = BufferList->buffer;
if(buffer != NULL)
@@ -2625,6 +2777,7 @@ static ALdouble GetSourceSecOffset(const ALsource *Source)
}
assert(Buffer != NULL);
+ ReadUnlock(&Source->queue_lock);
return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency;
}
@@ -2634,18 +2787,21 @@ static ALdouble GetSourceSecOffset(const ALsource *Source)
* appropriate format (Bytes, Samples or Seconds). The offsets are relative to
* the start of the queue (not the start of the current buffer).
*/
-static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
+static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
{
const ALbufferlistitem *BufferList;
+ const ALbufferlistitem *Current;
const ALbuffer *Buffer = NULL;
ALboolean readFin = AL_FALSE;
- ALuint readPos, writePos;
+ ALuint readPos, readPosFrac, writePos;
ALuint totalBufferLen;
+ ReadLock(&Source->queue_lock);
if(Source->state != AL_PLAYING && Source->state != AL_PAUSED)
{
offset[0] = 0.0;
offset[1] = 0.0;
+ ReadUnlock(&Source->queue_lock);
return;
}
@@ -2656,11 +2812,13 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of
* any played buffers */
totalBufferLen = 0;
readPos = Source->position;
- BufferList = Source->queue;
+ readPosFrac = Source->position_fraction;
+ BufferList = ATOMIC_LOAD(&Source->queue);
+ Current = ATOMIC_LOAD(&Source->current_buffer);
while(BufferList != NULL)
{
const ALbuffer *buffer;
- readFin = readFin || (BufferList == Source->current_buffer);
+ readFin = readFin || (BufferList == Current);
if((buffer=BufferList->buffer) != NULL)
{
if(!Buffer) Buffer = buffer;
@@ -2672,7 +2830,7 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of
assert(Buffer != NULL);
if(Source->state == AL_PLAYING)
- writePos = readPos + (ALuint)(updateLen*Buffer->Frequency);
+ writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f);
else
writePos = readPos;
@@ -2685,7 +2843,7 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of
{
/* Wrap positions back to 0 */
if(readPos >= totalBufferLen)
- readPos = 0;
+ readPos = readPosFrac = 0;
if(writePos >= totalBufferLen)
writePos = 0;
}
@@ -2693,13 +2851,13 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of
switch(name)
{
case AL_SEC_OFFSET:
- offset[0] = (ALdouble)readPos / Buffer->Frequency;
- offset[1] = (ALdouble)writePos / Buffer->Frequency;
+ offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency;
+ offset[1] = (ALdouble)writePos/Buffer->Frequency;
break;
case AL_SAMPLE_OFFSET:
case AL_SAMPLE_RW_OFFSETS_SOFT:
- offset[0] = (ALdouble)readPos;
+ offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE;
offset[1] = (ALdouble)writePos;
break;
@@ -2747,6 +2905,8 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of
}
break;
}
+
+ ReadUnlock(&Source->queue_lock);
}
@@ -2759,16 +2919,15 @@ ALboolean ApplyOffset(ALsource *Source)
{
ALbufferlistitem *BufferList;
const ALbuffer *Buffer;
- ALint bufferLen, totalBufferLen;
- ALint offset;
+ ALuint bufferLen, totalBufferLen;
+ ALuint offset=0, frac=0;
/* Get sample frame offset */
- offset = GetSampleOffset(Source);
- if(offset == -1)
+ if(!GetSampleOffset(Source, &offset, &frac))
return AL_FALSE;
totalBufferLen = 0;
- BufferList = Source->queue;
+ BufferList = ATOMIC_LOAD(&Source->queue);
while(BufferList && totalBufferLen <= offset)
{
Buffer = BufferList->buffer;
@@ -2777,10 +2936,10 @@ ALboolean ApplyOffset(ALsource *Source)
if(bufferLen > offset-totalBufferLen)
{
/* Offset is in this buffer */
- Source->current_buffer = BufferList;
+ ATOMIC_STORE(&Source->current_buffer, BufferList);
Source->position = offset - totalBufferLen;
- Source->position_fraction = 0;
+ Source->position_fraction = frac;
return AL_TRUE;
}
@@ -2796,18 +2955,18 @@ ALboolean ApplyOffset(ALsource *Source)
/* GetSampleOffset
*
- * Returns the sample offset into the Source's queue (from the Sample, Byte or
- * Second offset supplied by the application). This takes into account the fact
- * that the buffer format may have been modifed since.
+ * Retrieves the sample offset into the Source's queue (from the Sample, Byte
+ * or Second offset supplied by the application). This takes into account the
+ * fact that the buffer format may have been modifed since.
*/
-static ALint GetSampleOffset(ALsource *Source)
+static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac)
{
const ALbuffer *Buffer = NULL;
const ALbufferlistitem *BufferList;
- ALint Offset = -1;
+ ALdouble dbloff, dblfrac;
/* Find the first valid Buffer in the Queue */
- BufferList = Source->queue;
+ BufferList = ATOMIC_LOAD(&Source->queue);
while(BufferList)
{
if(BufferList->buffer)
@@ -2817,45 +2976,49 @@ static ALint GetSampleOffset(ALsource *Source)
}
BufferList = BufferList->next;
}
-
if(!Buffer)
{
Source->Offset = -1.0;
- return -1;
+ return AL_FALSE;
}
switch(Source->OffsetType)
{
case AL_BYTE_OFFSET:
/* Determine the ByteOffset (and ensure it is block aligned) */
- Offset = (ALint)Source->Offset;
+ *offset = (ALuint)Source->Offset;
if(Buffer->OriginalType == UserFmtIMA4)
{
ALsizei align = (Buffer->OriginalAlign-1)/2 + 4;
- Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
- Offset *= Buffer->OriginalAlign;
+ *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
+ *offset *= Buffer->OriginalAlign;
}
else if(Buffer->OriginalType == UserFmtMSADPCM)
{
ALsizei align = (Buffer->OriginalAlign-2)/2 + 7;
- Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
- Offset *= Buffer->OriginalAlign;
+ *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels);
+ *offset *= Buffer->OriginalAlign;
}
else
- Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
+ *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
+ *frac = 0;
break;
case AL_SAMPLE_OFFSET:
- Offset = (ALint)Source->Offset;
+ dblfrac = modf(Source->Offset, &dbloff);
+ *offset = (ALuint)mind(dbloff, UINT_MAX);
+ *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
break;
case AL_SEC_OFFSET:
- Offset = (ALint)(Source->Offset * Buffer->Frequency);
+ dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff);
+ *offset = (ALuint)mind(dbloff, UINT_MAX);
+ *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0);
break;
}
Source->Offset = -1.0;
- return Offset;
+ return AL_TRUE;
}
@@ -2865,6 +3028,7 @@ static ALint GetSampleOffset(ALsource *Source)
*/
ALvoid ReleaseALSources(ALCcontext *Context)
{
+ ALbufferlistitem *item;
ALsizei pos;
ALuint j;
for(pos = 0;pos < Context->SourceMap.size;pos++)
@@ -2872,14 +3036,14 @@ ALvoid ReleaseALSources(ALCcontext *Context)
ALsource *temp = Context->SourceMap.array[pos].value;
Context->SourceMap.array[pos].value = NULL;
- while(temp->queue != NULL)
+ item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL);
+ while(item != NULL)
{
- ALbufferlistitem *BufferList = temp->queue;
- temp->queue = BufferList->next;
-
- if(BufferList->buffer != NULL)
- DecrementRef(&BufferList->buffer->ref);
- free(BufferList);
+ ALbufferlistitem *next = item->next;
+ if(item->buffer != NULL)
+ DecrementRef(&item->buffer->ref);
+ free(item);
+ item = next;
}
for(j = 0;j < MAX_SENDS;++j)
diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c
index d499fcd1..dca41363 100644
--- a/OpenAL32/alState.c
+++ b/OpenAL32/alState.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -28,9 +28,8 @@
#include "alError.h"
#include "alSource.h"
#include "alAuxEffectSlot.h"
-#include "alMidi.h"
-#include "midi/base.h"
+#include "backends/base.h"
static const ALchar alVendor[] = "OpenAL Community";
@@ -56,7 +55,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 +77,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:
@@ -159,7 +158,6 @@ done:
AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
{
- ALCdevice *device;
ALCcontext *context;
ALdouble value = 0.0;
@@ -188,16 +186,6 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
value = (ALdouble)context->DeferUpdates;
break;
- case AL_MIDI_GAIN_SOFT:
- device = context->Device;
- value = (ALdouble)MidiSynth_getGain(device->Synth);
- break;
-
- case AL_MIDI_STATE_SOFT:
- device = context->Device;
- value = (ALdouble)MidiSynth_getState(device->Synth);
- break;
-
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -210,7 +198,6 @@ done:
AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
{
- ALCdevice *device;
ALCcontext *context;
ALfloat value = 0.0f;
@@ -239,16 +226,6 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
value = (ALfloat)context->DeferUpdates;
break;
- case AL_MIDI_GAIN_SOFT:
- device = context->Device;
- value = MidiSynth_getGain(device->Synth);
- break;
-
- case AL_MIDI_STATE_SOFT:
- device = context->Device;
- value = (ALfloat)MidiSynth_getState(device->Synth);
- break;
-
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -262,8 +239,6 @@ done:
AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
{
ALCcontext *context;
- ALCdevice *device;
- MidiSynth *synth;
ALint value = 0;
context = GetContextRef();
@@ -291,17 +266,6 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
value = (ALint)context->DeferUpdates;
break;
- case AL_SOUNDFONTS_SIZE_SOFT:
- device = context->Device;
- synth = device->Synth;
- value = synth->NumSoundfonts;
- break;
-
- case AL_MIDI_STATE_SOFT:
- device = context->Device;
- value = MidiSynth_getState(device->Synth);
- break;
-
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -315,8 +279,6 @@ done:
AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
{
ALCcontext *context;
- ALCdevice *device;
- MidiSynth *synth;
ALint64SOFT value = 0;
context = GetContextRef();
@@ -344,24 +306,6 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
value = (ALint64SOFT)context->DeferUpdates;
break;
- case AL_MIDI_CLOCK_SOFT:
- device = context->Device;
- ALCdevice_Lock(device);
- value = MidiSynth_getTime(device->Synth);
- ALCdevice_Unlock(device);
- break;
-
- case AL_SOUNDFONTS_SIZE_SOFT:
- device = context->Device;
- synth = device->Synth;
- value = (ALint64SOFT)synth->NumSoundfonts;
- break;
-
- case AL_MIDI_STATE_SOFT:
- device = context->Device;
- value = (ALint64SOFT)MidiSynth_getState(device->Synth);
- break;
-
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -418,8 +362,6 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
- case AL_MIDI_GAIN_SOFT:
- case AL_MIDI_STATE_SOFT:
values[0] = alGetDouble(pname);
return;
}
@@ -453,8 +395,6 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
- case AL_MIDI_GAIN_SOFT:
- case AL_MIDI_STATE_SOFT:
values[0] = alGetFloat(pname);
return;
}
@@ -478,9 +418,6 @@ done:
AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
{
ALCcontext *context;
- ALCdevice *device;
- MidiSynth *synth;
- ALsizei i;
if(values)
{
@@ -491,8 +428,6 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
- case AL_SOUNDFONTS_SIZE_SOFT:
- case AL_MIDI_STATE_SOFT:
values[0] = alGetInteger(pname);
return;
}
@@ -503,18 +438,6 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
switch(pname)
{
- case AL_SOUNDFONTS_SOFT:
- device = context->Device;
- synth = device->Synth;
- if(synth->NumSoundfonts > 0)
- {
- if(!(values))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- for(i = 0;i < synth->NumSoundfonts;i++)
- values[i] = synth->Soundfonts[i]->id;
- }
- break;
-
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -526,9 +449,6 @@ done:
AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
{
ALCcontext *context;
- ALCdevice *device;
- MidiSynth *synth;
- ALsizei i;
if(values)
{
@@ -539,9 +459,6 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
case AL_DISTANCE_MODEL:
case AL_SPEED_OF_SOUND:
case AL_DEFERRED_UPDATES_SOFT:
- case AL_MIDI_CLOCK_SOFT:
- case AL_SOUNDFONTS_SIZE_SOFT:
- case AL_MIDI_STATE_SOFT:
values[0] = alGetInteger64SOFT(pname);
return;
}
@@ -552,18 +469,6 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
switch(pname)
{
- case AL_SOUNDFONTS_SOFT:
- device = context->Device;
- synth = device->Synth;
- if(synth->NumSoundfonts > 0)
- {
- if(!(values))
- SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
- for(i = 0;i < synth->NumSoundfonts;i++)
- values[i] = (ALint64SOFT)synth->Soundfonts[i]->id;
- }
- break;
-
default:
SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
}
@@ -643,7 +548,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 +565,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 +582,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 +603,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);
@@ -712,54 +617,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
context = GetContextRef();
if(!context) return;
- if(!context->DeferUpdates)
- {
- ALboolean UpdateSources;
- ALactivesource **src, **src_end;
- ALeffectslot **slot, **slot_end;
- FPUCtl oldMode;
-
- SetMixerFPUMode(&oldMode);
-
- LockContext(context);
- context->DeferUpdates = AL_TRUE;
-
- /* Make sure all pending updates are performed */
- UpdateSources = ExchangeInt(&context->UpdateSources, AL_FALSE);
-
- src = context->ActiveSources;
- src_end = src + context->ActiveSourceCount;
- while(src != src_end)
- {
- ALsource *source = (*src)->Source;
-
- if(source->state != AL_PLAYING && source->state != AL_PAUSED)
- {
- ALactivesource *temp = *(--src_end);
- *src_end = *src;
- *src = temp;
- --(context->ActiveSourceCount);
- continue;
- }
-
- if(ExchangeInt(&source->NeedsUpdate, AL_FALSE) || UpdateSources)
- (*src)->Update(*src, context);
-
- src++;
- }
-
- slot = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
- slot_end = VECTOR_ITER_END(context->ActiveAuxSlots);
- while(slot != slot_end)
- {
- if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
- V((*slot)->EffectState,update)(context->Device, *slot);
- slot++;
- }
-
- UnlockContext(context);
- RestoreFPUMode(&oldMode);
- }
+ ALCcontext_DeferUpdates(context);
ALCcontext_DecRef(context);
}
@@ -771,32 +629,7 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
context = GetContextRef();
if(!context) return;
- if(ExchangeInt(&context->DeferUpdates, AL_FALSE))
- {
- ALsizei pos;
-
- LockContext(context);
- LockUIntMapRead(&context->SourceMap);
- for(pos = 0;pos < context->SourceMap.size;pos++)
- {
- ALsource *Source = context->SourceMap.array[pos].value;
- ALenum new_state;
-
- if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
- Source->Offset >= 0.0)
- {
- ReadLock(&Source->queue_lock);
- ApplyOffset(Source);
- ReadUnlock(&Source->queue_lock);
- }
-
- new_state = ExchangeInt(&Source->new_state, AL_NONE);
- if(new_state)
- SetSourceState(Source, context, new_state);
- }
- UnlockUIntMapRead(&context->SourceMap);
- UnlockContext(context);
- }
+ ALCcontext_ProcessUpdates(context);
ALCcontext_DecRef(context);
}
diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c
index c4b3b92b..0cebad42 100644
--- a/OpenAL32/alThunk.c
+++ b/OpenAL32/alThunk.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -26,33 +26,33 @@
#include "alThunk.h"
-static ALenum *ThunkArray;
-static ALuint ThunkArraySize;
-static RWLock ThunkLock;
+static ATOMIC(ALenum) *ThunkArray;
+static ALuint ThunkArraySize;
+static RWLock ThunkLock;
void ThunkInit(void)
{
RWLockInit(&ThunkLock);
ThunkArraySize = 1;
- ThunkArray = calloc(1, ThunkArraySize * sizeof(*ThunkArray));
+ ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray));
}
void ThunkExit(void)
{
- free(ThunkArray);
+ al_free(ThunkArray);
ThunkArray = NULL;
ThunkArraySize = 0;
}
ALenum NewThunkEntry(ALuint *index)
{
- ALenum *NewList;
+ void *NewList;
ALuint i;
ReadLock(&ThunkLock);
for(i = 0;i < ThunkArraySize;i++)
{
- if(ExchangeInt(&ThunkArray[i], AL_TRUE) == AL_FALSE)
+ if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
{
ReadUnlock(&ThunkLock);
*index = i+1;
@@ -62,18 +62,32 @@ ALenum NewThunkEntry(ALuint *index)
ReadUnlock(&ThunkLock);
WriteLock(&ThunkLock);
- NewList = realloc(ThunkArray, ThunkArraySize*2 * sizeof(*ThunkArray));
+ /* Double-check that there's still no free entries, in case another
+ * invocation just came through and increased the size of the array.
+ */
+ for(;i < ThunkArraySize;i++)
+ {
+ if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
+ {
+ WriteUnlock(&ThunkLock);
+ *index = i+1;
+ return AL_NO_ERROR;
+ }
+ }
+
+ NewList = al_calloc(16, ThunkArraySize*2 * sizeof(*ThunkArray));
if(!NewList)
{
WriteUnlock(&ThunkLock);
ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2);
return AL_OUT_OF_MEMORY;
}
- memset(&NewList[ThunkArraySize], 0, ThunkArraySize*sizeof(*ThunkArray));
- ThunkArraySize *= 2;
+ memcpy(NewList, ThunkArray, ThunkArraySize*sizeof(*ThunkArray));
+ al_free(ThunkArray);
ThunkArray = NewList;
+ ThunkArraySize *= 2;
- ThunkArray[i] = AL_TRUE;
+ ATOMIC_STORE(&ThunkArray[i], AL_TRUE);
WriteUnlock(&ThunkLock);
*index = i+1;
@@ -84,6 +98,6 @@ void FreeThunkEntry(ALuint index)
{
ReadLock(&ThunkLock);
if(index > 0 && index <= ThunkArraySize)
- ExchangeInt(&ThunkArray[index-1], AL_FALSE);
+ ATOMIC_STORE(&ThunkArray[index-1], AL_FALSE);
ReadUnlock(&ThunkLock);
}
diff --git a/README b/README
index ebca8f91..a0178ae5 100644
--- a/README
+++ b/README
@@ -45,9 +45,11 @@ Special thanks go to:
Creative Labs for the original source code this is based off of.
Christopher Fitzgerald for the current reverb effect implementation, and
-helping with the low-pass filter.
+helping with the low-pass and HRTF filters.
-Christian Borss for the 3D panning code the current implementation is heavilly
-based on.
+Christian Borss for the 3D panning code previous versions used as a base.
-Ben Davis for the idea behind the current click-removal code.
+Ben Davis for the idea behind a previous version of the click-removal code.
+
+Richard Furse for helping with my understanding of Ambisonics that is used by
+the various parts of the library.
diff --git a/XCompile-Android.txt b/XCompile-Android.txt
new file mode 100644
index 00000000..3dd88e80
--- /dev/null
+++ b/XCompile-Android.txt
@@ -0,0 +1,39 @@
+# Cross-compiling requires CMake 2.6 or newer. Example:
+# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile-Android.txt -DHOST=arm-linux-androideabi
+# Where 'arm-linux-androideabi' is the host prefix for the cross-compiler. If
+# you already have a toolchain file setup, you may use that instead of this
+# file. Make sure to set CMAKE_FIND_ROOT_PATH to where the NDK toolchain was
+# installed (e.g. "$ENV{HOME}/toolchains/arm-linux-androideabi-r10c-21").
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Linux)
+
+# which compilers to use for C and C++
+SET(CMAKE_C_COMPILER "${HOST}-gcc")
+SET(CMAKE_CXX_COMPILER "${HOST}-g++")
+SET(CMAKE_RC_COMPILER "${HOST}-windres")
+
+# here is the target environment located
+SET(CMAKE_FIND_ROOT_PATH "SET THIS TO THE NDK TOOLCHAIN'S INSTALL PATH")
+
+# here is where stuff gets installed to
+SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+# set env vars so that pkg-config will look in the appropriate directory for
+# .pc files (as there seems to be no way to force using ${HOST}-pkg-config)
+set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
+set(ENV{PKG_CONFIG_PATH} "")
+
+# Qt4 tools
+SET(QT_QMAKE_EXECUTABLE ${HOST}-qmake)
+SET(QT_MOC_EXECUTABLE ${HOST}-moc)
+SET(QT_RCC_EXECUTABLE ${HOST}-rcc)
+SET(QT_UIC_EXECUTABLE ${HOST}-uic)
+SET(QT_LRELEASE_EXECUTABLE ${HOST}-lrelease)
diff --git a/XCompile.txt b/XCompile.txt
index 035f1e21..32706bc1 100644
--- a/XCompile.txt
+++ b/XCompile.txt
@@ -1,7 +1,6 @@
-# Cross-compiling requires CMake 2.6 or newer. To use it from build/, call it
-# like this:
-# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-pc-mingw32
-# Where 'i686-pc-mingw32' is the host prefix for your cross-compiler. If you
+# Cross-compiling requires CMake 2.6 or newer. Example:
+# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-w64-mingw32
+# Where 'i686-w64-mingw32' is the host prefix for your cross-compiler. If you
# already have a toolchain file setup, you may use that instead of this file.
# the name of the target operating system
@@ -10,12 +9,13 @@ SET(CMAKE_SYSTEM_NAME Windows)
# which compilers to use for C and C++
SET(CMAKE_C_COMPILER "${HOST}-gcc")
SET(CMAKE_CXX_COMPILER "${HOST}-g++")
+SET(CMAKE_RC_COMPILER "${HOST}-windres")
# here is the target environment located
SET(CMAKE_FIND_ROOT_PATH "/usr/${HOST}")
# here is where stuff gets installed to
-SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}/usr" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
+SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
@@ -28,3 +28,10 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# .pc files (as there seems to be no way to force using ${HOST}-pkg-config)
set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
set(ENV{PKG_CONFIG_PATH} "")
+
+# Qt4 tools
+SET(QT_QMAKE_EXECUTABLE ${HOST}-qmake)
+SET(QT_MOC_EXECUTABLE ${HOST}-moc)
+SET(QT_RCC_EXECUTABLE ${HOST}-rcc)
+SET(QT_UIC_EXECUTABLE ${HOST}-uic)
+SET(QT_LRELEASE_EXECUTABLE ${HOST}-lrelease)
diff --git a/alsoftrc.sample b/alsoftrc.sample
index 2e6dd92a..eccc88b5 100644
--- a/alsoftrc.sample
+++ b/alsoftrc.sample
@@ -8,12 +8,18 @@
# specifying "$HOME/file.ext" would typically result in something like
# "/home/user/file.ext". To specify an actual "$" character, use "$$".
#
+# Device-specific values may be specified by including the device name in the
+# block name, with "general" replaced by the device name. That is, general
+# options for the device "Name of Device" would be in the [Name of Device]
+# block, while ALSA options would be in the [alsa/Name of Device] block.
+# Options marked as "(global)" are not influenced by the device.
+#
# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
# specific override settings in $HOME/.alsoftrc.
# For Windows, these settings should go into $AppData\alsoft.ini
#
-# Option and block names are case-insenstive. The supplied values are only
-# hints and may not be honored (though generally it'll try to get as close as
+# Option and block names are case-senstive. The supplied values are only hints
+# and may not be honored (though generally it'll try to get as close as
# possible). Note: options that are left unset may default to app- or system-
# specified values. These are the current available settings:
@@ -22,18 +28,27 @@
##
[general]
-## disable-cpu-exts:
+## disable-cpu-exts: (global)
# Disables use of specialized methods that use specific CPU intrinsics.
# Certain methods may utilize CPU extensions for improved performance, and
# this option is useful for preventing some or all of those methods from being
-# used. The available extensions are: sse, sse2, sse4.1, and neon. Specifying
-# 'all' disables use of all such specialized methods.
+# used. The available extensions are: sse, sse2, sse3, sse4.1, and neon.
+# Specifying 'all' disables use of all such specialized methods.
#disable-cpu-exts =
+## drivers: (global)
+# Sets the backend driver list order, comma-seperated. Unknown backends and
+# duplicated names are ignored. Unlisted backends won't be considered for use
+# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before
+# other backends, while 'oss' will try OSS only). Backends prepended with -
+# won't be considered for use (e.g. '-oss,' will try all available backends
+# except OSS). An empty list means to try all backends.
+#drivers =
+
## channels:
# Sets the output channel configuration. If left unspecified, one will try to
# be detected from the system, and defaulting to stereo. The available values
-# are: mono, stereo, quad, surround51, surround61, surround71
+# are: mono, stereo, quad, surround51, surround51rear, surround61, surround71
#channels =
## sample-type:
@@ -48,14 +63,40 @@
# float32 - 32-bit float
#sample-type = float32
-## hrtf:
-# Enables HRTF filters. These filters provide for better sound spatialization
-# while using headphones. The default filter will only work when output is
-# 44100hz stereo. While HRTF is active, the cf_level option is disabled.
-# Default is disabled since stereo speaker output quality may suffer.
-#hrtf = false
+## frequency:
+# Sets the output frequency. If left unspecified it will try to detect a
+# default from the system, otherwise it will default to 44100.
+#frequency =
+
+## period_size:
+# Sets the update period size, in frames. This is the number of frames needed
+# for each mixing update. Acceptable values range between 64 and 8192.
+#period_size = 1024
+
+## periods:
+# Sets the number of update periods. Higher values create a larger mix ahead,
+# which helps protect against skips when the CPU is under load, but increases
+# the delay between a sound getting mixed and being heard. Acceptable values
+# range between 2 and 16.
+#periods = 4
+
+## stereo-mode:
+# Specifies if stereo output is treated as being headphones or speakers. With
+# headphones, HRTF or crossfeed filters may be used for better audio quality.
+# Valid settings are auto, speakers, and headphones.
+#stereo-mode = auto
-## hrtf_tables
+## hrtf:
+# Controls HRTF processing. These filters provide better spatialization of
+# sounds while using headphones, but do require a bit more CPU power. The
+# default filters will only work with 44100hz or 48000hz stereo output. While
+# HRTF is used, the cf_level option is ignored. Setting this to auto (default)
+# will allow HRTF to be used when headphones are detected or the app requests
+# it, while setting true or false will forcefully enable or disable HRTF
+# respectively.
+#hrtf = auto
+
+## hrtf_tables:
# Specifies a comma-separated list of files containing HRTF data sets. The
# format of the files are described in hrtf.txt. The filenames may contain
# these markers, which will be replaced as needed:
@@ -84,28 +125,18 @@
# stereo modes.
#cf_level = 0
-## wide-stereo:
-# Specifies that stereo sources are given a width of about 120 degrees on each
-# channel, centering on -90 (left) and +90 (right), as opposed to being points
-# placed at -30 (left) and +30 (right). This can be useful for surround-sound
-# to give stereo sources a more encompassing sound. Note that the sound's
-# overall volume will be slightly reduced to account for the extra output.
-#wide-stereo = false
-
-## frequency:
-# Sets the output frequency. If left unspecified it will try to detect a
-# default from the system, otherwise it will default to 44100.
-#frequency =
-
-## resampler:
+## resampler: (global)
# Selects the resampler used when mixing sources. Valid values are:
# point - nearest sample, no interpolation
# linear - extrapolates samples using a linear slope between samples
-# cubic - extrapolates samples using a Catmull-Rom spline
+# sinc4 - extrapolates samples using a 4-point Sinc filter
+# sinc8 - extrapolates samples using an 8-point Sinc filter
+# bsinc - extrapolates samples using a band-limited Sinc filter (varying
+# between 12 and 24 points, with anti-aliasing)
# Specifying other values will result in using the default (linear).
#resampler = linear
-## rt-prio:
+## rt-prio: (global)
# Sets real-time priority for the mixing thread. Not all drivers may use this
# (eg. PortAudio) as they already control the priority of the mixing thread.
# 0 and negative values will disable it. Note that this may constitute a
@@ -114,39 +145,11 @@
# disabled.
#rt-prio = 0
-## period_size:
-# Sets the update period size, in frames. This is the number of frames needed
-# for each mixing update. Acceptable values range between 64 and 8192.
-#period_size = 1024
-
-## periods:
-# Sets the number of update periods. Higher values create a larger mix ahead,
-# which helps protect against skips when the CPU is under load, but increases
-# the delay between a sound getting mixed and being heard. Acceptable values
-# range between 2 and 16.
-#periods = 4
-
## sources:
# Sets the maximum number of allocatable sources. Lower values may help for
# systems with apps that try to play more sounds than the CPU can handle.
#sources = 256
-## drivers:
-# Sets the backend driver list order, comma-seperated. Unknown backends and
-# duplicated names are ignored. Unlisted backends won't be considered for use
-# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before
-# other backends, while 'oss' will try OSS only). Backends prepended with -
-# won't be considered for use (e.g. '-oss,' will try all available backends
-# except OSS). An empty list means to try all backends.
-#drivers =
-
-## excludefx:
-# Sets which effects to exclude, preventing apps from using them. This can
-# help for apps that try to use effects which are too CPU intensive for the
-# system to handle. Available effects are: eaxreverb,reverb,autowah,chorus,
-# compressor,distortion,echo,equalizer,flanger,modulator,dedicated
-#excludefx =
-
## slots:
# Sets the maximum number of Auxiliary Effect Slots an app can create. A slot
# can use a non-negligible amount of CPU time if an effect is set on it even
@@ -160,26 +163,14 @@
# possible is 4.
#sends =
-## layout:
-# Sets the virtual speaker layout. Values are specified in degrees, where 0 is
-# straight in front, negative goes left, and positive goes right. Unspecified
-# speakers will remain at their default positions (which are dependant on the
-# output format). Available speakers are back-left(bl), side-left(sl), front-
-# left(fl), front-center(fc), front-right(fr), side-right(sr), back-right(br),
-# and back-center(bc).
-#layout =
-
-## layout_*:
-# Channel-specific layouts may be specified to override the layout option. The
-# same speakers as the layout option are available, and the default settings
-# are shown below.
-#layout_stereo = fl=-90, fr=90
-#layout_quad = fl=-45, fr=45, bl=-135, br=135
-#layout_surround51 = fl=-30, fr=30, fc=0, bl=-110, br=110
-#layout_surround61 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bc=180
-#layout_surround71 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bl=-150, br=150
-
-## default-reverb:
+## excludefx: (global)
+# Sets which effects to exclude, preventing apps from using them. This can
+# help for apps that try to use effects which are too CPU intensive for the
+# system to handle. Available effects are: eaxreverb,reverb,chorus,compressor,
+# distortion,echo,equalizer,flanger,modulator,dedicated
+#excludefx =
+
+## default-reverb: (global)
# A reverb preset that applies by default to all sources on send 0
# (applications that set their own slots on send 0 will override this).
# Available presets are: None, Generic, PaddedCell, Room, Bathroom,
@@ -188,54 +179,31 @@
# Quarry, Plain, ParkingLot, SewerPipe, Underwater, Drugged, Dizzy, Psychotic.
#default-reverb =
-## trap-alc-error:
+## trap-alc-error: (global)
# Generates a SIGTRAP signal when an ALC device error is generated, on systems
# that support it. This helps when debugging, while trying to find the cause
# of a device error. On Windows, a breakpoint exception is generated.
#trap-alc-error = false
-## trap-al-error:
+## trap-al-error: (global)
# Generates a SIGTRAP signal when an AL context error is generated, on systems
# that support it. This helps when debugging, while trying to find the cause
# of a context error. On Windows, a breakpoint exception is generated.
#trap-al-error = false
##
-## MIDI stuff (EXPERIMENTAL)
-##
-[midi]
-
-## soundfont:
-# A default soundfont (sf2 format). Used when an app requests the system
-# default. The listed file is relative to system-dependant data directories.
-# On Windows this is:
-# $AppData\openal\soundfonts
-# And on other systems, it's (in order):
-# $XDG_DATA_HOME/openal/soundfonts
-# $XDG_DATA_DIRS/openal/soundfonts
-# An absolute path may also be specified, if the given file is elsewhere.
-#soundfont =
-
-## volume:
-# Additional attenuation applied to MIDI output, expressed in decibels. This
-# is used to help keep the mix from clipping, and so must be 0 or less. The
-# value is logarithmic, so -6 will be about half amplitude, and -12 about
-# 1/4th. The default is roughly -13.9794 (0.2, or 1/5th).
-#volume =
-
-##
## Reverb effect stuff (includes EAX reverb)
##
[reverb]
-## boost:
+## boost: (global)
# A global amplification for reverb output, expressed in decibels. The value
# is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will be a
# scale of 4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
# value of 0 means no change.
#boost = 0
-## emulate-eax:
+## emulate-eax: (global)
# Allows the standard reverb effect to be used in place of EAX reverb. EAX
# reverb processing is a bit more CPU intensive than standard, so this option
# allows a simpler effect to be used at the loss of some quality.
@@ -246,52 +214,59 @@
##
[pulse]
-## spawn-server:
+## spawn-server: (global)
# Attempts to autospawn a PulseAudio server whenever needed (initializing the
# backend, enumerating devices, etc). Setting autospawn to false in Pulse's
# client.conf will still prevent autospawning even if this is set to true.
#spawn-server = true
-## allow-moves:
+## allow-moves: (global)
# Allows PulseAudio to move active streams to different devices. Note that the
# device specifier (seen by applications) will not be updated when this
# occurs, and neither will the AL device configuration (sample rate, format,
# etc).
#allow-moves = false
+## fix-rate:
+# Specifies whether to match the playback stream's sample rate to the device's
+# sample rate. Enabling this forces OpenAL Soft to mix sources and effects
+# directly to the actual output rate, avoiding a second resample pass by the
+# PulseAudio server.
+#fix-rate = false
+
##
## ALSA backend stuff
##
[alsa]
-## device:
+## device: (global)
# Sets the device name for the default playback device.
#device = default
-## device-prefix:
+## device-prefix: (global)
# Sets the prefix used by the discovered (non-default) playback devices. This
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
# device index for the requested device name.
#device-prefix = plughw:
-## device-prefix-*:
+## device-prefix-*: (global)
# Card- and device-specific prefixes may be used to override the device-prefix
# option. The option may specify the card id (eg, device-prefix-NVidia), or
# the card id and device index (eg, device-prefix-NVidia-0). The card id is
# case-sensitive.
#device-prefix- =
-## capture:
+## capture: (global)
# Sets the device name for the default capture device.
#capture = default
-## capture-prefix:
+## capture-prefix: (global)
# Sets the prefix used by the discovered (non-default) capture devices. This
# will be appended with "CARD=c,DEV=d", where c is the card id and d is the
# device number for the requested device name.
#capture-prefix = plughw:
-## capture-prefix-*:
+## capture-prefix-*: (global)
# Card- and device-specific prefixes may be used to override the
# capture-prefix option. The option may specify the card id (eg,
# capture-prefix-NVidia), or the card id and device index (eg,
@@ -305,16 +280,23 @@
# and anything else will force mmap off.
#mmap = true
+## allow-resampler:
+# Specifies whether to allow ALSA's built-in resampler. Enabling this will
+# allow the playback device to be set to a different sample rate than the
+# actual output, causing ALSA to apply its own resampling pass after OpenAL
+# Soft resamples and mixes the sources and effects for output.
+#allow-resampler = false
+
##
## OSS backend stuff
##
[oss]
-## device:
+## device: (global)
# Sets the device name for OSS output.
#device = /dev/dsp
-## capture:
+## capture: (global)
# Sets the device name for OSS capture.
#capture = /dev/dsp
@@ -323,7 +305,7 @@
##
[solaris]
-## device:
+## device: (global)
# Sets the device name for Solaris output.
#device = /dev/audio
@@ -332,13 +314,24 @@
##
[qsa]
-## device:
-# Sets the device name for the default playback device.
-#device = default
-
-## capture:
-# Sets the device name for the default capture device.
-#capture = default
+##
+## JACK backend stuff
+##
+[jack]
+
+## spawn-server: (global)
+# Attempts to autospawn a JACK server whenever needed (initializing the
+# backend, opening devices, etc).
+#spawn-server = false
+
+## buffer-size:
+# Sets the update buffer size, in samples, that the backend will keep buffered
+# to handle the server's real-time processing requests. This value must be a
+# power of 2, or else it will be rounded up to the next power of 2. If it is
+# less than JACK's buffer update size, it will be clamped. This option may
+# be useful in case the server's update size is too small and doesn't give the
+# mixer time to keep enough audio available for the processing requests.
+#buffer-size = 0
##
## MMDevApi backend stuff
@@ -360,12 +353,12 @@
##
[port]
-## device:
+## device: (global)
# Sets the device index for output. Negative values will use the default as
# given by PortAudio itself.
#device = -1
-## capture:
+## capture: (global)
# Sets the device index for capture. Negative values will use the default as
# given by PortAudio itself.
#capture = -1
@@ -375,8 +368,13 @@
##
[wave]
-## file:
+## file: (global)
# Sets the filename of the wave file to write to. An empty name prevents the
# backend from opening, even when explicitly requested.
# THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION!
#file =
+
+## bformat: (global)
+# Creates AMB format files using first-order ambisonics instead of a standard
+# single- or multi-channel .wav file.
+#bformat = false
diff --git a/cmake/CheckFileOffsetBits.c b/cmake/CheckFileOffsetBits.c
new file mode 100644
index 00000000..de98296e
--- /dev/null
+++ b/cmake/CheckFileOffsetBits.c
@@ -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; }
diff --git a/cmake/CheckFileOffsetBits.cmake b/cmake/CheckFileOffsetBits.cmake
new file mode 100644
index 00000000..1dc154e4
--- /dev/null
+++ b/cmake/CheckFileOffsetBits.cmake
@@ -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_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
+ IF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
+ TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
+ ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
+
+ 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) \ No newline at end of file
diff --git a/cmake/CheckSharedFunctionExists.cmake b/cmake/CheckSharedFunctionExists.cmake
index 4980effa..7975f233 100644
--- a/cmake/CheckSharedFunctionExists.cmake
+++ b/cmake/CheckSharedFunctionExists.cmake
@@ -58,12 +58,12 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE)
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\nvoid cmakeRequireSymbol(int dummy,...){(void)dummy;}\nint main()\n{\n cmakeRequireSymbol(0,&${SYMBOL});\n return 0;\n}\n")
CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
- "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY)
+ "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY)
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY}")
TRY_COMPILE(${VARIABLE}
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
CMAKE_FLAGS
-DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS}
@@ -74,18 +74,18 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE)
IF(${VARIABLE})
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - found")
SET(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determining if the ${SYMBOL} "
"exist in ${LIBRARY} passed with the following output:\n"
- "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
+ "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
ELSE(${VARIABLE})
MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - not found.")
SET(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if the ${SYMBOL} "
"exist in ${LIBRARY} failed with the following output:\n"
- "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
+ "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
"${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
ENDIF(${VARIABLE})
ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")
diff --git a/cmake/FindDSound.cmake b/cmake/FindDSound.cmake
index 36cdf4b5..0ddf98aa 100644
--- a/cmake/FindDSound.cmake
+++ b/cmake/FindDSound.cmake
@@ -9,14 +9,16 @@
#
find_path(DSOUND_INCLUDE_DIR
- PATHS "${DXSDK_DIR}/include"
NAMES dsound.h
+ PATHS "${DXSDK_DIR}"
+ PATH_SUFFIXES include
DOC "The DirectSound include directory"
)
find_library(DSOUND_LIBRARY
- PATHS "${DXSDK_DIR}/lib"
NAMES dsound
+ PATHS "${DXSDK_DIR}"
+ PATH_SUFFIXES lib lib/x86 lib/x64
DOC "The DirectSound library"
)
diff --git a/cmake/FindFluidSynth.cmake b/cmake/FindFluidSynth.cmake
deleted file mode 100644
index fe96b225..00000000
--- a/cmake/FindFluidSynth.cmake
+++ /dev/null
@@ -1,19 +0,0 @@
-# - Find fluidsynth
-# Find the native fluidsynth includes and library
-#
-# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h
-# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth.
-# FLUIDSYNTH_FOUND - True if fluidsynth found.
-
-
-FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h)
-
-FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth )
-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
- REQUIRED_VARS FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR)
-
diff --git a/cmake/FindJACK.cmake b/cmake/FindJACK.cmake
new file mode 100644
index 00000000..b72fe3f9
--- /dev/null
+++ b/cmake/FindJACK.cmake
@@ -0,0 +1,60 @@
+# - Find JACK
+# Find the JACK libraries
+#
+# This module defines the following variables:
+# JACK_FOUND - True if JACK_INCLUDE_DIR & JACK_LIBRARY are found
+# JACK_INCLUDE_DIRS - where to find jack.h, etc.
+# JACK_LIBRARIES - the jack library
+#
+
+#=============================================================================
+# Copyright 2009-2011 Kitware, Inc.
+# Copyright 2009-2011 Philip Lowman <[email protected]>
+#
+# 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(JACK_INCLUDE_DIR NAMES jack/jack.h
+ DOC "The JACK include directory"
+)
+
+find_library(JACK_LIBRARY NAMES jack
+ DOC "The JACK library"
+)
+
+# handle the QUIETLY and REQUIRED arguments and set JACK_FOUND to TRUE if
+# all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(JACK REQUIRED_VARS JACK_LIBRARY JACK_INCLUDE_DIR)
+
+if(JACK_FOUND)
+ set(JACK_LIBRARIES ${JACK_LIBRARY})
+ set(JACK_INCLUDE_DIRS ${JACK_INCLUDE_DIR})
+endif()
+
+mark_as_advanced(JACK_INCLUDE_DIR JACK_LIBRARY)
diff --git a/cmake/FindSDL_sound.cmake b/cmake/FindSDL_sound.cmake
index 2dab1a1c..5557b55b 100644
--- a/cmake/FindSDL_sound.cmake
+++ b/cmake/FindSDL_sound.cmake
@@ -146,196 +146,219 @@ if(SDL2_FOUND OR SDL_FOUND)
# The ;-framework Cocoa seems to be confusing CMake once the OS X
# framework support was added. I was told that breaking up the list
# would fix the problem.
- set(TMP_TRY_LIBS)
+ set(TMP_LIBS "")
if(SDL2_FOUND)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY})
foreach(lib ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY})
- set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"")
+ set(TMP_LIBS "${TMP_LIBS} \"${lib}\"")
endforeach()
set(TMP_INCLUDE_DIRS ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
else()
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
- set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"")
+ set(TMP_LIBS "${TMP_LIBS} \"${lib}\"")
endforeach()
set(TMP_INCLUDE_DIRS ${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
endif()
- # message("TMP_TRY_LIBS ${TMP_TRY_LIBS}")
+ # Keep trying to build a temp project until we find all missing libs.
+ set(TRY_AGAIN TRUE)
+ WHILE(TRY_AGAIN)
+ set(TRY_AGAIN FALSE)
+ # message("TMP_TRY_LIBS ${TMP_TRY_LIBS}")
- # Write the CMakeLists.txt and test project
- # Weird, this is still sketchy. If I don't quote the variables
- # in the TARGET_LINK_LIBRARIES, I seem to loose everything
- # in the SDL2_LIBRARY string after the "-framework".
- # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
- file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
- "cmake_minimum_required(VERSION 2.8)
- project(DetermineSoundLibs C)
- include_directories(${TMP_INCLUDE_DIRS})
- add_executable(DetermineSoundLibs DetermineSoundLibs.c)
- target_link_libraries(DetermineSoundLibs ${TMP_TRY_LIBS})"
- )
- unset(TMP_INCLUDE_DIRS)
- unset(TMP_TRY_LIBS)
+ # Write the CMakeLists.txt and test project
+ # Weird, this is still sketchy. If I don't quote the variables
+ # in the TARGET_LINK_LIBRARIES, I seem to loose everything
+ # in the SDL2_LIBRARY string after the "-framework".
+ # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
+ file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
+ "cmake_minimum_required(VERSION 2.8)
+ project(DetermineSoundLibs C)
+ include_directories(${TMP_INCLUDE_DIRS})
+ add_executable(DetermineSoundLibs DetermineSoundLibs.c)
+ target_link_libraries(DetermineSoundLibs ${TMP_LIBS})"
+ )
- try_compile(
- MY_RESULT
- ${PROJECT_BINARY_DIR}/CMakeTmp
- ${PROJECT_BINARY_DIR}/CMakeTmp
- DetermineSoundLibs
- OUTPUT_VARIABLE MY_OUTPUT
- )
- # message("${MY_RESULT}")
- # message(${MY_OUTPUT})
+ try_compile(
+ MY_RESULT
+ ${PROJECT_BINARY_DIR}/CMakeTmp
+ ${PROJECT_BINARY_DIR}/CMakeTmp
+ DetermineSoundLibs
+ OUTPUT_VARIABLE MY_OUTPUT
+ )
+ # message("${MY_RESULT}")
+ # message(${MY_OUTPUT})
- if(NOT MY_RESULT)
- # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
- # I think Timidity is also compiled in statically.
- # I've never had to explcitly link against Quicktime, so I'll skip that for now.
+ if(NOT MY_RESULT)
+ # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
+ # I think Timidity is also compiled in statically.
+ # I've never had to explcitly link against Quicktime, so I'll skip that for now.
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY})
+ # Find libmath
+ if("${MY_OUTPUT}" MATCHES "cos@@GLIBC")
+ find_library(MATH_LIBRARY NAMES m)
+ if(MATH_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MATH_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MATH_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif(MATH_LIBRARY)
+ endif("${MY_OUTPUT}" MATCHES "cos@@GLIBC")
- # Find MikMod
- if("${MY_OUTPUT}" MATCHES "MikMod_")
- find_library(MIKMOD_LIBRARY
- NAMES libmikmod-coreaudio mikmod
- PATHS
- ENV MIKMODDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES lib
- )
- if(MIKMOD_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
- endif(MIKMOD_LIBRARY)
- endif("${MY_OUTPUT}" MATCHES "MikMod_")
+ # Find MikMod
+ if("${MY_OUTPUT}" MATCHES "MikMod_")
+ find_library(MIKMOD_LIBRARY
+ NAMES libmikmod-coreaudio mikmod
+ PATHS
+ ENV MIKMODDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(MIKMOD_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MIKMOD_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif(MIKMOD_LIBRARY)
+ endif("${MY_OUTPUT}" MATCHES "MikMod_")
- # Find ModPlug
- if("${MY_OUTPUT}" MATCHES "MODPLUG_")
- find_library(MODPLUG_LIBRARY
- NAMES modplug
- PATHS
- ENV MODPLUGDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES lib
- )
- if(MODPLUG_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
+ # Find ModPlug
+ if("${MY_OUTPUT}" MATCHES "MODPLUG_")
+ find_library(MODPLUG_LIBRARY
+ NAMES modplug
+ PATHS
+ ENV MODPLUGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(MODPLUG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MODPLUG_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif()
endif()
- endif()
- # Find Ogg and Vorbis
- if("${MY_OUTPUT}" MATCHES "ov_")
- find_library(VORBIS_LIBRARY
- NAMES vorbis Vorbis VORBIS
- PATHS
- ENV VORBISDIR
- ENV OGGDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES lib
- )
- if(VORBIS_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
- endif()
- find_library(OGG_LIBRARY
- NAMES ogg Ogg OGG
- PATHS
- ENV OGGDIR
- ENV VORBISDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES lib
- )
- if(OGG_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
- endif()
- endif()
+ # Find Ogg and Vorbis
+ if("${MY_OUTPUT}" MATCHES "ov_")
+ find_library(VORBISFILE_LIBRARY
+ NAMES vorbisfile VorbisFile VORBISFILE
+ PATHS
+ ENV VORBISDIR
+ ENV OGGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(VORBISFILE_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBISFILE_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${VORBISFILE_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif()
- # Find SMPEG
- if("${MY_OUTPUT}" MATCHES "SMPEG_")
- find_library(SMPEG_LIBRARY
- NAMES smpeg SMPEG Smpeg SMpeg
- PATHS
- ENV SMPEGDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES lib
- )
- if(SMPEG_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
- endif()
- endif()
+ find_library(VORBIS_LIBRARY
+ NAMES vorbis Vorbis VORBIS
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(VORBIS_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${VORBIS_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif()
+ find_library(OGG_LIBRARY
+ NAMES ogg Ogg OGG
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(OGG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${OGG_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif()
+ endif()
- # Find FLAC
- if("${MY_OUTPUT}" MATCHES "FLAC_")
- find_library(FLAC_LIBRARY
- NAMES flac FLAC
- PATHS
- ENV FLACDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES lib
- )
- if(FLAC_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
+ # Find SMPEG
+ if("${MY_OUTPUT}" MATCHES "SMPEG_")
+ find_library(SMPEG_LIBRARY
+ NAMES smpeg SMPEG Smpeg SMpeg
+ PATHS
+ ENV SMPEGDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(SMPEG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${SMPEG_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif()
endif()
- endif()
- # Hmmm...Speex seems to depend on Ogg. This might be a problem if
- # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
- # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
- # above for here or if two ogg entries will screw up things.
- if("${MY_OUTPUT}" MATCHES "speex_")
- find_library(SPEEX_LIBRARY
- NAMES speex SPEEX
- PATHS
- ENV SPEEXDIR
- ENV SDLSOUNDDIR
- ENV SDLDIR
- /sw
- /opt/local
- /opt/csw
- /opt
- PATH_SUFFIXES lib
- )
- if(SPEEX_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
+ # Find FLAC
+ if("${MY_OUTPUT}" MATCHES "FLAC_")
+ find_library(FLAC_LIBRARY
+ NAMES flac FLAC
+ PATHS
+ ENV FLACDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(FLAC_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${FLAC_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif()
endif()
- # Find OGG (needed for Speex)
- # We might have already found Ogg for Vorbis, so skip it if so.
- if(NOT OGG_LIBRARY)
- find_library(OGG_LIBRARY
- NAMES ogg Ogg OGG
+
+ # Hmmm...Speex seems to depend on Ogg. This might be a problem if
+ # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
+ # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
+ # above for here or if two ogg entries will screw up things.
+ if("${MY_OUTPUT}" MATCHES "speex_")
+ find_library(SPEEX_LIBRARY
+ NAMES speex SPEEX
PATHS
- ENV OGGDIR
- ENV VORBISDIR
ENV SPEEXDIR
ENV SDLSOUNDDIR
ENV SDLDIR
@@ -345,16 +368,42 @@ if(SDL2_FOUND OR SDL_FOUND)
/opt
PATH_SUFFIXES lib
)
- if(OGG_LIBRARY)
- set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ if(SPEEX_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${SPEEX_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif()
+
+ # Find OGG (needed for Speex)
+ # We might have already found Ogg for Vorbis, so skip it if so.
+ if(NOT OGG_LIBRARY)
+ find_library(OGG_LIBRARY
+ NAMES ogg Ogg OGG
+ PATHS
+ ENV OGGDIR
+ ENV VORBISDIR
+ ENV SPEEXDIR
+ ENV SDLSOUNDDIR
+ ENV SDLDIR
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ PATH_SUFFIXES lib
+ )
+ if(OGG_LIBRARY)
+ set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+ set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${OGG_LIBRARY}\"")
+ set(TRY_AGAIN TRUE)
+ endif()
endif()
endif()
endif()
+ ENDWHILE()
+ unset(TMP_INCLUDE_DIRS)
+ unset(TMP_LIBS)
- set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries")
- else()
- set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARY} CACHE INTERNAL "SDL_sound and dependent libraries")
- endif()
+ set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries")
endif()
endif()
diff --git a/common/atomic.c b/common/atomic.c
index 634587e4..3cdb77f4 100644
--- a/common/atomic.c
+++ b/common/atomic.c
@@ -4,13 +4,10 @@
#include "atomic.h"
-extern inline void InitRef(volatile RefCount *ptr, uint value);
-extern inline uint ReadRef(volatile RefCount *ptr);
-extern inline uint IncrementRef(volatile RefCount *ptr);
-extern inline uint DecrementRef(volatile RefCount *ptr);
-extern inline uint ExchangeRef(volatile RefCount *ptr, uint newval);
-extern inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval);
+extern inline void InitRef(RefCount *ptr, uint value);
+extern inline uint ReadRef(RefCount *ptr);
+extern inline uint IncrementRef(RefCount *ptr);
+extern inline uint DecrementRef(RefCount *ptr);
+
extern inline int ExchangeInt(volatile int *ptr, int newval);
extern inline void *ExchangePtr(XchgPtr *ptr, void *newval);
-extern inline int CompExchangeInt(volatile int *ptr, int oldval, int newval);
-extern inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval);
diff --git a/common/rwlock.c b/common/rwlock.c
index ff7aa418..cfa3aee4 100644
--- a/common/rwlock.c
+++ b/common/rwlock.c
@@ -10,53 +10,48 @@
/* A simple spinlock. Yield the thread while the given integer is set by
* another. Could probably be improved... */
-static void Lock(volatile int *l)
-{
- while(ExchangeInt(l, true) == true)
- althrd_yield();
-}
-
-static void Unlock(volatile int *l)
-{
- ExchangeInt(l, false);
-}
+#define LOCK(l) do { \
+ while(ATOMIC_EXCHANGE(int, &(l), true) == true) \
+ althrd_yield(); \
+} while(0)
+#define UNLOCK(l) ATOMIC_STORE(&(l), false)
void RWLockInit(RWLock *lock)
{
InitRef(&lock->read_count, 0);
InitRef(&lock->write_count, 0);
- lock->read_lock = false;
- lock->read_entry_lock = false;
- lock->write_lock = false;
+ ATOMIC_INIT(&lock->read_lock, false);
+ ATOMIC_INIT(&lock->read_entry_lock, false);
+ ATOMIC_INIT(&lock->write_lock, false);
}
void ReadLock(RWLock *lock)
{
- Lock(&lock->read_entry_lock);
- Lock(&lock->read_lock);
+ LOCK(lock->read_entry_lock);
+ LOCK(lock->read_lock);
if(IncrementRef(&lock->read_count) == 1)
- Lock(&lock->write_lock);
- Unlock(&lock->read_lock);
- Unlock(&lock->read_entry_lock);
+ LOCK(lock->write_lock);
+ UNLOCK(lock->read_lock);
+ UNLOCK(lock->read_entry_lock);
}
void ReadUnlock(RWLock *lock)
{
if(DecrementRef(&lock->read_count) == 0)
- Unlock(&lock->write_lock);
+ UNLOCK(lock->write_lock);
}
void WriteLock(RWLock *lock)
{
if(IncrementRef(&lock->write_count) == 1)
- Lock(&lock->read_lock);
- Lock(&lock->write_lock);
+ LOCK(lock->read_lock);
+ LOCK(lock->write_lock);
}
void WriteUnlock(RWLock *lock)
{
- Unlock(&lock->write_lock);
+ UNLOCK(lock->write_lock);
if(DecrementRef(&lock->write_count) == 0)
- Unlock(&lock->read_lock);
+ UNLOCK(lock->read_lock);
}
diff --git a/common/threads.c b/common/threads.c
index cd9f6755..71fa6ab9 100644
--- a/common/threads.c
+++ b/common/threads.c
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -733,11 +733,11 @@ int altimespec_get(struct timespec *ts, int base)
#endif
-void al_nssleep(time_t sec, long nsec)
+void al_nssleep(unsigned long nsec)
{
struct timespec ts, rem;
- ts.tv_sec = sec;
- ts.tv_nsec = nsec;
+ ts.tv_sec = nsec / 1000000000ul;
+ ts.tv_nsec = nsec % 1000000000ul;
while(althrd_sleep(&ts, &rem) == -1)
ts = rem;
diff --git a/config.h.in b/config.h.in
index 3fdc0c7e..e66b1fe8 100644
--- a/config.h.in
+++ b/config.h.in
@@ -9,7 +9,7 @@
/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
* recent versions (at least 4.5.1) do recognize GCC's __restrict. */
#define restrict __restrict
-#endif
+#endif
/* Define any available alignment declaration */
#define ALIGN(x) ${ALIGN_DECL}
@@ -26,14 +26,12 @@
/* Define if we have SSE CPU extensions */
#cmakedefine HAVE_SSE
#cmakedefine HAVE_SSE2
+#cmakedefine HAVE_SSE3
#cmakedefine HAVE_SSE4_1
/* Define if we have ARM Neon CPU extensions */
#cmakedefine HAVE_NEON
-/* Define if we have FluidSynth support */
-#cmakedefine HAVE_FLUIDSYNTH
-
/* Define if we have the ALSA backend */
#cmakedefine HAVE_ALSA
@@ -64,6 +62,9 @@
/* Define if we have the PulseAudio backend */
#cmakedefine HAVE_PULSEAUDIO
+/* Define if we have the JACK backend */
+#cmakedefine HAVE_JACK
+
/* Define if we have the CoreAudio backend */
#cmakedefine HAVE_COREAUDIO
@@ -79,6 +80,9 @@
/* Define if we have the lrintf function */
#cmakedefine HAVE_LRINTF
+/* Define if we have the modff function */
+#cmakedefine HAVE_MODFF
+
/* Define if we have the strtof function */
#cmakedefine HAVE_STRTOF
@@ -103,6 +107,9 @@
/* Define if we have C11 _Alignas support */
#cmakedefine HAVE_C11_ALIGNAS
+/* Define if we have C11 _Atomic support */
+#cmakedefine HAVE_C11_ATOMIC
+
/* Define if we have GCC's destructor attribute */
#cmakedefine HAVE_GCC_DESTRUCTOR
@@ -127,20 +134,14 @@
/* Define if we have pthread_np.h */
#cmakedefine HAVE_PTHREAD_NP_H
-/* Define if we have xmmintrin.h */
-#cmakedefine HAVE_XMMINTRIN_H
-
-/* Define if we have arm_neon.h */
-#cmakedefine HAVE_ARM_NEON_H
-
/* Define if we have alloca.h */
#cmakedefine HAVE_ALLOCA_H
/* Define if we have malloc.h */
#cmakedefine HAVE_MALLOC_H
-/* Define if we have ftw.h */
-#cmakedefine HAVE_FTW_H
+/* Define if we have dirent.h */
+#cmakedefine HAVE_DIRENT_H
/* Define if we have io.h */
#cmakedefine HAVE_IO_H
@@ -151,6 +152,9 @@
/* Define if we have cpuid.h */
#cmakedefine HAVE_CPUID_H
+/* Define if we have intrin.h */
+#cmakedefine HAVE_INTRIN_H
+
/* Define if we have sys/sysconf.h */
#cmakedefine HAVE_SYS_SYSCONF_H
@@ -169,18 +173,18 @@
/* Define if we have fenv.h */
#cmakedefine HAVE_FENV_H
+/* Define if we have GCC's __get_cpuid() */
+#cmakedefine HAVE_GCC_GET_CPUID
+
+/* Define if we have the __cpuid() intrinsic */
+#cmakedefine HAVE_CPUID_INTRINSIC
+
/* Define if we have _controlfp() */
#cmakedefine HAVE__CONTROLFP
/* Define if we have __control87_2() */
#cmakedefine HAVE___CONTROL87_2
-/* Define if we have ftw() */
-#cmakedefine HAVE_FTW
-
-/* Define if we have _wfindfirst() */
-#cmakedefine HAVE__WFINDFIRST
-
/* Define if we have pthread_setschedparam() */
#cmakedefine HAVE_PTHREAD_SETSCHEDPARAM
diff --git a/env-vars.txt b/env-vars.txt
index 47dce032..b2268643 100644
--- a/env-vars.txt
+++ b/env-vars.txt
@@ -69,3 +69,13 @@ sound (i.e., sounds that are supposed to be behind you sound like they're in
front, and vice-versa). Setting this to "true" or "1" will negate the localized
Z coordinate to attempt to fix output for apps that have incorrect front/back
panning.
+
+__ALSOFT_SUSPEND_CONTEXT
+Due to the OpenAL spec not being very clear about them, behavior of the
+alcSuspendContext and alcProcessContext methods has varied, and because of
+that, previous versions of OpenAL Soft had them no-op. Creative's hardware
+drivers and the Rapture3D driver, however, use these methods to batch changes,
+which some applications make use of to protect against partial updates. In an
+attempt to standardize on that behavior, OpenAL Soft has changed those methods
+accordingly. Setting this to "ignore" restores the previous no-op behavior for
+applications that interact poorly with the new behavior.
diff --git a/examples/alffplay.c b/examples/alffplay.c
index 762582c4..17f6d3bc 100644
--- a/examples/alffplay.c
+++ b/examples/alffplay.c
@@ -17,6 +17,7 @@
#include <libavformat/avio.h>
#include <libavutil/time.h>
#include <libavutil/avstring.h>
+#include <libavutil/channel_layout.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
@@ -547,6 +548,7 @@ static int audio_thread(void *userdata)
MovieState *movState = (MovieState*)userdata;
uint8_t *samples = NULL;
ALsizei buffer_len;
+ ALenum fmt;
alGenBuffers(AUDIO_BUFFER_QUEUE_SIZE, movState->audio.buffer);
alGenSources(1, &movState->audio.source);
@@ -556,56 +558,107 @@ static int audio_thread(void *userdata)
av_new_packet(&movState->audio.pkt, 0);
- /* Find a suitable format for OpenAL. Currently does not handle surround
- * sound (everything non-mono becomes stereo). */
+ /* Find a suitable format for OpenAL. */
+ movState->audio.format = AL_NONE;
if(movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8 ||
movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
{
movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_U8;
movState->audio.frame_size = 1;
+ if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
+ alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+ (fmt=alGetEnumValue("AL_FORMAT_71CHN8")) != AL_NONE && fmt != -1)
+ {
+ movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+ movState->audio.frame_size *= 8;
+ movState->audio.format = fmt;
+ }
+ if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
+ movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
+ alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+ (fmt=alGetEnumValue("AL_FORMAT_51CHN8")) != AL_NONE && fmt != -1)
+ {
+ movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+ movState->audio.frame_size *= 6;
+ movState->audio.format = fmt;
+ }
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
movState->audio.frame_size *= 1;
movState->audio.format = AL_FORMAT_MONO8;
}
- else
+ if(movState->audio.format == AL_NONE)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
movState->audio.frame_size *= 2;
movState->audio.format = AL_FORMAT_STEREO8;
}
}
- else if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT ||
- movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) &&
- alIsExtensionPresent("AL_EXT_FLOAT32"))
+ if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT ||
+ movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) &&
+ alIsExtensionPresent("AL_EXT_FLOAT32"))
{
movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_FLT;
movState->audio.frame_size = 4;
+ if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
+ alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+ (fmt=alGetEnumValue("AL_FORMAT_71CHN32")) != AL_NONE && fmt != -1)
+ {
+ movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+ movState->audio.frame_size *= 8;
+ movState->audio.format = fmt;
+ }
+ if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
+ movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
+ alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+ (fmt=alGetEnumValue("AL_FORMAT_51CHN32")) != AL_NONE && fmt != -1)
+ {
+ movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+ movState->audio.frame_size *= 6;
+ movState->audio.format = fmt;
+ }
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
movState->audio.frame_size *= 1;
movState->audio.format = AL_FORMAT_MONO_FLOAT32;
}
- else
+ if(movState->audio.format == AL_NONE)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
movState->audio.frame_size *= 2;
movState->audio.format = AL_FORMAT_STEREO_FLOAT32;
}
}
- else
+ if(movState->audio.format == AL_NONE)
{
movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_S16;
movState->audio.frame_size = 2;
+ if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
+ alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+ (fmt=alGetEnumValue("AL_FORMAT_71CHN16")) != AL_NONE && fmt != -1)
+ {
+ movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+ movState->audio.frame_size *= 8;
+ movState->audio.format = fmt;
+ }
+ if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
+ movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
+ alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+ (fmt=alGetEnumValue("AL_FORMAT_51CHN16")) != AL_NONE && fmt != -1)
+ {
+ movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+ movState->audio.frame_size *= 6;
+ movState->audio.format = fmt;
+ }
if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
movState->audio.frame_size *= 1;
movState->audio.format = AL_FORMAT_MONO16;
}
- else
+ if(movState->audio.format == AL_NONE)
{
movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
movState->audio.frame_size *= 2;
@@ -631,7 +684,9 @@ static int audio_thread(void *userdata)
movState->audio.dst_ch_layout,
movState->audio.dst_sample_fmt,
movState->audio.st->codec->sample_rate,
- movState->audio.st->codec->channel_layout,
+ movState->audio.st->codec->channel_layout ?
+ movState->audio.st->codec->channel_layout :
+ av_get_default_channel_layout(movState->audio.st->codec->channels),
movState->audio.st->codec->sample_fmt,
movState->audio.st->codec->sample_rate,
0, NULL
@@ -1336,7 +1391,7 @@ int main(int argc, char *argv[])
return 1;
}
- if(!alIsExtensionPresent("AL_SOFTX_source_length")) /* FIXME */
+ if(!alIsExtensionPresent("AL_SOFT_source_length"))
{
fprintf(stderr, "Required AL_SOFT_source_length not supported - exiting\n");
return 1;
diff --git a/examples/alhrtf.c b/examples/alhrtf.c
new file mode 100644
index 00000000..6dac5308
--- /dev/null
+++ b/examples/alhrtf.c
@@ -0,0 +1,248 @@
+/*
+ * OpenAL HRTF Example
+ *
+ * Copyright (c) 2015 by Chris Robinson <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This file contains an example for selecting an HRTF. */
+
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include "common/alhelpers.h"
+#include "common/sdl_sound.h"
+
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
+static LPALCGETSTRINGISOFT alcGetStringiSOFT;
+static LPALCRESETDEVICESOFT alcResetDeviceSOFT;
+
+/* LoadBuffer loads the named audio file into an OpenAL buffer object, and
+ * returns the new buffer ID. */
+static ALuint LoadSound(const char *filename)
+{
+ ALenum err, format, type, channels;
+ ALuint rate, buffer;
+ size_t datalen;
+ void *data;
+ FilePtr sound;
+
+ /* Open the audio file */
+ sound = openAudioFile(filename, 1000);
+ if(!sound)
+ {
+ fprintf(stderr, "Could not open audio in %s\n", filename);
+ closeAudioFile(sound);
+ return 0;
+ }
+
+ /* Get the sound format, and figure out the OpenAL format */
+ if(getAudioInfo(sound, &rate, &channels, &type) != 0)
+ {
+ fprintf(stderr, "Error getting audio info for %s\n", filename);
+ closeAudioFile(sound);
+ return 0;
+ }
+
+ format = GetFormat(channels, type, NULL);
+ if(format == AL_NONE)
+ {
+ fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
+ ChannelsName(channels), TypeName(type), filename);
+ closeAudioFile(sound);
+ return 0;
+ }
+
+ /* Decode the whole audio stream to a buffer. */
+ data = decodeAudioStream(sound, &datalen);
+ if(!data)
+ {
+ fprintf(stderr, "Failed to read audio from %s\n", filename);
+ closeAudioFile(sound);
+ return 0;
+ }
+
+ /* Buffer the audio data into a new buffer object, then free the data and
+ * close the file. */
+ buffer = 0;
+ alGenBuffers(1, &buffer);
+ alBufferData(buffer, format, data, datalen, rate);
+ free(data);
+ closeAudioFile(sound);
+
+ /* Check if an error occured, and clean up if so. */
+ err = alGetError();
+ if(err != AL_NO_ERROR)
+ {
+ fprintf(stderr, "OpenAL Error: %s\n", alGetString(err));
+ if(buffer && alIsBuffer(buffer))
+ alDeleteBuffers(1, &buffer);
+ return 0;
+ }
+
+ return buffer;
+}
+
+
+int main(int argc, char **argv)
+{
+ ALCdevice *device;
+ ALuint source, buffer;
+ const char *soundname;
+ const char *hrtfname;
+ ALCint hrtf_state;
+ ALCint num_hrtf;
+ ALdouble angle;
+ ALenum state;
+
+ /* Print out usage if no file was specified */
+ if(argc < 2 || (strcmp(argv[1], "-hrtf") == 0 && argc < 4))
+ {
+ fprintf(stderr, "Usage: %s [-hrtf <name>] <soundfile>\n", argv[0]);
+ return 1;
+ }
+
+ /* Initialize OpenAL with the default device, and check for HRTF support. */
+ if(InitAL() != 0)
+ return 1;
+
+ if(strcmp(argv[1], "-hrtf") == 0)
+ {
+ hrtfname = argv[2];
+ soundname = argv[3];
+ }
+ else
+ {
+ hrtfname = NULL;
+ soundname = argv[1];
+ }
+
+ device = alcGetContextsDevice(alcGetCurrentContext());
+ if(!alcIsExtensionPresent(device, "ALC_SOFT_HRTF"))
+ {
+ fprintf(stderr, "Error: ALC_SOFT_HRTF not supported\n");
+ CloseAL();
+ return 1;
+ }
+
+ /* Define a macro to help load the function pointers. */
+#define LOAD_PROC(d, x) ((x) = alcGetProcAddress((d), #x))
+ LOAD_PROC(device, alcGetStringiSOFT);
+ LOAD_PROC(device, alcResetDeviceSOFT);
+#undef LOAD_PROC
+
+ /* Enumerate available HRTFs, and reset the device using one. */
+ alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
+ if(!num_hrtf)
+ printf("No HRTFs found\n");
+ else
+ {
+ ALCint attr[5];
+ ALCint index = -1;
+ ALCint i;
+
+ printf("Available HRTFs:\n");
+ for(i = 0;i < num_hrtf;i++)
+ {
+ const ALCchar *name = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
+ printf(" %d: %s\n", i, name);
+
+ /* Check if this is the HRTF the user requested. */
+ if(hrtfname && strcmp(name, hrtfname) == 0)
+ index = i;
+ }
+
+ if(index == -1)
+ {
+ if(hrtfname)
+ printf("HRTF \"%s\" not found\n", hrtfname);
+ index = 0;
+ }
+ printf("Selecting HRTF %d...\n", index);
+
+ attr[0] = ALC_HRTF_SOFT;
+ attr[1] = ALC_TRUE;
+ attr[2] = ALC_HRTF_ID_SOFT;
+ attr[3] = index;
+ attr[4] = 0;
+
+ if(!alcResetDeviceSOFT(device, attr))
+ printf("Failed to reset device: %s\n", alcGetString(device, alcGetError(device)));
+ }
+
+ /* Check if HRTF is enabled, and show which is being used. */
+ alcGetIntegerv(device, ALC_HRTF_SOFT, 1, &hrtf_state);
+ if(!hrtf_state)
+ printf("HRTF not enabled!\n");
+ else
+ {
+ const ALchar *name = alcGetString(device, ALC_HRTF_SPECIFIER_SOFT);
+ printf("HRTF enabled, using %s\n", name);
+ }
+ fflush(stdout);
+
+ /* Load the sound into a buffer. */
+ buffer = LoadSound(soundname);
+ if(!buffer)
+ {
+ CloseAL();
+ return 1;
+ }
+
+ /* Create the source to play the sound with. */
+ source = 0;
+ alGenSources(1, &source);
+ alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
+ alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f);
+ alSourcei(source, AL_BUFFER, buffer);
+ assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source");
+
+ /* Play the sound until it finishes. */
+ angle = 0.0;
+ alSourcePlay(source);
+ do {
+ Sleep(10);
+
+ /* Rotate the source around the listener by about 1/4 cycle per second.
+ * Only affects mono sounds.
+ */
+ angle += 0.01 * M_PI * 0.5;
+ alSource3f(source, AL_POSITION, (ALfloat)sin(angle), 0.0f, -(ALfloat)cos(angle));
+
+ alGetSourcei(source, AL_SOURCE_STATE, &state);
+ } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING);
+
+ /* All done. Delete resources, and close OpenAL. */
+ alDeleteSources(1, &source);
+ alDeleteBuffers(1, &buffer);
+
+ CloseAL();
+
+ return 0;
+}
diff --git a/examples/alloopback.c b/examples/alloopback.c
index 2361ada1..04c92818 100644
--- a/examples/alloopback.c
+++ b/examples/alloopback.c
@@ -65,13 +65,13 @@ void SDLCALL RenderSDLSamples(void *userdata, Uint8 *stream, int len)
* buffer ID. */
static ALuint CreateSineWave(void)
{
- ALshort data[44100];
+ ALshort data[44100*4];
ALuint buffer;
ALenum err;
ALuint i;
- for(i = 0;i < 44100;i++)
- data[i] = (ALshort)(sin(i * 441.0 / 44100.0 * 2.0*M_PI)*32767.0);
+ for(i = 0;i < 44100*4;i++)
+ data[i] = (ALshort)(sin(i/44100.0 * 1000.0 * 2.0*M_PI) * 32767.0);
/* Buffer the audio data into a new buffer object. */
buffer = 0;
diff --git a/examples/altonegen.c b/examples/altonegen.c
new file mode 100644
index 00000000..65980529
--- /dev/null
+++ b/examples/altonegen.c
@@ -0,0 +1,271 @@
+/*
+ * OpenAL Tone Generator Test
+ *
+ * Copyright (c) 2015 by Chris Robinson <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This file contains a test for generating waveforms and plays them for a
+ * given length of time. Intended to inspect the behavior of the mixer by
+ * checking the output with a spectrum analyzer and oscilloscope.
+ *
+ * TODO: This would actually be nicer as a GUI app with buttons to start and
+ * stop individual waveforms, include additional whitenoise and pinknoise
+ * generators, and have the ability to hook up EFX filters and effects.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include "common/alhelpers.h"
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
+enum WaveType {
+ WT_Sine,
+ WT_Square,
+ WT_Sawtooth,
+ WT_Triangle,
+ WT_Impulse,
+};
+
+static const char *GetWaveTypeName(enum WaveType type)
+{
+ switch(type)
+ {
+ case WT_Sine: return "sine";
+ case WT_Square: return "square";
+ case WT_Sawtooth: return "sawtooth";
+ case WT_Triangle: return "triangle";
+ case WT_Impulse: return "impulse";
+ }
+ return "(unknown)";
+}
+
+static void ApplySin(ALfloat *data, ALdouble g, ALuint srate, ALuint freq)
+{
+ ALdouble smps_per_cycle = (ALdouble)srate / freq;
+ ALuint i;
+ for(i = 0;i < srate;i++)
+ data[i] += (ALfloat)(sin(i/smps_per_cycle * 2.0*M_PI) * g);
+}
+
+/* Generates waveforms using additive synthesis. Each waveform is constructed
+ * by summing one or more sine waves, up to (and excluding) nyquist.
+ */
+static ALuint CreateWave(enum WaveType type, ALuint freq, ALuint srate)
+{
+ ALint data_size;
+ ALfloat *data;
+ ALuint buffer;
+ ALenum err;
+ ALuint i;
+
+ data_size = srate * sizeof(ALfloat);
+ data = calloc(1, data_size);
+ if(type == WT_Sine)
+ ApplySin(data, 1.0, srate, freq);
+ else if(type == WT_Square)
+ for(i = 1;freq*i < srate/2;i+=2)
+ ApplySin(data, 4.0/M_PI * 1.0/i, srate, freq*i);
+ else if(type == WT_Sawtooth)
+ for(i = 1;freq*i < srate/2;i++)
+ ApplySin(data, 2.0/M_PI * ((i&1)*2 - 1.0) / i, srate, freq*i);
+ else if(type == WT_Triangle)
+ for(i = 1;freq*i < srate/2;i+=2)
+ ApplySin(data, 8.0/(M_PI*M_PI) * (1.0 - (i&2)) / (i*i), srate, freq*i);
+ else if(type == WT_Impulse)
+ {
+ /* NOTE: Impulse isn't really a waveform, but it can still be useful to
+ * test (other than resampling, the ALSOFT_DEFAULT_REVERB environment
+ * variable can prove useful here to test the reverb response).
+ */
+ for(i = 0;i < srate;i++)
+ data[i] = (i%(srate/freq)) ? 0.0f : 1.0f;
+ }
+
+ /* Buffer the audio data into a new buffer object. */
+ buffer = 0;
+ alGenBuffers(1, &buffer);
+ alBufferData(buffer, AL_FORMAT_MONO_FLOAT32, data, data_size, srate);
+ free(data);
+
+ /* Check if an error occured, and clean up if so. */
+ err = alGetError();
+ if(err != AL_NO_ERROR)
+ {
+ fprintf(stderr, "OpenAL Error: %s\n", alGetString(err));
+ if(alIsBuffer(buffer))
+ alDeleteBuffers(1, &buffer);
+ return 0;
+ }
+
+ return buffer;
+}
+
+
+int main(int argc, char *argv[])
+{
+ enum WaveType wavetype = WT_Sine;
+ ALuint source, buffer;
+ ALint last_pos, num_loops;
+ ALint max_loops = 4;
+ ALint srate = -1;
+ ALint tone_freq = 1000;
+ ALCint dev_rate;
+ ALenum state;
+ int i;
+
+ for(i = 1;i < argc;i++)
+ {
+ if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
+ {
+ fprintf(stderr, "OpenAL Tone Generator\n"
+"\n"
+"Usage: %s <options>\n"
+"\n"
+"Available options:\n"
+" --help/-h This help text\n"
+" -t <seconds> Time to play a tone (default 5 seconds)\n"
+" --waveform/-w <type> Waveform type: sine (default), square, sawtooth,\n"
+" triangle, impulse\n"
+" --freq/-f <hz> Tone frequency (default 1000 hz)\n"
+" --srate/-s <sample rate> Sampling rate (default output rate)\n",
+ argv[0]
+ );
+ return 1;
+ }
+ else if(i+1 < argc && strcmp(argv[i], "-t") == 0)
+ {
+ i++;
+ max_loops = atoi(argv[i]) - 1;
+ }
+ else if(i+1 < argc && (strcmp(argv[i], "--waveform") == 0 || strcmp(argv[i], "-w") == 0))
+ {
+ i++;
+ if(strcmp(argv[i], "sine") == 0)
+ wavetype = WT_Sine;
+ else if(strcmp(argv[i], "square") == 0)
+ wavetype = WT_Square;
+ else if(strcmp(argv[i], "sawtooth") == 0)
+ wavetype = WT_Sawtooth;
+ else if(strcmp(argv[i], "triangle") == 0)
+ wavetype = WT_Triangle;
+ else if(strcmp(argv[i], "impulse") == 0)
+ wavetype = WT_Impulse;
+ else
+ fprintf(stderr, "Unhandled waveform: %s\n", argv[i]);
+ }
+ else if(i+1 < argc && (strcmp(argv[i], "--freq") == 0 || strcmp(argv[i], "-f") == 0))
+ {
+ i++;
+ tone_freq = atoi(argv[i]);
+ if(tone_freq < 1)
+ {
+ fprintf(stderr, "Invalid tone frequency: %s (min: 1hz)\n", argv[i]);
+ tone_freq = 1;
+ }
+ }
+ else if(i+1 < argc && (strcmp(argv[i], "--srate") == 0 || strcmp(argv[i], "-s") == 0))
+ {
+ i++;
+ srate = atoi(argv[i]);
+ if(srate < 40)
+ {
+ fprintf(stderr, "Invalid sample rate: %s (min: 40hz)\n", argv[i]);
+ srate = 40;
+ }
+ }
+ }
+
+ InitAL();
+
+ if(!alIsExtensionPresent("AL_EXT_FLOAT32"))
+ {
+ fprintf(stderr, "Required AL_EXT_FLOAT32 extension not supported on this device!\n");
+ CloseAL();
+ return 1;
+ }
+
+ {
+ ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
+ alcGetIntegerv(device, ALC_FREQUENCY, 1, &dev_rate);
+ assert(alcGetError(device)==ALC_NO_ERROR && "Failed to get device sample rate");
+ }
+ if(srate < 0)
+ srate = dev_rate;
+
+ /* Load the sound into a buffer. */
+ buffer = CreateWave(wavetype, tone_freq, srate);
+ if(!buffer)
+ {
+ CloseAL();
+ return 1;
+ }
+
+ printf("Playing %dhz %s-wave tone with %dhz sample rate and %dhz output, for %d second%s...\n",
+ tone_freq, GetWaveTypeName(wavetype), srate, dev_rate, max_loops+1, max_loops?"s":"");
+ fflush(stdout);
+
+ /* Create the source to play the sound with. */
+ source = 0;
+ alGenSources(1, &source);
+ alSourcei(source, AL_BUFFER, buffer);
+ assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source");
+
+ /* Play the sound for a while. */
+ num_loops = 0;
+ last_pos = 0;
+ alSourcei(source, AL_LOOPING, (max_loops > 0) ? AL_TRUE : AL_FALSE);
+ alSourcePlay(source);
+ do {
+ ALint pos;
+ Sleep(10);
+ alGetSourcei(source, AL_SAMPLE_OFFSET, &pos);
+ alGetSourcei(source, AL_SOURCE_STATE, &state);
+ if(pos < last_pos && state == AL_PLAYING)
+ {
+ ++num_loops;
+ if(num_loops >= max_loops)
+ alSourcei(source, AL_LOOPING, AL_FALSE);
+ printf("%d...\n", max_loops - num_loops + 1);
+ fflush(stdout);
+ }
+ last_pos = pos;
+ } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING);
+
+ /* All done. Delete resources, and close OpenAL. */
+ alDeleteSources(1, &source);
+ alDeleteBuffers(1, &buffer);
+
+ /* Close up OpenAL. */
+ CloseAL();
+
+ return 0;
+}
diff --git a/hrtf.txt b/hrtf.txt
index e19fb0b8..37a329d2 100644
--- a/hrtf.txt
+++ b/hrtf.txt
@@ -14,7 +14,7 @@ sides.
The default data set is based on the KEMAR HRTF data provided by MIT, which can
be found at <http://sound.media.mit.edu/resources/KEMAR.html>. It's only
-available when using 44100hz playback.
+available when using 44100hz or 48000hz playback.
Custom HRTF Data Sets
diff --git a/hrtf/default-48000.mhr b/hrtf/default-48000.mhr
new file mode 100644
index 00000000..0ad547ad
--- /dev/null
+++ b/hrtf/default-48000.mhr
Binary files differ
diff --git a/include/AL/alext.h b/include/AL/alext.h
index 33f3a034..6af581aa 100644
--- a/include/AL/alext.h
+++ b/include/AL/alext.h
@@ -13,8 +13,8 @@
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* Or go to http://www.gnu.org/copyleft/lgpl.html
*/
@@ -370,6 +370,67 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void);
#define AL_PACK_BLOCK_ALIGNMENT_SOFT 0x200D
#endif
+#ifndef AL_SOFT_MSADPCM
+#define AL_SOFT_MSADPCM 1
+#define AL_FORMAT_MONO_MSADPCM_SOFT 0x1302
+#define AL_FORMAT_STEREO_MSADPCM_SOFT 0x1303
+#endif
+
+#ifndef AL_SOFT_source_length
+#define AL_SOFT_source_length 1
+/*#define AL_BYTE_LENGTH_SOFT 0x2009*/
+/*#define AL_SAMPLE_LENGTH_SOFT 0x200A*/
+/*#define AL_SEC_LENGTH_SOFT 0x200B*/
+#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);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device);
+ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device);
+#endif
+#endif
+
+#ifndef AL_EXT_BFORMAT
+#define AL_EXT_BFORMAT 1
+#define AL_FORMAT_BFORMAT2D_8 0x20021
+#define AL_FORMAT_BFORMAT2D_16 0x20022
+#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023
+#define AL_FORMAT_BFORMAT3D_8 0x20031
+#define AL_FORMAT_BFORMAT3D_16 0x20032
+#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033
+#endif
+
+#ifndef AL_EXT_MULAW_BFORMAT
+#define AL_EXT_MULAW_BFORMAT 1
+#define AL_FORMAT_BFORMAT2D_MULAW 0x10031
+#define AL_FORMAT_BFORMAT3D_MULAW 0x10032
+#endif
+
+#ifndef ALC_SOFT_HRTF
+#define ALC_SOFT_HRTF 1
+#define ALC_HRTF_SOFT 0x1992
+#define ALC_DONT_CARE_SOFT 0x0002
+#define ALC_HRTF_STATUS_SOFT 0x1993
+#define ALC_HRTF_DISABLED_SOFT 0x0000
+#define ALC_HRTF_ENABLED_SOFT 0x0001
+#define ALC_HRTF_DENIED_SOFT 0x0002
+#define ALC_HRTF_REQUIRED_SOFT 0x0003
+#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004
+#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005
+#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994
+#define ALC_HRTF_SPECIFIER_SOFT 0x1995
+#define ALC_HRTF_ID_SOFT 0x1996
+typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index);
+typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index);
+ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/include/AL/efx-presets.h b/include/AL/efx-presets.h
index 86dcbda2..8539fd51 100644
--- a/include/AL/efx-presets.h
+++ b/include/AL/efx-presets.h
@@ -345,7 +345,7 @@ typedef struct {
/* Driving Presets */
#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \
- { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+ { 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \
{ 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }
diff --git a/include/align.h b/include/align.h
index babd4106..e2dc81df 100644
--- a/include/align.h
+++ b/include/align.h
@@ -1,16 +1,16 @@
#ifndef AL_ALIGN_H
#define AL_ALIGN_H
-#ifdef HAVE_STDALIGN_H
+#if defined(HAVE_STDALIGN_H) && defined(HAVE_C11_ALIGNAS)
#include <stdalign.h>
#endif
#ifndef alignas
-#ifdef HAVE_C11_ALIGNAS
-#define alignas _Alignas
-#elif defined(IN_IDE_PARSER)
+#if defined(IN_IDE_PARSER)
/* KDevelop has problems with our align macro, so just use nothing for parsing. */
#define alignas(x)
+#elif defined(HAVE_C11_ALIGNAS)
+#define alignas _Alignas
#else
/* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For
* maximum compatibility, only provide constant integer values to alignas. */
diff --git a/include/atomic.h b/include/atomic.h
index 4adb7a94..8eb6820b 100644
--- a/include/atomic.h
+++ b/include/atomic.h
@@ -2,204 +2,330 @@
#define AL_ATOMIC_H
#include "static_assert.h"
+#include "bool.h"
#ifdef __cplusplus
extern "C" {
#endif
-typedef void *volatile XchgPtr;
+/* Atomics using C11 */
+#ifdef HAVE_C11_ATOMIC
-typedef unsigned int uint;
-typedef union {
- uint value;
-} RefCount;
-
-#define STATIC_REFCOUNT_INIT(V) {(V)}
-
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
-
-inline void InitRef(volatile RefCount *ptr, uint value)
-{ ptr->value = value; }
-inline uint ReadRef(volatile RefCount *ptr)
-{ __sync_synchronize(); return ptr->value; }
-inline uint IncrementRef(volatile RefCount *ptr)
-{ return __sync_add_and_fetch(&ptr->value, 1); }
-inline uint DecrementRef(volatile RefCount *ptr)
-{ return __sync_sub_and_fetch(&ptr->value, 1); }
-inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
-{ return __sync_lock_test_and_set(&ptr->value, newval); }
-inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
-{ return __sync_val_compare_and_swap(&ptr->value, oldval, newval); }
+#include <stdatomic.h>
-inline int ExchangeInt(volatile int *ptr, int newval)
-{ return __sync_lock_test_and_set(ptr, newval); }
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{ return __sync_lock_test_and_set(ptr, newval); }
-inline int CompExchangeInt(volatile int *ptr, int oldval, int newval)
-{ return __sync_val_compare_and_swap(ptr, oldval, newval); }
-inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
-{ return __sync_val_compare_and_swap(ptr, oldval, newval); }
+#define almemory_order memory_order
+#define almemory_order_relaxed memory_order_relaxed
+#define almemory_order_consume memory_order_consume
+#define almemory_order_acquire memory_order_acquire
+#define almemory_order_release memory_order_release
+#define almemory_order_acq_rel memory_order_acq_rel
+#define almemory_order_seq_cst memory_order_seq_cst
+
+#define ATOMIC(T) T _Atomic
+
+#define ATOMIC_INIT(_val, _newval) atomic_init((_val), (_newval))
+#define ATOMIC_INIT_STATIC(_newval) ATOMIC_VAR_INIT(_newval)
+
+#define PARAM2(f, a, b, ...) (f((a), (b)))
+#define PARAM3(f, a, b, c, ...) (f((a), (b), (c)))
+#define PARAM5(f, a, b, c, d, e, ...) (f((a), (b), (c), (d), (e)))
+
+#define ATOMIC_LOAD(...) PARAM2(atomic_load_explicit, __VA_ARGS__, memory_order_seq_cst)
+#define ATOMIC_STORE(...) PARAM3(atomic_store_explicit, __VA_ARGS__, memory_order_seq_cst)
+
+#define ATOMIC_ADD(T, ...) PARAM3(atomic_fetch_add_explicit, __VA_ARGS__, memory_order_seq_cst)
+#define ATOMIC_SUB(T, ...) PARAM3(atomic_fetch_sub_explicit, __VA_ARGS__, memory_order_seq_cst)
+
+#define ATOMIC_EXCHANGE(T, ...) PARAM3(atomic_exchange_explicit, __VA_ARGS__, memory_order_seq_cst)
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, ...) \
+ PARAM5(atomic_compare_exchange_strong_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst)
+#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...) \
+ PARAM5(atomic_compare_exchange_weak_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst)
+/* Atomics using GCC intrinsics */
+#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
+
+enum almemory_order {
+ almemory_order_relaxed,
+ almemory_order_consume,
+ almemory_order_acquire,
+ almemory_order_release,
+ almemory_order_acq_rel,
+ almemory_order_seq_cst
+};
+
+#define ATOMIC(T) struct { T volatile value; }
+
+#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
+#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
+
+#define ATOMIC_LOAD(_val, ...) __extension__({ \
+ __typeof((_val)->value) _r = (_val)->value; \
+ __asm__ __volatile__("" ::: "memory"); \
+ _r; \
+})
+#define ATOMIC_STORE(_val, _newval, ...) do { \
+ __asm__ __volatile__("" ::: "memory"); \
+ (_val)->value = (_newval); \
+} while(0)
+
+#define ATOMIC_ADD(T, _val, _incr, ...) __extension__({ \
+ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
+ __sync_fetch_and_add(&(_val)->value, (_incr)); \
+})
+#define ATOMIC_SUB(T, _val, _decr, ...) __extension__({ \
+ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
+ __sync_fetch_and_sub(&(_val)->value, (_decr)); \
+})
+
+#define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \
+ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
+ __sync_lock_test_and_set(&(_val)->value, (_newval)); \
+})
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \
+ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
+ T _o = *(_oldval); \
+ *(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \
+ *(_oldval) == _o; \
+})
+
+/* Atomics using x86/x86-64 GCC inline assembly */
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-inline uint xaddl(volatile uint *dest, int incr)
-{
- unsigned int ret;
- __asm__ __volatile__("lock; xaddl %0,(%1)"
- : "=r" (ret)
- : "r" (dest), "0" (incr)
- : "memory");
- return ret;
-}
+#define WRAP_ADD(ret, dest, incr) __asm__ __volatile__( \
+ "lock; xaddl %0,(%1)" \
+ : "=r" (ret) \
+ : "r" (dest), "0" (incr) \
+ : "memory" \
+)
+#define WRAP_SUB(ret, dest, decr) __asm__ __volatile__( \
+ "lock; xaddl %0,(%1)" \
+ : "=r" (ret) \
+ : "r" (dest), "0" (-(decr)) \
+ : "memory" \
+)
-inline void InitRef(volatile RefCount *ptr, uint value)
-{ ptr->value = value; }
-inline uint ReadRef(volatile RefCount *ptr)
-{ __asm__ __volatile__("" ::: "memory"); return ptr->value; }
-inline uint IncrementRef(volatile RefCount *ptr)
-{ return xaddl(&ptr->value, 1)+1; }
-inline uint DecrementRef(volatile RefCount *ptr)
-{ return xaddl(&ptr->value, -1)-1; }
-inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
-{
- int ret;
- __asm__ __volatile__("lock; xchgl %0,(%1)"
- : "=r" (ret)
- : "r" (&ptr->value), "0" (newval)
- : "memory");
- return ret;
-}
-inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
-{
- int ret;
- __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
- : "=a" (ret)
- : "r" (&ptr->value), "r" (newval), "0" (oldval)
- : "memory");
- return ret;
-}
+#define WRAP_XCHG(S, ret, dest, newval) __asm__ __volatile__( \
+ "lock; xchg"S" %0,(%1)" \
+ : "=r" (ret) \
+ : "r" (dest), "0" (newval) \
+ : "memory" \
+)
+#define WRAP_CMPXCHG(S, ret, dest, oldval, newval) __asm__ __volatile__( \
+ "lock; cmpxchg"S" %2,(%1)" \
+ : "=a" (ret) \
+ : "r" (dest), "r" (newval), "0" (oldval) \
+ : "memory" \
+)
-inline int ExchangeInt(volatile int *dest, int newval)
-{
- int ret;
- __asm__ __volatile__("lock; xchgl %0,(%1)"
- : "=r" (ret)
- : "r" (dest), "0" (newval)
- : "memory");
- return ret;
-}
-inline void *ExchangePtr(XchgPtr *dest, void *newval)
-{
- void *ret;
- __asm__ __volatile__(
-#ifdef __i386__
- "lock; xchgl %0,(%1)"
-#else
- "lock; xchgq %0,(%1)"
-#endif
- : "=r" (ret)
- : "r" (dest), "0" (newval)
- : "memory"
- );
- return ret;
-}
-inline int CompExchangeInt(volatile int *dest, int oldval, int newval)
-{
- int ret;
- __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
- : "=a" (ret)
- : "r" (dest), "r" (newval), "0" (oldval)
- : "memory");
- return ret;
-}
-inline void *CompExchangePtr(XchgPtr *dest, void *oldval, void *newval)
-{
- void *ret;
- __asm__ __volatile__(
-#ifdef __i386__
- "lock; cmpxchgl %2,(%1)"
-#else
- "lock; cmpxchgq %2,(%1)"
-#endif
- : "=a" (ret)
- : "r" (dest), "r" (newval), "0" (oldval)
- : "memory"
- );
- return ret;
-}
+enum almemory_order {
+ almemory_order_relaxed,
+ almemory_order_consume,
+ almemory_order_acquire,
+ almemory_order_release,
+ almemory_order_acq_rel,
+ almemory_order_seq_cst
+};
+
+#define ATOMIC(T) struct { T volatile value; }
+
+#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
+#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
+
+#define ATOMIC_LOAD(_val, ...) __extension__({ \
+ __typeof((_val)->value) _r = (_val)->value; \
+ __asm__ __volatile__("" ::: "memory"); \
+ _r; \
+})
+#define ATOMIC_STORE(_val, _newval, ...) do { \
+ __asm__ __volatile__("" ::: "memory"); \
+ (_val)->value = (_newval); \
+} while(0)
+
+#define ATOMIC_ADD(T, _val, _incr, ...) __extension__({ \
+ static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \
+ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
+ T _r; \
+ WRAP_ADD(_r, &(_val)->value, (T)(_incr)); \
+ _r; \
+})
+#define ATOMIC_SUB(T, _val, _decr, ...) __extension__({ \
+ static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \
+ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
+ T _r; \
+ WRAP_SUB(_r, &(_val)->value, (T)(_decr)); \
+ _r; \
+})
+
+#define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \
+ static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \
+ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
+ T _r; \
+ if(sizeof(T) == 4) WRAP_XCHG("l", _r, &(_val)->value, (T)(_newval)); \
+ else if(sizeof(T) == 8) WRAP_XCHG("q", _r, &(_val)->value, (T)(_newval)); \
+ _r; \
+})
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \
+ static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \
+ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
+ T _old = *(_oldval); \
+ if(sizeof(T) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (T)(_newval)); \
+ else if(sizeof(T) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (T)(_newval)); \
+ *(_oldval) == _old; \
+})
+
+/* Atomics using Windows methods */
#elif defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-static_assert(sizeof(LONG)==sizeof(uint), "sizeof LONG does not match sizeof uint");
+/* NOTE: This mess is *extremely* noisy, at least on GCC. It works by wrapping
+ * Windows' 32-bit and 64-bit atomic methods, which are then casted to use the
+ * given type based on its size (e.g. int and float use 32-bit atomics). This
+ * is fine for the swap and compare-and-swap methods, although the add and
+ * subtract methods only work properly for integer types.
+ *
+ * Despite how noisy it is, it's unfortunately the only way that doesn't rely
+ * on C99 (damn MSVC).
+ */
-inline void InitRef(volatile RefCount *ptr, uint value)
-{ ptr->value = value; }
-inline uint ReadRef(volatile RefCount *ptr)
-{ _ReadBarrier(); return ptr->value; }
-inline uint IncrementRef(volatile RefCount *ptr)
+inline LONG AtomicAdd32(volatile LONG *dest, LONG incr)
{
- union {
- volatile uint *u;
- volatile LONG *l;
- } u = { &ptr->value };
- return InterlockedIncrement(u.l);
+ return InterlockedExchangeAdd(dest, incr);
}
-inline uint DecrementRef(volatile RefCount *ptr)
+inline LONG AtomicSub32(volatile LONG *dest, LONG decr)
{
- union {
- volatile uint *u;
- volatile LONG *l;
- } u = { &ptr->value };
- return InterlockedDecrement(u.l);
+ return InterlockedExchangeAdd(dest, -decr);
}
-inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
+
+inline LONG AtomicSwap32(volatile LONG *dest, LONG newval)
{
- union {
- volatile uint *i;
- volatile LONG *l;
- } u = { &ptr->value };
- return InterlockedExchange(u.l, newval);
+ return InterlockedExchange(dest, newval);
}
-inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
+inline LONGLONG AtomicSwap64(volatile LONGLONG *dest, LONGLONG newval)
{
- union {
- volatile uint *i;
- volatile LONG *l;
- } u = { &ptr->value };
- return InterlockedCompareExchange(u.l, newval, oldval);
+ return InterlockedExchange64(dest, newval);
}
-inline int ExchangeInt(volatile int *ptr, int newval)
+inline bool CompareAndSwap32(volatile LONG *dest, LONG newval, LONG *oldval)
{
- union {
- volatile int *i;
- volatile LONG *l;
- } u = { ptr };
- return InterlockedExchange(u.l, newval);
+ LONG old = *oldval;
+ *oldval = InterlockedCompareExchange(dest, newval, *oldval);
+ return old == *oldval;
}
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
+inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG *oldval)
{
- return InterlockedExchangePointer(ptr, newval);
+ LONGLONG old = *oldval;
+ *oldval = InterlockedCompareExchange64(dest, newval, *oldval);
+ return old == *oldval;
}
-inline int CompExchangeInt(volatile int *ptr, int oldval, int newval)
+
+#define WRAP_ADDSUB(T, _func, _ptr, _amnt) ((T(*)(T volatile*,T))_func)((_ptr), (_amnt))
+#define WRAP_XCHG(T, _func, _ptr, _newval) ((T(*)(T volatile*,T))_func)((_ptr), (_newval))
+#define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) ((bool(*)(T volatile*,T,T*))_func)((_ptr), (_newval), (_oldval))
+
+
+enum almemory_order {
+ almemory_order_relaxed,
+ almemory_order_consume,
+ almemory_order_acquire,
+ almemory_order_release,
+ almemory_order_acq_rel,
+ almemory_order_seq_cst
+};
+
+#define ATOMIC(T) struct { T volatile value; }
+
+#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
+#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
+
+#define ATOMIC_LOAD(_val, ...) ((_val)->value)
+#define ATOMIC_STORE(_val, _newval, ...) do { \
+ (_val)->value = (_newval); \
+} while(0)
+
+int _al_invalid_atomic_size(); /* not defined */
+
+#define ATOMIC_ADD(T, _val, _incr, ...) \
+ ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicAdd32, &(_val)->value, (_incr)) : \
+ (T)_al_invalid_atomic_size())
+#define ATOMIC_SUB(T, _val, _decr, ...) \
+ ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicSub32, &(_val)->value, (_decr)) : \
+ (T)_al_invalid_atomic_size())
+
+#define ATOMIC_EXCHANGE(T, _val, _newval, ...) \
+ ((sizeof(T)==4) ? WRAP_XCHG(T, AtomicSwap32, &(_val)->value, (_newval)) : \
+ (sizeof(T)==8) ? WRAP_XCHG(T, AtomicSwap64, &(_val)->value, (_newval)) : \
+ (T)_al_invalid_atomic_size())
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) \
+ ((sizeof(T)==4) ? WRAP_CMPXCHG(T, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \
+ (sizeof(T)==8) ? WRAP_CMPXCHG(T, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \
+ (bool)_al_invalid_atomic_size())
+
+#else
+
+#error "No atomic functions available on this platform!"
+
+#define ATOMIC(T) T
+
+#define ATOMIC_INIT_STATIC(_newval) (0)
+
+#define ATOMIC_LOAD_UNSAFE(_val) (0)
+#define ATOMIC_STORE_UNSAFE(_val, _newval) ((void)0)
+
+#define ATOMIC_LOAD(_val, ...) (0)
+#define ATOMIC_STORE(_val, _newval, ...) ((void)0)
+
+#define ATOMIC_ADD(T, _val, _incr, ...) (0)
+#define ATOMIC_SUB(T, _val, _decr, ...) (0)
+
+#define ATOMIC_EXCHANGE(T, _val, _newval, ...) (0)
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) (0)
+#endif
+
+/* If no weak cmpxchg is provided (not all systems will have one), substitute a
+ * strong cmpxchg. */
+#ifndef ATOMIC_COMPARE_EXCHANGE_WEAK
+#define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG
+#endif
+
+
+typedef unsigned int uint;
+typedef ATOMIC(uint) RefCount;
+
+inline void InitRef(RefCount *ptr, uint value)
+{ ATOMIC_INIT(ptr, value); }
+inline uint ReadRef(RefCount *ptr)
+{ return ATOMIC_LOAD(ptr); }
+inline uint IncrementRef(RefCount *ptr)
+{ return ATOMIC_ADD(uint, ptr, 1)+1; }
+inline uint DecrementRef(RefCount *ptr)
+{ return ATOMIC_SUB(uint, ptr, 1)-1; }
+
+
+/* NOTE: Not atomic! */
+inline int ExchangeInt(volatile int *ptr, int newval)
{
- union {
- volatile int *i;
- volatile LONG *l;
- } u = { ptr };
- return InterlockedCompareExchange(u.l, newval, oldval);
+ int old = *ptr;
+ *ptr = newval;
+ return old;
}
-inline void *CompExchangePtr(XchgPtr *ptr, void *oldval, void *newval)
+
+typedef void *volatile XchgPtr;
+/* NOTE: Not atomic! */
+inline void *ExchangePtr(XchgPtr *ptr, void *newval)
{
- return InterlockedCompareExchangePointer(ptr, newval, oldval);
+ void *old = *ptr;
+ *ptr = newval;
+ return old;
}
-#else
-#error "No atomic functions available on this platform!"
-#endif
+/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non-
+ * atomic variables. */
+#define COMPARE_EXCHANGE(_val, _oldval, _newval) ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false))
+
#ifdef __cplusplus
}
diff --git a/include/math_defs.h b/include/math_defs.h
new file mode 100644
index 00000000..149cf80b
--- /dev/null
+++ b/include/math_defs.h
@@ -0,0 +1,19 @@
+#ifndef AL_MATH_DEFS_H
+#define AL_MATH_DEFS_H
+
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+
+#define F_PI (3.14159265358979323846f)
+#define F_PI_2 (1.57079632679489661923f)
+#define F_TAU (6.28318530717958647692f)
+
+#ifndef FLT_EPSILON
+#define FLT_EPSILON (1.19209290e-07f)
+#endif
+
+#define DEG2RAD(x) ((ALfloat)(x) * (F_PI/180.0f))
+#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI))
+
+#endif /* AL_MATH_DEFS_H */
diff --git a/include/rwlock.h b/include/rwlock.h
index 03482515..158a0670 100644
--- a/include/rwlock.h
+++ b/include/rwlock.h
@@ -11,11 +11,13 @@ extern "C" {
typedef struct {
RefCount read_count;
RefCount write_count;
- volatile int read_lock;
- volatile int read_entry_lock;
- volatile int write_lock;
+ ATOMIC(int) read_lock;
+ ATOMIC(int) read_entry_lock;
+ ATOMIC(int) write_lock;
} RWLock;
-#define RWLOCK_STATIC_INITIALIZE { STATIC_REFCOUNT_INIT(0), STATIC_REFCOUNT_INIT(0), false, false, false }
+#define RWLOCK_STATIC_INITIALIZE { ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \
+ ATOMIC_INIT_STATIC(false), ATOMIC_INIT_STATIC(false), \
+ ATOMIC_INIT_STATIC(false) }
void RWLockInit(RWLock *lock);
void ReadLock(RWLock *lock);
diff --git a/include/static_assert.h b/include/static_assert.h
index 65283cf0..bf0ce065 100644
--- a/include/static_assert.h
+++ b/include/static_assert.h
@@ -10,7 +10,11 @@
#else
#define CTASTR2(_pre,_post) _pre##_post
#define CTASTR(_pre,_post) CTASTR2(_pre,_post)
+#if defined(__COUNTER__)
#define static_assert(_cond, _msg) typedef struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } CTASTR(static_assertion_,__COUNTER__)
+#else
+#define static_assert(_cond, _msg) struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); }
+#endif
#endif
#endif
diff --git a/include/threads.h b/include/threads.h
index 25a75625..a11405f7 100644
--- a/include/threads.h
+++ b/include/threads.h
@@ -33,7 +33,7 @@ typedef void (*altss_dtor_t)(void*);
#include <windows.h>
-#ifndef _TIMESPEC_DEFINED
+#if !defined(_TIMESPEC_DEFINED) && !(defined(_MSC_VER) && (_MSC_VER >= 1900))
#define _TIMESPEC_DEFINED
struct timespec {
time_t tv_sec;
@@ -234,7 +234,7 @@ void altss_delete(altss_t tss_id);
int altimespec_get(struct timespec *ts, int base);
-void al_nssleep(time_t sec, long nsec);
+void al_nssleep(unsigned long nsec);
#ifdef __cplusplus
}
diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp
index 0047233f..01f59e4b 100644
--- a/utils/alsoft-config/mainwindow.cpp
+++ b/utils/alsoft-config/mainwindow.cpp
@@ -1,3 +1,6 @@
+
+#include "config.h"
+
#include <QFileDialog>
#include <QMessageBox>
#include <QSettings>
@@ -10,26 +13,92 @@ static const struct {
char backend_name[16];
char menu_string[32];
} backendMenuList[] = {
-#ifdef Q_OS_WIN32
- { "mmdevapi", "Add MMDevAPI" },
- { "dsound", "Add DirectSound" },
- { "winmm", "Add Windows Multimedia" },
-#endif
-#ifdef Q_OS_MAC
- { "core", "Add CoreAudio" },
+#ifdef HAVE_JACK
+ { "jack", "Add JACK" },
#endif
+#ifdef HAVE_PULSEAUDIO
{ "pulse", "Add PulseAudio" },
-#ifdef Q_OS_UNIX
+#endif
+#ifdef HAVE_ALSA
{ "alsa", "Add ALSA" },
+#endif
+#ifdef HAVE_COREAUDIO
+ { "core", "Add CoreAudio" },
+#endif
+#ifdef HAVE_OSS
{ "oss", "Add OSS" },
+#endif
+#ifdef HAVE_SOLARIS
{ "solaris", "Add Solaris" },
+#endif
+#ifdef HAVE_SNDIO
{ "sndio", "Add SndIO" },
+#endif
+#ifdef HAVE_QSA
{ "qsa", "Add QSA" },
#endif
+#ifdef HAVE_MMDEVAPI
+ { "mmdevapi", "Add MMDevAPI" },
+#endif
+#ifdef HAVE_DSOUND
+ { "dsound", "Add DirectSound" },
+#endif
+#ifdef HAVE_WINMM
+ { "winmm", "Add Windows Multimedia" },
+#endif
+#ifdef HAVE_PORTAUDIO
{ "port", "Add PortAudio" },
+#endif
+#ifdef HAVE_OPENSL
{ "opensl", "Add OpenSL" },
+#endif
+
{ "null", "Add Null Output" },
+#ifdef HAVE_WAVE
{ "wave", "Add Wave Writer" },
+#endif
+ { "", "" }
+};
+
+static const struct {
+ const char name[64];
+ const char value[16];
+} speakerModeList[] = {
+ { "Autodetect", "" },
+ { "Mono", "mono" },
+ { "Stereo", "stereo" },
+ { "Quadrophonic", "quad" },
+ { "5.1 Surround (Side)", "surround51" },
+ { "5.1 Surround (Rear)", "surround51rear" },
+ { "6.1 Surround", "surround61" },
+ { "7.1 Surround", "surround71" },
+
+ { "", "" }
+}, sampleTypeList[] = {
+ { "Autodetect", "" },
+ { "8-bit int", "int8" },
+ { "8-bit uint", "uint8" },
+ { "16-bit int", "int16" },
+ { "16-bit uint", "uint16" },
+ { "32-bit int", "int32" },
+ { "32-bit uint", "uint32" },
+ { "32-bit float", "float32" },
+
+ { "", "" }
+}, resamplerList[] = {
+ { "Default", "" },
+ { "Point (low quality, very fast)", "point" },
+ { "Linear (basic quality, fast)", "linear" },
+ { "4-Point Sinc (good quality)", "sinc4" },
+ { "8-Point Sinc (high quality, slow)", "sinc8" },
+ { "Band-limited Sinc (very high quality, very slow)", "bsinc" },
+
+ { "", "" }
+}, stereoModeList[] = {
+ { "Autodetect", "" },
+ { "Speakers", "speakers" },
+ { "Headphones", "headphones" },
+
{ "", "" }
};
@@ -52,6 +121,48 @@ static QString getDefaultConfigName()
return base +'/'+ fname;
return fname;
}
+
+static QString getBaseDataPath()
+{
+#ifdef Q_OS_WIN32
+ QByteArray base = qgetenv("AppData");
+#else
+ QByteArray base = qgetenv("XDG_DATA_HOME");
+ if(base.isEmpty())
+ {
+ base = qgetenv("HOME");
+ if(!base.isEmpty())
+ base += "/.local/share";
+ }
+#endif
+ return base;
+}
+
+static QStringList getAllDataPaths(QString append=QString())
+{
+ QStringList list;
+ list.append(getBaseDataPath());
+#ifdef Q_OS_WIN32
+ // TODO: Common AppData path
+#else
+ QString paths = qgetenv("XDG_DATA_DIRS");
+ if(paths.isEmpty())
+ paths = "/usr/local/share/:/usr/share/";
+ list += paths.split(QChar(':'), QString::SkipEmptyParts);
+#endif
+ QStringList::iterator iter = list.begin();
+ while(iter != list.end())
+ {
+ if(iter->isEmpty())
+ iter = list.erase(iter);
+ else
+ {
+ iter->append(append);
+ iter++;
+ }
+ }
+ return list;
+}
}
MainWindow::MainWindow(QWidget *parent) :
@@ -62,11 +173,65 @@ MainWindow::MainWindow(QWidget *parent) :
mSourceCountValidator(NULL),
mEffectSlotValidator(NULL),
mSourceSendValidator(NULL),
- mSampleRateValidator(NULL),
- mReverbBoostValidator(NULL)
+ mSampleRateValidator(NULL)
{
ui->setupUi(this);
+ for(int i = 0;speakerModeList[i].name[0];i++)
+ ui->channelConfigCombo->addItem(speakerModeList[i].name);
+ ui->channelConfigCombo->adjustSize();
+ for(int i = 0;sampleTypeList[i].name[0];i++)
+ ui->sampleFormatCombo->addItem(sampleTypeList[i].name);
+ ui->sampleFormatCombo->adjustSize();
+ for(int i = 0;resamplerList[i].name[0];i++)
+ ui->resamplerComboBox->addItem(resamplerList[i].name);
+ ui->resamplerComboBox->adjustSize();
+ for(int i = 0;stereoModeList[i].name[0];i++)
+ ui->stereoModeCombo->addItem(stereoModeList[i].name);
+ ui->stereoModeCombo->adjustSize();
+
+ ui->hrtfStateComboBox->adjustSize();
+
+#if !defined(HAVE_NEON) && !defined(HAVE_SSE)
+ ui->cpuExtDisabledLabel->move(ui->cpuExtDisabledLabel->x(), ui->cpuExtDisabledLabel->y() - 60);
+#else
+ ui->cpuExtDisabledLabel->setVisible(false);
+#endif
+
+#ifndef HAVE_NEON
+
+#ifndef HAVE_SSE4_1
+#ifndef HAVE_SSE3
+#ifndef HAVE_SSE2
+#ifndef HAVE_SSE
+ ui->enableSSECheckBox->setVisible(false);
+#endif /* !SSE */
+ ui->enableSSE2CheckBox->setVisible(false);
+#endif /* !SSE2 */
+ ui->enableSSE3CheckBox->setVisible(false);
+#endif /* !SSE3 */
+ ui->enableSSE41CheckBox->setVisible(false);
+#endif /* !SSE4.1 */
+ ui->enableNeonCheckBox->setVisible(false);
+
+#else /* !Neon */
+
+#ifndef HAVE_SSE4_1
+#ifndef HAVE_SSE3
+#ifndef HAVE_SSE2
+#ifndef HAVE_SSE
+ ui->enableNeonCheckBox->move(ui->enableNeonCheckBox->x(), ui->enableNeonCheckBox->y() - 30);
+ ui->enableSSECheckBox->setVisible(false);
+#endif /* !SSE */
+ ui->enableSSE2CheckBox->setVisible(false);
+#endif /* !SSE2 */
+ ui->enableSSE3CheckBox->setVisible(false);
+#endif /* !SSE3 */
+ ui->enableSSE41CheckBox->setVisible(false);
+#endif /* !SSE4.1 */
+
+#endif
+
mPeriodSizeValidator = new QIntValidator(64, 8192, this);
ui->periodSizeEdit->setValidator(mPeriodSizeValidator);
mPeriodCountValidator = new QIntValidator(2, 16, this);
@@ -81,9 +246,6 @@ MainWindow::MainWindow(QWidget *parent) :
mSampleRateValidator = new QIntValidator(8000, 192000, this);
ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator);
- mReverbBoostValidator = new QDoubleValidator(-12.0, +12.0, 1, this);
- ui->reverbBoostEdit->setValidator(mReverbBoostValidator);
-
connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile()));
connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile()));
@@ -104,9 +266,6 @@ MainWindow::MainWindow(QWidget *parent) :
ui->disabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->disabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDisabledBackendMenu(QPoint)));
- connect(ui->reverbBoostSlider, SIGNAL(valueChanged(int)), this, SLOT(updateReverbBoostEdit(int)));
- connect(ui->reverbBoostEdit, SIGNAL(textEdited(QString)), this, SLOT(updateReverbBoostSlider(QString)));
-
loadConfig(getDefaultConfigName());
}
@@ -119,7 +278,6 @@ MainWindow::~MainWindow()
delete mEffectSlotValidator;
delete mSourceSendValidator;
delete mSampleRateValidator;
- delete mReverbBoostValidator;
}
void MainWindow::loadConfigFromFile()
@@ -137,12 +295,19 @@ void MainWindow::loadConfig(const QString &fname)
ui->sampleFormatCombo->setCurrentIndex(0);
if(sampletype.isEmpty() == false)
{
- for(int i = 1;i < ui->sampleFormatCombo->count();i++)
+ for(int i = 0;sampleTypeList[i].name[i];i++)
{
- QString item = ui->sampleFormatCombo->itemText(i);
- if(item.startsWith(sampletype))
+ if(sampletype == sampleTypeList[i].value)
{
- ui->sampleFormatCombo->setCurrentIndex(i);
+ for(int j = 1;j < ui->sampleFormatCombo->count();j++)
+ {
+ QString item = ui->sampleFormatCombo->itemText(j);
+ if(item == sampleTypeList[i].name)
+ {
+ ui->sampleFormatCombo->setCurrentIndex(j);
+ break;
+ }
+ }
break;
}
}
@@ -152,12 +317,19 @@ void MainWindow::loadConfig(const QString &fname)
ui->channelConfigCombo->setCurrentIndex(0);
if(channelconfig.isEmpty() == false)
{
- for(int i = 1;i < ui->channelConfigCombo->count();i++)
+ for(int i = 0;speakerModeList[i].name[i];i++)
{
- QString item = ui->channelConfigCombo->itemText(i);
- if(item.startsWith(channelconfig))
+ if(channelconfig == speakerModeList[i].value)
{
- ui->channelConfigCombo->setCurrentIndex(i);
+ for(int j = 1;j < ui->channelConfigCombo->count();j++)
+ {
+ QString item = ui->channelConfigCombo->itemText(j);
+ if(item == speakerModeList[i].name)
+ {
+ ui->channelConfigCombo->setCurrentIndex(j);
+ break;
+ }
+ }
break;
}
}
@@ -180,18 +352,49 @@ void MainWindow::loadConfig(const QString &fname)
ui->srcSendLineEdit->insert(settings.value("sends").toString());
QString resampler = settings.value("resampler").toString().trimmed();
- if(resampler.isEmpty())
- ui->resamplerComboBox->setCurrentIndex(0);
- else
+ ui->resamplerComboBox->setCurrentIndex(0);
+ if(resampler.isEmpty() == false)
{
- for(int i = 1;i < ui->resamplerComboBox->count();i++)
+ /* The "cubic" resampler is no longer supported. It's been replaced by
+ * "sinc4". */
+ if(resampler == "cubic")
+ resampler = "sinc4";
+
+ for(int i = 0;resamplerList[i].name[i];i++)
{
- QString item = ui->resamplerComboBox->itemText(i);
- int end = item.indexOf(' ');
- if(end < 0) end = item.size();
- if(resampler.size() == end && resampler.compare(item.leftRef(end), Qt::CaseInsensitive) == 0)
+ if(resampler == resamplerList[i].value)
{
- ui->resamplerComboBox->setCurrentIndex(i);
+ for(int j = 1;j < ui->resamplerComboBox->count();j++)
+ {
+ QString item = ui->resamplerComboBox->itemText(j);
+ if(item == resamplerList[i].name)
+ {
+ ui->resamplerComboBox->setCurrentIndex(j);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ QString stereomode = settings.value("stereo-mode").toString().trimmed();
+ ui->stereoModeCombo->setCurrentIndex(0);
+ if(stereomode.isEmpty() == false)
+ {
+ for(int i = 0;stereoModeList[i].name[i];i++)
+ {
+ if(stereomode == stereoModeList[i].value)
+ {
+ for(int j = 1;j < ui->stereoModeCombo->count();j++)
+ {
+ QString item = ui->stereoModeCombo->itemText(j);
+ if(item == stereoModeList[i].name)
+ {
+ ui->stereoModeCombo->setCurrentIndex(j);
+ break;
+ }
+ }
break;
}
}
@@ -218,18 +421,20 @@ void MainWindow::loadConfig(const QString &fname)
disabledCpuExts = disabledCpuExts[0].split(QChar(','));
std::transform(disabledCpuExts.begin(), disabledCpuExts.end(),
disabledCpuExts.begin(), std::mem_fun_ref(&QString::trimmed));
- ui->disableSSECheckBox->setChecked(disabledCpuExts.contains("sse", Qt::CaseInsensitive));
- ui->disableSSE2CheckBox->setChecked(disabledCpuExts.contains("sse2", Qt::CaseInsensitive));
- ui->disableNeonCheckBox->setChecked(disabledCpuExts.contains("neon", Qt::CaseInsensitive));
+ ui->enableSSECheckBox->setChecked(!disabledCpuExts.contains("sse", Qt::CaseInsensitive));
+ ui->enableSSE2CheckBox->setChecked(!disabledCpuExts.contains("sse2", Qt::CaseInsensitive));
+ ui->enableSSE3CheckBox->setChecked(!disabledCpuExts.contains("sse3", Qt::CaseInsensitive));
+ ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive));
+ ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive));
if(settings.value("hrtf").toString() == QString())
- ui->hrtfEnableButton->setChecked(true);
+ ui->hrtfStateComboBox->setCurrentIndex(0);
else
{
if(settings.value("hrtf", true).toBool())
- ui->hrtfForceButton->setChecked(true);
+ ui->hrtfStateComboBox->setCurrentIndex(1);
else
- ui->hrtfDisableButton->setChecked(true);
+ ui->hrtfStateComboBox->setCurrentIndex(2);
}
QStringList hrtf_tables = settings.value("hrtf_tables").toStringList();
@@ -280,23 +485,22 @@ void MainWindow::loadConfig(const QString &fname)
}
ui->emulateEaxCheckBox->setChecked(settings.value("reverb/emulate-eax", false).toBool());
- ui->reverbBoostEdit->clear();
- ui->reverbBoostEdit->insert(settings.value("reverb/boost").toString());
QStringList excludefx = settings.value("excludefx").toStringList();
if(excludefx.size() == 1)
excludefx = excludefx[0].split(QChar(','));
std::transform(excludefx.begin(), excludefx.end(),
excludefx.begin(), std::mem_fun_ref(&QString::trimmed));
- ui->disableEaxReverbCheck->setChecked(excludefx.contains("eaxreverb", Qt::CaseInsensitive));
- ui->disableStdReverbCheck->setChecked(excludefx.contains("reverb", Qt::CaseInsensitive));
- ui->disableChorusCheck->setChecked(excludefx.contains("chorus", Qt::CaseInsensitive));
- ui->disableDistortionCheck->setChecked(excludefx.contains("distortion", Qt::CaseInsensitive));
- ui->disableEchoCheck->setChecked(excludefx.contains("echo", Qt::CaseInsensitive));
- ui->disableEqualizerCheck->setChecked(excludefx.contains("equalizer", Qt::CaseInsensitive));
- ui->disableFlangerCheck->setChecked(excludefx.contains("flanger", Qt::CaseInsensitive));
- ui->disableModulatorCheck->setChecked(excludefx.contains("modulator", Qt::CaseInsensitive));
- ui->disableDedicatedCheck->setChecked(excludefx.contains("dedicated", Qt::CaseInsensitive));
+ ui->enableEaxReverbCheck->setChecked(!excludefx.contains("eaxreverb", Qt::CaseInsensitive));
+ ui->enableStdReverbCheck->setChecked(!excludefx.contains("reverb", Qt::CaseInsensitive));
+ ui->enableChorusCheck->setChecked(!excludefx.contains("chorus", Qt::CaseInsensitive));
+ ui->enableCompressorCheck->setChecked(!excludefx.contains("compressor", Qt::CaseInsensitive));
+ ui->enableDistortionCheck->setChecked(!excludefx.contains("distortion", Qt::CaseInsensitive));
+ ui->enableEchoCheck->setChecked(!excludefx.contains("echo", Qt::CaseInsensitive));
+ ui->enableEqualizerCheck->setChecked(!excludefx.contains("equalizer", Qt::CaseInsensitive));
+ ui->enableFlangerCheck->setChecked(!excludefx.contains("flanger", Qt::CaseInsensitive));
+ ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive));
+ ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive));
}
void MainWindow::saveCurrentConfig()
@@ -327,15 +531,27 @@ void MainWindow::saveConfig(const QString &fname) const
}
QString str = ui->sampleFormatCombo->currentText();
- str.truncate(str.indexOf('-'));
- settings.setValue("sample-type", str.trimmed());
+ for(int i = 0;sampleTypeList[i].name[0];i++)
+ {
+ if(str == sampleTypeList[i].name)
+ {
+ settings.setValue("sample-type", sampleTypeList[i].value);
+ break;
+ }
+ }
str = ui->channelConfigCombo->currentText();
- str.truncate(str.indexOf('-'));
- settings.setValue("channels", str.trimmed());
+ for(int i = 0;speakerModeList[i].name[0];i++)
+ {
+ if(str == speakerModeList[i].name)
+ {
+ settings.setValue("channels", speakerModeList[i].value);
+ break;
+ }
+ }
uint rate = ui->sampleRateCombo->currentText().toUInt();
- if(rate == 0)
+ if(!(rate > 0))
settings.setValue("frequency", QString());
else
settings.setValue("frequency", rate);
@@ -346,26 +562,42 @@ void MainWindow::saveConfig(const QString &fname) const
settings.setValue("sources", ui->srcCountLineEdit->text());
settings.setValue("slots", ui->effectSlotLineEdit->text());
- if(ui->resamplerComboBox->currentIndex() == 0)
- settings.setValue("resampler", QString());
- else
+ str = ui->resamplerComboBox->currentText();
+ for(int i = 0;resamplerList[i].name[0];i++)
+ {
+ if(str == resamplerList[i].name)
+ {
+ settings.setValue("resampler", resamplerList[i].value);
+ break;
+ }
+ }
+
+ str = ui->stereoModeCombo->currentText();
+ for(int i = 0;stereoModeList[i].name[0];i++)
{
- str = ui->resamplerComboBox->currentText();
- settings.setValue("resampler", str.split(' ').first().toLower());
+ if(str == stereoModeList[i].name)
+ {
+ settings.setValue("stereo-mode", stereoModeList[i].value);
+ break;
+ }
}
QStringList strlist;
- if(ui->disableSSECheckBox->isChecked())
+ if(!ui->enableSSECheckBox->isChecked())
strlist.append("sse");
- if(ui->disableSSE2CheckBox->isChecked())
+ if(!ui->enableSSE2CheckBox->isChecked())
strlist.append("sse2");
- if(ui->disableNeonCheckBox->isChecked())
+ if(!ui->enableSSE3CheckBox->isChecked())
+ strlist.append("sse3");
+ if(!ui->enableSSE41CheckBox->isChecked())
+ strlist.append("sse4.1");
+ if(!ui->enableNeonCheckBox->isChecked())
strlist.append("neon");
settings.setValue("disable-cpu-exts", strlist.join(QChar(',')));
- if(ui->hrtfForceButton->isChecked())
+ if(ui->hrtfStateComboBox->currentIndex() == 1)
settings.setValue("hrtf", "true");
- else if(ui->hrtfDisableButton->isChecked())
+ else if(ui->hrtfStateComboBox->currentIndex() == 2)
settings.setValue("hrtf", "false");
else
settings.setValue("hrtf", QString());
@@ -403,30 +635,26 @@ void MainWindow::saveConfig(const QString &fname) const
else
settings.setValue("reverb/emulate-eax", QString()/*"false"*/);
- // TODO: Remove check when we can properly match global values.
- if(ui->reverbBoostSlider->sliderPosition() == 0)
- settings.setValue("reverb/boost", QString());
- else
- settings.setValue("reverb/boost", ui->reverbBoostEdit->text());
-
strlist.clear();
- if(ui->disableEaxReverbCheck->isChecked())
+ if(!ui->enableEaxReverbCheck->isChecked())
strlist.append("eaxreverb");
- if(ui->disableStdReverbCheck->isChecked())
+ if(!ui->enableStdReverbCheck->isChecked())
strlist.append("reverb");
- if(ui->disableChorusCheck->isChecked())
+ if(!ui->enableChorusCheck->isChecked())
strlist.append("chorus");
- if(ui->disableDistortionCheck->isChecked())
+ if(!ui->enableDistortionCheck->isChecked())
strlist.append("distortion");
- if(ui->disableEchoCheck->isChecked())
+ if(!ui->enableCompressorCheck->isChecked())
+ strlist.append("compressor");
+ if(!ui->enableEchoCheck->isChecked())
strlist.append("echo");
- if(ui->disableEqualizerCheck->isChecked())
+ if(!ui->enableEqualizerCheck->isChecked())
strlist.append("equalizer");
- if(ui->disableFlangerCheck->isChecked())
+ if(!ui->enableFlangerCheck->isChecked())
strlist.append("flanger");
- if(ui->disableModulatorCheck->isChecked())
+ if(!ui->enableModulatorCheck->isChecked())
strlist.append("modulator");
- if(ui->disableDedicatedCheck->isChecked())
+ if(!ui->enableDedicatedCheck->isChecked())
strlist.append("dedicated");
settings.setValue("excludefx", strlist.join(QChar(',')));
@@ -484,10 +712,36 @@ void MainWindow::updatePeriodCountSlider()
void MainWindow::addHrtfFile()
{
- QStringList fnames = QFileDialog::getOpenFileNames(this, tr("Select Files"), QString(),
+ const QStringList datapaths = getAllDataPaths("/openal/hrtf");
+ QStringList fnames = QFileDialog::getOpenFileNames(this, tr("Select Files"),
+ datapaths.empty() ? QString() : datapaths[0],
"HRTF Datasets(*.mhr);;All Files(*.*)");
if(fnames.isEmpty() == false)
- ui->hrtfFileList->addItems(fnames);
+ {
+ for(QStringList::iterator iter = fnames.begin();iter != fnames.end();iter++)
+ {
+ QStringList::const_iterator path = datapaths.constBegin();
+ for(;path != datapaths.constEnd();path++)
+ {
+ QDir hrtfdir(*path);
+ if(!hrtfdir.isAbsolute())
+ continue;
+
+ const QString relname = hrtfdir.relativeFilePath(*iter);
+ if(!relname.startsWith(".."))
+ {
+ // If filename is within this path, use the relative pathname
+ ui->hrtfFileList->addItem(relname);
+ break;
+ }
+ }
+ if(path == datapaths.constEnd())
+ {
+ // Filename is not within any data path, use the absolute pathname
+ ui->hrtfFileList->addItem(*iter);
+ }
+ }
+ }
}
void MainWindow::removeHrtfFile()
@@ -571,16 +825,3 @@ void MainWindow::showDisabledBackendMenu(QPoint pt)
ui->disabledBackendList->addItem(iter.value());
}
}
-
-void MainWindow::updateReverbBoostEdit(int value)
-{
- ui->reverbBoostEdit->clear();
- if(value != 0)
- ui->reverbBoostEdit->insert(QString::number(value/10.0, 'f', 1));
-}
-
-void MainWindow::updateReverbBoostSlider(QString value)
-{
- int pos = int(value.toFloat()*10.0f);
- ui->reverbBoostSlider->setSliderPosition(pos);
-}
diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h
index 0421aabb..b5a1ae7c 100644
--- a/utils/alsoft-config/mainwindow.h
+++ b/utils/alsoft-config/mainwindow.h
@@ -35,9 +35,6 @@ private slots:
void showEnabledBackendMenu(QPoint pt);
void showDisabledBackendMenu(QPoint pt);
- void updateReverbBoostEdit(int size);
- void updateReverbBoostSlider(QString value);
-
private:
Ui::MainWindow *ui;
@@ -47,7 +44,6 @@ private:
QValidator *mEffectSlotValidator;
QValidator *mSourceSendValidator;
QValidator *mSampleRateValidator;
- QValidator *mReverbBoostValidator;
void loadConfig(const QString &fname);
void saveConfig(const QString &fname) const;
diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui
index 4c7d0c69..78564ada 100644
--- a/utils/alsoft-config/mainwindow.ui
+++ b/utils/alsoft-config/mainwindow.ui
@@ -57,9 +57,9 @@
<property name="geometry">
<rect>
<x>120</x>
- <y>20</y>
- <width>206</width>
- <height>23</height>
+ <y>50</y>
+ <width>78</width>
+ <height>22</height>
</rect>
</property>
<property name="toolTip">
@@ -69,52 +69,12 @@ float and converted to the output sample type as needed.</string>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
- <item>
- <property name="text">
- <string>- Autodetect -</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>int8 - signed 8-bit int</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>uint8 - unsigned 8-bit int</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>int16 - signed 16-bit int</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>uint16 - unsigned 16-bit int</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>int32 - signed 32-bit int</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>uint32 - unsigned 32-bit int</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>float32 - 32-bit float</string>
- </property>
- </item>
</widget>
<widget class="QLabel" name="label_5">
<property name="geometry">
<rect>
<x>10</x>
- <y>20</y>
+ <y>50</y>
<width>101</width>
<height>21</height>
</rect>
@@ -130,7 +90,7 @@ float and converted to the output sample type as needed.</string>
<property name="geometry">
<rect>
<x>10</x>
- <y>50</y>
+ <y>20</y>
<width>101</width>
<height>21</height>
</rect>
@@ -146,9 +106,9 @@ float and converted to the output sample type as needed.</string>
<property name="geometry">
<rect>
<x>120</x>
- <y>50</y>
- <width>247</width>
- <height>23</height>
+ <y>20</y>
+ <width>78</width>
+ <height>22</height>
</rect>
</property>
<property name="toolTip">
@@ -159,48 +119,13 @@ to stereo output.</string>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
- <item>
- <property name="text">
- <string>- Autodetect -</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>mono - 1-channel Mono</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>stereo - 2-channel Stereo</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>quad - 4-channel Quadraphonic</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>surround51 - 5.1 Surround Sound</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>surround61 - 6.1 Surround Sound</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>surround71 - 7.1 Surround Sound</string>
- </property>
- </item>
</widget>
<widget class="QComboBox" name="sampleRateCombo">
<property name="geometry">
<rect>
- <x>120</x>
- <y>80</y>
- <width>123</width>
+ <x>370</x>
+ <y>20</y>
+ <width>96</width>
<height>22</height>
</rect>
</property>
@@ -218,27 +143,22 @@ to stereo output.</string>
</property>
<item>
<property name="text">
- <string>- Autodetect -</string>
+ <string>Autodetect</string>
</property>
</item>
<item>
<property name="text">
- <string>96000</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>48000</string>
+ <string>8000</string>
</property>
</item>
<item>
<property name="text">
- <string>44100</string>
+ <string>11025</string>
</property>
</item>
<item>
<property name="text">
- <string>32000</string>
+ <string>16000</string>
</property>
</item>
<item>
@@ -248,26 +168,26 @@ to stereo output.</string>
</item>
<item>
<property name="text">
- <string>16000</string>
+ <string>32000</string>
</property>
</item>
<item>
<property name="text">
- <string>11025</string>
+ <string>44100</string>
</property>
</item>
<item>
<property name="text">
- <string>8000</string>
+ <string>48000</string>
</property>
</item>
</widget>
<widget class="QLabel" name="label_7">
<property name="geometry">
<rect>
- <x>10</x>
- <y>80</y>
- <width>101</width>
+ <x>280</x>
+ <y>20</y>
+ <width>81</width>
<height>21</height>
</rect>
</property>
@@ -282,81 +202,27 @@ to stereo output.</string>
<property name="geometry">
<rect>
<x>10</x>
- <y>200</y>
+ <y>180</y>
<width>511</width>
- <height>161</height>
+ <height>191</height>
</rect>
</property>
<property name="title">
<string>HRTF (Stereo only)</string>
</property>
- <widget class="QRadioButton" name="hrtfEnableButton">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>30</y>
- <width>71</width>
- <height>21</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Allows applications to request HRTF mixing.</string>
- </property>
- <property name="text">
- <string>Enable</string>
- </property>
- <property name="checked">
- <bool>true</bool>
- </property>
- </widget>
- <widget class="QRadioButton" name="hrtfDisableButton">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>50</y>
- <width>71</width>
- <height>21</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Does not allow HRTF mixing, even when requested.</string>
- </property>
- <property name="text">
- <string>Disable</string>
- </property>
- </widget>
- <widget class="QRadioButton" name="hrtfForceButton">
- <property name="geometry">
- <rect>
- <x>20</x>
- <y>70</y>
- <width>71</width>
- <height>21</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Attempts to force HRTF mixing, even if applications request not
-to do it. This may override the channel configuration and
-sample rate.</string>
- </property>
- <property name="text">
- <string>Force</string>
- </property>
- </widget>
<widget class="QListWidget" name="hrtfFileList">
<property name="geometry">
<rect>
- <x>110</x>
+ <x>20</x>
<y>30</y>
- <width>361</width>
+ <width>391</width>
<height>121</height>
</rect>
</property>
<property name="toolTip">
<string>A list of files containing HRTF data sets. The listed data sets
-are used in place of or in addiiton to the the built-in set. The
-filenames may contain these markers, which will be replaced
-as needed:
+are used in place of the default sets. The filenames may
+contain these markers, which will be replaced as needed:
%r - Device sampling rate
%% - Percent sign (%)</string>
</property>
@@ -379,14 +245,14 @@ as needed:
<widget class="QPushButton" name="hrtfAddButton">
<property name="geometry">
<rect>
- <x>475</x>
+ <x>420</x>
<y>30</y>
- <width>25</width>
+ <width>81</width>
<height>25</height>
</rect>
</property>
<property name="text">
- <string/>
+ <string>Add...</string>
</property>
<property name="icon">
<iconset theme="list-add">
@@ -400,14 +266,14 @@ as needed:
<widget class="QPushButton" name="hrtfRemoveButton">
<property name="geometry">
<rect>
- <x>475</x>
+ <x>420</x>
<y>60</y>
- <width>25</width>
+ <width>81</width>
<height>25</height>
</rect>
</property>
<property name="text">
- <string/>
+ <string>Remove</string>
</property>
<property name="icon">
<iconset theme="list-remove">
@@ -415,12 +281,56 @@ as needed:
</iconset>
</property>
</widget>
+ <widget class="QComboBox" name="hrtfStateComboBox">
+ <property name="geometry">
+ <rect>
+ <x>110</x>
+ <y>160</y>
+ <width>161</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="sizeAdjustPolicy">
+ <enum>QComboBox::AdjustToContentsOnFirstShow</enum>
+ </property>
+ <item>
+ <property name="text">
+ <string>Application preference</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Force on</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Force off</string>
+ </property>
+ </item>
+ </widget>
+ <widget class="QLabel" name="label_15">
+ <property name="geometry">
+ <rect>
+ <x>30</x>
+ <y>160</y>
+ <width>71</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>HRTF Mode:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
</widget>
<widget class="QGroupBox" name="groupBox_3">
<property name="geometry">
<rect>
<x>10</x>
- <y>110</y>
+ <y>90</y>
<width>511</width>
<height>91</height>
</rect>
@@ -591,6 +501,37 @@ frames needed for each mixing update.</string>
</widget>
</widget>
</widget>
+ <widget class="QLabel" name="label_14">
+ <property name="geometry">
+ <rect>
+ <x>280</x>
+ <y>50</y>
+ <width>81</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Stereo Mode:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QComboBox" name="stereoModeCombo">
+ <property name="geometry">
+ <rect>
+ <x>370</x>
+ <y>50</y>
+ <width>78</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <property name="toolTip">
+ <string>How to treat stereo output. As headphones, HRTF or crossfeed
+filters may be used to improve binaural quality, which may not
+otherwise be suitable for speakers.</string>
+ </property>
+ </widget>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
@@ -738,8 +679,8 @@ value currently possible is 4.</string>
<rect>
<x>110</x>
<y>120</y>
- <width>203</width>
- <height>23</height>
+ <width>78</width>
+ <height>22</height>
</rect>
</property>
<property name="toolTip">
@@ -748,81 +689,115 @@ value currently possible is 4.</string>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
- <item>
- <property name="text">
- <string>- Default -</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Point (low quality, fast)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Linear (basic quality, fast)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Cubic Spline (good quality)</string>
- </property>
- </item>
</widget>
- <widget class="QGroupBox" name="groupBox_2">
+ <widget class="QGroupBox" name="cpuExtGroupBox">
<property name="geometry">
<rect>
<x>10</x>
<y>150</y>
<width>511</width>
- <height>61</height>
+ <height>121</height>
</rect>
</property>
<property name="toolTip">
- <string>Disables use of specific CPU extensions. Certain methods may
-utilize CPU extensions when detected, and this is useful for
-preventing those extensions from being used.</string>
+ <string>Enables use of specific CPU extensions. Certain methods may
+utilize CPU extensions when detected, and disabling these can
+be useful for preventing those extensions from being used.</string>
</property>
<property name="title">
<string>CPU Extensions</string>
</property>
- <widget class="QCheckBox" name="disableSSECheckBox">
+ <widget class="QCheckBox" name="enableSSECheckBox">
<property name="geometry">
<rect>
- <x>10</x>
+ <x>100</x>
<y>20</y>
- <width>101</width>
+ <width>71</width>
<height>31</height>
</rect>
</property>
<property name="text">
- <string>Disable SSE</string>
+ <string>SSE</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
</property>
</widget>
- <widget class="QCheckBox" name="disableSSE2CheckBox">
+ <widget class="QCheckBox" name="enableSSE2CheckBox">
<property name="geometry">
<rect>
- <x>200</x>
+ <x>180</x>
<y>20</y>
- <width>111</width>
+ <width>71</width>
<height>31</height>
</rect>
</property>
<property name="text">
- <string>Disable SSE2</string>
+ <string>SSE2</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
</property>
</widget>
- <widget class="QCheckBox" name="disableNeonCheckBox">
+ <widget class="QCheckBox" name="enableNeonCheckBox">
<property name="geometry">
<rect>
- <x>380</x>
+ <x>100</x>
+ <y>50</y>
+ <width>71</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Neon</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="enableSSE41CheckBox">
+ <property name="geometry">
+ <rect>
+ <x>340</x>
<y>20</y>
- <width>111</width>
+ <width>71</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>SSE4.1</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="enableSSE3CheckBox">
+ <property name="geometry">
+ <rect>
+ <x>260</x>
+ <y>20</y>
+ <width>71</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>SSE3</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" name="cpuExtDisabledLabel">
+ <property name="geometry">
+ <rect>
+ <x>101</x>
+ <y>80</y>
+ <width>311</width>
<height>31</height>
</rect>
</property>
<property name="text">
- <string>Disable Neon</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;No support enabled for CPU Extensions&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</widget>
@@ -932,100 +907,24 @@ some quality.</string>
<string>Emulate EAX Reverb:</string>
</property>
</widget>
- <widget class="QGroupBox" name="groupBox_4">
+ <widget class="QGroupBox" name="groupBox_5">
<property name="geometry">
<rect>
<x>10</x>
<y>100</y>
<width>511</width>
- <height>61</height>
+ <height>191</height>
</rect>
</property>
<property name="toolTip">
- <string>Global amplification for reverb output, expressed in decibels.
-+6 will be a scale of (approximately) 2x, +12 will be a scale of
-4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
-value of 0 means no change.</string>
+ <string>Specifies which effects apps can recognize. Disabling effects
+can help for apps that try to use ones that are too intensive
+for the system to handle.</string>
</property>
<property name="title">
- <string>Reverb Boost</string>
+ <string>Enabled Effects</string>
</property>
- <widget class="QSlider" name="reverbBoostSlider">
- <property name="geometry">
- <rect>
- <x>10</x>
- <y>30</y>
- <width>391</width>
- <height>23</height>
- </rect>
- </property>
- <property name="toolTip">
- <string/>
- </property>
- <property name="minimum">
- <number>-120</number>
- </property>
- <property name="maximum">
- <number>120</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="tickPosition">
- <enum>QSlider::TicksBelow</enum>
- </property>
- <property name="tickInterval">
- <number>10</number>
- </property>
- </widget>
- <widget class="QLineEdit" name="reverbBoostEdit">
- <property name="geometry">
- <rect>
- <x>410</x>
- <y>30</y>
- <width>51</width>
- <height>22</height>
- </rect>
- </property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
- </property>
- <property name="placeholderText">
- <string>0.0</string>
- </property>
- </widget>
- <widget class="QLabel" name="label_12">
- <property name="geometry">
- <rect>
- <x>460</x>
- <y>30</y>
- <width>31</width>
- <height>21</height>
- </rect>
- </property>
- <property name="text">
- <string>dB</string>
- </property>
- </widget>
- </widget>
- <widget class="QGroupBox" name="groupBox_5">
- <property name="geometry">
- <rect>
- <x>9</x>
- <y>170</y>
- <width>511</width>
- <height>181</height>
- </rect>
- </property>
- <property name="toolTip">
- <string>Disables effects, preventing apps from recognizing them. This
-can help for apps that try to use effects which are too CPU
-intensive for the system to handle.</string>
- </property>
- <property name="title">
- <string>Disabled Effects</string>
- </property>
- <widget class="QCheckBox" name="disableEaxReverbCheck">
+ <widget class="QCheckBox" name="enableEaxReverbCheck">
<property name="geometry">
<rect>
<x>70</x>
@@ -1037,8 +936,11 @@ intensive for the system to handle.</string>
<property name="text">
<string>EAX Reverb</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
- <widget class="QCheckBox" name="disableStdReverbCheck">
+ <widget class="QCheckBox" name="enableStdReverbCheck">
<property name="geometry">
<rect>
<x>70</x>
@@ -1050,8 +952,11 @@ intensive for the system to handle.</string>
<property name="text">
<string>Standard Reverb</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
- <widget class="QCheckBox" name="disableChorusCheck">
+ <widget class="QCheckBox" name="enableChorusCheck">
<property name="geometry">
<rect>
<x>70</x>
@@ -1063,12 +968,15 @@ intensive for the system to handle.</string>
<property name="text">
<string>Chorus</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
- <widget class="QCheckBox" name="disableDistortionCheck">
+ <widget class="QCheckBox" name="enableDistortionCheck">
<property name="geometry">
<rect>
<x>70</x>
- <y>120</y>
+ <y>150</y>
<width>131</width>
<height>21</height>
</rect>
@@ -1076,12 +984,15 @@ intensive for the system to handle.</string>
<property name="text">
<string>Distortion</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
- <widget class="QCheckBox" name="disableEchoCheck">
+ <widget class="QCheckBox" name="enableEchoCheck">
<property name="geometry">
<rect>
- <x>70</x>
- <y>150</y>
+ <x>320</x>
+ <y>30</y>
<width>131</width>
<height>21</height>
</rect>
@@ -1089,12 +1000,15 @@ intensive for the system to handle.</string>
<property name="text">
<string>Echo</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
- <widget class="QCheckBox" name="disableEqualizerCheck">
+ <widget class="QCheckBox" name="enableEqualizerCheck">
<property name="geometry">
<rect>
<x>320</x>
- <y>30</y>
+ <y>60</y>
<width>131</width>
<height>21</height>
</rect>
@@ -1102,12 +1016,15 @@ intensive for the system to handle.</string>
<property name="text">
<string>Equalizer</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
- <widget class="QCheckBox" name="disableFlangerCheck">
+ <widget class="QCheckBox" name="enableFlangerCheck">
<property name="geometry">
<rect>
<x>320</x>
- <y>60</y>
+ <y>90</y>
<width>131</width>
<height>21</height>
</rect>
@@ -1115,12 +1032,15 @@ intensive for the system to handle.</string>
<property name="text">
<string>Flanger</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
- <widget class="QCheckBox" name="disableModulatorCheck">
+ <widget class="QCheckBox" name="enableModulatorCheck">
<property name="geometry">
<rect>
<x>320</x>
- <y>90</y>
+ <y>120</y>
<width>131</width>
<height>21</height>
</rect>
@@ -1128,23 +1048,45 @@ intensive for the system to handle.</string>
<property name="text">
<string>Ring Modulator</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
- <widget class="QCheckBox" name="disableDedicatedCheck">
+ <widget class="QCheckBox" name="enableDedicatedCheck">
<property name="geometry">
<rect>
<x>320</x>
- <y>120</y>
+ <y>150</y>
<width>131</width>
<height>21</height>
</rect>
</property>
<property name="toolTip">
- <string>Disables both the Dedicated Dialog and Dedicated LFE effects
+ <string>Enables both the Dedicated Dialog and Dedicated LFE effects
added by the ALC_EXT_DEDICATED extension.</string>
</property>
<property name="text">
<string>Dedicated ...</string>
</property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox" name="enableCompressorCheck">
+ <property name="geometry">
+ <rect>
+ <x>70</x>
+ <y>120</y>
+ <width>111</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Compressor</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
</widget>
</widget>
<widget class="QLabel" name="label_13">
@@ -1168,8 +1110,8 @@ added by the ALC_EXT_DEDICATED extension.</string>
<rect>
<x>160</x>
<y>20</y>
- <width>142</width>
- <height>23</height>
+ <width>131</width>
+ <height>22</height>
</rect>
</property>
<property name="sizeAdjustPolicy">
@@ -1320,7 +1262,7 @@ added by the ALC_EXT_DEDICATED extension.</string>
<x>0</x>
<y>0</y>
<width>564</width>
- <height>20</height>
+ <height>19</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
diff --git a/utils/bsincgen.c b/utils/bsincgen.c
new file mode 100644
index 00000000..d53b3cb5
--- /dev/null
+++ b/utils/bsincgen.c
@@ -0,0 +1,374 @@
+/*
+ * Sinc interpolator coefficient and delta generator for the OpenAL Soft
+ * cross platform audio library.
+ *
+ * Copyright (C) 2015 by Christopher Fitzgerald.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or visit: http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html
+ *
+ * --------------------------------------------------------------------------
+ *
+ * This is a modified version of the bandlimited windowed sinc interpolator
+ * algorithm presented here:
+ *
+ * Smith, J.O. "Windowed Sinc Interpolation", in
+ * Physical Audio Signal Processing,
+ * https://ccrma.stanford.edu/~jos/pasp/Windowed_Sinc_Interpolation.html,
+ * online book,
+ * accessed October 2012.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
+// The number of distinct scale and phase intervals within the filter table.
+#define BSINC_SCALE_COUNT (16)
+#define BSINC_PHASE_COUNT (16)
+
+#define BSINC_REJECTION (60.0)
+#define BSINC_POINTS_MIN (12)
+
+static double MinDouble(double a, double b)
+{ return (a <= b) ? a : b; }
+
+static double MaxDouble(double a, double b)
+{ return (a >= b) ? a : b; }
+
+/* NOTE: This is the normalized (instead of just sin(x)/x) cardinal sine
+ * function.
+ * 2 f_t sinc(2 f_t x)
+ * f_t -- normalized transition frequency (0.5 is nyquist)
+ * x -- sample index (-N to N)
+ */
+static double Sinc(const double x)
+{
+ if(fabs(x) < 1e-15)
+ return 1.0;
+ return sin(M_PI * x) / (M_PI * x);
+}
+
+static double BesselI_0(const double x)
+{
+ double term, sum, last_sum, x2, y;
+ int i;
+
+ term = 1.0;
+ sum = 1.0;
+ x2 = x / 2.0;
+ i = 1;
+
+ do {
+ y = x2 / i;
+ i++;
+ last_sum = sum;
+ term *= y * y;
+ sum += term;
+ } while(sum != last_sum);
+
+ return sum;
+}
+
+/* NOTE: k is assumed normalized (-1 to 1)
+ * beta is equivalent to 2 alpha
+ */
+static double Kaiser(const double b, const double k)
+{
+ double k2;
+
+ if((k < -1.0) || (k > 1.0))
+ return 0.0;
+
+ k2 = MaxDouble(1.0 - (k * k), 0.0);
+
+ return BesselI_0(b * sqrt(k2)) / BesselI_0(b);
+}
+
+/* NOTE: Calculates the transition width of the Kaiser window. Rejection is
+ * in dB.
+ */
+static double CalcKaiserWidth(const double rejection, const int order)
+{
+ double w_t = 2.0 * M_PI;
+
+ if(rejection > 21.0)
+ return (rejection - 7.95) / (order * 2.285 * w_t);
+
+ return 5.79 / (order * w_t);
+}
+
+static double CalcKaiserBeta(const double rejection)
+{
+ if(rejection > 50.0)
+ return 0.1102 * (rejection - 8.7);
+ else if(rejection >= 21.0)
+ return (0.5842 * pow(rejection - 21.0, 0.4)) +
+ (0.07886 * (rejection - 21.0));
+ return 0.0;
+}
+
+/* Generates the coefficient, delta, and index tables required by the bsinc resampler */
+static void BsiGenerateTables()
+{
+ static double filter[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT + 1][2 * BSINC_POINTS_MIN];
+ static double scDeltas[BSINC_SCALE_COUNT - 1][BSINC_PHASE_COUNT][2 * BSINC_POINTS_MIN];
+ static double phDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT + 1][2 * BSINC_POINTS_MIN];
+ static double spDeltas[BSINC_SCALE_COUNT - 1][BSINC_PHASE_COUNT][2 * BSINC_POINTS_MIN];
+ static int mt[BSINC_SCALE_COUNT];
+ static double at[BSINC_SCALE_COUNT];
+ double width, beta, scaleBase, scaleRange;
+ int si, pi, i;
+
+ memset(filter, 0, sizeof(filter));
+ memset(scDeltas, 0, sizeof(scDeltas));
+ memset(phDeltas, 0, sizeof(phDeltas));
+ memset(spDeltas, 0, sizeof(spDeltas));
+
+ /* Calculate windowing parameters. The width describes the transition
+ band, but it may vary due to the linear interpolation between scales
+ of the filter.
+ */
+ width = CalcKaiserWidth(BSINC_REJECTION, BSINC_POINTS_MIN);
+ beta = CalcKaiserBeta(BSINC_REJECTION);
+ scaleBase = width / 2.0;
+ scaleRange = 1.0 - scaleBase;
+
+ // Determine filter scaling.
+ for(si = 0; si < BSINC_SCALE_COUNT; si++)
+ {
+ const double scale = scaleBase + (scaleRange * si / (BSINC_SCALE_COUNT - 1));
+ const double a = MinDouble(BSINC_POINTS_MIN, BSINC_POINTS_MIN / (2.0 * scale));
+ int m = 2 * (int)floor(a);
+
+ // Make sure the number of points is a multiple of 4 (for SSE).
+ m += ~(m - 1) & 3;
+
+ mt[si] = m;
+ at[si] = a;
+ }
+
+ /* Calculate the Kaiser-windowed Sinc filter coefficients for each scale
+ and phase.
+ */
+ for(si = 0; si < BSINC_SCALE_COUNT; si++)
+ {
+ const int m = mt[si];
+ const int o = BSINC_POINTS_MIN - (m / 2);
+ const int l = (m / 2) - 1;
+ const double a = at[si];
+ const double scale = scaleBase + (scaleRange * si / (BSINC_SCALE_COUNT - 1));
+ const double cutoff = (0.5 * scale) - (scaleBase * MaxDouble(0.5, scale));
+
+ for(pi = 0; pi <= BSINC_PHASE_COUNT; pi++)
+ {
+ const double phase = l + ((double)pi / BSINC_PHASE_COUNT);
+
+ for(i = 0; i < m; i++)
+ {
+ const double x = i - phase;
+ filter[si][pi][o + i] = Kaiser(beta, x / a) * 2.0 * cutoff * Sinc(2.0 * cutoff * x);
+ }
+ }
+ }
+
+ /* Linear interpolation between scales is simplified by pre-calculating
+ the delta (b - a) in: x = a + f (b - a)
+
+ Given a difference in points between scales, the destination points
+ will be 0, thus: x = a + f (-a)
+ */
+ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++)
+ {
+ const int m = mt[si];
+ const int o = BSINC_POINTS_MIN - (m / 2);
+
+ for(pi = 0; pi < BSINC_PHASE_COUNT; pi++)
+ {
+ for(i = 0; i < m; i++)
+ scDeltas[si][pi][o + i] = filter[si + 1][pi][o + i] - filter[si][pi][o + i];
+ }
+ }
+
+ // Linear interpolation between phases is also simplified.
+ for(si = 0; si < BSINC_SCALE_COUNT; si++)
+ {
+ const int m = mt[si];
+ const int o = BSINC_POINTS_MIN - (m / 2);
+
+ for(pi = 0; pi < BSINC_PHASE_COUNT; pi++)
+ {
+ for(i = 0; i < m; i++)
+ phDeltas[si][pi][o + i] = filter[si][pi + 1][o + i] - filter[si][pi][o + i];
+ }
+ }
+
+ /* This last simplification is done to complete the bilinear equation for
+ the combination of scale and phase.
+ */
+ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++)
+ {
+ const int m = mt[si];
+ const int o = BSINC_POINTS_MIN - (m / 2);
+
+ for(pi = 0; pi < BSINC_PHASE_COUNT; pi++)
+ {
+ for(i = 0; i < m; i++)
+ spDeltas[si][pi][o + i] = phDeltas[si + 1][pi][o + i] - phDeltas[si][pi][o + i];
+ }
+ }
+
+ // Calculate the table size.
+ i = mt[0];
+ for(si = 1; si < BSINC_SCALE_COUNT; si++)
+ i += BSINC_PHASE_COUNT * mt[si];
+ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++)
+ i += 2 * BSINC_PHASE_COUNT * mt[si];
+ for(si = 1; si < BSINC_SCALE_COUNT; si++)
+ i += BSINC_PHASE_COUNT * mt[si];
+
+ fprintf(stdout, "static const float bsincTab[%d] =\n{\n", i);
+
+ /* Only output enough coefficients for the first (cut) scale as needed to
+ perform interpolation without extra branching.
+ */
+ fprintf(stdout, " /* %2d,%2d */", mt[0], 0);
+ for(i = 0; i < mt[0]; i++)
+ fprintf(stdout, " %+14.9ef,", filter[0][0][i]);
+ fprintf(stdout, "\n\n");
+
+ for(si = 1; si < BSINC_SCALE_COUNT; si++)
+ {
+ const int m = mt[si];
+ const int o = BSINC_POINTS_MIN - (m / 2);
+
+ for(pi = 0; pi < BSINC_PHASE_COUNT; pi++)
+ {
+ fprintf(stdout, " /* %2d,%2d */", m, pi);
+ for(i = 0; i < m; i++)
+ fprintf(stdout, " %+14.9ef,", filter[si][pi][o + i]);
+ fprintf(stdout, "\n");
+ }
+ }
+ fprintf(stdout, "\n");
+
+ // There are N-1 scale deltas for N scales.
+ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++)
+ {
+ const int m = mt[si];
+ const int o = BSINC_POINTS_MIN - (m / 2);
+
+ for(pi = 0; pi < BSINC_PHASE_COUNT; pi++)
+ {
+ fprintf(stdout, " /* %2d,%2d */", m, pi);
+ for(i = 0; i < m; i++)
+ fprintf(stdout, " %+14.9ef,", scDeltas[si][pi][o + i]);
+ fprintf(stdout, "\n");
+ }
+ }
+ fprintf(stdout, "\n");
+
+ // Exclude phases for the first (cut) scale.
+ for(si = 1; si < BSINC_SCALE_COUNT; si++)
+ {
+ const int m = mt[si];
+ const int o = BSINC_POINTS_MIN - (m / 2);
+
+ for(pi = 0; pi < BSINC_PHASE_COUNT; pi++)
+ {
+ fprintf(stdout, " /* %2d,%2d */", m, pi);
+ for(i = 0; i < m; i++)
+ fprintf(stdout, " %+14.9ef,", phDeltas[si][pi][o + i]);
+ fprintf(stdout, "\n");
+ }
+ }
+ fprintf(stdout, "\n");
+
+ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++)
+ {
+ const int m = mt[si];
+ const int o = BSINC_POINTS_MIN - (m / 2);
+
+ for(pi = 0; pi < BSINC_PHASE_COUNT; pi++)
+ {
+ fprintf(stdout, " /* %2d,%2d */", m, pi);
+ for(i = 0; i < m; i++)
+ fprintf(stdout, " %+14.9ef,", spDeltas[si][pi][o + i]);
+ fprintf(stdout, "\n");
+ }
+ }
+ fprintf(stdout, "};\n\n");
+
+ /* The scaleBase is calculated from the Kaiser window transition width.
+ It represents the absolute limit to the filter before it fully cuts
+ the signal. The limit in octaves can be calculated by taking the
+ base-2 logarithm of its inverse: log_2(1 / scaleBase)
+ */
+ fprintf(stdout, " static const ALfloat scaleBase = %.9ef, scaleRange = %.9ef;\n", scaleBase, 1.0 / scaleRange);
+ fprintf(stdout, " static const ALuint m[BSINC_SCALE_COUNT] = {");
+
+ fprintf(stdout, " %d", mt[0]);
+ for(si = 1; si < BSINC_SCALE_COUNT; si++)
+ fprintf(stdout, ", %d", mt[si]);
+
+ fprintf(stdout, " };\n");
+ fprintf(stdout, " static const ALuint to[4][BSINC_SCALE_COUNT] =\n {\n { 0");
+
+ i = mt[0];
+ for(si = 1; si < BSINC_SCALE_COUNT; si++)
+ {
+ fprintf(stdout, ", %d", i);
+ i += BSINC_PHASE_COUNT * mt[si];
+ }
+ fprintf(stdout, " },\n {");
+ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++)
+ {
+ fprintf(stdout, " %d,", i);
+ i += BSINC_PHASE_COUNT * mt[si];
+ }
+ fprintf(stdout, " 0 },\n { 0");
+ for(si = 1; si < BSINC_SCALE_COUNT; si++)
+ {
+ fprintf(stdout, ", %d", i);
+ i += BSINC_PHASE_COUNT * mt[si];
+ }
+ fprintf (stdout, " },\n {");
+ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++)
+ {
+ fprintf(stdout, " %d,", i);
+ i += BSINC_PHASE_COUNT * mt[si];
+ }
+ fprintf(stdout, " 0 }\n };\n");
+
+ fprintf(stdout, " static const ALuint tm[2][BSINC_SCALE_COUNT] = \n {\n { 0");
+ for(si = 1; si < BSINC_SCALE_COUNT; si++)
+ fprintf(stdout, ", %d", mt[si]);
+ fprintf(stdout, " },\n {");
+ for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++)
+ fprintf(stdout, " %d,", mt[si]);
+ fprintf(stdout, " 0 }\n };\n");
+}
+
+int main(void)
+{
+ BsiGenerateTables();
+ return 0;
+}
diff --git a/utils/makehrtf.c b/utils/makehrtf.c
index 7c836b33..57d8a91a 100644
--- a/utils/makehrtf.c
+++ b/utils/makehrtf.c
@@ -227,8 +227,7 @@ enum HeadModelT {
// Desired output format from the command line.
enum OutputFormatT {
OF_NONE = 0,
- OF_MHR , // OpenAL Soft MHR data set file.
- OF_TABLE // OpenAL Soft built-in table file (used when compiling).
+ OF_MHR // OpenAL Soft MHR data set file.
};
// Unsigned integer type.
@@ -771,10 +770,11 @@ static int HpTpdfDither (const double in, int * hpHist) {
}
// Allocates an array of doubles.
-static double *CreateArray(const size_t n)
+static double *CreateArray(size_t n)
{
double *a;
+ if(n == 0) n = 1;
a = calloc(n, sizeof(double));
if(a == NULL)
{
@@ -2088,84 +2088,6 @@ static int StoreMhr (const HrirDataT * hData, const char * filename) {
return (1);
}
-// Store the OpenAL Soft built-in table.
-static int StoreTable (const HrirDataT * hData, const char * filename) {
- FILE * fp = NULL;
- uint step, end, n, j, i;
- int hpHist, v;
- char text [128 + 1];
-
- if ((fp = fopen (filename, "wb")) == NULL) {
- fprintf (stderr, "Error: Could not open table file '%s'.\n", filename);
- return (0);
- }
- snprintf (text, 128, "/* Elevation metrics */\n"
- "static const ALubyte defaultAzCount[%u] = { ", hData -> mEvCount);
- if (! WriteAscii (text, fp, filename))
- return (0);
- for (i = 0; i < hData -> mEvCount; i ++) {
- snprintf (text, 128, "%u, ", hData -> mAzCount [i]);
- if (! WriteAscii (text, fp, filename))
- return (0);
- }
- snprintf (text, 128, "};\n"
- "static const ALushort defaultEvOffset[%u] = { ", hData -> mEvCount);
- if (! WriteAscii (text, fp, filename))
- return (0);
- for (i = 0; i < hData -> mEvCount; i ++) {
- snprintf (text, 128, "%u, ", hData -> mEvOffset [i]);
- if (! WriteAscii (text, fp, filename))
- return (0);
- }
- step = hData -> mIrSize;
- end = hData -> mIrCount * step;
- n = hData -> mIrPoints;
- snprintf (text, 128, "};\n\n"
- "/* HRIR Coefficients */\n"
- "static const ALshort defaultCoeffs[%u] =\n{\n", hData -> mIrCount * n);
- if (! WriteAscii (text, fp, filename))
- return (0);
- srand (0x31DF840C);
- for (j = 0; j < end; j += step) {
- if (! WriteAscii (" ", fp, filename))
- return (0);
- hpHist = 0;
- for (i = 0; i < n; i ++) {
- v = HpTpdfDither (32767.0 * hData -> mHrirs [j + i], & hpHist);
- snprintf (text, 128, " %+d,", v);
- if (! WriteAscii (text, fp, filename))
- return (0);
- }
- if (! WriteAscii ("\n", fp, filename))
- return (0);
- }
- snprintf (text, 128, "};\n\n"
- "/* HRIR Delays */\n"
- "static const ALubyte defaultDelays[%u] =\n{\n"
- " ", hData -> mIrCount);
- if (! WriteAscii (text, fp, filename))
- return (0);
- for (j = 0; j < hData -> mIrCount; j ++) {
- v = (int) fmin (round (hData -> mIrRate * hData -> mHrtds [j]), MAX_HRTD);
- snprintf (text, 128, " %d,", v);
- if (! WriteAscii (text, fp, filename))
- return (0);
- }
- if (! WriteAscii ("\n};\n\n"
- "/* Default HRTF Definition */\n", fp, filename))
- return (0);
- snprintf (text, 128, "static const struct Hrtf DefaultHrtf = {\n"
- " %u, %u, %u, defaultAzCount, defaultEvOffset,\n",
- hData -> mIrRate, hData -> mIrPoints, hData -> mEvCount);
- if (! WriteAscii (text, fp, filename))
- return (0);
- if (! WriteAscii (" defaultCoeffs, defaultDelays, NULL\n"
- "};\n", fp, filename))
- return (0);
- fclose (fp);
- return (1);
-}
-
// Process the data set definition to read and validate the data set metrics.
static int ProcessMetrics (TokenReaderT * tr, const uint fftSize, const uint truncSize, HrirDataT * hData) {
char ident [MAX_IDENT_LEN + 1];
@@ -2203,7 +2125,7 @@ static int ProcessMetrics (TokenReaderT * tr, const uint fftSize, const uint tru
return (0);
points = (uint) intVal;
if ((fftSize > 0) && (points > fftSize)) {
- TrErrorAt (tr, line, col, "Value exceeds the overriden FFT size.\n");
+ TrErrorAt (tr, line, col, "Value exceeds the overridden FFT size.\n");
return (0);
}
if (points < truncSize) {
@@ -2582,11 +2504,6 @@ static int ProcessDefinition (const char * inName, const uint outRate, const uin
if (! StoreMhr (& hData, expName))
return (0);
break;
- case OF_TABLE :
- fprintf (stderr, "Creating OpenAL Soft table file...\n");
- if (! StoreTable (& hData, expName))
- return (0);
- break;
default :
break;
}
@@ -2618,8 +2535,6 @@ int main (const int argc, const char * argv []) {
fprintf (stdout, "Commands:\n");
fprintf (stdout, " -m, --make-mhr Makes an OpenAL Soft compatible HRTF data set.\n");
fprintf (stdout, " Defaults output to: ./oalsoft_hrtf_%%r.mhr\n");
- fprintf (stdout, " -t, --make-tab Makes the built-in table used when compiling OpenAL Soft.\n");
- fprintf (stdout, " Defaults output to: ./hrtf_tables.inc\n");
fprintf (stdout, " -h, --help Displays this help information.\n\n");
fprintf (stdout, "Options:\n");
fprintf (stdout, " -r=<rate> Change the data set sample rate to the specified value and\n");
@@ -2646,12 +2561,6 @@ int main (const int argc, const char * argv []) {
else
outName = "./oalsoft_hrtf_%r.mhr";
outFormat = OF_MHR;
- } else if ((strcmp (argv [1], "--make-tab") == 0) || (strcmp (argv [1], "-t") == 0)) {
- if (argc > 3)
- outName = argv [3];
- else
- outName = "./hrtf_tables.inc";
- outFormat = OF_TABLE;
} else {
fprintf (stderr, "Error: Invalid command '%s'.\n", argv [1]);
return (-1);
diff --git a/utils/openal-info.c b/utils/openal-info.c
index 61af00f0..5b45ceef 100644
--- a/utils/openal-info.c
+++ b/utils/openal-info.c
@@ -147,6 +147,35 @@ static void printALCInfo(ALCdevice *device)
}
}
+static void printHRTFInfo(ALCdevice *device)
+{
+ LPALCGETSTRINGISOFT alcGetStringiSOFT;
+ ALCint num_hrtfs;
+
+ if(alcIsExtensionPresent(device, "ALC_SOFT_HRTF") == ALC_FALSE)
+ {
+ printf("HRTF extension not available\n");
+ return;
+ }
+
+ alcGetStringiSOFT = alcGetProcAddress(device, "alcGetStringiSOFT");
+
+ alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtfs);
+ if(!num_hrtfs)
+ printf("No HRTFs found\n");
+ else
+ {
+ ALCint i;
+ printf("Available HRTFs:\n");
+ for(i = 0;i < num_hrtfs;++i)
+ {
+ const ALCchar *name = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
+ printf(" %s\n", name);
+ }
+ }
+ checkALCErrors(device);
+}
+
static void printALInfo(void)
{
printf("OpenAL vendor string: %s\n", alGetString(AL_VENDOR));
@@ -287,6 +316,7 @@ int main(int argc, char *argv[])
return 1;
}
printALCInfo(device);
+ printHRTFInfo(device);
context = alcCreateContext(device, NULL);
if(!context || alcMakeContextCurrent(context) == ALC_FALSE)