rextimmy преди 7 години
родител
ревизия
925d8b27cf
променени са 100 файла, в които са добавени 13796 реда и са изтрити 10269 реда
  1. 4 6
      Engine/lib/openal-soft/.gitignore
  2. 65 4
      Engine/lib/openal-soft/.travis.yml
  3. 310 275
      Engine/lib/openal-soft/Alc/ALc.c
  4. 835 548
      Engine/lib/openal-soft/Alc/ALu.c
  5. 0 301
      Engine/lib/openal-soft/Alc/alcRing.c
  6. 127 50
      Engine/lib/openal-soft/Alc/alconfig.c
  7. 17 0
      Engine/lib/openal-soft/Alc/alconfig.h
  8. 27 18
      Engine/lib/openal-soft/Alc/alstring.h
  9. 21 12
      Engine/lib/openal-soft/Alc/ambdec.c
  10. 1 1
      Engine/lib/openal-soft/Alc/ambdec.h
  11. 120 58
      Engine/lib/openal-soft/Alc/backends/alsa.c
  12. 17 159
      Engine/lib/openal-soft/Alc/backends/base.c
  13. 20 5
      Engine/lib/openal-soft/Alc/backends/base.h
  14. 313 227
      Engine/lib/openal-soft/Alc/backends/coreaudio.c
  15. 172 158
      Engine/lib/openal-soft/Alc/backends/dsound.c
  16. 63 83
      Engine/lib/openal-soft/Alc/backends/jack.c
  17. 1 6
      Engine/lib/openal-soft/Alc/backends/loopback.c
  18. 10 12
      Engine/lib/openal-soft/Alc/backends/null.c
  19. 812 174
      Engine/lib/openal-soft/Alc/backends/opensl.c
  20. 193 136
      Engine/lib/openal-soft/Alc/backends/oss.c
  21. 17 32
      Engine/lib/openal-soft/Alc/backends/portaudio.c
  22. 203 131
      Engine/lib/openal-soft/Alc/backends/pulseaudio.c
  23. 269 112
      Engine/lib/openal-soft/Alc/backends/qsa.c
  24. 287 0
      Engine/lib/openal-soft/Alc/backends/sdl2.c
  25. 133 85
      Engine/lib/openal-soft/Alc/backends/sndio.c
  26. 62 41
      Engine/lib/openal-soft/Alc/backends/solaris.c
  27. 301 218
      Engine/lib/openal-soft/Alc/backends/wasapi.c
  28. 39 32
      Engine/lib/openal-soft/Alc/backends/wave.c
  29. 64 75
      Engine/lib/openal-soft/Alc/backends/winmm.c
  30. 182 360
      Engine/lib/openal-soft/Alc/bformatdec.c
  31. 34 26
      Engine/lib/openal-soft/Alc/bformatdec.h
  32. 4 4
      Engine/lib/openal-soft/Alc/bs2b.c
  33. 0 981
      Engine/lib/openal-soft/Alc/bsinc.c
  34. 17 1
      Engine/lib/openal-soft/Alc/compat.h
  35. 468 0
      Engine/lib/openal-soft/Alc/converter.c
  36. 55 0
      Engine/lib/openal-soft/Alc/converter.h
  37. 15 0
      Engine/lib/openal-soft/Alc/cpu_caps.h
  38. 299 156
      Engine/lib/openal-soft/Alc/effects/chorus.c
  39. 34 38
      Engine/lib/openal-soft/Alc/effects/compressor.c
  40. 46 63
      Engine/lib/openal-soft/Alc/effects/dedicated.c
  41. 96 107
      Engine/lib/openal-soft/Alc/effects/distortion.c
  42. 94 110
      Engine/lib/openal-soft/Alc/effects/echo.c
  43. 93 142
      Engine/lib/openal-soft/Alc/effects/equalizer.c
  44. 0 411
      Engine/lib/openal-soft/Alc/effects/flanger.c
  45. 87 95
      Engine/lib/openal-soft/Alc/effects/modulator.c
  46. 37 37
      Engine/lib/openal-soft/Alc/effects/null.c
  47. 526 0
      Engine/lib/openal-soft/Alc/effects/pshifter.c
  48. 924 700
      Engine/lib/openal-soft/Alc/effects/reverb.c
  49. 112 0
      Engine/lib/openal-soft/Alc/filters/defs.h
  50. 129 0
      Engine/lib/openal-soft/Alc/filters/filter.c
  51. 426 0
      Engine/lib/openal-soft/Alc/filters/nfc.c
  52. 49 0
      Engine/lib/openal-soft/Alc/filters/nfc.h
  53. 109 0
      Engine/lib/openal-soft/Alc/filters/splitter.c
  54. 40 0
      Engine/lib/openal-soft/Alc/filters/splitter.h
  55. 34 0
      Engine/lib/openal-soft/Alc/fpu_modes.h
  56. 282 229
      Engine/lib/openal-soft/Alc/helpers.c
  57. 661 343
      Engine/lib/openal-soft/Alc/hrtf.c
  58. 62 25
      Engine/lib/openal-soft/Alc/hrtf.h
  59. 0 5
      Engine/lib/openal-soft/Alc/hrtf_res.h
  60. 0 4
      Engine/lib/openal-soft/Alc/hrtf_res.rc
  61. 79 0
      Engine/lib/openal-soft/Alc/inprogext.h
  62. 69 0
      Engine/lib/openal-soft/Alc/logging.h
  63. 232 0
      Engine/lib/openal-soft/Alc/mastering.c
  64. 57 0
      Engine/lib/openal-soft/Alc/mastering.h
  65. 0 702
      Engine/lib/openal-soft/Alc/mixer.c
  66. 119 0
      Engine/lib/openal-soft/Alc/mixer/defs.h
  67. 123 0
      Engine/lib/openal-soft/Alc/mixer/hrtf_inc.c
  68. 176 0
      Engine/lib/openal-soft/Alc/mixer/mixer_c.c
  69. 269 0
      Engine/lib/openal-soft/Alc/mixer/mixer_neon.c
  70. 54 110
      Engine/lib/openal-soft/Alc/mixer/mixer_sse.c
  71. 10 8
      Engine/lib/openal-soft/Alc/mixer/mixer_sse2.c
  72. 0 0
      Engine/lib/openal-soft/Alc/mixer/mixer_sse3.c
  73. 88 0
      Engine/lib/openal-soft/Alc/mixer/mixer_sse41.c
  74. 0 228
      Engine/lib/openal-soft/Alc/mixer_c.c
  75. 0 110
      Engine/lib/openal-soft/Alc/mixer_defs.h
  76. 0 149
      Engine/lib/openal-soft/Alc/mixer_inc.c
  77. 0 173
      Engine/lib/openal-soft/Alc/mixer_neon.c
  78. 0 164
      Engine/lib/openal-soft/Alc/mixer_sse3.c
  79. 0 227
      Engine/lib/openal-soft/Alc/mixer_sse41.c
  80. 761 0
      Engine/lib/openal-soft/Alc/mixvoice.c
  81. 432 275
      Engine/lib/openal-soft/Alc/panning.c
  82. 105 0
      Engine/lib/openal-soft/Alc/polymorphism.h
  83. 295 0
      Engine/lib/openal-soft/Alc/ringbuffer.c
  84. 77 0
      Engine/lib/openal-soft/Alc/ringbuffer.h
  85. 38 52
      Engine/lib/openal-soft/Alc/uhjfilter.c
  86. 6 5
      Engine/lib/openal-soft/Alc/uhjfilter.h
  87. 4 20
      Engine/lib/openal-soft/Alc/vector.h
  88. 366 217
      Engine/lib/openal-soft/CMakeLists.txt
  89. 165 0
      Engine/lib/openal-soft/ChangeLog
  90. 56 56
      Engine/lib/openal-soft/OpenAL32/Include/alAuxEffectSlot.h
  91. 47 62
      Engine/lib/openal-soft/OpenAL32/Include/alBuffer.h
  92. 39 39
      Engine/lib/openal-soft/OpenAL32/Include/alEffect.h
  93. 8 12
      Engine/lib/openal-soft/OpenAL32/Include/alError.h
  94. 30 118
      Engine/lib/openal-soft/OpenAL32/Include/alFilter.h
  95. 25 24
      Engine/lib/openal-soft/OpenAL32/Include/alListener.h
  96. 358 462
      Engine/lib/openal-soft/OpenAL32/Include/alMain.h
  97. 21 132
      Engine/lib/openal-soft/OpenAL32/Include/alSource.h
  98. 0 20
      Engine/lib/openal-soft/OpenAL32/Include/alThunk.h
  99. 268 107
      Engine/lib/openal-soft/OpenAL32/Include/alu.h
  100. 1 1
      Engine/lib/openal-soft/OpenAL32/Include/bs2b.h

+ 4 - 6
Engine/lib/openal-soft/.gitignore

@@ -1,7 +1,5 @@
-build
-winbuild
-win64build
-include/SLES
-include/sndio.h
-include/sys
+build*/
+winbuild/
+win64build/
 openal-soft.kdev4
 openal-soft.kdev4
+.kdev4/

+ 65 - 4
Engine/lib/openal-soft/.travis.yml

@@ -1,5 +1,66 @@
-os:
-  - linux
-  - osx
 language: c
 language: c
-script: cmake . && make -j2
+matrix:
+  include:
+    - os: linux
+      dist: trusty
+    - os: linux
+      dist: trusty
+      env:
+        - BUILD_ANDROID=true
+    - os: osx
+sudo: required
+install:
+  - >
+    if [[ "${TRAVIS_OS_NAME}" == "linux" && -z "${BUILD_ANDROID}" ]]; then
+      # Install pulseaudio, portaudio, ALSA, JACK dependencies for
+      # corresponding backends.
+      # Install Qt5 dependency for alsoft-config.
+      sudo apt-get install -qq \
+        libpulse-dev \
+        portaudio19-dev \
+        libasound2-dev \
+        libjack-dev \
+        qtbase5-dev
+    fi
+  - >
+    if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then
+      curl -o ~/android-ndk.zip https://dl.google.com/android/repository/android-ndk-r15-linux-x86_64.zip
+      unzip -q ~/android-ndk.zip -d ~ \
+        'android-ndk-r15/build/cmake/*' \
+        'android-ndk-r15/build/core/toolchains/arm-linux-androideabi-*/*' \
+        'android-ndk-r15/platforms/android-14/arch-arm/*' \
+        'android-ndk-r15/source.properties' \
+        'android-ndk-r15/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/*' \
+        'android-ndk-r15/sources/cxx-stl/gnu-libstdc++/4.9/include/*' \
+        'android-ndk-r15/sysroot/*' \
+        'android-ndk-r15/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/*' \
+        'android-ndk-r15/toolchains/llvm/prebuilt/linux-x86_64/*'
+    fi
+script:
+  - >
+    if [[ "${TRAVIS_OS_NAME}" == "linux" && -z "${BUILD_ANDROID}" ]]; then
+      cmake \
+        -DALSOFT_REQUIRE_ALSA=ON \
+        -DALSOFT_REQUIRE_OSS=ON \
+        -DALSOFT_REQUIRE_PORTAUDIO=ON \
+        -DALSOFT_REQUIRE_PULSEAUDIO=ON \
+        -DALSOFT_REQUIRE_JACK=ON \
+        -DALSOFT_EMBED_HRTF_DATA=YES \
+        .
+    fi
+  - >
+    if [[ "${TRAVIS_OS_NAME}" == "linux" && "${BUILD_ANDROID}" == "true" ]]; then
+      cmake \
+        -DCMAKE_TOOLCHAIN_FILE=~/android-ndk-r15/build/cmake/android.toolchain.cmake \
+        -DALSOFT_REQUIRE_OPENSL=ON \
+        -DALSOFT_EMBED_HRTF_DATA=YES \
+        .
+    fi
+  - >
+    if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
+      cmake \
+        -DALSOFT_REQUIRE_COREAUDIO=ON \
+        -DALSOFT_EMBED_HRTF_DATA=YES \
+        .
+    fi
+  - make -j2

Файловите разлики са ограничени, защото са твърде много
+ 310 - 275
Engine/lib/openal-soft/Alc/ALc.c


Файловите разлики са ограничени, защото са твърде много
+ 835 - 548
Engine/lib/openal-soft/Alc/ALu.c


+ 0 - 301
Engine/lib/openal-soft/Alc/alcRing.c

@@ -1,301 +0,0 @@
-/**
- * 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 <string.h>
-#include <stdlib.h>
-
-#include "alMain.h"
-#include "threads.h"
-#include "almalloc.h"
-#include "compat.h"
-
-
-/* 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;
-    }
-}

+ 127 - 50
Engine/lib/openal-soft/Alc/alcConfig.c → Engine/lib/openal-soft/Alc/alconfig.c

@@ -38,6 +38,7 @@
 #endif
 #endif
 
 
 #include "alMain.h"
 #include "alMain.h"
+#include "alconfig.h"
 #include "compat.h"
 #include "compat.h"
 #include "bool.h"
 #include "bool.h"
 
 
@@ -233,7 +234,61 @@ static void LoadConfigFromFile(FILE *f)
                 curSection[0] = 0;
                 curSection[0] = 0;
             else
             else
             {
             {
-                strncpy(curSection, section, sizeof(curSection)-1);
+                size_t len, p = 0;
+                do {
+                    char *nextp = strchr(section, '%');
+                    if(!nextp)
+                    {
+                        strncpy(curSection+p, section, sizeof(curSection)-1-p);
+                        break;
+                    }
+
+                    len = nextp - section;
+                    if(len > sizeof(curSection)-1-p)
+                        len = sizeof(curSection)-1-p;
+                    strncpy(curSection+p, section, len);
+                    p += len;
+                    section = nextp;
+
+                    if(((section[1] >= '0' && section[1] <= '9') ||
+                        (section[1] >= 'a' && section[1] <= 'f') ||
+                        (section[1] >= 'A' && section[1] <= 'F')) &&
+                       ((section[2] >= '0' && section[2] <= '9') ||
+                        (section[2] >= 'a' && section[2] <= 'f') ||
+                        (section[2] >= 'A' && section[2] <= 'F')))
+                    {
+                        unsigned char b = 0;
+                        if(section[1] >= '0' && section[1] <= '9')
+                            b = (section[1]-'0') << 4;
+                        else if(section[1] >= 'a' && section[1] <= 'f')
+                            b = (section[1]-'a'+0xa) << 4;
+                        else if(section[1] >= 'A' && section[1] <= 'F')
+                            b = (section[1]-'A'+0x0a) << 4;
+                        if(section[2] >= '0' && section[2] <= '9')
+                            b |= (section[2]-'0');
+                        else if(section[2] >= 'a' && section[2] <= 'f')
+                            b |= (section[2]-'a'+0xa);
+                        else if(section[2] >= 'A' && section[2] <= 'F')
+                            b |= (section[2]-'A'+0x0a);
+                        if(p < sizeof(curSection)-1)
+                            curSection[p++] = b;
+                        section += 3;
+                    }
+                    else if(section[1] == '%')
+                    {
+                        if(p < sizeof(curSection)-1)
+                            curSection[p++] = '%';
+                        section += 2;
+                    }
+                    else
+                    {
+                        if(p < sizeof(curSection)-1)
+                            curSection[p++] = '%';
+                        section += 1;
+                    }
+                    if(p < sizeof(curSection)-1)
+                        curSection[p] = 0;
+                } while(p < sizeof(curSection)-1 && *section != 0);
                 curSection[sizeof(curSection)-1] = 0;
                 curSection[sizeof(curSection)-1] = 0;
             }
             }
 
 
@@ -311,33 +366,33 @@ static void LoadConfigFromFile(FILE *f)
 #ifdef _WIN32
 #ifdef _WIN32
 void ReadALConfig(void)
 void ReadALConfig(void)
 {
 {
-    WCHAR buffer[PATH_MAX];
+    al_string ppath = AL_STRING_INIT_STATIC();
+    WCHAR buffer[MAX_PATH];
     const WCHAR *str;
     const WCHAR *str;
-    al_string ppath;
     FILE *f;
     FILE *f;
 
 
     if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
     if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
     {
     {
         al_string filepath = AL_STRING_INIT_STATIC();
         al_string filepath = AL_STRING_INIT_STATIC();
-        al_string_copy_wcstr(&filepath, buffer);
-        al_string_append_cstr(&filepath, "\\alsoft.ini");
+        alstr_copy_wcstr(&filepath, buffer);
+        alstr_append_cstr(&filepath, "\\alsoft.ini");
 
 
-        TRACE("Loading config %s...\n", al_string_get_cstr(filepath));
-        f = al_fopen(al_string_get_cstr(filepath), "rt");
+        TRACE("Loading config %s...\n", alstr_get_cstr(filepath));
+        f = al_fopen(alstr_get_cstr(filepath), "rt");
         if(f)
         if(f)
         {
         {
             LoadConfigFromFile(f);
             LoadConfigFromFile(f);
             fclose(f);
             fclose(f);
         }
         }
-        al_string_deinit(&filepath);
+        alstr_reset(&filepath);
     }
     }
 
 
-    ppath = GetProcPath();
-    if(!al_string_empty(ppath))
+    GetProcBinary(&ppath, NULL);
+    if(!alstr_empty(ppath))
     {
     {
-        al_string_append_cstr(&ppath, "\\alsoft.ini");
-        TRACE("Loading config %s...\n", al_string_get_cstr(ppath));
-        f = al_fopen(al_string_get_cstr(ppath), "r");
+        alstr_append_cstr(&ppath, "\\alsoft.ini");
+        TRACE("Loading config %s...\n", alstr_get_cstr(ppath));
+        f = al_fopen(alstr_get_cstr(ppath), "r");
         if(f)
         if(f)
         {
         {
             LoadConfigFromFile(f);
             LoadConfigFromFile(f);
@@ -348,26 +403,26 @@ void ReadALConfig(void)
     if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str)
     if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str)
     {
     {
         al_string filepath = AL_STRING_INIT_STATIC();
         al_string filepath = AL_STRING_INIT_STATIC();
-        al_string_copy_wcstr(&filepath, str);
+        alstr_copy_wcstr(&filepath, str);
 
 
-        TRACE("Loading config %s...\n", al_string_get_cstr(filepath));
-        f = al_fopen(al_string_get_cstr(filepath), "rt");
+        TRACE("Loading config %s...\n", alstr_get_cstr(filepath));
+        f = al_fopen(alstr_get_cstr(filepath), "rt");
         if(f)
         if(f)
         {
         {
             LoadConfigFromFile(f);
             LoadConfigFromFile(f);
             fclose(f);
             fclose(f);
         }
         }
-        al_string_deinit(&filepath);
+        alstr_reset(&filepath);
     }
     }
 
 
-    al_string_deinit(&ppath);
+    alstr_reset(&ppath);
 }
 }
 #else
 #else
 void ReadALConfig(void)
 void ReadALConfig(void)
 {
 {
-    char buffer[PATH_MAX];
+    al_string confpaths = AL_STRING_INIT_STATIC();
+    al_string fname = AL_STRING_INIT_STATIC();
     const char *str;
     const char *str;
-    al_string ppath;
     FILE *f;
     FILE *f;
 
 
     str = "/etc/openal/alsoft.conf";
     str = "/etc/openal/alsoft.conf";
@@ -382,45 +437,55 @@ void ReadALConfig(void)
 
 
     if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0)
     if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0)
         str = "/etc/xdg";
         str = "/etc/xdg";
-    strncpy(buffer, str, sizeof(buffer)-1);
-    buffer[sizeof(buffer)-1] = 0;
+    alstr_copy_cstr(&confpaths, str);
     /* Go through the list in reverse, since "the order of base directories
     /* Go through the list in reverse, since "the order of base directories
      * denotes their importance; the first directory listed is the most
      * denotes their importance; the first directory listed is the most
      * important". Ergo, we need to load the settings from the later dirs
      * important". Ergo, we need to load the settings from the later dirs
      * first so that the settings in the earlier dirs override them.
      * first so that the settings in the earlier dirs override them.
      */
      */
-    while(1)
+    while(!alstr_empty(confpaths))
     {
     {
-        char *next = strrchr(buffer, ':');
-        if(next) *(next++) = 0;
-        else next = buffer;
+        char *next = strrchr(alstr_get_cstr(confpaths), ':');
+        if(next)
+        {
+            size_t len = next - alstr_get_cstr(confpaths);
+            alstr_copy_cstr(&fname, next+1);
+            VECTOR_RESIZE(confpaths, len, len+1);
+            VECTOR_ELEM(confpaths, len) = 0;
+        }
+        else
+        {
+            alstr_reset(&fname);
+            fname = confpaths;
+            AL_STRING_INIT(confpaths);
+        }
 
 
-        if(next[0] != '/')
-            WARN("Ignoring XDG config dir: %s\n", next);
+        if(alstr_empty(fname) || VECTOR_FRONT(fname) != '/')
+            WARN("Ignoring XDG config dir: %s\n", alstr_get_cstr(fname));
         else
         else
         {
         {
-            size_t len = strlen(next);
-            strncpy(next+len, "/alsoft.conf", buffer+sizeof(buffer)-next-len);
-            buffer[sizeof(buffer)-1] = 0;
+            if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf");
+            else alstr_append_cstr(&fname, "alsoft.conf");
 
 
-            TRACE("Loading config %s...\n", next);
-            f = al_fopen(next, "r");
+            TRACE("Loading config %s...\n", alstr_get_cstr(fname));
+            f = al_fopen(alstr_get_cstr(fname), "r");
             if(f)
             if(f)
             {
             {
                 LoadConfigFromFile(f);
                 LoadConfigFromFile(f);
                 fclose(f);
                 fclose(f);
             }
             }
         }
         }
-        if(next == buffer)
-            break;
+        alstr_clear(&fname);
     }
     }
 
 
     if((str=getenv("HOME")) != NULL && *str)
     if((str=getenv("HOME")) != NULL && *str)
     {
     {
-        snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", str);
+        alstr_copy_cstr(&fname, str);
+        if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.alsoftrc");
+        else alstr_append_cstr(&fname, ".alsoftrc");
 
 
-        TRACE("Loading config %s...\n", buffer);
-        f = al_fopen(buffer, "r");
+        TRACE("Loading config %s...\n", alstr_get_cstr(fname));
+        f = al_fopen(alstr_get_cstr(fname), "r");
         if(f)
         if(f)
         {
         {
             LoadConfigFromFile(f);
             LoadConfigFromFile(f);
@@ -429,17 +494,25 @@ void ReadALConfig(void)
     }
     }
 
 
     if((str=getenv("XDG_CONFIG_HOME")) != NULL && str[0] != 0)
     if((str=getenv("XDG_CONFIG_HOME")) != NULL && str[0] != 0)
-        snprintf(buffer, sizeof(buffer), "%s/%s", str, "alsoft.conf");
+    {
+        alstr_copy_cstr(&fname, str);
+        if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf");
+        else alstr_append_cstr(&fname, "alsoft.conf");
+    }
     else
     else
     {
     {
-        buffer[0] = 0;
+        alstr_clear(&fname);
         if((str=getenv("HOME")) != NULL && str[0] != 0)
         if((str=getenv("HOME")) != NULL && str[0] != 0)
-            snprintf(buffer, sizeof(buffer), "%s/.config/%s", str, "alsoft.conf");
+        {
+            alstr_copy_cstr(&fname, str);
+            if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.config/alsoft.conf");
+            else alstr_append_cstr(&fname, ".config/alsoft.conf");
+        }
     }
     }
-    if(buffer[0] != 0)
+    if(!alstr_empty(fname))
     {
     {
-        TRACE("Loading config %s...\n", buffer);
-        f = al_fopen(buffer, "r");
+        TRACE("Loading config %s...\n", alstr_get_cstr(fname));
+        f = al_fopen(alstr_get_cstr(fname), "r");
         if(f)
         if(f)
         {
         {
             LoadConfigFromFile(f);
             LoadConfigFromFile(f);
@@ -447,12 +520,15 @@ void ReadALConfig(void)
         }
         }
     }
     }
 
 
-    ppath = GetProcPath();
-    if(!al_string_empty(ppath))
+    alstr_clear(&fname);
+    GetProcBinary(&fname, NULL);
+    if(!alstr_empty(fname))
     {
     {
-        al_string_append_cstr(&ppath, "/alsoft.conf");
-        TRACE("Loading config %s...\n", al_string_get_cstr(ppath));
-        f = al_fopen(al_string_get_cstr(ppath), "r");
+        if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf");
+        else alstr_append_cstr(&fname, "alsoft.conf");
+
+        TRACE("Loading config %s...\n", alstr_get_cstr(fname));
+        f = al_fopen(alstr_get_cstr(fname), "r");
         if(f)
         if(f)
         {
         {
             LoadConfigFromFile(f);
             LoadConfigFromFile(f);
@@ -471,7 +547,8 @@ void ReadALConfig(void)
         }
         }
     }
     }
 
 
-    al_string_deinit(&ppath);
+    alstr_reset(&fname);
+    alstr_reset(&confpaths);
 }
 }
 #endif
 #endif
 
 

+ 17 - 0
Engine/lib/openal-soft/Alc/alconfig.h

@@ -0,0 +1,17 @@
+#ifndef ALCONFIG_H
+#define ALCONFIG_H
+
+void ReadALConfig(void);
+void FreeALConfig(void);
+
+int ConfigValueExists(const char *devName, const char *blockName, const char *keyName);
+const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def);
+int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def);
+
+int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret);
+int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret);
+int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret);
+int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret);
+int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret);
+
+#endif /* ALCONFIG_H */

+ 27 - 18
Engine/lib/openal-soft/Alc/alstring.h

@@ -6,44 +6,53 @@
 #include "vector.h"
 #include "vector.h"
 
 
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef char al_string_char_type;
 typedef char al_string_char_type;
 TYPEDEF_VECTOR(al_string_char_type, al_string)
 TYPEDEF_VECTOR(al_string_char_type, al_string)
 TYPEDEF_VECTOR(al_string, vector_al_string)
 TYPEDEF_VECTOR(al_string, vector_al_string)
 
 
-inline void al_string_deinit(al_string *str)
+inline void alstr_reset(al_string *str)
 { VECTOR_DEINIT(*str); }
 { VECTOR_DEINIT(*str); }
 #define AL_STRING_INIT(_x)       do { (_x) = (al_string)NULL; } while(0)
 #define AL_STRING_INIT(_x)       do { (_x) = (al_string)NULL; } while(0)
 #define AL_STRING_INIT_STATIC()  ((al_string)NULL)
 #define AL_STRING_INIT_STATIC()  ((al_string)NULL)
-#define AL_STRING_DEINIT(_x)     al_string_deinit(&(_x))
+#define AL_STRING_DEINIT(_x)     alstr_reset(&(_x))
 
 
-inline size_t al_string_length(const_al_string str)
+inline size_t alstr_length(const_al_string str)
 { return VECTOR_SIZE(str); }
 { return VECTOR_SIZE(str); }
 
 
-inline ALboolean al_string_empty(const_al_string str)
-{ return al_string_length(str) == 0; }
+inline ALboolean alstr_empty(const_al_string str)
+{ return alstr_length(str) == 0; }
 
 
-inline const al_string_char_type *al_string_get_cstr(const_al_string str)
+inline const al_string_char_type *alstr_get_cstr(const_al_string str)
 { return str ? &VECTOR_FRONT(str) : ""; }
 { return str ? &VECTOR_FRONT(str) : ""; }
 
 
-void al_string_clear(al_string *str);
+void alstr_clear(al_string *str);
 
 
-int al_string_cmp(const_al_string str1, const_al_string str2);
-int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2);
+int alstr_cmp(const_al_string str1, const_al_string str2);
+int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2);
 
 
-void al_string_copy(al_string *str, const_al_string from);
-void al_string_copy_cstr(al_string *str, const al_string_char_type *from);
-void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to);
+void alstr_copy(al_string *str, const_al_string from);
+void alstr_copy_cstr(al_string *str, const al_string_char_type *from);
+void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to);
 
 
-void al_string_append_char(al_string *str, const al_string_char_type c);
-void al_string_append_cstr(al_string *str, const al_string_char_type *from);
-void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to);
+void alstr_append_char(al_string *str, const al_string_char_type c);
+void alstr_append_cstr(al_string *str, const al_string_char_type *from);
+void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to);
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #include <wchar.h>
 #include <wchar.h>
 /* Windows-only methods to deal with WideChar strings. */
 /* 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);
+void alstr_copy_wcstr(al_string *str, const wchar_t *from);
+void alstr_append_wcstr(al_string *str, const wchar_t *from);
+void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to);
+void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to);
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
 #endif
 #endif
 
 
 #endif /* ALSTRING_H */
 #endif /* ALSTRING_H */

+ 21 - 12
Engine/lib/openal-soft/Alc/ambdec.c

@@ -90,6 +90,15 @@ static char *my_strtok_r(char *str, const char *delim, char **saveptr)
     return str;
     return str;
 }
 }
 
 
+static char *read_int(ALint *num, const char *line, int base)
+{
+    char *end;
+    *num = strtol(line, &end, base);
+    if(end && *end != '\0')
+        end = lstrip(end);
+    return end;
+}
+
 static char *read_uint(ALuint *num, const char *line, int base)
 static char *read_uint(ALuint *num, const char *line, int base)
 {
 {
     char *end;
     char *end;
@@ -131,7 +140,7 @@ char *read_clipped_line(FILE *f, char **buffer, size_t *maxlen)
 
 
 static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxlen, char **saveptr)
 static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t *maxlen, char **saveptr)
 {
 {
-    ALuint cur = 0;
+    ALsizei cur = 0;
     while(cur < conf->NumSpeakers)
     while(cur < conf->NumSpeakers)
     {
     {
         const char *cmd = my_strtok_r(NULL, " \t", saveptr);
         const char *cmd = my_strtok_r(NULL, " \t", saveptr);
@@ -155,7 +164,7 @@ static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t
             const char *conn = my_strtok_r(NULL, " \t", saveptr);
             const char *conn = my_strtok_r(NULL, " \t", saveptr);
 
 
             if(!name) WARN("Name not specified for speaker %u\n", cur+1);
             if(!name) WARN("Name not specified for speaker %u\n", cur+1);
-            else al_string_copy_cstr(&conf->Speakers[cur].Name, name);
+            else alstr_copy_cstr(&conf->Speakers[cur].Name, name);
             if(!dist) WARN("Distance not specified for speaker %u\n", cur+1);
             if(!dist) WARN("Distance not specified for speaker %u\n", cur+1);
             else read_float(&conf->Speakers[cur].Distance, dist);
             else read_float(&conf->Speakers[cur].Distance, dist);
             if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1);
             if(!az) WARN("Azimuth not specified for speaker %u\n", cur+1);
@@ -163,7 +172,7 @@ static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t
             if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1);
             if(!elev) WARN("Elevation not specified for speaker %u\n", cur+1);
             else read_float(&conf->Speakers[cur].Elevation, elev);
             else read_float(&conf->Speakers[cur].Elevation, elev);
             if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1);
             if(!conn) TRACE("Connection not specified for speaker %u\n", cur+1);
-            else al_string_copy_cstr(&conf->Speakers[cur].Connection, conn);
+            else alstr_copy_cstr(&conf->Speakers[cur].Connection, conn);
 
 
             cur++;
             cur++;
         }
         }
@@ -184,10 +193,10 @@ static int load_ambdec_speakers(AmbDecConf *conf, FILE *f, char **buffer, size_t
     return 1;
     return 1;
 }
 }
 
 
-static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALuint maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr)
+static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, FILE *f, char **buffer, size_t *maxlen, char **saveptr)
 {
 {
     int gotgains = 0;
     int gotgains = 0;
-    ALuint cur = 0;
+    ALsizei cur = 0;
     while(cur < maxrow)
     while(cur < maxrow)
     {
     {
         const char *cmd = my_strtok_r(NULL, " \t", saveptr);
         const char *cmd = my_strtok_r(NULL, " \t", saveptr);
@@ -269,7 +278,7 @@ static int load_ambdec_matrix(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS]
 
 
 void ambdec_init(AmbDecConf *conf)
 void ambdec_init(AmbDecConf *conf)
 {
 {
-    ALuint i;
+    ALsizei i;
 
 
     memset(conf, 0, sizeof(*conf));
     memset(conf, 0, sizeof(*conf));
     AL_STRING_INIT(conf->Description);
     AL_STRING_INIT(conf->Description);
@@ -282,13 +291,13 @@ void ambdec_init(AmbDecConf *conf)
 
 
 void ambdec_deinit(AmbDecConf *conf)
 void ambdec_deinit(AmbDecConf *conf)
 {
 {
-    ALuint i;
+    ALsizei i;
 
 
-    al_string_deinit(&conf->Description);
+    alstr_reset(&conf->Description);
     for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
     for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
     {
     {
-        al_string_deinit(&conf->Speakers[i].Name);
-        al_string_deinit(&conf->Speakers[i].Connection);
+        alstr_reset(&conf->Speakers[i].Name);
+        alstr_reset(&conf->Speakers[i].Connection);
     }
     }
     memset(conf, 0, sizeof(*conf));
     memset(conf, 0, sizeof(*conf));
 }
 }
@@ -322,7 +331,7 @@ int ambdec_load(AmbDecConf *conf, const char *fname)
         if(strcmp(command, "description") == 0)
         if(strcmp(command, "description") == 0)
         {
         {
             char *value = my_strtok_r(NULL, "", &saveptr);
             char *value = my_strtok_r(NULL, "", &saveptr);
-            al_string_copy_cstr(&conf->Description, lstrip(value));
+            alstr_copy_cstr(&conf->Description, lstrip(value));
         }
         }
         else if(strcmp(command, "version") == 0)
         else if(strcmp(command, "version") == 0)
         {
         {
@@ -370,7 +379,7 @@ int ambdec_load(AmbDecConf *conf, const char *fname)
             else if(strcmp(dec, "speakers") == 0)
             else if(strcmp(dec, "speakers") == 0)
             {
             {
                 line = my_strtok_r(NULL, "", &saveptr);
                 line = my_strtok_r(NULL, "", &saveptr);
-                line = read_uint(&conf->NumSpeakers, line, 10);
+                line = read_int(&conf->NumSpeakers, line, 10);
                 if(line && *line != '\0')
                 if(line && *line != '\0')
                 {
                 {
                     ERR("Extra junk after speakers: %s\n", line);
                     ERR("Extra junk after speakers: %s\n", line);

+ 1 - 1
Engine/lib/openal-soft/Alc/ambdec.h

@@ -17,7 +17,7 @@ typedef struct AmbDecConf {
 
 
     ALuint ChanMask;
     ALuint ChanMask;
     ALuint FreqBands; /* Must be 1 or 2 */
     ALuint FreqBands; /* Must be 1 or 2 */
-    ALuint NumSpeakers;
+    ALsizei NumSpeakers;
     enum AmbDecScaleType CoeffScale;
     enum AmbDecScaleType CoeffScale;
 
 
     ALfloat XOverFreq;
     ALfloat XOverFreq;

+ 120 - 58
Engine/lib/openal-soft/Alc/backends/alsa.c

@@ -26,6 +26,8 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "alconfig.h"
+#include "ringbuffer.h"
 #include "threads.h"
 #include "threads.h"
 #include "compat.h"
 #include "compat.h"
 
 
@@ -199,15 +201,21 @@ static ALCboolean alsa_load(void)
 #ifdef HAVE_DYNLOAD
 #ifdef HAVE_DYNLOAD
     if(!alsa_handle)
     if(!alsa_handle)
     {
     {
+        al_string missing_funcs = AL_STRING_INIT_STATIC();
+
         alsa_handle = LoadLib("libasound.so.2");
         alsa_handle = LoadLib("libasound.so.2");
         if(!alsa_handle)
         if(!alsa_handle)
+        {
+            WARN("Failed to load %s\n", "libasound.so.2");
             return ALC_FALSE;
             return ALC_FALSE;
+        }
 
 
         error = ALC_FALSE;
         error = ALC_FALSE;
 #define LOAD_FUNC(f) do {                                                     \
 #define LOAD_FUNC(f) do {                                                     \
     p##f = GetSymbol(alsa_handle, #f);                                        \
     p##f = GetSymbol(alsa_handle, #f);                                        \
     if(p##f == NULL) {                                                        \
     if(p##f == NULL) {                                                        \
         error = ALC_TRUE;                                                     \
         error = ALC_TRUE;                                                     \
+        alstr_append_cstr(&missing_funcs, "\n" #f);                           \
     }                                                                         \
     }                                                                         \
 } while(0)
 } while(0)
         ALSA_FUNCS(LOAD_FUNC);
         ALSA_FUNCS(LOAD_FUNC);
@@ -215,10 +223,11 @@ static ALCboolean alsa_load(void)
 
 
         if(error)
         if(error)
         {
         {
+            WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs));
             CloseLib(alsa_handle);
             CloseLib(alsa_handle);
             alsa_handle = NULL;
             alsa_handle = NULL;
-            return ALC_FALSE;
         }
         }
+        alstr_reset(&missing_funcs);
     }
     }
 #endif
 #endif
 
 
@@ -269,11 +278,45 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
 
 
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.device_name);
     AL_STRING_INIT(entry.device_name);
-    al_string_copy_cstr(&entry.name, alsaDevice);
-    al_string_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
-                                                           "device" : "capture", "default"));
+    alstr_copy_cstr(&entry.name, alsaDevice);
+    alstr_copy_cstr(&entry.device_name, GetConfigValue(
+        NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default"
+    ));
     VECTOR_PUSH_BACK(*DeviceList, entry);
     VECTOR_PUSH_BACK(*DeviceList, entry);
 
 
+    if(stream == SND_PCM_STREAM_PLAYBACK)
+    {
+        const char *customdevs, *sep, *next;
+        next = GetConfigValue(NULL, "alsa", "custom-devices", "");
+        while((customdevs=next) != NULL && customdevs[0])
+        {
+            next = strchr(customdevs, ';');
+            sep = strchr(customdevs, '=');
+            if(!sep)
+            {
+                al_string spec = AL_STRING_INIT_STATIC();
+                if(next)
+                    alstr_copy_range(&spec, customdevs, next++);
+                else
+                    alstr_copy_cstr(&spec, customdevs);
+                ERR("Invalid ALSA device specification \"%s\"\n", alstr_get_cstr(spec));
+                alstr_reset(&spec);
+                continue;
+            }
+
+            AL_STRING_INIT(entry.name);
+            AL_STRING_INIT(entry.device_name);
+            alstr_copy_range(&entry.name, customdevs, sep++);
+            if(next)
+                alstr_copy_range(&entry.device_name, sep, next++);
+            else
+                alstr_copy_cstr(&entry.device_name, sep);
+            TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name),
+                  alstr_get_cstr(entry.device_name));
+            VECTOR_PUSH_BACK(*DeviceList, entry);
+        }
+    }
+
     card = -1;
     card = -1;
     if((err=snd_card_next(&card)) < 0)
     if((err=snd_card_next(&card)) < 0)
         ERR("Failed to find a card: %s\n", snd_strerror(err));
         ERR("Failed to find a card: %s\n", snd_strerror(err));
@@ -318,7 +361,8 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
             snd_pcm_info_set_device(pcminfo, dev);
             snd_pcm_info_set_device(pcminfo, dev);
             snd_pcm_info_set_subdevice(pcminfo, 0);
             snd_pcm_info_set_subdevice(pcminfo, 0);
             snd_pcm_info_set_stream(pcminfo, stream);
             snd_pcm_info_set_stream(pcminfo, stream);
-            if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
+            if((err = snd_ctl_pcm_info(handle, pcminfo)) < 0)
+            {
                 if(err != -ENOENT)
                 if(err != -ENOENT)
                     ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
                     ERR("control digital audio info (hw:%d): %s\n", card, snd_strerror(err));
                 continue;
                 continue;
@@ -330,15 +374,15 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
             ConfigValueStr(NULL, "alsa", name, &device_prefix);
             ConfigValueStr(NULL, "alsa", name, &device_prefix);
 
 
             snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
             snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
-                        cardname, devname, cardid, dev);
+                     cardname, devname, cardid, dev);
             snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
             snprintf(device, sizeof(device), "%sCARD=%s,DEV=%d",
-                        device_prefix, cardid, dev);
+                     device_prefix, cardid, dev);
 
 
             TRACE("Got device \"%s\", \"%s\"\n", name, device);
             TRACE("Got device \"%s\", \"%s\"\n", name, device);
             AL_STRING_INIT(entry.name);
             AL_STRING_INIT(entry.name);
             AL_STRING_INIT(entry.device_name);
             AL_STRING_INIT(entry.device_name);
-            al_string_copy_cstr(&entry.name, name);
-            al_string_copy_cstr(&entry.device_name, device);
+            alstr_copy_cstr(&entry.name, name);
+            alstr_copy_cstr(&entry.device_name, device);
             VECTOR_PUSH_BACK(*DeviceList, entry);
             VECTOR_PUSH_BACK(*DeviceList, entry);
         }
         }
         snd_ctl_close(handle);
         snd_ctl_close(handle);
@@ -394,7 +438,7 @@ typedef struct ALCplaybackAlsa {
     ALvoid *buffer;
     ALvoid *buffer;
     ALsizei size;
     ALsizei size;
 
 
-    volatile int killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCplaybackAlsa;
 } ALCplaybackAlsa;
 
 
@@ -402,9 +446,8 @@ static int ALCplaybackAlsa_mixerProc(void *ptr);
 static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr);
 static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr);
 
 
 static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
 static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCplaybackAlsa, ALCbackend, void, Destruct)
+static void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self);
 static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name);
 static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name);
-static void ALCplaybackAlsa_close(ALCplaybackAlsa *self);
 static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self);
 static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self);
 static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
 static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self);
 static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
 static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self);
@@ -422,6 +465,19 @@ static void ALCplaybackAlsa_Construct(ALCplaybackAlsa *self, ALCdevice *device)
 {
 {
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self);
     SET_VTABLE2(ALCplaybackAlsa, ALCbackend, self);
+
+    self->pcmHandle = NULL;
+    self->buffer = NULL;
+
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
+}
+
+void ALCplaybackAlsa_Destruct(ALCplaybackAlsa *self)
+{
+    if(self->pcmHandle)
+        snd_pcm_close(self->pcmHandle);
+    self->pcmHandle = NULL;
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
 
 
 
 
@@ -441,14 +497,14 @@ static int ALCplaybackAlsa_mixerProc(void *ptr)
 
 
     update_size = device->UpdateSize;
     update_size = device->UpdateSize;
     num_updates = device->NumUpdates;
     num_updates = device->NumUpdates;
-    while(!self->killNow)
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
     {
     {
         int state = verify_state(self->pcmHandle);
         int state = verify_state(self->pcmHandle);
         if(state < 0)
         if(state < 0)
         {
         {
             ERR("Invalid state detected: %s\n", snd_strerror(state));
             ERR("Invalid state detected: %s\n", snd_strerror(state));
             ALCplaybackAlsa_lock(self);
             ALCplaybackAlsa_lock(self);
-            aluHandleDisconnect(device);
+            aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state));
             ALCplaybackAlsa_unlock(self);
             ALCplaybackAlsa_unlock(self);
             break;
             break;
         }
         }
@@ -531,14 +587,14 @@ static int ALCplaybackAlsa_mixerNoMMapProc(void *ptr)
 
 
     update_size = device->UpdateSize;
     update_size = device->UpdateSize;
     num_updates = device->NumUpdates;
     num_updates = device->NumUpdates;
-    while(!self->killNow)
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
     {
     {
         int state = verify_state(self->pcmHandle);
         int state = verify_state(self->pcmHandle);
         if(state < 0)
         if(state < 0)
         {
         {
             ERR("Invalid state detected: %s\n", snd_strerror(state));
             ERR("Invalid state detected: %s\n", snd_strerror(state));
             ALCplaybackAlsa_lock(self);
             ALCplaybackAlsa_lock(self);
-            aluHandleDisconnect(device);
+            aluHandleDisconnect(device, "Bad state: %s", snd_strerror(state));
             ALCplaybackAlsa_unlock(self);
             ALCplaybackAlsa_unlock(self);
             break;
             break;
         }
         }
@@ -629,12 +685,12 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
         if(VECTOR_SIZE(PlaybackDevices) == 0)
         if(VECTOR_SIZE(PlaybackDevices) == 0)
             probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
             probe_devices(SND_PCM_STREAM_PLAYBACK, &PlaybackDevices);
 
 
-#define MATCH_NAME(i)  (al_string_cmp_cstr((i)->name, name) == 0)
+#define MATCH_NAME(i)  (alstr_cmp_cstr((i)->name, name) == 0)
         VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
         VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
 #undef MATCH_NAME
 #undef MATCH_NAME
         if(iter == VECTOR_END(PlaybackDevices))
         if(iter == VECTOR_END(PlaybackDevices))
             return ALC_INVALID_VALUE;
             return ALC_INVALID_VALUE;
-        driver = al_string_get_cstr(iter->device_name);
+        driver = alstr_get_cstr(iter->device_name);
     }
     }
     else
     else
     {
     {
@@ -653,16 +709,11 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
     /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
     /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
     snd_config_update_free_global();
     snd_config_update_free_global();
 
 
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCplaybackAlsa_close(ALCplaybackAlsa *self)
-{
-    snd_pcm_close(self->pcmHandle);
-}
-
 static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
 static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -704,7 +755,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
             break;
             break;
     }
     }
 
 
-    allowmmap = GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "mmap", 1);
+    allowmmap = GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "mmap", 1);
     periods = device->NumUpdates;
     periods = device->NumUpdates;
     periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
     periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
     bufferLen = periodLen * periods;
     bufferLen = periodLen * periods;
@@ -748,7 +799,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
     }
     }
     CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
     CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
     /* test and set channels (implicitly sets frame bits) */
     /* test and set channels (implicitly sets frame bits) */
-    if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)) < 0)
+    if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)) < 0)
     {
     {
         static const enum DevFmtChannels channellist[] = {
         static const enum DevFmtChannels channellist[] = {
             DevFmtStereo,
             DevFmtStereo,
@@ -761,16 +812,17 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
 
 
         for(k = 0;k < COUNTOF(channellist);k++)
         for(k = 0;k < COUNTOF(channellist);k++)
         {
         {
-            if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k])) >= 0)
+            if(snd_pcm_hw_params_test_channels(self->pcmHandle, hp, ChannelsFromDevFmt(channellist[k], 0)) >= 0)
             {
             {
                 device->FmtChans = channellist[k];
                 device->FmtChans = channellist[k];
+                device->AmbiOrder = 0;
                 break;
                 break;
             }
             }
         }
         }
     }
     }
-    CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
+    CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)));
     /* set rate (implicitly constrains period/buffer parameters) */
     /* set rate (implicitly constrains period/buffer parameters) */
-    if(!GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) ||
+    if(!GetConfigValueBool(alstr_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0) ||
        !(device->Flags&DEVICE_FREQUENCY_REQUEST))
        !(device->Flags&DEVICE_FREQUENCY_REQUEST))
     {
     {
         if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
         if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
@@ -860,7 +912,7 @@ static ALCboolean ALCplaybackAlsa_start(ALCplaybackAlsa *self)
         }
         }
         thread_func = ALCplaybackAlsa_mixerProc;
         thread_func = ALCplaybackAlsa_mixerProc;
     }
     }
-    self->killNow = 0;
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
     if(althrd_create(&self->thread, thread_func, self) != althrd_success)
     if(althrd_create(&self->thread, thread_func, self) != althrd_success)
     {
     {
         ERR("Could not create playback thread\n");
         ERR("Could not create playback thread\n");
@@ -881,10 +933,8 @@ static void ALCplaybackAlsa_stop(ALCplaybackAlsa *self)
 {
 {
     int res;
     int res;
 
 
-    if(self->killNow)
+    if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         return;
-
-    self->killNow = 1;
     althrd_join(self->thread, &res);
     althrd_join(self->thread, &res);
 
 
     al_free(self->buffer);
     al_free(self->buffer);
@@ -928,9 +978,8 @@ typedef struct ALCcaptureAlsa {
 } ALCcaptureAlsa;
 } ALCcaptureAlsa;
 
 
 static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
 static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, void, Destruct)
+static void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self);
 static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name);
 static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name);
-static void ALCcaptureAlsa_close(ALCcaptureAlsa *self);
 static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset)
 static DECLARE_FORWARD(ALCcaptureAlsa, ALCbackend, ALCboolean, reset)
 static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
 static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self);
 static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
 static void ALCcaptureAlsa_stop(ALCcaptureAlsa *self);
@@ -948,6 +997,25 @@ static void ALCcaptureAlsa_Construct(ALCcaptureAlsa *self, ALCdevice *device)
 {
 {
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self);
     SET_VTABLE2(ALCcaptureAlsa, ALCbackend, self);
+
+    self->pcmHandle = NULL;
+    self->buffer = NULL;
+    self->ring = NULL;
+}
+
+void ALCcaptureAlsa_Destruct(ALCcaptureAlsa *self)
+{
+    if(self->pcmHandle)
+        snd_pcm_close(self->pcmHandle);
+    self->pcmHandle = NULL;
+
+    al_free(self->buffer);
+    self->buffer = NULL;
+
+    ll_ringbuffer_free(self->ring);
+    self->ring = NULL;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
 
 
 
 
@@ -970,12 +1038,12 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
         if(VECTOR_SIZE(CaptureDevices) == 0)
         if(VECTOR_SIZE(CaptureDevices) == 0)
             probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
             probe_devices(SND_PCM_STREAM_CAPTURE, &CaptureDevices);
 
 
-#define MATCH_NAME(i)  (al_string_cmp_cstr((i)->name, name) == 0)
+#define MATCH_NAME(i)  (alstr_cmp_cstr((i)->name, name) == 0)
         VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
         VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
 #undef MATCH_NAME
 #undef MATCH_NAME
         if(iter == VECTOR_END(CaptureDevices))
         if(iter == VECTOR_END(CaptureDevices))
             return ALC_INVALID_VALUE;
             return ALC_INVALID_VALUE;
-        driver = al_string_get_cstr(iter->device_name);
+        driver = alstr_get_cstr(iter->device_name);
     }
     }
     else
     else
     {
     {
@@ -1032,7 +1100,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
     /* set format (implicitly sets sample bits) */
     /* set format (implicitly sets sample bits) */
     CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
     CHECK(snd_pcm_hw_params_set_format(self->pcmHandle, hp, format));
     /* set channels (implicitly sets frame bits) */
     /* set channels (implicitly sets frame bits) */
-    CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
+    CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder)));
     /* set rate (implicitly constrains period/buffer parameters) */
     /* set rate (implicitly constrains period/buffer parameters) */
     CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0));
     CHECK(snd_pcm_hw_params_set_rate(self->pcmHandle, hp, device->Frequency, 0));
     /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
     /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
@@ -1055,8 +1123,9 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
     if(needring)
     if(needring)
     {
     {
         self->ring = ll_ringbuffer_create(
         self->ring = ll_ringbuffer_create(
-            device->UpdateSize*device->NumUpdates + 1,
-            FrameSizeFromDevFmt(device->FmtChans, device->FmtType)
+            device->UpdateSize*device->NumUpdates,
+            FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder),
+            false
         );
         );
         if(!self->ring)
         if(!self->ring)
         {
         {
@@ -1065,7 +1134,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
         }
         }
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 
 
@@ -1077,26 +1146,19 @@ error2:
     ll_ringbuffer_free(self->ring);
     ll_ringbuffer_free(self->ring);
     self->ring = NULL;
     self->ring = NULL;
     snd_pcm_close(self->pcmHandle);
     snd_pcm_close(self->pcmHandle);
+    self->pcmHandle = NULL;
 
 
     return ALC_INVALID_VALUE;
     return ALC_INVALID_VALUE;
 }
 }
 
 
-static void ALCcaptureAlsa_close(ALCcaptureAlsa *self)
-{
-    snd_pcm_close(self->pcmHandle);
-    ll_ringbuffer_free(self->ring);
-
-    al_free(self->buffer);
-    self->buffer = NULL;
-}
-
 static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self)
 static ALCboolean ALCcaptureAlsa_start(ALCcaptureAlsa *self)
 {
 {
     int err = snd_pcm_start(self->pcmHandle);
     int err = snd_pcm_start(self->pcmHandle);
     if(err < 0)
     if(err < 0)
     {
     {
         ERR("start failed: %s\n", snd_strerror(err));
         ERR("start failed: %s\n", snd_strerror(err));
-        aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
+        aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice, "Capture state failure: %s",
+                            snd_strerror(err));
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
 
 
@@ -1147,7 +1209,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
     }
     }
 
 
     self->last_avail -= samples;
     self->last_avail -= samples;
-    while(device->Connected && samples > 0)
+    while(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && samples > 0)
     {
     {
         snd_pcm_sframes_t amt = 0;
         snd_pcm_sframes_t amt = 0;
 
 
@@ -1190,7 +1252,7 @@ static ALCenum ALCcaptureAlsa_captureSamples(ALCcaptureAlsa *self, ALCvoid *buff
             if(amt < 0)
             if(amt < 0)
             {
             {
                 ERR("restore error: %s\n", snd_strerror(amt));
                 ERR("restore error: %s\n", snd_strerror(amt));
-                aluHandleDisconnect(device);
+                aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt));
                 break;
                 break;
             }
             }
             /* If the amount available is less than what's asked, we lost it
             /* If the amount available is less than what's asked, we lost it
@@ -1215,7 +1277,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     snd_pcm_sframes_t avail = 0;
     snd_pcm_sframes_t avail = 0;
 
 
-    if(device->Connected && self->doCapture)
+    if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire) && self->doCapture)
         avail = snd_pcm_avail_update(self->pcmHandle);
         avail = snd_pcm_avail_update(self->pcmHandle);
     if(avail < 0)
     if(avail < 0)
     {
     {
@@ -1231,7 +1293,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
         if(avail < 0)
         if(avail < 0)
         {
         {
             ERR("restore error: %s\n", snd_strerror(avail));
             ERR("restore error: %s\n", snd_strerror(avail));
-            aluHandleDisconnect(device);
+            aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(avail));
         }
         }
     }
     }
 
 
@@ -1270,7 +1332,7 @@ static ALCuint ALCcaptureAlsa_availableSamples(ALCcaptureAlsa *self)
             if(amt < 0)
             if(amt < 0)
             {
             {
                 ERR("restore error: %s\n", snd_strerror(amt));
                 ERR("restore error: %s\n", snd_strerror(amt));
-                aluHandleDisconnect(device);
+                aluHandleDisconnect(device, "Capture recovery failure: %s", snd_strerror(amt));
                 break;
                 break;
             }
             }
             avail = amt;
             avail = amt;
@@ -1307,9 +1369,9 @@ static ClockLatency ALCcaptureAlsa_getClockLatency(ALCcaptureAlsa *self)
 
 
 
 
 static inline void AppendAllDevicesList2(const DevMap *entry)
 static inline void AppendAllDevicesList2(const DevMap *entry)
-{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
+{ AppendAllDevicesList(alstr_get_cstr(entry->name)); }
 static inline void AppendCaptureDeviceList2(const DevMap *entry)
 static inline void AppendCaptureDeviceList2(const DevMap *entry)
-{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
+{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); }
 
 
 typedef struct ALCalsaBackendFactory {
 typedef struct ALCalsaBackendFactory {
     DERIVE_FROM_TYPE(ALCbackendFactory);
     DERIVE_FROM_TYPE(ALCbackendFactory);

+ 17 - 159
Engine/lib/openal-soft/Alc/backends/base.c

@@ -4,11 +4,14 @@
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "alMain.h"
 #include "alMain.h"
+#include "alu.h"
 
 
 #include "backends/base.h"
 #include "backends/base.h"
 
 
 
 
 extern inline ALuint64 GetDeviceClockTime(ALCdevice *device);
 extern inline ALuint64 GetDeviceClockTime(ALCdevice *device);
+extern inline void ALCdevice_Lock(ALCdevice *device);
+extern inline void ALCdevice_Unlock(ALCdevice *device);
 
 
 /* Base ALCbackend method implementations. */
 /* Base ALCbackend method implementations. */
 void ALCbackend_Construct(ALCbackend *self, ALCdevice *device)
 void ALCbackend_Construct(ALCbackend *self, ALCdevice *device)
@@ -41,13 +44,22 @@ ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self))
 ClockLatency ALCbackend_getClockLatency(ALCbackend *self)
 ClockLatency ALCbackend_getClockLatency(ALCbackend *self)
 {
 {
     ALCdevice *device = self->mDevice;
     ALCdevice *device = self->mDevice;
+    ALuint refcount;
     ClockLatency ret;
     ClockLatency ret;
 
 
-    almtx_lock(&self->mMutex);
-    ret.ClockTime = GetDeviceClockTime(device);
-    // TODO: Perhaps should be NumUpdates-1 worth of UpdateSize?
-    ret.Latency = 0;
-    almtx_unlock(&self->mMutex);
+    do {
+        while(((refcount=ATOMIC_LOAD(&device->MixCount, almemory_order_acquire))&1))
+            althrd_yield();
+        ret.ClockTime = GetDeviceClockTime(device);
+        ATOMIC_THREAD_FENCE(almemory_order_acquire);
+    } while(refcount != ATOMIC_LOAD(&device->MixCount, almemory_order_relaxed));
+
+    /* NOTE: The device will generally have about all but one periods filled at
+     * any given time during playback. Without a more accurate measurement from
+     * the output, this is an okay approximation.
+     */
+    ret.Latency = device->UpdateSize * DEVICE_CLOCK_RES / device->Frequency *
+                  maxu(device->NumUpdates-1, 1);
 
 
     return ret;
     return ret;
 }
 }
@@ -69,157 +81,3 @@ void ALCbackend_unlock(ALCbackend *self)
 void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self))
 void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self))
 {
 {
 }
 }
-
-
-/* Wrappers to use an old-style backend with the new interface. */
-typedef struct PlaybackWrapper {
-    DERIVE_FROM_TYPE(ALCbackend);
-
-    const BackendFuncs *Funcs;
-} PlaybackWrapper;
-
-static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs);
-static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, Destruct)
-static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name);
-static void PlaybackWrapper_close(PlaybackWrapper *self);
-static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self);
-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 DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency)
-static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
-static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
-DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
-DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper);
-
-static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
-{
-    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
-    SET_VTABLE2(PlaybackWrapper, ALCbackend, self);
-
-    self->Funcs = funcs;
-}
-
-static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    return self->Funcs->OpenPlayback(device, name);
-}
-
-static void PlaybackWrapper_close(PlaybackWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    self->Funcs->ClosePlayback(device);
-}
-
-static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    return self->Funcs->ResetPlayback(device);
-}
-
-static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    return self->Funcs->StartPlayback(device);
-}
-
-static void PlaybackWrapper_stop(PlaybackWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    self->Funcs->StopPlayback(device);
-}
-
-
-typedef struct CaptureWrapper {
-    DERIVE_FROM_TYPE(ALCbackend);
-
-    const BackendFuncs *Funcs;
-} CaptureWrapper;
-
-static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs);
-static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, Destruct)
-static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name);
-static void CaptureWrapper_close(CaptureWrapper *self);
-static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset)
-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 DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency)
-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);
-    SET_VTABLE2(CaptureWrapper, ALCbackend, self);
-
-    self->Funcs = funcs;
-}
-
-static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    return self->Funcs->OpenCapture(device, name);
-}
-
-static void CaptureWrapper_close(CaptureWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    self->Funcs->CloseCapture(device);
-}
-
-static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    self->Funcs->StartCapture(device);
-    return ALC_TRUE;
-}
-
-static void CaptureWrapper_stop(CaptureWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    self->Funcs->StopCapture(device);
-}
-
-static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    return self->Funcs->CaptureSamples(device, buffer, samples);
-}
-
-static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    return self->Funcs->AvailableSamples(device);
-}
-
-
-ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type)
-{
-    if(type == ALCbackend_Playback)
-    {
-        PlaybackWrapper *backend;
-
-        NEW_OBJ(backend, PlaybackWrapper)(device, funcs);
-        if(!backend) return NULL;
-
-        return STATIC_CAST(ALCbackend, backend);
-    }
-
-    if(type == ALCbackend_Capture)
-    {
-        CaptureWrapper *backend;
-
-        NEW_OBJ(backend, CaptureWrapper)(device, funcs);
-        if(!backend) return NULL;
-
-        return STATIC_CAST(ALCbackend, backend);
-    }
-
-    return NULL;
-}

+ 20 - 5
Engine/lib/openal-soft/Alc/backends/base.h

@@ -5,6 +5,10 @@
 #include "threads.h"
 #include "threads.h"
 
 
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct ClockLatency {
 typedef struct ClockLatency {
     ALint64 ClockTime;
     ALint64 ClockTime;
     ALint64 Latency;
     ALint64 Latency;
@@ -43,7 +47,6 @@ struct ALCbackendVtable {
     void (*const Destruct)(ALCbackend*);
     void (*const Destruct)(ALCbackend*);
 
 
     ALCenum (*const open)(ALCbackend*, const ALCchar*);
     ALCenum (*const open)(ALCbackend*, const ALCchar*);
-    void (*const close)(ALCbackend*);
 
 
     ALCboolean (*const reset)(ALCbackend*);
     ALCboolean (*const reset)(ALCbackend*);
     ALCboolean (*const start)(ALCbackend*);
     ALCboolean (*const start)(ALCbackend*);
@@ -63,7 +66,6 @@ struct ALCbackendVtable {
 #define DEFINE_ALCBACKEND_VTABLE(T)                                           \
 #define DEFINE_ALCBACKEND_VTABLE(T)                                           \
 DECLARE_THUNK(T, ALCbackend, void, Destruct)                                  \
 DECLARE_THUNK(T, ALCbackend, void, Destruct)                                  \
 DECLARE_THUNK1(T, ALCbackend, ALCenum, open, const ALCchar*)                  \
 DECLARE_THUNK1(T, ALCbackend, ALCenum, open, const ALCchar*)                  \
-DECLARE_THUNK(T, ALCbackend, void, close)                                     \
 DECLARE_THUNK(T, ALCbackend, ALCboolean, reset)                               \
 DECLARE_THUNK(T, ALCbackend, ALCboolean, reset)                               \
 DECLARE_THUNK(T, ALCbackend, ALCboolean, start)                               \
 DECLARE_THUNK(T, ALCbackend, ALCboolean, start)                               \
 DECLARE_THUNK(T, ALCbackend, void, stop)                                      \
 DECLARE_THUNK(T, ALCbackend, void, stop)                                      \
@@ -79,7 +81,6 @@ static const struct ALCbackendVtable T##_ALCbackend_vtable = {                \
     T##_ALCbackend_Destruct,                                                  \
     T##_ALCbackend_Destruct,                                                  \
                                                                               \
                                                                               \
     T##_ALCbackend_open,                                                      \
     T##_ALCbackend_open,                                                      \
-    T##_ALCbackend_close,                                                     \
     T##_ALCbackend_reset,                                                     \
     T##_ALCbackend_reset,                                                     \
     T##_ALCbackend_start,                                                     \
     T##_ALCbackend_start,                                                     \
     T##_ALCbackend_stop,                                                      \
     T##_ALCbackend_stop,                                                      \
@@ -137,17 +138,31 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = {  \
 
 
 ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
 ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
 ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
 ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
+ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void);
 ALCbackendFactory *ALCossBackendFactory_getFactory(void);
 ALCbackendFactory *ALCossBackendFactory_getFactory(void);
 ALCbackendFactory *ALCjackBackendFactory_getFactory(void);
 ALCbackendFactory *ALCjackBackendFactory_getFactory(void);
 ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
 ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
-ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
+ALCbackendFactory *ALCsndioBackendFactory_getFactory(void);
+ALCbackendFactory *ALCqsaBackendFactory_getFactory(void);
+ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void);
 ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
 ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
 ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void);
 ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void);
 ALCbackendFactory *ALCportBackendFactory_getFactory(void);
 ALCbackendFactory *ALCportBackendFactory_getFactory(void);
+ALCbackendFactory *ALCopenslBackendFactory_getFactory(void);
 ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
 ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
 ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
 ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
+ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void);
 ALCbackendFactory *ALCloopbackFactory_getFactory(void);
 ALCbackendFactory *ALCloopbackFactory_getFactory(void);
 
 
-ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type);
+
+inline void ALCdevice_Lock(ALCdevice *device)
+{ V0(device->Backend,lock)(); }
+
+inline void ALCdevice_Unlock(ALCdevice *device)
+{ V0(device->Backend,unlock)(); }
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
 
 
 #endif /* AL_BACKENDS_BASE_H */
 #endif /* AL_BACKENDS_BASE_H */

+ 313 - 227
Engine/lib/openal-soft/Alc/backends/coreaudio.c

@@ -23,128 +23,91 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
-#include <alloca.h>
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "ringbuffer.h"
 
 
 #include <CoreServices/CoreServices.h>
 #include <CoreServices/CoreServices.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <AudioUnit/AudioUnit.h>
 #include <AudioUnit/AudioUnit.h>
 #include <AudioToolbox/AudioToolbox.h>
 #include <AudioToolbox/AudioToolbox.h>
 
 
+#include "backends/base.h"
 
 
-typedef struct {
-    AudioUnit audioUnit;
 
 
-    ALuint frameSize;
-    ALdouble sampleRateRatio;              // Ratio of hardware sample rate / requested sample rate
-    AudioStreamBasicDescription format;    // This is the OpenAL format as a CoreAudio ASBD
+static const ALCchar ca_device[] = "CoreAudio Default";
 
 
-    AudioConverterRef audioConverter;      // Sample rate converter if needed
-    AudioBufferList *bufferList;           // Buffer for data coming from the input device
-    ALCvoid *resampleBuffer;               // Buffer for returned RingBuffer data when resampling
 
 
-    ll_ringbuffer_t *ring;
-} ca_data;
+typedef struct ALCcoreAudioPlayback {
+    DERIVE_FROM_TYPE(ALCbackend);
 
 
-static const ALCchar ca_device[] = "CoreAudio Default";
+    AudioUnit audioUnit;
 
 
+    ALuint frameSize;
+    AudioStreamBasicDescription format;    // This is the OpenAL format as a CoreAudio ASBD
+} ALCcoreAudioPlayback;
 
 
-static void destroy_buffer_list(AudioBufferList* list)
-{
-    if(list)
-    {
-        UInt32 i;
-        for(i = 0;i < list->mNumberBuffers;i++)
-            free(list->mBuffers[i].mData);
-        free(list);
-    }
-}
+static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device);
+static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self);
+static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name);
+static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self);
+static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self);
+static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self);
+static DECLARE_FORWARD2(ALCcoreAudioPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCcoreAudioPlayback, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioPlayback)
 
 
-static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize)
-{
-    AudioBufferList *list;
+DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioPlayback);
 
 
-    list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer));
-    if(list)
-    {
-        list->mNumberBuffers = 1;
-
-        list->mBuffers[0].mNumberChannels = channelCount;
-        list->mBuffers[0].mDataByteSize = byteSize;
-        list->mBuffers[0].mData = malloc(byteSize);
-        if(list->mBuffers[0].mData == NULL)
-        {
-            free(list);
-            list = NULL;
-        }
-    }
-    return list;
-}
 
 
-static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp,
-                            UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
+static void ALCcoreAudioPlayback_Construct(ALCcoreAudioPlayback *self, ALCdevice *device)
 {
 {
-    ALCdevice *device = (ALCdevice*)inRefCon;
-    ca_data *data = (ca_data*)device->ExtraData;
-
-    aluMixData(device, ioData->mBuffers[0].mData,
-               ioData->mBuffers[0].mDataByteSize / data->frameSize);
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCcoreAudioPlayback, ALCbackend, self);
 
 
-    return noErr;
+    self->frameSize = 0;
+    memset(&self->format, 0, sizeof(self->format));
 }
 }
 
 
-static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
-        AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData)
+static void ALCcoreAudioPlayback_Destruct(ALCcoreAudioPlayback *self)
 {
 {
-    ALCdevice *device = (ALCdevice*)inUserData;
-    ca_data *data = (ca_data*)device->ExtraData;
-
-    // Read from the ring buffer and store temporarily in a large buffer
-    ll_ringbuffer_read(data->ring, data->resampleBuffer, *ioNumberDataPackets);
-
-    // Set the input data
-    ioData->mNumberBuffers = 1;
-    ioData->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame;
-    ioData->mBuffers[0].mData = data->resampleBuffer;
-    ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * data->format.mBytesPerFrame;
+    AudioUnitUninitialize(self->audioUnit);
+    AudioComponentInstanceDispose(self->audioUnit);
 
 
-    return noErr;
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
 
 
-static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
-                                    const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
-                                    UInt32 inNumberFrames, AudioBufferList *ioData)
-{
-    ALCdevice *device = (ALCdevice*)inRefCon;
-    ca_data *data = (ca_data*)device->ExtraData;
-    AudioUnitRenderActionFlags flags = 0;
-    OSStatus err;
 
 
-    // fill the bufferList with data from the input device
-    err = AudioUnitRender(data->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, data->bufferList);
-    if(err != noErr)
-    {
-        ERR("AudioUnitRender error: %d\n", err);
-        return err;
-    }
+static OSStatus ALCcoreAudioPlayback_MixerProc(void *inRefCon,
+  AudioUnitRenderActionFlags* UNUSED(ioActionFlags), const AudioTimeStamp* UNUSED(inTimeStamp),
+  UInt32 UNUSED(inBusNumber), UInt32 UNUSED(inNumberFrames), AudioBufferList *ioData)
+{
+    ALCcoreAudioPlayback *self = inRefCon;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
 
 
-    ll_ringbuffer_write(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames);
+    ALCcoreAudioPlayback_lock(self);
+    aluMixData(device, ioData->mBuffers[0].mData,
+               ioData->mBuffers[0].mDataByteSize / self->frameSize);
+    ALCcoreAudioPlayback_unlock(self);
 
 
     return noErr;
     return noErr;
 }
 }
 
 
-static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName)
+
+static ALCenum ALCcoreAudioPlayback_open(ALCcoreAudioPlayback *self, const ALCchar *name)
 {
 {
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     AudioComponentDescription desc;
     AudioComponentDescription desc;
     AudioComponent comp;
     AudioComponent comp;
-    ca_data *data;
     OSStatus err;
     OSStatus err;
 
 
-    if(!deviceName)
-        deviceName = ca_device;
-    else if(strcmp(deviceName, ca_device) != 0)
+    if(!name)
+        name = ca_device;
+    else if(strcmp(name, ca_device) != 0)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
 
 
     /* open the default output unit */
     /* open the default output unit */
@@ -161,57 +124,41 @@ static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    data = calloc(1, sizeof(*data));
-
-    err = AudioComponentInstanceNew(comp, &data->audioUnit);
+    err = AudioComponentInstanceNew(comp, &self->audioUnit);
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioComponentInstanceNew failed\n");
         ERR("AudioComponentInstanceNew failed\n");
-        free(data);
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
     /* init and start the default audio unit... */
     /* init and start the default audio unit... */
-    err = AudioUnitInitialize(data->audioUnit);
+    err = AudioUnitInitialize(self->audioUnit);
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitInitialize failed\n");
         ERR("AudioUnitInitialize failed\n");
-        AudioComponentInstanceDispose(data->audioUnit);
-        free(data);
+        AudioComponentInstanceDispose(self->audioUnit);
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
-    device->ExtraData = data;
+    alstr_copy_cstr(&device->DeviceName, name);
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ca_close_playback(ALCdevice *device)
+static ALCboolean ALCcoreAudioPlayback_reset(ALCcoreAudioPlayback *self)
 {
 {
-    ca_data *data = (ca_data*)device->ExtraData;
-
-    AudioUnitUninitialize(data->audioUnit);
-    AudioComponentInstanceDispose(data->audioUnit);
-
-    free(data);
-    device->ExtraData = NULL;
-}
-
-static ALCboolean ca_reset_playback(ALCdevice *device)
-{
-    ca_data *data = (ca_data*)device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     AudioStreamBasicDescription streamFormat;
     AudioStreamBasicDescription streamFormat;
     AURenderCallbackStruct input;
     AURenderCallbackStruct input;
     OSStatus err;
     OSStatus err;
     UInt32 size;
     UInt32 size;
 
 
-    err = AudioUnitUninitialize(data->audioUnit);
+    err = AudioUnitUninitialize(self->audioUnit);
     if(err != noErr)
     if(err != noErr)
         ERR("-- AudioUnitUninitialize failed.\n");
         ERR("-- AudioUnitUninitialize failed.\n");
 
 
     /* retrieve default output unit's properties (output side) */
     /* retrieve default output unit's properties (output side) */
     size = sizeof(AudioStreamBasicDescription);
     size = sizeof(AudioStreamBasicDescription);
-    err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
+    err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
     if(err != noErr || size != sizeof(AudioStreamBasicDescription))
     if(err != noErr || size != sizeof(AudioStreamBasicDescription))
     {
     {
         ERR("AudioUnitGetProperty failed\n");
         ERR("AudioUnitGetProperty failed\n");
@@ -229,7 +176,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
 #endif
 #endif
 
 
     /* set default output unit's input side to match output side */
     /* set default output unit's input side to match output side */
-    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size);
+    err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size);
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed\n");
         ERR("AudioUnitSetProperty failed\n");
@@ -313,7 +260,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
     streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian |
     streamFormat.mFormatFlags |= kAudioFormatFlagsNativeEndian |
                                  kLinearPCMFormatFlagIsPacked;
                                  kLinearPCMFormatFlagIsPacked;
 
 
-    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription));
+    err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription));
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed\n");
         ERR("AudioUnitSetProperty failed\n");
@@ -321,11 +268,11 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
     }
     }
 
 
     /* setup callback */
     /* setup callback */
-    data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
-    input.inputProc = ca_callback;
-    input.inputProcRefCon = device;
+    self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
+    input.inputProc = ALCcoreAudioPlayback_MixerProc;
+    input.inputProcRefCon = self;
 
 
-    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
+    err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed\n");
         ERR("AudioUnitSetProperty failed\n");
@@ -333,7 +280,7 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
     }
     }
 
 
     /* init the default audio unit... */
     /* init the default audio unit... */
-    err = AudioUnitInitialize(data->audioUnit);
+    err = AudioUnitInitialize(self->audioUnit);
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitInitialize failed\n");
         ERR("AudioUnitInitialize failed\n");
@@ -343,12 +290,9 @@ static ALCboolean ca_reset_playback(ALCdevice *device)
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-static ALCboolean ca_start_playback(ALCdevice *device)
+static ALCboolean ALCcoreAudioPlayback_start(ALCcoreAudioPlayback *self)
 {
 {
-    ca_data *data = (ca_data*)device->ExtraData;
-    OSStatus err;
-
-    err = AudioOutputUnitStart(data->audioUnit);
+    OSStatus err = AudioOutputUnitStart(self->audioUnit);
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioOutputUnitStart failed\n");
         ERR("AudioOutputUnitStart failed\n");
@@ -358,18 +302,150 @@ static ALCboolean ca_start_playback(ALCdevice *device)
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-static void ca_stop_playback(ALCdevice *device)
+static void ALCcoreAudioPlayback_stop(ALCcoreAudioPlayback *self)
+{
+    OSStatus err = AudioOutputUnitStop(self->audioUnit);
+    if(err != noErr)
+        ERR("AudioOutputUnitStop failed\n");
+}
+
+
+
+
+typedef struct ALCcoreAudioCapture {
+    DERIVE_FROM_TYPE(ALCbackend);
+
+    AudioUnit audioUnit;
+
+    ALuint frameSize;
+    ALdouble sampleRateRatio;              // Ratio of hardware sample rate / requested sample rate
+    AudioStreamBasicDescription format;    // This is the OpenAL format as a CoreAudio ASBD
+
+    AudioConverterRef audioConverter;      // Sample rate converter if needed
+    AudioBufferList *bufferList;           // Buffer for data coming from the input device
+    ALCvoid *resampleBuffer;               // Buffer for returned RingBuffer data when resampling
+
+    ll_ringbuffer_t *ring;
+} ALCcoreAudioCapture;
+
+static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device);
+static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self);
+static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name);
+static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self);
+static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self);
+static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self);
+static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCcoreAudioCapture, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCcoreAudioCapture)
+
+DEFINE_ALCBACKEND_VTABLE(ALCcoreAudioCapture);
+
+
+static AudioBufferList *allocate_buffer_list(UInt32 channelCount, UInt32 byteSize)
 {
 {
-    ca_data *data = (ca_data*)device->ExtraData;
+    AudioBufferList *list;
+
+    list = calloc(1, FAM_SIZE(AudioBufferList, mBuffers, 1) + byteSize);
+    if(list)
+    {
+        list->mNumberBuffers = 1;
+
+        list->mBuffers[0].mNumberChannels = channelCount;
+        list->mBuffers[0].mDataByteSize = byteSize;
+        list->mBuffers[0].mData = &list->mBuffers[1];
+    }
+    return list;
+}
+
+static void destroy_buffer_list(AudioBufferList *list)
+{
+    free(list);
+}
+
+
+static void ALCcoreAudioCapture_Construct(ALCcoreAudioCapture *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCcoreAudioCapture, ALCbackend, self);
+
+    self->audioUnit = 0;
+    self->audioConverter = NULL;
+    self->bufferList = NULL;
+    self->resampleBuffer = NULL;
+    self->ring = NULL;
+}
+
+static void ALCcoreAudioCapture_Destruct(ALCcoreAudioCapture *self)
+{
+    ll_ringbuffer_free(self->ring);
+    self->ring = NULL;
+
+    free(self->resampleBuffer);
+    self->resampleBuffer = NULL;
+
+    destroy_buffer_list(self->bufferList);
+    self->bufferList = NULL;
+
+    if(self->audioConverter)
+        AudioConverterDispose(self->audioConverter);
+    self->audioConverter = NULL;
+
+    if(self->audioUnit)
+        AudioComponentInstanceDispose(self->audioUnit);
+    self->audioUnit = 0;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+static OSStatus ALCcoreAudioCapture_RecordProc(void *inRefCon,
+  AudioUnitRenderActionFlags* UNUSED(ioActionFlags),
+  const AudioTimeStamp *inTimeStamp, UInt32 UNUSED(inBusNumber),
+  UInt32 inNumberFrames, AudioBufferList* UNUSED(ioData))
+{
+    ALCcoreAudioCapture *self = inRefCon;
+    AudioUnitRenderActionFlags flags = 0;
     OSStatus err;
     OSStatus err;
 
 
-    err = AudioOutputUnitStop(data->audioUnit);
+    // fill the bufferList with data from the input device
+    err = AudioUnitRender(self->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, self->bufferList);
     if(err != noErr)
     if(err != noErr)
-        ERR("AudioOutputUnitStop failed\n");
+    {
+        ERR("AudioUnitRender error: %d\n", err);
+        return err;
+    }
+
+    ll_ringbuffer_write(self->ring, self->bufferList->mBuffers[0].mData, inNumberFrames);
+
+    return noErr;
 }
 }
 
 
-static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
+static OSStatus ALCcoreAudioCapture_ConvertCallback(AudioConverterRef UNUSED(inAudioConverter),
+  UInt32 *ioNumberDataPackets, AudioBufferList *ioData,
+  AudioStreamPacketDescription** UNUSED(outDataPacketDescription),
+  void *inUserData)
 {
 {
+    ALCcoreAudioCapture *self = inUserData;
+
+    // Read from the ring buffer and store temporarily in a large buffer
+    ll_ringbuffer_read(self->ring, self->resampleBuffer, *ioNumberDataPackets);
+
+    // Set the input data
+    ioData->mNumberBuffers = 1;
+    ioData->mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame;
+    ioData->mBuffers[0].mData = self->resampleBuffer;
+    ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * self->format.mBytesPerFrame;
+
+    return noErr;
+}
+
+
+static ALCenum ALCcoreAudioCapture_open(ALCcoreAudioCapture *self, const ALCchar *name)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     AudioStreamBasicDescription requestedFormat;  // The application requested format
     AudioStreamBasicDescription requestedFormat;  // The application requested format
     AudioStreamBasicDescription hardwareFormat;   // The hardware format
     AudioStreamBasicDescription hardwareFormat;   // The hardware format
     AudioStreamBasicDescription outputFormat;     // The AudioUnit output format
     AudioStreamBasicDescription outputFormat;     // The AudioUnit output format
@@ -381,12 +457,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     AudioObjectPropertyAddress propertyAddress;
     AudioObjectPropertyAddress propertyAddress;
     UInt32 enableIO;
     UInt32 enableIO;
     AudioComponent comp;
     AudioComponent comp;
-    ca_data *data;
     OSStatus err;
     OSStatus err;
 
 
-    if(!deviceName)
-        deviceName = ca_device;
-    else if(strcmp(deviceName, ca_device) != 0)
+    if(!name)
+        name = ca_device;
+    else if(strcmp(name, ca_device) != 0)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
 
 
     desc.componentType = kAudioUnitType_Output;
     desc.componentType = kAudioUnitType_Output;
@@ -403,11 +478,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    data = calloc(1, sizeof(*data));
-    device->ExtraData = data;
-
     // Open the component
     // Open the component
-    err = AudioComponentInstanceNew(comp, &data->audioUnit);
+    err = AudioComponentInstanceNew(comp, &self->audioUnit);
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioComponentInstanceNew failed\n");
         ERR("AudioComponentInstanceNew failed\n");
@@ -416,7 +488,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
 
 
     // Turn off AudioUnit output
     // Turn off AudioUnit output
     enableIO = 0;
     enableIO = 0;
-    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
+    err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed\n");
         ERR("AudioUnitSetProperty failed\n");
@@ -425,7 +497,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
 
 
     // Turn on AudioUnit input
     // Turn on AudioUnit input
     enableIO = 1;
     enableIO = 1;
-    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
+    err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed\n");
         ERR("AudioUnitSetProperty failed\n");
@@ -453,7 +525,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     }
     }
 
 
     // Track the input device
     // Track the input device
-    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
+    err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed\n");
         ERR("AudioUnitSetProperty failed\n");
@@ -461,10 +533,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     }
     }
 
 
     // set capture callback
     // set capture callback
-    input.inputProc = ca_capture_callback;
-    input.inputProcRefCon = device;
+    input.inputProc = ALCcoreAudioCapture_RecordProc;
+    input.inputProcRefCon = self;
 
 
-    err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
+    err = AudioUnitSetProperty(self->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed\n");
         ERR("AudioUnitSetProperty failed\n");
@@ -472,7 +544,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     }
     }
 
 
     // Initialize the device
     // Initialize the device
-    err = AudioUnitInitialize(data->audioUnit);
+    err = AudioUnitInitialize(self->audioUnit);
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitInitialize failed\n");
         ERR("AudioUnitInitialize failed\n");
@@ -481,7 +553,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
 
 
     // Get the hardware format
     // Get the hardware format
     propertySize = sizeof(AudioStreamBasicDescription);
     propertySize = sizeof(AudioStreamBasicDescription);
-    err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize);
+    err = AudioUnitGetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize);
     if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription))
     if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription))
     {
     {
         ERR("AudioUnitGetProperty failed\n");
         ERR("AudioUnitGetProperty failed\n");
@@ -528,9 +600,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
         case DevFmtX51Rear:
         case DevFmtX51Rear:
         case DevFmtX61:
         case DevFmtX61:
         case DevFmtX71:
         case DevFmtX71:
-        case DevFmtAmbi1:
-        case DevFmtAmbi2:
-        case DevFmtAmbi3:
+        case DevFmtAmbi3D:
             ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
             ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
             goto error;
             goto error;
     }
     }
@@ -543,8 +613,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     requestedFormat.mFramesPerPacket = 1;
     requestedFormat.mFramesPerPacket = 1;
 
 
     // save requested format description for later use
     // save requested format description for later use
-    data->format = requestedFormat;
-    data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    self->format = requestedFormat;
+    self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
     // Use intermediate format for sample rate conversion (outputFormat)
     // Use intermediate format for sample rate conversion (outputFormat)
     // Set sample rate to the same as hardware for resampling later
     // Set sample rate to the same as hardware for resampling later
@@ -552,11 +622,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     outputFormat.mSampleRate = hardwareFormat.mSampleRate;
     outputFormat.mSampleRate = hardwareFormat.mSampleRate;
 
 
     // Determine sample rate ratio for resampling
     // Determine sample rate ratio for resampling
-    data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency;
+    self->sampleRateRatio = outputFormat.mSampleRate / device->Frequency;
 
 
     // The output format should be the requested format, but using the hardware sample rate
     // The output format should be the requested format, but using the hardware sample rate
     // This is because the AudioUnit will automatically scale other properties, except for sample rate
     // This is because the AudioUnit will automatically scale other properties, except for sample rate
-    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat));
+    err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat));
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed\n");
         ERR("AudioUnitSetProperty failed\n");
@@ -564,8 +634,8 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     }
     }
 
 
     // Set the AudioUnit output format frame count
     // Set the AudioUnit output format frame count
-    outputFrameCount = device->UpdateSize * data->sampleRateRatio;
-    err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount));
+    outputFrameCount = device->UpdateSize * self->sampleRateRatio;
+    err = AudioUnitSetProperty(self->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount));
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioUnitSetProperty failed: %d\n", err);
         ERR("AudioUnitSetProperty failed: %d\n", err);
@@ -573,7 +643,7 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     }
     }
 
 
     // Set up sample converter
     // Set up sample converter
-    err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter);
+    err = AudioConverterNew(&outputFormat, &requestedFormat, &self->audioConverter);
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioConverterNew failed: %d\n", err);
         ERR("AudioConverterNew failed: %d\n", err);
@@ -581,96 +651,83 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     }
     }
 
 
     // Create a buffer for use in the resample callback
     // Create a buffer for use in the resample callback
-    data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio);
+    self->resampleBuffer = malloc(device->UpdateSize * self->frameSize * self->sampleRateRatio);
 
 
     // Allocate buffer for the AudioUnit output
     // Allocate buffer for the AudioUnit output
-    data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio);
-    if(data->bufferList == NULL)
+    self->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * self->frameSize * self->sampleRateRatio);
+    if(self->bufferList == NULL)
         goto error;
         goto error;
 
 
-    data->ring = ll_ringbuffer_create(
-        device->UpdateSize*data->sampleRateRatio*device->NumUpdates + 1,
-        data->frameSize
+    self->ring = ll_ringbuffer_create(
+        (size_t)ceil(device->UpdateSize*self->sampleRateRatio*device->NumUpdates),
+        self->frameSize, false
     );
     );
-    if(!data->ring) goto error;
+    if(!self->ring) goto error;
 
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 
 
 error:
 error:
-    ll_ringbuffer_free(data->ring);
-    data->ring = NULL;
-    free(data->resampleBuffer);
-    destroy_buffer_list(data->bufferList);
-
-    if(data->audioConverter)
-        AudioConverterDispose(data->audioConverter);
-    if(data->audioUnit)
-        AudioComponentInstanceDispose(data->audioUnit);
-
-    free(data);
-    device->ExtraData = NULL;
+    ll_ringbuffer_free(self->ring);
+    self->ring = NULL;
+    free(self->resampleBuffer);
+    self->resampleBuffer = NULL;
+    destroy_buffer_list(self->bufferList);
+    self->bufferList = NULL;
+
+    if(self->audioConverter)
+        AudioConverterDispose(self->audioConverter);
+    self->audioConverter = NULL;
+    if(self->audioUnit)
+        AudioComponentInstanceDispose(self->audioUnit);
+    self->audioUnit = 0;
 
 
     return ALC_INVALID_VALUE;
     return ALC_INVALID_VALUE;
 }
 }
 
 
-static void ca_close_capture(ALCdevice *device)
-{
-    ca_data *data = (ca_data*)device->ExtraData;
-
-    ll_ringbuffer_free(data->ring);
-    data->ring = NULL;
-    free(data->resampleBuffer);
-    destroy_buffer_list(data->bufferList);
-
-    AudioConverterDispose(data->audioConverter);
-    AudioComponentInstanceDispose(data->audioUnit);
 
 
-    free(data);
-    device->ExtraData = NULL;
-}
-
-static void ca_start_capture(ALCdevice *device)
+static ALCboolean ALCcoreAudioCapture_start(ALCcoreAudioCapture *self)
 {
 {
-    ca_data *data = (ca_data*)device->ExtraData;
-    OSStatus err = AudioOutputUnitStart(data->audioUnit);
+    OSStatus err = AudioOutputUnitStart(self->audioUnit);
     if(err != noErr)
     if(err != noErr)
+    {
         ERR("AudioOutputUnitStart failed\n");
         ERR("AudioOutputUnitStart failed\n");
+        return ALC_FALSE;
+    }
+    return ALC_TRUE;
 }
 }
 
 
-static void ca_stop_capture(ALCdevice *device)
+static void ALCcoreAudioCapture_stop(ALCcoreAudioCapture *self)
 {
 {
-    ca_data *data = (ca_data*)device->ExtraData;
-    OSStatus err = AudioOutputUnitStop(data->audioUnit);
+    OSStatus err = AudioOutputUnitStop(self->audioUnit);
     if(err != noErr)
     if(err != noErr)
         ERR("AudioOutputUnitStop failed\n");
         ERR("AudioOutputUnitStop failed\n");
 }
 }
 
 
-static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+static ALCenum ALCcoreAudioCapture_captureSamples(ALCcoreAudioCapture *self, ALCvoid *buffer, ALCuint samples)
 {
 {
-    ca_data *data = (ca_data*)device->ExtraData;
-    AudioBufferList *list;
+    union {
+        ALbyte _[sizeof(AudioBufferList) + sizeof(AudioBuffer)];
+        AudioBufferList list;
+    } audiobuf = { { 0 } };
     UInt32 frameCount;
     UInt32 frameCount;
     OSStatus err;
     OSStatus err;
 
 
     // If no samples are requested, just return
     // If no samples are requested, just return
-    if(samples == 0)
-        return ALC_NO_ERROR;
-
-    // Allocate a temporary AudioBufferList to use as the return resamples data
-    list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer));
+    if(samples == 0) return ALC_NO_ERROR;
 
 
     // Point the resampling buffer to the capture buffer
     // Point the resampling buffer to the capture buffer
-    list->mNumberBuffers = 1;
-    list->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame;
-    list->mBuffers[0].mDataByteSize = samples * data->frameSize;
-    list->mBuffers[0].mData = buffer;
+    audiobuf.list.mNumberBuffers = 1;
+    audiobuf.list.mBuffers[0].mNumberChannels = self->format.mChannelsPerFrame;
+    audiobuf.list.mBuffers[0].mDataByteSize = samples * self->frameSize;
+    audiobuf.list.mBuffers[0].mData = buffer;
 
 
     // Resample into another AudioBufferList
     // Resample into another AudioBufferList
     frameCount = samples;
     frameCount = samples;
-    err = AudioConverterFillComplexBuffer(data->audioConverter, ca_capture_conversion_callback,
-                                          device, &frameCount, list, NULL);
+    err = AudioConverterFillComplexBuffer(self->audioConverter,
+        ALCcoreAudioCapture_ConvertCallback, self, &frameCount, &audiobuf.list, NULL
+    );
     if(err != noErr)
     if(err != noErr)
     {
     {
         ERR("AudioConverterFillComplexBuffer error: %d\n", err);
         ERR("AudioConverterFillComplexBuffer error: %d\n", err);
@@ -679,38 +736,47 @@ static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint sa
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static ALCuint ca_available_samples(ALCdevice *device)
+static ALCuint ALCcoreAudioCapture_availableSamples(ALCcoreAudioCapture *self)
+{
+    return ll_ringbuffer_read_space(self->ring) / self->sampleRateRatio;
+}
+
+
+typedef struct ALCcoreAudioBackendFactory {
+    DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCcoreAudioBackendFactory;
+#define ALCCOREAUDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCcoreAudioBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void);
+
+static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory *self);
+static DECLARE_FORWARD(ALCcoreAudioBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory *self, ALCbackend_Type type);
+static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCcoreAudioBackendFactory);
+
+
+ALCbackendFactory *ALCcoreAudioBackendFactory_getFactory(void)
 {
 {
-    ca_data *data = device->ExtraData;
-    return ll_ringbuffer_read_space(data->ring) / data->sampleRateRatio;
+    static ALCcoreAudioBackendFactory factory = ALCCOREAUDIOBACKENDFACTORY_INITIALIZER;
+    return STATIC_CAST(ALCbackendFactory, &factory);
 }
 }
 
 
 
 
-static const BackendFuncs ca_funcs = {
-    ca_open_playback,
-    ca_close_playback,
-    ca_reset_playback,
-    ca_start_playback,
-    ca_stop_playback,
-    ca_open_capture,
-    ca_close_capture,
-    ca_start_capture,
-    ca_stop_capture,
-    ca_capture_samples,
-    ca_available_samples
-};
-
-ALCboolean alc_ca_init(BackendFuncs *func_list)
+static ALCboolean ALCcoreAudioBackendFactory_init(ALCcoreAudioBackendFactory* UNUSED(self))
 {
 {
-    *func_list = ca_funcs;
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-void alc_ca_deinit(void)
+static ALCboolean ALCcoreAudioBackendFactory_querySupport(ALCcoreAudioBackendFactory* UNUSED(self), ALCbackend_Type type)
 {
 {
+    if(type == ALCbackend_Playback || ALCbackend_Capture)
+        return ALC_TRUE;
+    return ALC_FALSE;
 }
 }
 
 
-void alc_ca_probe(enum DevProbe type)
+static void ALCcoreAudioBackendFactory_probe(ALCcoreAudioBackendFactory* UNUSED(self), enum DevProbe type)
 {
 {
     switch(type)
     switch(type)
     {
     {
@@ -722,3 +788,23 @@ void alc_ca_probe(enum DevProbe type)
             break;
             break;
     }
     }
 }
 }
+
+static ALCbackend* ALCcoreAudioBackendFactory_createBackend(ALCcoreAudioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+    {
+        ALCcoreAudioPlayback *backend;
+        NEW_OBJ(backend, ALCcoreAudioPlayback)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+    if(type == ALCbackend_Capture)
+    {
+        ALCcoreAudioCapture *backend;
+        NEW_OBJ(backend, ALCcoreAudioCapture)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+
+    return NULL;
+}

+ 172 - 158
Engine/lib/openal-soft/Alc/backends/dsound.c

@@ -34,6 +34,7 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "ringbuffer.h"
 #include "threads.h"
 #include "threads.h"
 #include "compat.h"
 #include "compat.h"
 #include "alstring.h"
 #include "alstring.h"
@@ -145,16 +146,16 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA
     {
     {
         const DevMap *iter;
         const DevMap *iter;
 
 
-        al_string_copy_cstr(&entry.name, DEVNAME_HEAD);
-        al_string_append_wcstr(&entry.name, desc);
+        alstr_copy_cstr(&entry.name, DEVNAME_HEAD);
+        alstr_append_wcstr(&entry.name, desc);
         if(count != 0)
         if(count != 0)
         {
         {
             char str[64];
             char str[64];
             snprintf(str, sizeof(str), " #%d", count+1);
             snprintf(str, sizeof(str), " #%d", count+1);
-            al_string_append_cstr(&entry.name, str);
+            alstr_append_cstr(&entry.name, str);
         }
         }
 
 
-#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0)
         VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY);
         VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY);
         if(iter == VECTOR_END(*devices)) break;
         if(iter == VECTOR_END(*devices)) break;
 #undef MATCH_ENTRY
 #undef MATCH_ENTRY
@@ -165,7 +166,7 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA
     hr = StringFromCLSID(guid, &guidstr);
     hr = StringFromCLSID(guid, &guidstr);
     if(SUCCEEDED(hr))
     if(SUCCEEDED(hr))
     {
     {
-        TRACE("Got device \"%s\", GUID \"%ls\"\n", al_string_get_cstr(entry.name), guidstr);
+        TRACE("Got device \"%s\", GUID \"%ls\"\n", alstr_get_cstr(entry.name), guidstr);
         CoTaskMemFree(guidstr);
         CoTaskMemFree(guidstr);
     }
     }
 
 
@@ -184,16 +185,15 @@ typedef struct ALCdsoundPlayback {
     IDirectSoundNotify *Notifies;
     IDirectSoundNotify *Notifies;
     HANDLE             NotifyEvent;
     HANDLE             NotifyEvent;
 
 
-    volatile int killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCdsoundPlayback;
 } ALCdsoundPlayback;
 
 
 static int ALCdsoundPlayback_mixerProc(void *ptr);
 static int ALCdsoundPlayback_mixerProc(void *ptr);
 
 
 static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device);
 static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, Destruct)
+static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self);
 static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name);
 static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name);
-static void ALCdsoundPlayback_close(ALCdsoundPlayback *self);
 static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self);
 static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self);
 static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self);
 static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self);
 static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self);
 static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self);
@@ -211,6 +211,35 @@ static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *devi
 {
 {
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self);
     SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self);
+
+    self->DS = NULL;
+    self->PrimaryBuffer = NULL;
+    self->Buffer = NULL;
+    self->Notifies = NULL;
+    self->NotifyEvent = NULL;
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
+}
+
+static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self)
+{
+    if(self->Notifies)
+        IDirectSoundNotify_Release(self->Notifies);
+    self->Notifies = NULL;
+    if(self->Buffer)
+        IDirectSoundBuffer_Release(self->Buffer);
+    self->Buffer = NULL;
+    if(self->PrimaryBuffer != NULL)
+        IDirectSoundBuffer_Release(self->PrimaryBuffer);
+    self->PrimaryBuffer = NULL;
+
+    if(self->DS)
+        IDirectSound_Release(self->DS);
+    self->DS = NULL;
+    if(self->NotifyEvent)
+        CloseHandle(self->NotifyEvent);
+    self->NotifyEvent = NULL;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
 
 
 
 
@@ -239,16 +268,17 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
     {
     {
         ERR("Failed to get buffer caps: 0x%lx\n", err);
         ERR("Failed to get buffer caps: 0x%lx\n", err);
         ALCdevice_Lock(device);
         ALCdevice_Lock(device);
-        aluHandleDisconnect(device);
+        aluHandleDisconnect(device, "Failure retrieving playback buffer info: 0x%lx", err);
         ALCdevice_Unlock(device);
         ALCdevice_Unlock(device);
         return 1;
         return 1;
     }
     }
 
 
-    FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
     FragSize = device->UpdateSize * FrameSize;
     FragSize = device->UpdateSize * FrameSize;
 
 
     IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL);
     IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL);
-    while(!self->killNow)
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
     {
     {
         // Get current play cursor
         // Get current play cursor
         IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &PlayCursor, NULL);
         IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &PlayCursor, NULL);
@@ -263,7 +293,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
                 {
                 {
                     ERR("Failed to play buffer: 0x%lx\n", err);
                     ERR("Failed to play buffer: 0x%lx\n", err);
                     ALCdevice_Lock(device);
                     ALCdevice_Lock(device);
-                    aluHandleDisconnect(device);
+                    aluHandleDisconnect(device, "Failure starting playback: 0x%lx", err);
                     ALCdevice_Unlock(device);
                     ALCdevice_Unlock(device);
                     return 1;
                     return 1;
                 }
                 }
@@ -299,8 +329,10 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
         if(SUCCEEDED(err))
         if(SUCCEEDED(err))
         {
         {
             // If we have an active context, mix data directly into output buffer otherwise fill with silence
             // If we have an active context, mix data directly into output buffer otherwise fill with silence
+            ALCdevice_Lock(device);
             aluMixData(device, WritePtr1, WriteCnt1/FrameSize);
             aluMixData(device, WritePtr1, WriteCnt1/FrameSize);
             aluMixData(device, WritePtr2, WriteCnt2/FrameSize);
             aluMixData(device, WritePtr2, WriteCnt2/FrameSize);
+            ALCdevice_Unlock(device);
 
 
             // Unlock output buffer only when successfully locked
             // Unlock output buffer only when successfully locked
             IDirectSoundBuffer_Unlock(self->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
             IDirectSoundBuffer_Unlock(self->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
@@ -309,7 +341,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
         {
         {
             ERR("Buffer lock error: %#lx\n", err);
             ERR("Buffer lock error: %#lx\n", err);
             ALCdevice_Lock(device);
             ALCdevice_Lock(device);
-            aluHandleDisconnect(device);
+            aluHandleDisconnect(device, "Failed to lock output buffer: 0x%lx", err);
             ALCdevice_Unlock(device);
             ALCdevice_Unlock(device);
             return 1;
             return 1;
         }
         }
@@ -341,14 +373,14 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de
 
 
     if(!deviceName && VECTOR_SIZE(PlaybackDevices) > 0)
     if(!deviceName && VECTOR_SIZE(PlaybackDevices) > 0)
     {
     {
-        deviceName = al_string_get_cstr(VECTOR_FRONT(PlaybackDevices).name);
+        deviceName = alstr_get_cstr(VECTOR_FRONT(PlaybackDevices).name);
         guid = &VECTOR_FRONT(PlaybackDevices).guid;
         guid = &VECTOR_FRONT(PlaybackDevices).guid;
     }
     }
     else
     else
     {
     {
         const DevMap *iter;
         const DevMap *iter;
 
 
-#define MATCH_NAME(i)  (al_string_cmp_cstr((i)->name, deviceName) == 0)
+#define MATCH_NAME(i)  (alstr_cmp_cstr((i)->name, deviceName) == 0)
         VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
         VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
 #undef MATCH_NAME
 #undef MATCH_NAME
         if(iter == VECTOR_END(PlaybackDevices))
         if(iter == VECTOR_END(PlaybackDevices))
@@ -379,29 +411,11 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
+    alstr_copy_cstr(&device->DeviceName, deviceName);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCdsoundPlayback_close(ALCdsoundPlayback *self)
-{
-    if(self->Notifies)
-        IDirectSoundNotify_Release(self->Notifies);
-    self->Notifies = NULL;
-    if(self->Buffer)
-        IDirectSoundBuffer_Release(self->Buffer);
-    self->Buffer = NULL;
-    if(self->PrimaryBuffer != NULL)
-        IDirectSoundBuffer_Release(self->PrimaryBuffer);
-    self->PrimaryBuffer = NULL;
-
-    IDirectSound_Release(self->DS);
-    self->DS = NULL;
-    CloseHandle(self->NotifyEvent);
-    self->NotifyEvent = NULL;
-}
-
 static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
 static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -472,9 +486,7 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
             case DevFmtMono:
             case DevFmtMono:
                 OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
                 OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
                 break;
                 break;
-            case DevFmtAmbi1:
-            case DevFmtAmbi2:
-            case DevFmtAmbi3:
+            case DevFmtAmbi3D:
                 device->FmtChans = DevFmtStereo;
                 device->FmtChans = DevFmtStereo;
                 /*fall-through*/
                 /*fall-through*/
             case DevFmtStereo:
             case DevFmtStereo:
@@ -527,7 +539,7 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
 retry_open:
 retry_open:
         hr = S_OK;
         hr = S_OK;
         OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
         OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
-        OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
+        OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
         OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
         OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
         OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
         OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
         OutputType.Format.nSamplesPerSec = device->Frequency;
         OutputType.Format.nSamplesPerSec = device->Frequency;
@@ -626,7 +638,7 @@ retry_open:
 
 
 static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self)
 static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self)
 {
 {
-    self->killNow = 0;
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
     if(althrd_create(&self->thread, ALCdsoundPlayback_mixerProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCdsoundPlayback_mixerProc, self) != althrd_success)
         return ALC_FALSE;
         return ALC_FALSE;
 
 
@@ -637,10 +649,8 @@ static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self)
 {
 {
     int res;
     int res;
 
 
-    if(self->killNow)
+    if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         return;
-
-    self->killNow = 1;
     althrd_join(self->thread, &res);
     althrd_join(self->thread, &res);
 
 
     IDirectSoundBuffer_Stop(self->Buffer);
     IDirectSoundBuffer_Stop(self->Buffer);
@@ -660,9 +670,8 @@ typedef struct ALCdsoundCapture {
 } ALCdsoundCapture;
 } ALCdsoundCapture;
 
 
 static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device);
 static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, Destruct)
+static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self);
 static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name);
 static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name);
-static void ALCdsoundCapture_close(ALCdsoundCapture *self);
 static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset)
 static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset)
 static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self);
 static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self);
 static void ALCdsoundCapture_stop(ALCdsoundCapture *self);
 static void ALCdsoundCapture_stop(ALCdsoundCapture *self);
@@ -679,6 +688,29 @@ static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device
 {
 {
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCdsoundCapture, ALCbackend, self);
     SET_VTABLE2(ALCdsoundCapture, ALCbackend, self);
+
+    self->DSC = NULL;
+    self->DSCbuffer = NULL;
+    self->Ring = NULL;
+}
+
+static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self)
+{
+    ll_ringbuffer_free(self->Ring);
+    self->Ring = NULL;
+
+    if(self->DSCbuffer != NULL)
+    {
+        IDirectSoundCaptureBuffer_Stop(self->DSCbuffer);
+        IDirectSoundCaptureBuffer_Release(self->DSCbuffer);
+        self->DSCbuffer = NULL;
+    }
+
+    if(self->DSC)
+        IDirectSoundCapture_Release(self->DSC);
+    self->DSC = NULL;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
 
 
 
 
@@ -704,14 +736,14 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
 
 
     if(!deviceName && VECTOR_SIZE(CaptureDevices) > 0)
     if(!deviceName && VECTOR_SIZE(CaptureDevices) > 0)
     {
     {
-        deviceName = al_string_get_cstr(VECTOR_FRONT(CaptureDevices).name);
+        deviceName = alstr_get_cstr(VECTOR_FRONT(CaptureDevices).name);
         guid = &VECTOR_FRONT(CaptureDevices).guid;
         guid = &VECTOR_FRONT(CaptureDevices).guid;
     }
     }
     else
     else
     {
     {
         const DevMap *iter;
         const DevMap *iter;
 
 
-#define MATCH_NAME(i)  (al_string_cmp_cstr((i)->name, deviceName) == 0)
+#define MATCH_NAME(i)  (alstr_cmp_cstr((i)->name, deviceName) == 0)
         VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
         VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
 #undef MATCH_NAME
 #undef MATCH_NAME
         if(iter == VECTOR_END(CaptureDevices))
         if(iter == VECTOR_END(CaptureDevices))
@@ -734,102 +766,98 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
             break;
             break;
     }
     }
 
 
-    //DirectSoundCapture Init code
-    hr = DirectSoundCaptureCreate(guid, &self->DSC, NULL);
-    if(SUCCEEDED(hr))
+    memset(&InputType, 0, sizeof(InputType));
+    switch(device->FmtChans)
     {
     {
-        memset(&InputType, 0, sizeof(InputType));
-
-        switch(device->FmtChans)
-        {
-            case DevFmtMono:
-                InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
-                break;
-            case DevFmtStereo:
-                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
-                                          SPEAKER_FRONT_RIGHT;
-                break;
-            case DevFmtQuad:
-                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
-                                          SPEAKER_FRONT_RIGHT |
-                                          SPEAKER_BACK_LEFT |
-                                          SPEAKER_BACK_RIGHT;
-                break;
-            case DevFmtX51:
-                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
-                                          SPEAKER_FRONT_RIGHT |
-                                          SPEAKER_FRONT_CENTER |
-                                          SPEAKER_LOW_FREQUENCY |
-                                          SPEAKER_SIDE_LEFT |
-                                          SPEAKER_SIDE_RIGHT;
-                break;
-            case DevFmtX51Rear:
-                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
-                                          SPEAKER_FRONT_RIGHT |
-                                          SPEAKER_FRONT_CENTER |
-                                          SPEAKER_LOW_FREQUENCY |
-                                          SPEAKER_BACK_LEFT |
-                                          SPEAKER_BACK_RIGHT;
-                break;
-            case DevFmtX61:
-                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
-                                          SPEAKER_FRONT_RIGHT |
-                                          SPEAKER_FRONT_CENTER |
-                                          SPEAKER_LOW_FREQUENCY |
-                                          SPEAKER_BACK_CENTER |
-                                          SPEAKER_SIDE_LEFT |
-                                          SPEAKER_SIDE_RIGHT;
-                break;
-            case DevFmtX71:
-                InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
-                                          SPEAKER_FRONT_RIGHT |
-                                          SPEAKER_FRONT_CENTER |
-                                          SPEAKER_LOW_FREQUENCY |
-                                          SPEAKER_BACK_LEFT |
-                                          SPEAKER_BACK_RIGHT |
-                                          SPEAKER_SIDE_LEFT |
-                                          SPEAKER_SIDE_RIGHT;
-                break;
-            case DevFmtAmbi1:
-            case DevFmtAmbi2:
-            case DevFmtAmbi3:
-                break;
-        }
+        case DevFmtMono:
+            InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
+            break;
+        case DevFmtStereo:
+            InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                      SPEAKER_FRONT_RIGHT;
+            break;
+        case DevFmtQuad:
+            InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                      SPEAKER_FRONT_RIGHT |
+                                      SPEAKER_BACK_LEFT |
+                                      SPEAKER_BACK_RIGHT;
+            break;
+        case DevFmtX51:
+            InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                      SPEAKER_FRONT_RIGHT |
+                                      SPEAKER_FRONT_CENTER |
+                                      SPEAKER_LOW_FREQUENCY |
+                                      SPEAKER_SIDE_LEFT |
+                                      SPEAKER_SIDE_RIGHT;
+            break;
+        case DevFmtX51Rear:
+            InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                      SPEAKER_FRONT_RIGHT |
+                                      SPEAKER_FRONT_CENTER |
+                                      SPEAKER_LOW_FREQUENCY |
+                                      SPEAKER_BACK_LEFT |
+                                      SPEAKER_BACK_RIGHT;
+            break;
+        case DevFmtX61:
+            InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                      SPEAKER_FRONT_RIGHT |
+                                      SPEAKER_FRONT_CENTER |
+                                      SPEAKER_LOW_FREQUENCY |
+                                      SPEAKER_BACK_CENTER |
+                                      SPEAKER_SIDE_LEFT |
+                                      SPEAKER_SIDE_RIGHT;
+            break;
+        case DevFmtX71:
+            InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                      SPEAKER_FRONT_RIGHT |
+                                      SPEAKER_FRONT_CENTER |
+                                      SPEAKER_LOW_FREQUENCY |
+                                      SPEAKER_BACK_LEFT |
+                                      SPEAKER_BACK_RIGHT |
+                                      SPEAKER_SIDE_LEFT |
+                                      SPEAKER_SIDE_RIGHT;
+            break;
+        case DevFmtAmbi3D:
+            WARN("%s capture not supported\n", DevFmtChannelsString(device->FmtChans));
+            return ALC_INVALID_ENUM;
+    }
 
 
-        InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
-        InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
-        InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
-        InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
-        InputType.Format.nSamplesPerSec = device->Frequency;
-        InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
-        InputType.Format.cbSize = 0;
+    InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
+    InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
+    InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
+    InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
+    InputType.Format.nSamplesPerSec = device->Frequency;
+    InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
+    InputType.Format.cbSize = 0;
+    InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
+    if(device->FmtType == DevFmtFloat)
+        InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+    else
+        InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
 
 
-        if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
-        {
-            InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
-            InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
-            InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
-            if(device->FmtType == DevFmtFloat)
-                InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
-            else
-                InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
-        }
+    if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
+    {
+        InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+        InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
+    }
 
 
-        samples = device->UpdateSize * device->NumUpdates;
-        samples = maxu(samples, 100 * device->Frequency / 1000);
+    samples = device->UpdateSize * device->NumUpdates;
+    samples = maxu(samples, 100 * device->Frequency / 1000);
 
 
-        memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
-        DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
-        DSCBDescription.dwFlags = 0;
-        DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
-        DSCBDescription.lpwfxFormat = &InputType.Format;
+    memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
+    DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
+    DSCBDescription.dwFlags = 0;
+    DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
+    DSCBDescription.lpwfxFormat = &InputType.Format;
 
 
+    //DirectSoundCapture Init code
+    hr = DirectSoundCaptureCreate(guid, &self->DSC, NULL);
+    if(SUCCEEDED(hr))
         hr = IDirectSoundCapture_CreateCaptureBuffer(self->DSC, &DSCBDescription, &self->DSCbuffer, NULL);
         hr = IDirectSoundCapture_CreateCaptureBuffer(self->DSC, &DSCBDescription, &self->DSCbuffer, NULL);
-    }
     if(SUCCEEDED(hr))
     if(SUCCEEDED(hr))
     {
     {
-         self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1,
-                                           InputType.Format.nBlockAlign);
+         self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates,
+                                           InputType.Format.nBlockAlign, false);
          if(self->Ring == NULL)
          if(self->Ring == NULL)
              hr = DSERR_OUTOFMEMORY;
              hr = DSERR_OUTOFMEMORY;
     }
     }
@@ -853,27 +881,11 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
     self->BufferBytes = DSCBDescription.dwBufferBytes;
     self->BufferBytes = DSCBDescription.dwBufferBytes;
     SetDefaultWFXChannelOrder(device);
     SetDefaultWFXChannelOrder(device);
 
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
+    alstr_copy_cstr(&device->DeviceName, deviceName);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCdsoundCapture_close(ALCdsoundCapture *self)
-{
-    ll_ringbuffer_free(self->Ring);
-    self->Ring = NULL;
-
-    if(self->DSCbuffer != NULL)
-    {
-        IDirectSoundCaptureBuffer_Stop(self->DSCbuffer);
-        IDirectSoundCaptureBuffer_Release(self->DSCbuffer);
-        self->DSCbuffer = NULL;
-    }
-
-    IDirectSoundCapture_Release(self->DSC);
-    self->DSC = NULL;
-}
-
 static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self)
 static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self)
 {
 {
     HRESULT hr;
     HRESULT hr;
@@ -882,7 +894,8 @@ static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self)
     if(FAILED(hr))
     if(FAILED(hr))
     {
     {
         ERR("start failed: 0x%08lx\n", hr);
         ERR("start failed: 0x%08lx\n", hr);
-        aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
+        aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
+                            "Failure starting capture: 0x%lx", hr);
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
 
 
@@ -897,7 +910,8 @@ static void ALCdsoundCapture_stop(ALCdsoundCapture *self)
     if(FAILED(hr))
     if(FAILED(hr))
     {
     {
         ERR("stop failed: 0x%08lx\n", hr);
         ERR("stop failed: 0x%08lx\n", hr);
-        aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice);
+        aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
+                            "Failure stopping capture: 0x%lx", hr);
     }
     }
 }
 }
 
 
@@ -916,10 +930,10 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self)
     DWORD FrameSize;
     DWORD FrameSize;
     HRESULT hr;
     HRESULT hr;
 
 
-    if(!device->Connected)
+    if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
         goto done;
         goto done;
 
 
-    FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
     BufferBytes = self->BufferBytes;
     BufferBytes = self->BufferBytes;
     LastCursor = self->Cursor;
     LastCursor = self->Cursor;
 
 
@@ -947,18 +961,18 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self)
     if(FAILED(hr))
     if(FAILED(hr))
     {
     {
         ERR("update failed: 0x%08lx\n", hr);
         ERR("update failed: 0x%08lx\n", hr);
-        aluHandleDisconnect(device);
+        aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr);
     }
     }
 
 
 done:
 done:
-    return ll_ringbuffer_read_space(self->Ring);
+    return (ALCuint)ll_ringbuffer_read_space(self->Ring);
 }
 }
 
 
 
 
 static inline void AppendAllDevicesList2(const DevMap *entry)
 static inline void AppendAllDevicesList2(const DevMap *entry)
-{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
+{ AppendAllDevicesList(alstr_get_cstr(entry->name)); }
 static inline void AppendCaptureDeviceList2(const DevMap *entry)
 static inline void AppendCaptureDeviceList2(const DevMap *entry)
-{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
+{ AppendCaptureDeviceList(alstr_get_cstr(entry->name)); }
 
 
 typedef struct ALCdsoundBackendFactory {
 typedef struct ALCdsoundBackendFactory {
     DERIVE_FROM_TYPE(ALCbackendFactory);
     DERIVE_FROM_TYPE(ALCbackendFactory);

+ 63 - 83
Engine/lib/openal-soft/Alc/backends/jack.c

@@ -26,6 +26,8 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "alconfig.h"
+#include "ringbuffer.h"
 #include "threads.h"
 #include "threads.h"
 #include "compat.h"
 #include "compat.h"
 
 
@@ -63,6 +65,7 @@ static const ALCchar jackDevice[] = "JACK Default";
 static void *jack_handle;
 static void *jack_handle;
 #define MAKE_FUNC(f) static __typeof(f) * p##f
 #define MAKE_FUNC(f) static __typeof(f) * p##f
 JACK_FUNCS(MAKE_FUNC);
 JACK_FUNCS(MAKE_FUNC);
+static __typeof(jack_error_callback) * pjack_error_callback;
 #undef MAKE_FUNC
 #undef MAKE_FUNC
 
 
 #define jack_client_open pjack_client_open
 #define jack_client_open pjack_client_open
@@ -84,6 +87,7 @@ JACK_FUNCS(MAKE_FUNC);
 #define jack_set_buffer_size_callback pjack_set_buffer_size_callback
 #define jack_set_buffer_size_callback pjack_set_buffer_size_callback
 #define jack_set_buffer_size pjack_set_buffer_size
 #define jack_set_buffer_size pjack_set_buffer_size
 #define jack_get_buffer_size pjack_get_buffer_size
 #define jack_get_buffer_size pjack_get_buffer_size
+#define jack_error_callback (*pjack_error_callback)
 #endif
 #endif
 
 
 
 
@@ -96,6 +100,8 @@ static ALCboolean jack_load(void)
 #ifdef HAVE_DYNLOAD
 #ifdef HAVE_DYNLOAD
     if(!jack_handle)
     if(!jack_handle)
     {
     {
+        al_string missing_funcs = AL_STRING_INIT_STATIC();
+
 #ifdef _WIN32
 #ifdef _WIN32
 #define JACKLIB "libjack.dll"
 #define JACKLIB "libjack.dll"
 #else
 #else
@@ -103,24 +109,33 @@ static ALCboolean jack_load(void)
 #endif
 #endif
         jack_handle = LoadLib(JACKLIB);
         jack_handle = LoadLib(JACKLIB);
         if(!jack_handle)
         if(!jack_handle)
+        {
+            WARN("Failed to load %s\n", JACKLIB);
             return ALC_FALSE;
             return ALC_FALSE;
+        }
 
 
         error = ALC_FALSE;
         error = ALC_FALSE;
 #define LOAD_FUNC(f) do {                                                     \
 #define LOAD_FUNC(f) do {                                                     \
     p##f = GetSymbol(jack_handle, #f);                                        \
     p##f = GetSymbol(jack_handle, #f);                                        \
     if(p##f == NULL) {                                                        \
     if(p##f == NULL) {                                                        \
         error = ALC_TRUE;                                                     \
         error = ALC_TRUE;                                                     \
+        alstr_append_cstr(&missing_funcs, "\n" #f);                           \
     }                                                                         \
     }                                                                         \
 } while(0)
 } while(0)
         JACK_FUNCS(LOAD_FUNC);
         JACK_FUNCS(LOAD_FUNC);
 #undef LOAD_FUNC
 #undef LOAD_FUNC
+        /* Optional symbols. These don't exist in all versions of JACK. */
+#define LOAD_SYM(f) p##f = GetSymbol(jack_handle, #f)
+        LOAD_SYM(jack_error_callback);
+#undef LOAD_SYM
 
 
         if(error)
         if(error)
         {
         {
+            WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs));
             CloseLib(jack_handle);
             CloseLib(jack_handle);
             jack_handle = NULL;
             jack_handle = NULL;
-            return ALC_FALSE;
         }
         }
+        alstr_reset(&missing_funcs);
     }
     }
 #endif
 #endif
 
 
@@ -135,9 +150,9 @@ typedef struct ALCjackPlayback {
     jack_port_t *Port[MAX_OUTPUT_CHANNELS];
     jack_port_t *Port[MAX_OUTPUT_CHANNELS];
 
 
     ll_ringbuffer_t *Ring;
     ll_ringbuffer_t *Ring;
-    alcnd_t Cond;
+    alsem_t Sem;
 
 
-    volatile int killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCjackPlayback;
 } ALCjackPlayback;
 
 
@@ -149,15 +164,14 @@ static int ALCjackPlayback_mixerProc(void *arg);
 static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device);
 static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device);
 static void ALCjackPlayback_Destruct(ALCjackPlayback *self);
 static void ALCjackPlayback_Destruct(ALCjackPlayback *self);
 static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name);
 static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name);
-static void ALCjackPlayback_close(ALCjackPlayback *self);
 static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self);
 static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self);
 static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self);
 static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self);
 static void ALCjackPlayback_stop(ALCjackPlayback *self);
 static void ALCjackPlayback_stop(ALCjackPlayback *self);
 static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
 static DECLARE_FORWARD2(ALCjackPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples)
 static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, ALCuint, availableSamples)
 static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self);
 static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self);
-static void ALCjackPlayback_lock(ALCjackPlayback *self);
-static void ALCjackPlayback_unlock(ALCjackPlayback *self);
+static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCjackPlayback, ALCbackend, void, unlock)
 DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback)
 DECLARE_DEFAULT_ALLOCATORS(ALCjackPlayback)
 
 
 DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback);
 DEFINE_ALCBACKEND_VTABLE(ALCjackPlayback);
@@ -170,14 +184,14 @@ static void ALCjackPlayback_Construct(ALCjackPlayback *self, ALCdevice *device)
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCjackPlayback, ALCbackend, self);
     SET_VTABLE2(ALCjackPlayback, ALCbackend, self);
 
 
-    alcnd_init(&self->Cond);
+    alsem_init(&self->Sem, 0);
 
 
     self->Client = NULL;
     self->Client = NULL;
     for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
     for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
         self->Port[i] = NULL;
         self->Port[i] = NULL;
     self->Ring = NULL;
     self->Ring = NULL;
 
 
-    self->killNow = 1;
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
 }
 }
 
 
 static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
 static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
@@ -196,7 +210,7 @@ static void ALCjackPlayback_Destruct(ALCjackPlayback *self)
         self->Client = NULL;
         self->Client = NULL;
     }
     }
 
 
-    alcnd_destroy(&self->Cond);
+    alsem_destroy(&self->Sem);
 
 
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
@@ -211,19 +225,23 @@ static int ALCjackPlayback_bufferSizeNotify(jack_nframes_t numframes, void *arg)
     ALCjackPlayback_lock(self);
     ALCjackPlayback_lock(self);
     device->UpdateSize = numframes;
     device->UpdateSize = numframes;
     device->NumUpdates = 2;
     device->NumUpdates = 2;
-    TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates);
 
 
     bufsize = device->UpdateSize;
     bufsize = device->UpdateSize;
-    if(ConfigValueUInt(al_string_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize))
+    if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize))
         bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
         bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
-    bufsize += device->UpdateSize;
+    device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize;
+
+    TRACE("%u update size x%u\n", device->UpdateSize, device->NumUpdates);
 
 
     ll_ringbuffer_free(self->Ring);
     ll_ringbuffer_free(self->Ring);
-    self->Ring = ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType));
+    self->Ring = ll_ringbuffer_create(bufsize,
+        FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder),
+        true
+    );
     if(!self->Ring)
     if(!self->Ring)
     {
     {
         ERR("Failed to reallocate ringbuffer\n");
         ERR("Failed to reallocate ringbuffer\n");
-        aluHandleDisconnect(device);
+        aluHandleDisconnect(device, "Failed to reallocate %u-sample buffer", bufsize);
     }
     }
     ALCjackPlayback_unlock(self);
     ALCjackPlayback_unlock(self);
     return 0;
     return 0;
@@ -237,7 +255,7 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg)
     ll_ringbuffer_data_t data[2];
     ll_ringbuffer_data_t data[2];
     jack_nframes_t total = 0;
     jack_nframes_t total = 0;
     jack_nframes_t todo;
     jack_nframes_t todo;
-    ALuint i, c, numchans;
+    ALsizei i, c, numchans;
 
 
     ll_ringbuffer_get_read_vector(self->Ring, data);
     ll_ringbuffer_get_read_vector(self->Ring, data);
 
 
@@ -248,8 +266,9 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg)
     todo = minu(numframes, data[0].len);
     todo = minu(numframes, data[0].len);
     for(c = 0;c < numchans;c++)
     for(c = 0;c < numchans;c++)
     {
     {
-        for(i = 0;i < todo;i++)
-            out[c][i] = ((ALfloat*)data[0].buf)[i*numchans + c];
+        const ALfloat *restrict in = ((ALfloat*)data[0].buf) + c;
+        for(i = 0;(jack_nframes_t)i < todo;i++)
+            out[c][i] = in[i*numchans];
         out[c] += todo;
         out[c] += todo;
     }
     }
     total += todo;
     total += todo;
@@ -259,22 +278,23 @@ static int ALCjackPlayback_process(jack_nframes_t numframes, void *arg)
     {
     {
         for(c = 0;c < numchans;c++)
         for(c = 0;c < numchans;c++)
         {
         {
-            for(i = 0;i < todo;i++)
-                out[c][i] = ((ALfloat*)data[1].buf)[i*numchans + c];
+            const ALfloat *restrict in = ((ALfloat*)data[1].buf) + c;
+            for(i = 0;(jack_nframes_t)i < todo;i++)
+                out[c][i] = in[i*numchans];
             out[c] += todo;
             out[c] += todo;
         }
         }
         total += todo;
         total += todo;
     }
     }
 
 
     ll_ringbuffer_read_advance(self->Ring, total);
     ll_ringbuffer_read_advance(self->Ring, total);
-    alcnd_signal(&self->Cond);
+    alsem_post(&self->Sem);
 
 
     if(numframes > total)
     if(numframes > total)
     {
     {
         todo = numframes-total;
         todo = numframes-total;
         for(c = 0;c < numchans;c++)
         for(c = 0;c < numchans;c++)
         {
         {
-            for(i = 0;i < todo;i++)
+            for(i = 0;(jack_nframes_t)i < todo;i++)
                 out[c][i] = 0.0f;
                 out[c][i] = 0.0f;
         }
         }
     }
     }
@@ -292,27 +312,16 @@ static int ALCjackPlayback_mixerProc(void *arg)
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
 
 
     ALCjackPlayback_lock(self);
     ALCjackPlayback_lock(self);
-    while(!self->killNow && device->Connected)
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
     {
     {
         ALuint todo, len1, len2;
         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)
         if(ll_ringbuffer_write_space(self->Ring) < device->UpdateSize)
         {
         {
-            alcnd_wait(&self->Cond, &STATIC_CAST(ALCbackend,self)->mMutex);
+            ALCjackPlayback_unlock(self);
+            alsem_wait(&self->Sem);
+            ALCjackPlayback_lock(self);
             continue;
             continue;
         }
         }
 
 
@@ -362,29 +371,15 @@ static ALCenum ALCjackPlayback_open(ALCjackPlayback *self, const ALCchar *name)
     jack_set_process_callback(self->Client, ALCjackPlayback_process, self);
     jack_set_process_callback(self->Client, ALCjackPlayback_process, self);
     jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self);
     jack_set_buffer_size_callback(self->Client, ALCjackPlayback_bufferSizeNotify, self);
 
 
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     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)
 static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    ALuint numchans, i;
+    ALsizei numchans, i;
     ALuint bufsize;
     ALuint bufsize;
 
 
     for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
     for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
@@ -395,23 +390,21 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
     }
     }
 
 
     /* Ignore the requested buffer metrics and just keep one JACK-sized buffer
     /* 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.
+     * ready for when requested.
      */
      */
     device->Frequency = jack_get_sample_rate(self->Client);
     device->Frequency = jack_get_sample_rate(self->Client);
     device->UpdateSize = jack_get_buffer_size(self->Client);
     device->UpdateSize = jack_get_buffer_size(self->Client);
     device->NumUpdates = 2;
     device->NumUpdates = 2;
 
 
     bufsize = device->UpdateSize;
     bufsize = device->UpdateSize;
-    if(ConfigValueUInt(al_string_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize))
+    if(ConfigValueUInt(alstr_get_cstr(device->DeviceName), "jack", "buffer-size", &bufsize))
         bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
         bufsize = maxu(NextPowerOf2(bufsize), device->UpdateSize);
-    bufsize += device->UpdateSize;
+    device->NumUpdates = (bufsize+device->UpdateSize) / device->UpdateSize;
 
 
     /* Force 32-bit float output. */
     /* Force 32-bit float output. */
     device->FmtType = DevFmtFloat;
     device->FmtType = DevFmtFloat;
 
 
-    numchans = ChannelsFromDevFmt(device->FmtChans);
+    numchans = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
     for(i = 0;i < numchans;i++)
     for(i = 0;i < numchans;i++)
     {
     {
         char name[64];
         char name[64];
@@ -440,7 +433,10 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
     }
     }
 
 
     ll_ringbuffer_free(self->Ring);
     ll_ringbuffer_free(self->Ring);
-    self->Ring = ll_ringbuffer_create(bufsize, FrameSizeFromDevFmt(device->FmtChans, device->FmtType));
+    self->Ring = ll_ringbuffer_create(bufsize,
+        FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder),
+        true
+    );
     if(!self->Ring)
     if(!self->Ring)
     {
     {
         ERR("Failed to allocate ringbuffer\n");
         ERR("Failed to allocate ringbuffer\n");
@@ -455,7 +451,7 @@ static ALCboolean ALCjackPlayback_reset(ALCjackPlayback *self)
 static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self)
 static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self)
 {
 {
     const char **ports;
     const char **ports;
-    ALuint i;
+    ALsizei i;
 
 
     if(jack_activate(self->Client))
     if(jack_activate(self->Client))
     {
     {
@@ -482,7 +478,7 @@ static ALCboolean ALCjackPlayback_start(ALCjackPlayback *self)
     }
     }
     jack_free(ports);
     jack_free(ports);
 
 
-    self->killNow = 0;
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
     if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCjackPlayback_mixerProc, self) != althrd_success)
     {
     {
         jack_deactivate(self->Client);
         jack_deactivate(self->Client);
@@ -496,17 +492,10 @@ static void ALCjackPlayback_stop(ALCjackPlayback *self)
 {
 {
     int res;
     int res;
 
 
-    if(self->killNow)
+    if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         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);
+    alsem_post(&self->Sem);
     althrd_join(self->thread, &res);
     althrd_join(self->thread, &res);
 
 
     jack_deactivate(self->Client);
     jack_deactivate(self->Client);
@@ -528,17 +517,6 @@ static ClockLatency ALCjackPlayback_getClockLatency(ALCjackPlayback *self)
 }
 }
 
 
 
 
-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);
-}
-
-
 static void jack_msg_handler(const char *message)
 static void jack_msg_handler(const char *message)
 {
 {
     WARN("%s\n", message);
     WARN("%s\n", message);
@@ -551,6 +529,7 @@ typedef struct ALCjackBackendFactory {
 
 
 static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self))
 static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self))
 {
 {
+    void (*old_error_cb)(const char*);
     jack_client_t *client;
     jack_client_t *client;
     jack_status_t status;
     jack_status_t status;
 
 
@@ -560,9 +539,10 @@ static ALCboolean ALCjackBackendFactory_init(ALCjackBackendFactory* UNUSED(self)
     if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0))
     if(!GetConfigValueBool(NULL, "jack", "spawn-server", 0))
         ClientOptions |= JackNoStartServer;
         ClientOptions |= JackNoStartServer;
 
 
+    old_error_cb = (&jack_error_callback ? jack_error_callback : NULL);
     jack_set_error_function(jack_msg_handler);
     jack_set_error_function(jack_msg_handler);
     client = jack_client_open("alsoft", ClientOptions, &status, NULL);
     client = jack_client_open("alsoft", ClientOptions, &status, NULL);
-    jack_set_error_function(NULL);
+    jack_set_error_function(old_error_cb);
     if(client == NULL)
     if(client == NULL)
     {
     {
         WARN("jack_client_open() failed, 0x%02x\n", status);
         WARN("jack_client_open() failed, 0x%02x\n", status);

+ 1 - 6
Engine/lib/openal-soft/Alc/backends/loopback.c

@@ -35,7 +35,6 @@ typedef struct ALCloopback {
 static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device);
 static void ALCloopback_Construct(ALCloopback *self, ALCdevice *device);
 static DECLARE_FORWARD(ALCloopback, ALCbackend, void, Destruct)
 static DECLARE_FORWARD(ALCloopback, ALCbackend, void, Destruct)
 static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name);
 static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name);
-static void ALCloopback_close(ALCloopback *self);
 static ALCboolean ALCloopback_reset(ALCloopback *self);
 static ALCboolean ALCloopback_reset(ALCloopback *self);
 static ALCboolean ALCloopback_start(ALCloopback *self);
 static ALCboolean ALCloopback_start(ALCloopback *self);
 static void ALCloopback_stop(ALCloopback *self);
 static void ALCloopback_stop(ALCloopback *self);
@@ -59,14 +58,10 @@ static ALCenum ALCloopback_open(ALCloopback *self, const ALCchar *name)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
 
 
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCloopback_close(ALCloopback* UNUSED(self))
-{
-}
-
 static ALCboolean ALCloopback_reset(ALCloopback *self)
 static ALCboolean ALCloopback_reset(ALCloopback *self)
 {
 {
     SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);
     SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);

+ 10 - 12
Engine/lib/openal-soft/Alc/backends/null.c

@@ -36,7 +36,7 @@
 typedef struct ALCnullBackend {
 typedef struct ALCnullBackend {
     DERIVE_FROM_TYPE(ALCbackend);
     DERIVE_FROM_TYPE(ALCbackend);
 
 
-    volatile int killNow;
+    ATOMIC(int) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCnullBackend;
 } ALCnullBackend;
 
 
@@ -45,7 +45,6 @@ static int ALCnullBackend_mixerProc(void *ptr);
 static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device);
 static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device);
 static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, Destruct)
 static DECLARE_FORWARD(ALCnullBackend, ALCbackend, void, Destruct)
 static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name);
 static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name);
-static void ALCnullBackend_close(ALCnullBackend *self);
 static ALCboolean ALCnullBackend_reset(ALCnullBackend *self);
 static ALCboolean ALCnullBackend_reset(ALCnullBackend *self);
 static ALCboolean ALCnullBackend_start(ALCnullBackend *self);
 static ALCboolean ALCnullBackend_start(ALCnullBackend *self);
 static void ALCnullBackend_stop(ALCnullBackend *self);
 static void ALCnullBackend_stop(ALCnullBackend *self);
@@ -66,6 +65,8 @@ static void ALCnullBackend_Construct(ALCnullBackend *self, ALCdevice *device)
 {
 {
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCnullBackend, ALCbackend, self);
     SET_VTABLE2(ALCnullBackend, ALCbackend, self);
+
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
 }
 }
 
 
 
 
@@ -87,7 +88,8 @@ static int ALCnullBackend_mixerProc(void *ptr)
         ERR("Failed to get starting time\n");
         ERR("Failed to get starting time\n");
         return 1;
         return 1;
     }
     }
-    while(!self->killNow && device->Connected)
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
     {
     {
         if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
         if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
         {
         {
@@ -109,7 +111,9 @@ static int ALCnullBackend_mixerProc(void *ptr)
             al_nssleep(restTime);
             al_nssleep(restTime);
         else while(avail-done >= device->UpdateSize)
         else while(avail-done >= device->UpdateSize)
         {
         {
+            ALCnullBackend_lock(self);
             aluMixData(device, NULL, device->UpdateSize);
             aluMixData(device, NULL, device->UpdateSize);
+            ALCnullBackend_unlock(self);
             done += device->UpdateSize;
             done += device->UpdateSize;
         }
         }
     }
     }
@@ -128,15 +132,11 @@ static ALCenum ALCnullBackend_open(ALCnullBackend *self, const ALCchar *name)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
 
 
     device = STATIC_CAST(ALCbackend, self)->mDevice;
     device = STATIC_CAST(ALCbackend, self)->mDevice;
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCnullBackend_close(ALCnullBackend* UNUSED(self))
-{
-}
-
 static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
 static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
 {
 {
     SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);
     SetDefaultWFXChannelOrder(STATIC_CAST(ALCbackend, self)->mDevice);
@@ -145,7 +145,7 @@ static ALCboolean ALCnullBackend_reset(ALCnullBackend *self)
 
 
 static ALCboolean ALCnullBackend_start(ALCnullBackend *self)
 static ALCboolean ALCnullBackend_start(ALCnullBackend *self)
 {
 {
-    self->killNow = 0;
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
     if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCnullBackend_mixerProc, self) != althrd_success)
         return ALC_FALSE;
         return ALC_FALSE;
     return ALC_TRUE;
     return ALC_TRUE;
@@ -155,10 +155,8 @@ static void ALCnullBackend_stop(ALCnullBackend *self)
 {
 {
     int res;
     int res;
 
 
-    if(self->killNow)
+    if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         return;
-
-    self->killNow = 1;
     althrd_join(self->thread, &res);
     althrd_join(self->thread, &res);
 }
 }
 
 

+ 812 - 174
Engine/lib/openal-soft/Alc/backends/opensl.c

@@ -22,38 +22,25 @@
 #include "config.h"
 #include "config.h"
 
 
 #include <stdlib.h>
 #include <stdlib.h>
+#include <jni.h>
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "ringbuffer.h"
 #include "threads.h"
 #include "threads.h"
+#include "compat.h"
+
+#include "backends/base.h"
 
 
 #include <SLES/OpenSLES.h>
 #include <SLES/OpenSLES.h>
 #include <SLES/OpenSLES_Android.h>
 #include <SLES/OpenSLES_Android.h>
+#include <SLES/OpenSLES_AndroidConfiguration.h>
 
 
 /* Helper macros */
 /* Helper macros */
 #define VCALL(obj, func)  ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
 #define VCALL(obj, func)  ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
 #define VCALL0(obj, func)  ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
 #define VCALL0(obj, func)  ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
 
 
 
 
-typedef struct {
-    /* engine interfaces */
-    SLObjectItf engineObject;
-    SLEngineItf engine;
-
-    /* output mix interfaces */
-    SLObjectItf outputMix;
-
-    /* buffer queue player interfaces */
-    SLObjectItf bufferQueueObject;
-
-    void *buffer;
-    ALuint bufferSize;
-    ALuint curBuffer;
-
-    ALuint frameSize;
-} osl_data;
-
-
 static const ALCchar opensl_device[] = "OpenSL";
 static const ALCchar opensl_device[] = "OpenSL";
 
 
 
 
@@ -79,14 +66,32 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans)
                                SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
                                SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
                                SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT|
                                SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT|
                                SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
                                SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
-        case DevFmtAmbi1:
-        case DevFmtAmbi2:
-        case DevFmtAmbi3:
+        case DevFmtAmbi3D:
             break;
             break;
     }
     }
     return 0;
     return 0;
 }
 }
 
 
+#ifdef SL_DATAFORMAT_PCM_EX
+static SLuint32 GetTypeRepresentation(enum DevFmtType type)
+{
+    switch(type)
+    {
+        case DevFmtUByte:
+        case DevFmtUShort:
+        case DevFmtUInt:
+            return SL_PCM_REPRESENTATION_UNSIGNED_INT;
+        case DevFmtByte:
+        case DevFmtShort:
+        case DevFmtInt:
+            return SL_PCM_REPRESENTATION_SIGNED_INT;
+        case DevFmtFloat:
+            return SL_PCM_REPRESENTATION_FLOAT;
+    }
+    return 0;
+}
+#endif
+
 static const char *res_str(SLresult result)
 static const char *res_str(SLresult result)
 {
 {
     switch(result)
     switch(result)
@@ -126,168 +131,427 @@ static const char *res_str(SLresult result)
         ERR("%s: %s\n", (s), res_str((x)));                                      \
         ERR("%s: %s\n", (s), res_str((x)));                                      \
 } while(0)
 } while(0)
 
 
+
+typedef struct ALCopenslPlayback {
+    DERIVE_FROM_TYPE(ALCbackend);
+
+    /* engine interfaces */
+    SLObjectItf mEngineObj;
+    SLEngineItf mEngine;
+
+    /* output mix interfaces */
+    SLObjectItf mOutputMix;
+
+    /* buffer queue player interfaces */
+    SLObjectItf mBufferQueueObj;
+
+    ll_ringbuffer_t *mRing;
+    alsem_t mSem;
+
+    ALsizei mFrameSize;
+
+    ATOMIC(ALenum) mKillNow;
+    althrd_t mThread;
+} ALCopenslPlayback;
+
+static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf bq, void *context);
+static int ALCopenslPlayback_mixerProc(void *arg);
+
+static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device);
+static void ALCopenslPlayback_Destruct(ALCopenslPlayback *self);
+static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name);
+static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self);
+static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self);
+static void ALCopenslPlayback_stop(ALCopenslPlayback *self);
+static DECLARE_FORWARD2(ALCopenslPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, ALCuint, availableSamples)
+static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self);
+static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCopenslPlayback, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCopenslPlayback)
+
+DEFINE_ALCBACKEND_VTABLE(ALCopenslPlayback);
+
+
+static void ALCopenslPlayback_Construct(ALCopenslPlayback *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCopenslPlayback, ALCbackend, self);
+
+    self->mEngineObj = NULL;
+    self->mEngine = NULL;
+    self->mOutputMix = NULL;
+    self->mBufferQueueObj = NULL;
+
+    self->mRing = NULL;
+    alsem_init(&self->mSem, 0);
+
+    self->mFrameSize = 0;
+
+    ATOMIC_INIT(&self->mKillNow, AL_FALSE);
+}
+
+static void ALCopenslPlayback_Destruct(ALCopenslPlayback* self)
+{
+    if(self->mBufferQueueObj != NULL)
+        VCALL0(self->mBufferQueueObj,Destroy)();
+    self->mBufferQueueObj = NULL;
+
+    if(self->mOutputMix)
+        VCALL0(self->mOutputMix,Destroy)();
+    self->mOutputMix = NULL;
+
+    if(self->mEngineObj)
+        VCALL0(self->mEngineObj,Destroy)();
+    self->mEngineObj = NULL;
+    self->mEngine = NULL;
+
+    alsem_destroy(&self->mSem);
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
 /* this callback handler is called every time a buffer finishes playing */
 /* this callback handler is called every time a buffer finishes playing */
-static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
+static void ALCopenslPlayback_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context)
+{
+    ALCopenslPlayback *self = context;
+
+    /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
+     * pointer passed to the Enqueue method, rather than copying the audio.
+     * Consequently, the ringbuffer contains the audio that is currently queued
+     * and waiting to play. This process() callback is called when a buffer is
+     * finished, so we simply move the read pointer up to indicate the space is
+     * available for writing again, and wake up the mixer thread to mix and
+     * queue more audio.
+     */
+    ll_ringbuffer_read_advance(self->mRing, 1);
+
+    alsem_post(&self->mSem);
+}
+
+
+static int ALCopenslPlayback_mixerProc(void *arg)
 {
 {
-    ALCdevice *Device = context;
-    osl_data *data = Device->ExtraData;
-    ALvoid *buf;
+    ALCopenslPlayback *self = arg;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+    SLAndroidSimpleBufferQueueItf bufferQueue;
+    ll_ringbuffer_data_t data[2];
+    SLPlayItf player;
     SLresult result;
     SLresult result;
 
 
-    buf = (ALbyte*)data->buffer + data->curBuffer*data->bufferSize;
-    aluMixData(Device, buf, data->bufferSize/data->frameSize);
+    SetRTPriority();
+    althrd_setname(althrd_current(), MIXER_THREAD_NAME);
 
 
-    result = VCALL(bq,Enqueue)(buf, data->bufferSize);
-    PRINTERR(result, "bq->Enqueue");
+    result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+                                                       &bufferQueue);
+    PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
+    if(SL_RESULT_SUCCESS == result)
+    {
+        result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
+        PRINTERR(result, "bufferQueue->GetInterface SL_IID_PLAY");
+    }
+    if(SL_RESULT_SUCCESS != result)
+    {
+        ALCopenslPlayback_lock(self);
+        aluHandleDisconnect(device, "Failed to get playback buffer: 0x%08x", result);
+        ALCopenslPlayback_unlock(self);
+        return 1;
+    }
+
+    ALCopenslPlayback_lock(self);
+    while(!ATOMIC_LOAD(&self->mKillNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
+    {
+        size_t todo, len0, len1;
+
+        if(ll_ringbuffer_write_space(self->mRing) == 0)
+        {
+            SLuint32 state = 0;
+
+            result = VCALL(player,GetPlayState)(&state);
+            PRINTERR(result, "player->GetPlayState");
+            if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING)
+            {
+                result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
+                PRINTERR(result, "player->SetPlayState");
+            }
+            if(SL_RESULT_SUCCESS != result)
+            {
+                aluHandleDisconnect(device, "Failed to start platback: 0x%08x", result);
+                break;
+            }
+
+            if(ll_ringbuffer_write_space(self->mRing) == 0)
+            {
+                ALCopenslPlayback_unlock(self);
+                alsem_wait(&self->mSem);
+                ALCopenslPlayback_lock(self);
+                continue;
+            }
+        }
+
+        ll_ringbuffer_get_write_vector(self->mRing, data);
+        todo = data[0].len+data[1].len;
+
+        len0 = minu(todo, data[0].len);
+        len1 = minu(todo-len0, data[1].len);
 
 
-    data->curBuffer = (data->curBuffer+1) % Device->NumUpdates;
+        aluMixData(device, data[0].buf, len0*device->UpdateSize);
+        for(size_t i = 0;i < len0;i++)
+        {
+            result = VCALL(bufferQueue,Enqueue)(data[0].buf, device->UpdateSize*self->mFrameSize);
+            PRINTERR(result, "bufferQueue->Enqueue");
+            if(SL_RESULT_SUCCESS == result)
+                ll_ringbuffer_write_advance(self->mRing, 1);
+
+            data[0].buf += device->UpdateSize*self->mFrameSize;
+        }
+
+        if(len1 > 0)
+        {
+            aluMixData(device, data[1].buf, len1*device->UpdateSize);
+            for(size_t i = 0;i < len1;i++)
+            {
+                result = VCALL(bufferQueue,Enqueue)(data[1].buf, device->UpdateSize*self->mFrameSize);
+                PRINTERR(result, "bufferQueue->Enqueue");
+                if(SL_RESULT_SUCCESS == result)
+                    ll_ringbuffer_write_advance(self->mRing, 1);
+
+                data[1].buf += device->UpdateSize*self->mFrameSize;
+            }
+        }
+    }
+    ALCopenslPlayback_unlock(self);
+
+    return 0;
 }
 }
 
 
 
 
-static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName)
+static ALCenum ALCopenslPlayback_open(ALCopenslPlayback *self, const ALCchar *name)
 {
 {
-    osl_data *data = NULL;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     SLresult result;
     SLresult result;
 
 
-    if(!deviceName)
-        deviceName = opensl_device;
-    else if(strcmp(deviceName, opensl_device) != 0)
+    if(!name)
+        name = opensl_device;
+    else if(strcmp(name, opensl_device) != 0)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
 
 
-    data = calloc(1, sizeof(*data));
-    if(!data)
-        return ALC_OUT_OF_MEMORY;
-
     // create engine
     // create engine
-    result = slCreateEngine(&data->engineObject, 0, NULL, 0, NULL, NULL);
+    result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL);
     PRINTERR(result, "slCreateEngine");
     PRINTERR(result, "slCreateEngine");
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(data->engineObject,Realize)(SL_BOOLEAN_FALSE);
+        result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE);
         PRINTERR(result, "engine->Realize");
         PRINTERR(result, "engine->Realize");
     }
     }
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(data->engineObject,GetInterface)(SL_IID_ENGINE, &data->engine);
+        result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine);
         PRINTERR(result, "engine->GetInterface");
         PRINTERR(result, "engine->GetInterface");
     }
     }
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(data->engine,CreateOutputMix)(&data->outputMix, 0, NULL, NULL);
+        result = VCALL(self->mEngine,CreateOutputMix)(&self->mOutputMix, 0, NULL, NULL);
         PRINTERR(result, "engine->CreateOutputMix");
         PRINTERR(result, "engine->CreateOutputMix");
     }
     }
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(data->outputMix,Realize)(SL_BOOLEAN_FALSE);
+        result = VCALL(self->mOutputMix,Realize)(SL_BOOLEAN_FALSE);
         PRINTERR(result, "outputMix->Realize");
         PRINTERR(result, "outputMix->Realize");
     }
     }
 
 
     if(SL_RESULT_SUCCESS != result)
     if(SL_RESULT_SUCCESS != result)
     {
     {
-        if(data->outputMix != NULL)
-            VCALL0(data->outputMix,Destroy)();
-        data->outputMix = NULL;
+        if(self->mOutputMix != NULL)
+            VCALL0(self->mOutputMix,Destroy)();
+        self->mOutputMix = NULL;
 
 
-        if(data->engineObject != NULL)
-            VCALL0(data->engineObject,Destroy)();
-        data->engineObject = NULL;
-        data->engine = NULL;
+        if(self->mEngineObj != NULL)
+            VCALL0(self->mEngineObj,Destroy)();
+        self->mEngineObj = NULL;
+        self->mEngine = NULL;
 
 
-        free(data);
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    al_string_copy_cstr(&Device->DeviceName, deviceName);
-    Device->ExtraData = data;
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-
-static void opensl_close_playback(ALCdevice *Device)
-{
-    osl_data *data = Device->ExtraData;
-
-    if(data->bufferQueueObject != NULL)
-        VCALL0(data->bufferQueueObject,Destroy)();
-    data->bufferQueueObject = NULL;
-
-    VCALL0(data->outputMix,Destroy)();
-    data->outputMix = NULL;
-
-    VCALL0(data->engineObject,Destroy)();
-    data->engineObject = NULL;
-    data->engine = NULL;
-
-    free(data);
-    Device->ExtraData = NULL;
-}
-
-static ALCboolean opensl_reset_playback(ALCdevice *Device)
+static ALCboolean ALCopenslPlayback_reset(ALCopenslPlayback *self)
 {
 {
-    osl_data *data = Device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
     SLDataLocator_AndroidSimpleBufferQueue loc_bufq;
     SLDataLocator_OutputMix loc_outmix;
     SLDataLocator_OutputMix loc_outmix;
-    SLDataFormat_PCM format_pcm;
     SLDataSource audioSrc;
     SLDataSource audioSrc;
     SLDataSink audioSnk;
     SLDataSink audioSnk;
-    SLInterfaceID id;
-    SLboolean req;
+    ALuint sampleRate;
+    SLInterfaceID ids[2];
+    SLboolean reqs[2];
     SLresult result;
     SLresult result;
+    JNIEnv *env;
 
 
+    if(self->mBufferQueueObj != NULL)
+        VCALL0(self->mBufferQueueObj,Destroy)();
+    self->mBufferQueueObj = NULL;
 
 
-    Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency;
-    Device->UpdateSize = Device->UpdateSize * Device->NumUpdates / 2;
-    Device->NumUpdates = 2;
+    sampleRate = device->Frequency;
+    if(!(device->Flags&DEVICE_FREQUENCY_REQUEST) && (env=Android_GetJNIEnv()) != NULL)
+    {
+        /* FIXME: Disabled until I figure out how to get the Context needed for
+         * the getSystemService call.
+         */
+#if 0
+        /* Get necessary stuff for using java.lang.Integer,
+         * android.content.Context, and android.media.AudioManager.
+         */
+        jclass int_cls = JCALL(env,FindClass)("java/lang/Integer");
+        jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls,
+            "parseInt", "(Ljava/lang/String;)I"
+        );
+        TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint);
+
+        jclass ctx_cls = JCALL(env,FindClass)("android/content/Context");
+        jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls,
+            "AUDIO_SERVICE", "Ljava/lang/String;"
+        );
+        jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls,
+            "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
+        );
+        TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
+              ctx_cls, ctx_audsvc, ctx_getSysSvc);
+
+        jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager");
+        jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls,
+            "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
+        );
+        jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls,
+            "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
+        );
+        TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
+              audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty);
+
+        const char *strchars;
+        jstring strobj;
+
+        /* Now make the calls. */
+        //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
+        strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc);
+        jobject audMgr = JCALL(env,CallObjectMethod)(ctx_cls, ctx_getSysSvc, strobj);
+        strchars = JCALL(env,GetStringUTFChars)(strobj, NULL);
+        TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr);
+        JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
+
+        //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
+        strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate);
+        jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj);
+        strchars = JCALL(env,GetStringUTFChars)(strobj, NULL);
+        TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr);
+        JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
+
+        //int sampleRate = Integer.parseInt(srateStr);
+        sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr);
+
+        strchars = JCALL(env,GetStringUTFChars)(srateStr, NULL);
+        TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars);
+        JCALL(env,ReleaseStringUTFChars)(srateStr, strchars);
+
+        if(!sampleRate) sampleRate = device->Frequency;
+        else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE);
+#endif
+    }
 
 
-    Device->Frequency = 44100;
-    Device->FmtChans = DevFmtStereo;
-    Device->FmtType = DevFmtShort;
+    if(sampleRate != device->Frequency)
+    {
+        device->NumUpdates = (device->NumUpdates*sampleRate + (device->Frequency>>1)) /
+                             device->Frequency;
+        device->NumUpdates = maxu(device->NumUpdates, 2);
+        device->Frequency = sampleRate;
+    }
 
 
-    SetDefaultWFXChannelOrder(Device);
+    device->FmtChans = DevFmtStereo;
+    device->FmtType = DevFmtShort;
 
 
+    SetDefaultWFXChannelOrder(device);
+    self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
-    id  = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
-    req = SL_BOOLEAN_TRUE;
 
 
     loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
     loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
-    loc_bufq.numBuffers = Device->NumUpdates;
-
+    loc_bufq.numBuffers = device->NumUpdates;
+
+#ifdef SL_DATAFORMAT_PCM_EX
+    SLDataFormat_PCM_EX format_pcm;
+    format_pcm.formatType = SL_DATAFORMAT_PCM_EX;
+    format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
+    format_pcm.sampleRate = device->Frequency * 1000;
+    format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
+    format_pcm.containerSize = format_pcm.bitsPerSample;
+    format_pcm.channelMask = GetChannelMask(device->FmtChans);
+    format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
+                                               SL_BYTEORDER_BIGENDIAN;
+    format_pcm.representation = GetTypeRepresentation(device->FmtType);
+#else
+    SLDataFormat_PCM format_pcm;
     format_pcm.formatType = SL_DATAFORMAT_PCM;
     format_pcm.formatType = SL_DATAFORMAT_PCM;
-    format_pcm.numChannels = ChannelsFromDevFmt(Device->FmtChans);
-    format_pcm.samplesPerSec = Device->Frequency * 1000;
-    format_pcm.bitsPerSample = BytesFromDevFmt(Device->FmtType) * 8;
+    format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
+    format_pcm.samplesPerSec = device->Frequency * 1000;
+    format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
     format_pcm.containerSize = format_pcm.bitsPerSample;
     format_pcm.containerSize = format_pcm.bitsPerSample;
-    format_pcm.channelMask = GetChannelMask(Device->FmtChans);
+    format_pcm.channelMask = GetChannelMask(device->FmtChans);
     format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
     format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
                                                SL_BYTEORDER_BIGENDIAN;
                                                SL_BYTEORDER_BIGENDIAN;
+#endif
 
 
     audioSrc.pLocator = &loc_bufq;
     audioSrc.pLocator = &loc_bufq;
     audioSrc.pFormat = &format_pcm;
     audioSrc.pFormat = &format_pcm;
 
 
     loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
     loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
-    loc_outmix.outputMix = data->outputMix;
+    loc_outmix.outputMix = self->mOutputMix;
     audioSnk.pLocator = &loc_outmix;
     audioSnk.pLocator = &loc_outmix;
     audioSnk.pFormat = NULL;
     audioSnk.pFormat = NULL;
 
 
 
 
-    if(data->bufferQueueObject != NULL)
-        VCALL0(data->bufferQueueObject,Destroy)();
-    data->bufferQueueObject = NULL;
+    ids[0]  = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
+    reqs[0] = SL_BOOLEAN_TRUE;
+    ids[1]  = SL_IID_ANDROIDCONFIGURATION;
+    reqs[1] = SL_BOOLEAN_FALSE;
 
 
-    result = VCALL(data->engine,CreateAudioPlayer)(&data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req);
+    result = VCALL(self->mEngine,CreateAudioPlayer)(&self->mBufferQueueObj,
+        &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs
+    );
     PRINTERR(result, "engine->CreateAudioPlayer");
     PRINTERR(result, "engine->CreateAudioPlayer");
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(data->bufferQueueObject,Realize)(SL_BOOLEAN_FALSE);
+        /* Set the stream type to "media" (games, music, etc), if possible. */
+        SLAndroidConfigurationItf config;
+        result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
+        PRINTERR(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
+        if(SL_RESULT_SUCCESS == result)
+        {
+            SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
+            result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE,
+                &streamType, sizeof(streamType)
+            );
+            PRINTERR(result, "config->SetConfiguration");
+        }
+
+        /* Clear any error since this was optional. */
+        result = SL_RESULT_SUCCESS;
+    }
+    if(SL_RESULT_SUCCESS == result)
+    {
+        result = VCALL(self->mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE);
         PRINTERR(result, "bufferQueue->Realize");
         PRINTERR(result, "bufferQueue->Realize");
     }
     }
 
 
     if(SL_RESULT_SUCCESS != result)
     if(SL_RESULT_SUCCESS != result)
     {
     {
-        if(data->bufferQueueObject != NULL)
-            VCALL0(data->bufferQueueObject,Destroy)();
-        data->bufferQueueObject = NULL;
+        if(self->mBufferQueueObj != NULL)
+            VCALL0(self->mBufferQueueObj,Destroy)();
+        self->mBufferQueueObj = NULL;
 
 
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
@@ -295,142 +559,516 @@ static ALCboolean opensl_reset_playback(ALCdevice *Device)
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-static ALCboolean opensl_start_playback(ALCdevice *Device)
+static ALCboolean ALCopenslPlayback_start(ALCopenslPlayback *self)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+    SLAndroidSimpleBufferQueueItf bufferQueue;
+    SLresult result;
+
+    ll_ringbuffer_free(self->mRing);
+    self->mRing = ll_ringbuffer_create(device->NumUpdates, self->mFrameSize*device->UpdateSize,
+                                       true);
+
+    result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+                                                       &bufferQueue);
+    PRINTERR(result, "bufferQueue->GetInterface");
+    if(SL_RESULT_SUCCESS != result)
+        return ALC_FALSE;
+
+    result = VCALL(bufferQueue,RegisterCallback)(ALCopenslPlayback_process, self);
+    PRINTERR(result, "bufferQueue->RegisterCallback");
+    if(SL_RESULT_SUCCESS != result)
+        return ALC_FALSE;
+
+    ATOMIC_STORE_SEQ(&self->mKillNow, AL_FALSE);
+    if(althrd_create(&self->mThread, ALCopenslPlayback_mixerProc, self) != althrd_success)
+    {
+        ERR("Failed to start mixer thread\n");
+        return ALC_FALSE;
+    }
+
+    return ALC_TRUE;
+}
+
+
+static void ALCopenslPlayback_stop(ALCopenslPlayback *self)
 {
 {
-    osl_data *data = Device->ExtraData;
     SLAndroidSimpleBufferQueueItf bufferQueue;
     SLAndroidSimpleBufferQueueItf bufferQueue;
     SLPlayItf player;
     SLPlayItf player;
     SLresult result;
     SLresult result;
-    ALuint i;
+    int res;
+
+    if(ATOMIC_EXCHANGE_SEQ(&self->mKillNow, AL_TRUE))
+        return;
+
+    alsem_post(&self->mSem);
+    althrd_join(self->mThread, &res);
 
 
-    result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue);
+    result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
     PRINTERR(result, "bufferQueue->GetInterface");
     PRINTERR(result, "bufferQueue->GetInterface");
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(bufferQueue,RegisterCallback)(opensl_callback, Device);
+        result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
+        PRINTERR(result, "player->SetPlayState");
+    }
+
+    result = VCALL(self->mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+                                                       &bufferQueue);
+    PRINTERR(result, "bufferQueue->GetInterface");
+    if(SL_RESULT_SUCCESS == result)
+    {
+        result = VCALL0(bufferQueue,Clear)();
+        PRINTERR(result, "bufferQueue->Clear");
+    }
+    if(SL_RESULT_SUCCESS == result)
+    {
+        result = VCALL(bufferQueue,RegisterCallback)(NULL, NULL);
         PRINTERR(result, "bufferQueue->RegisterCallback");
         PRINTERR(result, "bufferQueue->RegisterCallback");
     }
     }
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        data->frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
-        data->bufferSize = Device->UpdateSize * data->frameSize;
-        data->buffer = calloc(Device->NumUpdates, data->bufferSize);
-        if(!data->buffer)
-        {
-            result = SL_RESULT_MEMORY_FAILURE;
-            PRINTERR(result, "calloc");
-        }
+        SLAndroidSimpleBufferQueueState state;
+        do {
+            althrd_yield();
+            result = VCALL(bufferQueue,GetState)(&state);
+        } while(SL_RESULT_SUCCESS == result && state.count > 0);
+        PRINTERR(result, "bufferQueue->GetState");
     }
     }
-    /* enqueue the first buffer to kick off the callbacks */
-    for(i = 0;i < Device->NumUpdates;i++)
+
+    ll_ringbuffer_free(self->mRing);
+    self->mRing = NULL;
+}
+
+static ClockLatency ALCopenslPlayback_getClockLatency(ALCopenslPlayback *self)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    ClockLatency ret;
+
+    ALCopenslPlayback_lock(self);
+    ret.ClockTime = GetDeviceClockTime(device);
+    ret.Latency = ll_ringbuffer_read_space(self->mRing)*device->UpdateSize *
+                  DEVICE_CLOCK_RES / device->Frequency;
+    ALCopenslPlayback_unlock(self);
+
+    return ret;
+}
+
+
+typedef struct ALCopenslCapture {
+    DERIVE_FROM_TYPE(ALCbackend);
+
+    /* engine interfaces */
+    SLObjectItf mEngineObj;
+    SLEngineItf mEngine;
+
+    /* recording interfaces */
+    SLObjectItf mRecordObj;
+
+    ll_ringbuffer_t *mRing;
+    ALCuint mSplOffset;
+
+    ALsizei mFrameSize;
+} ALCopenslCapture;
+
+static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf bq, void *context);
+
+static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device);
+static void ALCopenslCapture_Destruct(ALCopenslCapture *self);
+static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name);
+static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self);
+static void ALCopenslCapture_stop(ALCopenslCapture *self);
+static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self);
+static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCopenslCapture, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCopenslCapture)
+DEFINE_ALCBACKEND_VTABLE(ALCopenslCapture);
+
+
+static void ALCopenslCapture_process(SLAndroidSimpleBufferQueueItf UNUSED(bq), void *context)
+{
+    ALCopenslCapture *self = context;
+    /* A new chunk has been written into the ring buffer, advance it. */
+    ll_ringbuffer_write_advance(self->mRing, 1);
+}
+
+
+static void ALCopenslCapture_Construct(ALCopenslCapture *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCopenslCapture, ALCbackend, self);
+
+    self->mEngineObj = NULL;
+    self->mEngine = NULL;
+
+    self->mRecordObj = NULL;
+
+    self->mRing = NULL;
+    self->mSplOffset = 0;
+
+    self->mFrameSize = 0;
+}
+
+static void ALCopenslCapture_Destruct(ALCopenslCapture *self)
+{
+    ll_ringbuffer_free(self->mRing);
+    self->mRing = NULL;
+
+    if(self->mRecordObj != NULL)
+        VCALL0(self->mRecordObj,Destroy)();
+    self->mRecordObj = NULL;
+
+    if(self->mEngineObj != NULL)
+        VCALL0(self->mEngineObj,Destroy)();
+    self->mEngineObj = NULL;
+    self->mEngine = NULL;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+static ALCenum ALCopenslCapture_open(ALCopenslCapture *self, const ALCchar *name)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    SLDataLocator_AndroidSimpleBufferQueue loc_bq;
+    SLAndroidSimpleBufferQueueItf bufferQueue;
+    SLDataLocator_IODevice loc_dev;
+    SLDataSource audioSrc;
+    SLDataSink audioSnk;
+    SLresult result;
+
+    if(!name)
+        name = opensl_device;
+    else if(strcmp(name, opensl_device) != 0)
+        return ALC_INVALID_VALUE;
+
+    result = slCreateEngine(&self->mEngineObj, 0, NULL, 0, NULL, NULL);
+    PRINTERR(result, "slCreateEngine");
+    if(SL_RESULT_SUCCESS == result)
     {
     {
+        result = VCALL(self->mEngineObj,Realize)(SL_BOOLEAN_FALSE);
+        PRINTERR(result, "engine->Realize");
+    }
+    if(SL_RESULT_SUCCESS == result)
+    {
+        result = VCALL(self->mEngineObj,GetInterface)(SL_IID_ENGINE, &self->mEngine);
+        PRINTERR(result, "engine->GetInterface");
+    }
+    if(SL_RESULT_SUCCESS == result)
+    {
+        /* Ensure the total length is at least 100ms */
+        ALsizei length = maxi(device->NumUpdates * device->UpdateSize,
+                              device->Frequency / 10);
+        /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
+        ALsizei update_len = clampi(device->NumUpdates*device->UpdateSize / 3,
+                                    device->Frequency / 100,
+                                    device->Frequency / 100 * 5);
+
+        device->UpdateSize = update_len;
+        device->NumUpdates = (length+update_len-1) / update_len;
+
+        self->mFrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
+    }
+    loc_dev.locatorType = SL_DATALOCATOR_IODEVICE;
+    loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT;
+    loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
+    loc_dev.device = NULL;
+
+    audioSrc.pLocator = &loc_dev;
+    audioSrc.pFormat = NULL;
+
+    loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
+    loc_bq.numBuffers = device->NumUpdates;
+
+#ifdef SL_DATAFORMAT_PCM_EX
+    SLDataFormat_PCM_EX format_pcm;
+    format_pcm.formatType = SL_DATAFORMAT_PCM_EX;
+    format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
+    format_pcm.sampleRate = device->Frequency * 1000;
+    format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
+    format_pcm.containerSize = format_pcm.bitsPerSample;
+    format_pcm.channelMask = GetChannelMask(device->FmtChans);
+    format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
+                                               SL_BYTEORDER_BIGENDIAN;
+    format_pcm.representation = GetTypeRepresentation(device->FmtType);
+#else
+    SLDataFormat_PCM format_pcm;
+    format_pcm.formatType = SL_DATAFORMAT_PCM;
+    format_pcm.numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
+    format_pcm.samplesPerSec = device->Frequency * 1000;
+    format_pcm.bitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
+    format_pcm.containerSize = format_pcm.bitsPerSample;
+    format_pcm.channelMask = GetChannelMask(device->FmtChans);
+    format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN :
+                                               SL_BYTEORDER_BIGENDIAN;
+#endif
+
+    audioSnk.pLocator = &loc_bq;
+    audioSnk.pFormat = &format_pcm;
+
+    if(SL_RESULT_SUCCESS == result)
+    {
+        const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
+        const SLboolean reqs[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };
+
+        result = VCALL(self->mEngine,CreateAudioRecorder)(&self->mRecordObj,
+            &audioSrc, &audioSnk, COUNTOF(ids), ids, reqs
+        );
+        PRINTERR(result, "engine->CreateAudioRecorder");
+    }
+    if(SL_RESULT_SUCCESS == result)
+    {
+        /* Set the record preset to "generic", if possible. */
+        SLAndroidConfigurationItf config;
+        result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
+        PRINTERR(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
         if(SL_RESULT_SUCCESS == result)
         if(SL_RESULT_SUCCESS == result)
         {
         {
-            ALvoid *buf = (ALbyte*)data->buffer + i*data->bufferSize;
-            result = VCALL(bufferQueue,Enqueue)(buf, data->bufferSize);
-            PRINTERR(result, "bufferQueue->Enqueue");
+            SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC;
+            result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET,
+                &preset, sizeof(preset)
+            );
+            PRINTERR(result, "config->SetConfiguration");
         }
         }
+
+        /* Clear any error since this was optional. */
+        result = SL_RESULT_SUCCESS;
     }
     }
-    data->curBuffer = 0;
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player);
-        PRINTERR(result, "bufferQueue->GetInterface");
+        result = VCALL(self->mRecordObj,Realize)(SL_BOOLEAN_FALSE);
+        PRINTERR(result, "recordObj->Realize");
     }
     }
+
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
-        PRINTERR(result, "player->SetPlayState");
+        self->mRing = ll_ringbuffer_create(device->NumUpdates, device->UpdateSize*self->mFrameSize,
+                                           false);
+
+        result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+                                                      &bufferQueue);
+        PRINTERR(result, "recordObj->GetInterface");
+    }
+    if(SL_RESULT_SUCCESS == result)
+    {
+        result = VCALL(bufferQueue,RegisterCallback)(ALCopenslCapture_process, self);
+        PRINTERR(result, "bufferQueue->RegisterCallback");
+    }
+    if(SL_RESULT_SUCCESS == result)
+    {
+        ALsizei chunk_size = device->UpdateSize * self->mFrameSize;
+        ll_ringbuffer_data_t data[2];
+        size_t i;
+
+        ll_ringbuffer_get_write_vector(self->mRing, data);
+        for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++)
+        {
+            result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size);
+            PRINTERR(result, "bufferQueue->Enqueue");
+        }
+        for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++)
+        {
+            result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size);
+            PRINTERR(result, "bufferQueue->Enqueue");
+        }
     }
     }
 
 
     if(SL_RESULT_SUCCESS != result)
     if(SL_RESULT_SUCCESS != result)
     {
     {
-        if(data->bufferQueueObject != NULL)
-            VCALL0(data->bufferQueueObject,Destroy)();
-        data->bufferQueueObject = NULL;
+        if(self->mRecordObj != NULL)
+            VCALL0(self->mRecordObj,Destroy)();
+        self->mRecordObj = NULL;
+
+        if(self->mEngineObj != NULL)
+            VCALL0(self->mEngineObj,Destroy)();
+        self->mEngineObj = NULL;
+        self->mEngine = NULL;
+
+        return ALC_INVALID_VALUE;
+    }
+
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
-        free(data->buffer);
-        data->buffer = NULL;
-        data->bufferSize = 0;
+    return ALC_NO_ERROR;
+}
+
+static ALCboolean ALCopenslCapture_start(ALCopenslCapture *self)
+{
+    SLRecordItf record;
+    SLresult result;
+
+    result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record);
+    PRINTERR(result, "recordObj->GetInterface");
+
+    if(SL_RESULT_SUCCESS == result)
+    {
+        result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING);
+        PRINTERR(result, "record->SetRecordState");
+    }
 
 
+    if(SL_RESULT_SUCCESS != result)
+    {
+        ALCopenslCapture_lock(self);
+        aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
+                            "Failed to start capture: 0x%08x", result);
+        ALCopenslCapture_unlock(self);
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
 
 
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-
-static void opensl_stop_playback(ALCdevice *Device)
+static void ALCopenslCapture_stop(ALCopenslCapture *self)
 {
 {
-    osl_data *data = Device->ExtraData;
-    SLPlayItf player;
-    SLAndroidSimpleBufferQueueItf bufferQueue;
+    SLRecordItf record;
     SLresult result;
     SLresult result;
 
 
-    result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player);
-    PRINTERR(result, "bufferQueue->GetInterface");
+    result = VCALL(self->mRecordObj,GetInterface)(SL_IID_RECORD, &record);
+    PRINTERR(result, "recordObj->GetInterface");
+
     if(SL_RESULT_SUCCESS == result)
     if(SL_RESULT_SUCCESS == result)
     {
     {
-        result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
-        PRINTERR(result, "player->SetPlayState");
+        result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED);
+        PRINTERR(result, "record->SetRecordState");
     }
     }
+}
 
 
-    result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue);
-    PRINTERR(result, "bufferQueue->GetInterface");
-    if(SL_RESULT_SUCCESS == result)
+static ALCenum ALCopenslCapture_captureSamples(ALCopenslCapture *self, ALCvoid *buffer, ALCuint samples)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    ALsizei chunk_size = device->UpdateSize * self->mFrameSize;
+    SLAndroidSimpleBufferQueueItf bufferQueue;
+    ll_ringbuffer_data_t data[2];
+    SLresult result;
+    size_t advance;
+    ALCuint i;
+
+    /* Read the desired samples from the ring buffer then advance its read
+     * pointer.
+     */
+    ll_ringbuffer_get_read_vector(self->mRing, data);
+    advance = 0;
+    for(i = 0;i < samples;)
     {
     {
-        result = VCALL0(bufferQueue,Clear)();
-        PRINTERR(result, "bufferQueue->Clear");
+        ALCuint rem = minu(samples - i, device->UpdateSize - self->mSplOffset);
+        memcpy((ALCbyte*)buffer + i*self->mFrameSize,
+               data[0].buf + self->mSplOffset*self->mFrameSize,
+               rem * self->mFrameSize);
+
+        self->mSplOffset += rem;
+        if(self->mSplOffset == device->UpdateSize)
+        {
+            /* Finished a chunk, reset the offset and advance the read pointer. */
+            self->mSplOffset = 0;
+            advance++;
+
+            data[0].len--;
+            if(!data[0].len)
+                data[0] = data[1];
+            else
+                data[0].buf += chunk_size;
+        }
+
+        i += rem;
     }
     }
-    if(SL_RESULT_SUCCESS == result)
+    ll_ringbuffer_read_advance(self->mRing, advance);
+
+    result = VCALL(self->mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+                                                  &bufferQueue);
+    PRINTERR(result, "recordObj->GetInterface");
+
+    /* Enqueue any newly-writable chunks in the ring buffer. */
+    ll_ringbuffer_get_write_vector(self->mRing, data);
+    for(i = 0;i < data[0].len && SL_RESULT_SUCCESS == result;i++)
     {
     {
-        SLAndroidSimpleBufferQueueState state;
-        do {
-            althrd_yield();
-            result = VCALL(bufferQueue,GetState)(&state);
-        } while(SL_RESULT_SUCCESS == result && state.count > 0);
-        PRINTERR(result, "bufferQueue->GetState");
+        result = VCALL(bufferQueue,Enqueue)(data[0].buf + chunk_size*i, chunk_size);
+        PRINTERR(result, "bufferQueue->Enqueue");
+    }
+    for(i = 0;i < data[1].len && SL_RESULT_SUCCESS == result;i++)
+    {
+        result = VCALL(bufferQueue,Enqueue)(data[1].buf + chunk_size*i, chunk_size);
+        PRINTERR(result, "bufferQueue->Enqueue");
     }
     }
 
 
-    free(data->buffer);
-    data->buffer = NULL;
-    data->bufferSize = 0;
+    if(SL_RESULT_SUCCESS != result)
+    {
+        ALCopenslCapture_lock(self);
+        aluHandleDisconnect(device, "Failed to update capture buffer: 0x%08x", result);
+        ALCopenslCapture_unlock(self);
+        return ALC_INVALID_DEVICE;
+    }
+
+    return ALC_NO_ERROR;
 }
 }
 
 
+static ALCuint ALCopenslCapture_availableSamples(ALCopenslCapture *self)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    return ll_ringbuffer_read_space(self->mRing) * device->UpdateSize;
+}
 
 
-static const BackendFuncs opensl_funcs = {
-    opensl_open_playback,
-    opensl_close_playback,
-    opensl_reset_playback,
-    opensl_start_playback,
-    opensl_stop_playback,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
 
 
+typedef struct ALCopenslBackendFactory {
+    DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCopenslBackendFactory;
+#define ALCOPENSLBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCopenslBackendFactory, ALCbackendFactory) } }
 
 
-ALCboolean alc_opensl_init(BackendFuncs *func_list)
+static ALCboolean ALCopenslBackendFactory_init(ALCopenslBackendFactory* UNUSED(self))
 {
 {
-    *func_list = opensl_funcs;
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-void alc_opensl_deinit(void)
+static void ALCopenslBackendFactory_deinit(ALCopenslBackendFactory* UNUSED(self))
 {
 {
 }
 }
 
 
-void alc_opensl_probe(enum DevProbe type)
+static ALCboolean ALCopenslBackendFactory_querySupport(ALCopenslBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+        return ALC_TRUE;
+    return ALC_FALSE;
+}
+
+static void ALCopenslBackendFactory_probe(ALCopenslBackendFactory* UNUSED(self), enum DevProbe type)
 {
 {
     switch(type)
     switch(type)
     {
     {
         case ALL_DEVICE_PROBE:
         case ALL_DEVICE_PROBE:
             AppendAllDevicesList(opensl_device);
             AppendAllDevicesList(opensl_device);
             break;
             break;
+
         case CAPTURE_DEVICE_PROBE:
         case CAPTURE_DEVICE_PROBE:
+            AppendAllDevicesList(opensl_device);
             break;
             break;
     }
     }
 }
 }
+
+static ALCbackend* ALCopenslBackendFactory_createBackend(ALCopenslBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+    {
+        ALCopenslPlayback *backend;
+        NEW_OBJ(backend, ALCopenslPlayback)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+    if(type == ALCbackend_Capture)
+    {
+        ALCopenslCapture *backend;
+        NEW_OBJ(backend, ALCopenslCapture)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+
+    return NULL;
+}
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCopenslBackendFactory);
+
+
+ALCbackendFactory *ALCopenslBackendFactory_getFactory(void)
+{
+    static ALCopenslBackendFactory factory = ALCOPENSLBACKENDFACTORY_INITIALIZER;
+    return STATIC_CAST(ALCbackendFactory, &factory);
+}

+ 193 - 136
Engine/lib/openal-soft/Alc/backends/oss.c

@@ -35,6 +35,8 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "alconfig.h"
+#include "ringbuffer.h"
 #include "threads.h"
 #include "threads.h"
 #include "compat.h"
 #include "compat.h"
 
 
@@ -88,7 +90,9 @@ static struct oss_device oss_capture = {
 
 
 #ifdef ALC_OSS_COMPAT
 #ifdef ALC_OSS_COMPAT
 
 
-static void ALCossListPopulate(struct oss_device *UNUSED(playback), struct oss_device *UNUSED(capture))
+#define DSP_CAP_OUTPUT 0x00020000
+#define DSP_CAP_INPUT 0x00010000
+static void ALCossListPopulate(struct oss_device *UNUSED(devlist), int UNUSED(type_flag))
 {
 {
 }
 }
 
 
@@ -153,7 +157,7 @@ static void ALCossListAppend(struct oss_device *list, const char *handle, size_t
     TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path);
     TRACE("Got device \"%s\", \"%s\"\n", next->handle, next->path);
 }
 }
 
 
-static void ALCossListPopulate(struct oss_device *playback, struct oss_device *capture)
+static void ALCossListPopulate(struct oss_device *devlist, int type_flag)
 {
 {
     struct oss_sysinfo si;
     struct oss_sysinfo si;
     struct oss_audioinfo ai;
     struct oss_audioinfo ai;
@@ -161,12 +165,12 @@ static void ALCossListPopulate(struct oss_device *playback, struct oss_device *c
 
 
     if((fd=open("/dev/mixer", O_RDONLY)) < 0)
     if((fd=open("/dev/mixer", O_RDONLY)) < 0)
     {
     {
-        ERR("Could not open /dev/mixer\n");
+        TRACE("Could not open /dev/mixer: %s\n", strerror(errno));
         return;
         return;
     }
     }
     if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1)
     if(ioctl(fd, SNDCTL_SYSINFO, &si) == -1)
     {
     {
-        ERR("SNDCTL_SYSINFO failed: %s\n", strerror(errno));
+        TRACE("SNDCTL_SYSINFO failed: %s\n", strerror(errno));
         goto done;
         goto done;
     }
     }
     for(i = 0;i < si.numaudios;i++)
     for(i = 0;i < si.numaudios;i++)
@@ -193,10 +197,9 @@ static void ALCossListPopulate(struct oss_device *playback, struct oss_device *c
             len = strnlen(ai.name, sizeof(ai.name));
             len = strnlen(ai.name, sizeof(ai.name));
             handle = ai.name;
             handle = ai.name;
         }
         }
-        if((ai.caps&DSP_CAP_INPUT) && capture != NULL)
-            ALCossListAppend(capture, handle, len, ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode)));
-        if((ai.caps&DSP_CAP_OUTPUT) && playback != NULL)
-            ALCossListAppend(playback, handle, len, ai.devnode, strnlen(ai.devnode, sizeof(ai.devnode)));
+        if((ai.caps&type_flag))
+            ALCossListAppend(devlist, handle, len, ai.devnode,
+                             strnlen(ai.devnode, sizeof(ai.devnode)));
     }
     }
 
 
 done:
 done:
@@ -242,16 +245,15 @@ typedef struct ALCplaybackOSS {
     ALubyte *mix_data;
     ALubyte *mix_data;
     int data_size;
     int data_size;
 
 
-    volatile int killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCplaybackOSS;
 } ALCplaybackOSS;
 
 
 static int ALCplaybackOSS_mixerProc(void *ptr);
 static int ALCplaybackOSS_mixerProc(void *ptr);
 
 
 static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
 static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCplaybackOSS, ALCbackend, void, Destruct)
+static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self);
 static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name);
 static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name);
-static void ALCplaybackOSS_close(ALCplaybackOSS *self);
 static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self);
 static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self);
 static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self);
 static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self);
 static void ALCplaybackOSS_stop(ALCplaybackOSS *self);
 static void ALCplaybackOSS_stop(ALCplaybackOSS *self);
@@ -268,42 +270,66 @@ static int ALCplaybackOSS_mixerProc(void *ptr)
 {
 {
     ALCplaybackOSS *self = (ALCplaybackOSS*)ptr;
     ALCplaybackOSS *self = (ALCplaybackOSS*)ptr;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    ALint frameSize;
+    struct timeval timeout;
+    ALubyte *write_ptr;
+    ALint frame_size;
+    ALint to_write;
     ssize_t wrote;
     ssize_t wrote;
+    fd_set wfds;
+    int sret;
 
 
     SetRTPriority();
     SetRTPriority();
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
 
 
-    frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
-    while(!self->killNow && device->Connected)
+    ALCplaybackOSS_lock(self);
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
     {
     {
-        ALint len = self->data_size;
-        ALubyte *WritePtr = self->mix_data;
+        FD_ZERO(&wfds);
+        FD_SET(self->fd, &wfds);
+        timeout.tv_sec = 1;
+        timeout.tv_usec = 0;
+
+        ALCplaybackOSS_unlock(self);
+        sret = select(self->fd+1, NULL, &wfds, NULL, &timeout);
+        ALCplaybackOSS_lock(self);
+        if(sret < 0)
+        {
+            if(errno == EINTR)
+                continue;
+            ERR("select failed: %s\n", strerror(errno));
+            aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno));
+            break;
+        }
+        else if(sret == 0)
+        {
+            WARN("select timeout\n");
+            continue;
+        }
 
 
-        aluMixData(device, WritePtr, len/frameSize);
-        while(len > 0 && !self->killNow)
+        write_ptr = self->mix_data;
+        to_write = self->data_size;
+        aluMixData(device, write_ptr, to_write/frame_size);
+        while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow))
         {
         {
-            wrote = write(self->fd, WritePtr, len);
+            wrote = write(self->fd, write_ptr, to_write);
             if(wrote < 0)
             if(wrote < 0)
             {
             {
-                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
-                {
-                    ERR("write failed: %s\n", strerror(errno));
-                    ALCplaybackOSS_lock(self);
-                    aluHandleDisconnect(device);
-                    ALCplaybackOSS_unlock(self);
-                    break;
-                }
-
-                al_nssleep(1000000);
-                continue;
+                if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+                    continue;
+                ERR("write failed: %s\n", strerror(errno));
+                aluHandleDisconnect(device, "Failed writing playback samples: %s",
+                                    strerror(errno));
+                break;
             }
             }
 
 
-            len -= wrote;
-            WritePtr += wrote;
+            to_write -= wrote;
+            write_ptr += wrote;
         }
         }
     }
     }
+    ALCplaybackOSS_unlock(self);
 
 
     return 0;
     return 0;
 }
 }
@@ -313,6 +339,18 @@ static void ALCplaybackOSS_Construct(ALCplaybackOSS *self, ALCdevice *device)
 {
 {
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCplaybackOSS, ALCbackend, self);
     SET_VTABLE2(ALCplaybackOSS, ALCbackend, self);
+
+    self->fd = -1;
+    ATOMIC_INIT(&self->killNow, AL_FALSE);
+}
+
+static void ALCplaybackOSS_Destruct(ALCplaybackOSS *self)
+{
+    if(self->fd != -1)
+        close(self->fd);
+    self->fd = -1;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
 
 
 static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
 static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
@@ -320,22 +358,28 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
     struct oss_device *dev = &oss_playback;
     struct oss_device *dev = &oss_playback;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
 
 
-    if(!name)
+    if(!name || strcmp(name, dev->handle) == 0)
         name = dev->handle;
         name = dev->handle;
     else
     else
     {
     {
-        while (dev != NULL)
+        if(!dev->next)
+        {
+            ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT);
+            dev = &oss_playback;
+        }
+        while(dev != NULL)
         {
         {
             if (strcmp(dev->handle, name) == 0)
             if (strcmp(dev->handle, name) == 0)
                 break;
                 break;
             dev = dev->next;
             dev = dev->next;
         }
         }
-        if (dev == NULL)
+        if(dev == NULL)
+        {
+            WARN("Could not find \"%s\" in device list\n", name);
             return ALC_INVALID_VALUE;
             return ALC_INVALID_VALUE;
+        }
     }
     }
 
 
-    self->killNow = 0;
-
     self->fd = open(dev->path, O_WRONLY);
     self->fd = open(dev->path, O_WRONLY);
     if(self->fd == -1)
     if(self->fd == -1)
     {
     {
@@ -343,17 +387,11 @@ static ALCenum ALCplaybackOSS_open(ALCplaybackOSS *self, const ALCchar *name)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCplaybackOSS_close(ALCplaybackOSS *self)
-{
-    close(self->fd);
-    self->fd = -1;
-}
-
 static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
 static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -387,18 +425,11 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
     }
     }
 
 
     periods = device->NumUpdates;
     periods = device->NumUpdates;
-    numChannels = ChannelsFromDevFmt(device->FmtChans);
-    frameSize = numChannels * BytesFromDevFmt(device->FmtType);
-
+    numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
     ossSpeed = device->Frequency;
     ossSpeed = device->Frequency;
-    log2FragmentSize = log2i(device->UpdateSize * frameSize);
-
-    /* according to the OSS spec, 16 bytes are the minimum */
-    if (log2FragmentSize < 4)
-        log2FragmentSize = 4;
-    /* Subtract one period since the temp mixing buffer counts as one. Still
-     * need at least two on the card, though. */
-    if(periods > 2) periods--;
+    frameSize = numChannels * BytesFromDevFmt(device->FmtType);
+    /* According to the OSS spec, 16 bytes (log2(16)) is the minimum. */
+    log2FragmentSize = maxi(log2i(device->UpdateSize*frameSize), 4);
     numFragmentsLogSize = (periods << 16) | log2FragmentSize;
     numFragmentsLogSize = (periods << 16) | log2FragmentSize;
 
 
 #define CHECKERR(func) if((func) < 0) {                                       \
 #define CHECKERR(func) if((func) < 0) {                                       \
@@ -420,7 +451,7 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
     }
     }
 #undef CHECKERR
 #undef CHECKERR
 
 
-    if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
+    if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels)
     {
     {
         ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
         ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
         return ALC_FALSE;
         return ALC_FALSE;
@@ -436,7 +467,7 @@ static ALCboolean ALCplaybackOSS_reset(ALCplaybackOSS *self)
 
 
     device->Frequency = ossSpeed;
     device->Frequency = ossSpeed;
     device->UpdateSize = info.fragsize / frameSize;
     device->UpdateSize = info.fragsize / frameSize;
-    device->NumUpdates = info.fragments + 1;
+    device->NumUpdates = info.fragments;
 
 
     SetDefaultChannelOrder(device);
     SetDefaultChannelOrder(device);
 
 
@@ -447,10 +478,12 @@ static ALCboolean ALCplaybackOSS_start(ALCplaybackOSS *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
 
 
-    self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    self->data_size = device->UpdateSize * FrameSizeFromDevFmt(
+        device->FmtChans, device->FmtType, device->AmbiOrder
+    );
     self->mix_data = calloc(1, self->data_size);
     self->mix_data = calloc(1, self->data_size);
 
 
-    self->killNow = 0;
+    ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE);
     if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCplaybackOSS_mixerProc, self) != althrd_success)
     {
     {
         free(self->mix_data);
         free(self->mix_data);
@@ -465,10 +498,8 @@ static void ALCplaybackOSS_stop(ALCplaybackOSS *self)
 {
 {
     int res;
     int res;
 
 
-    if(self->killNow)
+    if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE))
         return;
         return;
-
-    self->killNow = 1;
     althrd_join(self->thread, &res);
     althrd_join(self->thread, &res);
 
 
     if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
     if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
@@ -485,18 +516,16 @@ typedef struct ALCcaptureOSS {
     int fd;
     int fd;
 
 
     ll_ringbuffer_t *ring;
     ll_ringbuffer_t *ring;
-    int doCapture;
 
 
-    volatile int killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCcaptureOSS;
 } ALCcaptureOSS;
 
 
 static int ALCcaptureOSS_recordProc(void *ptr);
 static int ALCcaptureOSS_recordProc(void *ptr);
 
 
 static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
 static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, void, Destruct)
+static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self);
 static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name);
 static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name);
-static void ALCcaptureOSS_close(ALCcaptureOSS *self);
 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset)
 static DECLARE_FORWARD(ALCcaptureOSS, ALCbackend, ALCboolean, reset)
 static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self);
 static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self);
 static void ALCcaptureOSS_stop(ALCcaptureOSS *self);
 static void ALCcaptureOSS_stop(ALCcaptureOSS *self);
@@ -513,41 +542,55 @@ static int ALCcaptureOSS_recordProc(void *ptr)
 {
 {
     ALCcaptureOSS *self = (ALCcaptureOSS*)ptr;
     ALCcaptureOSS *self = (ALCcaptureOSS*)ptr;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    int frameSize;
+    struct timeval timeout;
+    int frame_size;
+    fd_set rfds;
     ssize_t amt;
     ssize_t amt;
+    int sret;
 
 
     SetRTPriority();
     SetRTPriority();
     althrd_setname(althrd_current(), RECORD_THREAD_NAME);
     althrd_setname(althrd_current(), RECORD_THREAD_NAME);
 
 
-    frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
-    while(!self->killNow)
+    while(!ATOMIC_LOAD_SEQ(&self->killNow))
     {
     {
         ll_ringbuffer_data_t vec[2];
         ll_ringbuffer_data_t vec[2];
 
 
-        amt = 0;
-        if(self->doCapture)
+        FD_ZERO(&rfds);
+        FD_SET(self->fd, &rfds);
+        timeout.tv_sec = 1;
+        timeout.tv_usec = 0;
+
+        sret = select(self->fd+1, &rfds, NULL, NULL, &timeout);
+        if(sret < 0)
         {
         {
-            ll_ringbuffer_get_write_vector(self->ring, vec);
-            if(vec[0].len > 0)
-            {
-                amt = read(self->fd, vec[0].buf, vec[0].len*frameSize);
-                if(amt < 0)
-                {
-                    ERR("read failed: %s\n", strerror(errno));
-                    ALCcaptureOSS_lock(self);
-                    aluHandleDisconnect(device);
-                    ALCcaptureOSS_unlock(self);
-                    break;
-                }
-                ll_ringbuffer_write_advance(self->ring, amt/frameSize);
-            }
+            if(errno == EINTR)
+                continue;
+            ERR("select failed: %s\n", strerror(errno));
+            aluHandleDisconnect(device, "Failed to check capture samples: %s", strerror(errno));
+            break;
         }
         }
-        if(amt == 0)
+        else if(sret == 0)
         {
         {
-            al_nssleep(1000000);
+            WARN("select timeout\n");
             continue;
             continue;
         }
         }
+
+        ll_ringbuffer_get_write_vector(self->ring, vec);
+        if(vec[0].len > 0)
+        {
+            amt = read(self->fd, vec[0].buf, vec[0].len*frame_size);
+            if(amt < 0)
+            {
+                ERR("read failed: %s\n", strerror(errno));
+                ALCcaptureOSS_lock(self);
+                aluHandleDisconnect(device, "Failed reading capture samples: %s", strerror(errno));
+                ALCcaptureOSS_unlock(self);
+                break;
+            }
+            ll_ringbuffer_write_advance(self->ring, amt/frame_size);
+        }
     }
     }
 
 
     return 0;
     return 0;
@@ -558,6 +601,21 @@ static void ALCcaptureOSS_Construct(ALCcaptureOSS *self, ALCdevice *device)
 {
 {
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCcaptureOSS, ALCbackend, self);
     SET_VTABLE2(ALCcaptureOSS, ALCbackend, self);
+
+    self->fd = -1;
+    self->ring = NULL;
+    ATOMIC_INIT(&self->killNow, AL_FALSE);
+}
+
+static void ALCcaptureOSS_Destruct(ALCcaptureOSS *self)
+{
+    if(self->fd != -1)
+        close(self->fd);
+    self->fd = -1;
+
+    ll_ringbuffer_free(self->ring);
+    self->ring = NULL;
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
 
 
 static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
 static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
@@ -574,18 +632,26 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
     int ossSpeed;
     int ossSpeed;
     char *err;
     char *err;
 
 
-    if(!name)
+    if(!name || strcmp(name, dev->handle) == 0)
         name = dev->handle;
         name = dev->handle;
     else
     else
     {
     {
-        while (dev != NULL)
+        if(!dev->next)
+        {
+            ALCossListPopulate(&oss_capture, DSP_CAP_INPUT);
+            dev = &oss_capture;
+        }
+        while(dev != NULL)
         {
         {
             if (strcmp(dev->handle, name) == 0)
             if (strcmp(dev->handle, name) == 0)
                 break;
                 break;
             dev = dev->next;
             dev = dev->next;
         }
         }
-        if (dev == NULL)
+        if(dev == NULL)
+        {
+            WARN("Could not find \"%s\" in device list\n", name);
             return ALC_INVALID_VALUE;
             return ALC_INVALID_VALUE;
+        }
     }
     }
 
 
     self->fd = open(dev->path, O_RDONLY);
     self->fd = open(dev->path, O_RDONLY);
@@ -615,7 +681,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
     }
     }
 
 
     periods = 4;
     periods = 4;
-    numChannels = ChannelsFromDevFmt(device->FmtChans);
+    numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
     frameSize = numChannels * BytesFromDevFmt(device->FmtType);
     frameSize = numChannels * BytesFromDevFmt(device->FmtType);
     ossSpeed = device->Frequency;
     ossSpeed = device->Frequency;
     log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
     log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
@@ -645,7 +711,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
     }
     }
 #undef CHECKERR
 #undef CHECKERR
 
 
-    if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
+    if((int)ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != numChannels)
     {
     {
         ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
         ERR("Failed to set %s, got %d channels instead\n", DevFmtChannelsString(device->FmtChans), numChannels);
         close(self->fd);
         close(self->fd);
@@ -663,7 +729,7 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates + 1, frameSize);
+    self->ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates, frameSize, false);
     if(!self->ring)
     if(!self->ring)
     {
     {
         ERR("Ring buffer create failed\n");
         ERR("Ring buffer create failed\n");
@@ -672,44 +738,30 @@ static ALCenum ALCcaptureOSS_open(ALCcaptureOSS *self, const ALCchar *name)
         return ALC_OUT_OF_MEMORY;
         return ALC_OUT_OF_MEMORY;
     }
     }
 
 
-    self->killNow = 0;
-    if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success)
-    {
-        ll_ringbuffer_free(self->ring);
-        self->ring = NULL;
-        close(self->fd);
-        self->fd = -1;
-        return ALC_OUT_OF_MEMORY;
-    }
-
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCcaptureOSS_close(ALCcaptureOSS *self)
-{
-    int res;
-
-    self->killNow = 1;
-    althrd_join(self->thread, &res);
-
-    close(self->fd);
-    self->fd = -1;
-
-    ll_ringbuffer_free(self->ring);
-    self->ring = NULL;
-}
-
 static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self)
 static ALCboolean ALCcaptureOSS_start(ALCcaptureOSS *self)
 {
 {
-    self->doCapture = 1;
+    ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE);
+    if(althrd_create(&self->thread, ALCcaptureOSS_recordProc, self) != althrd_success)
+        return ALC_FALSE;
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
 static void ALCcaptureOSS_stop(ALCcaptureOSS *self)
 static void ALCcaptureOSS_stop(ALCcaptureOSS *self)
 {
 {
-    self->doCapture = 0;
+    int res;
+
+    if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE))
+        return;
+
+    althrd_join(self->thread, &res);
+
+    if(ioctl(self->fd, SNDCTL_DSP_RESET) != 0)
+        ERR("Error resetting device: %s\n", strerror(errno));
 }
 }
 
 
 static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples)
 static ALCenum ALCcaptureOSS_captureSamples(ALCcaptureOSS *self, ALCvoid *buffer, ALCuint samples)
@@ -770,33 +822,38 @@ ALCboolean ALCossBackendFactory_querySupport(ALCossBackendFactory* UNUSED(self),
 
 
 void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type)
 void ALCossBackendFactory_probe(ALCossBackendFactory* UNUSED(self), enum DevProbe type)
 {
 {
+    struct oss_device *cur;
     switch(type)
     switch(type)
     {
     {
         case ALL_DEVICE_PROBE:
         case ALL_DEVICE_PROBE:
-        {
-            struct oss_device *cur = &oss_playback;
-            ALCossListFree(cur);
-            ALCossListPopulate(cur, NULL);
-            while (cur != NULL)
+            ALCossListFree(&oss_playback);
+            ALCossListPopulate(&oss_playback, DSP_CAP_OUTPUT);
+            cur = &oss_playback;
+            while(cur != NULL)
             {
             {
-                AppendAllDevicesList(cur->handle);
+#ifdef HAVE_STAT
+                struct stat buf;
+                if(stat(cur->path, &buf) == 0)
+#endif
+                    AppendAllDevicesList(cur->handle);
                 cur = cur->next;
                 cur = cur->next;
             }
             }
-        }
-        break;
+            break;
 
 
         case CAPTURE_DEVICE_PROBE:
         case CAPTURE_DEVICE_PROBE:
-        {
-            struct oss_device *cur = &oss_capture;
-            ALCossListFree(cur);
-            ALCossListPopulate(NULL, cur);
-            while (cur != NULL)
+            ALCossListFree(&oss_capture);
+            ALCossListPopulate(&oss_capture, DSP_CAP_INPUT);
+            cur = &oss_capture;
+            while(cur != NULL)
             {
             {
-                AppendCaptureDeviceList(cur->handle);
+#ifdef HAVE_STAT
+                struct stat buf;
+                if(stat(cur->path, &buf) == 0)
+#endif
+                    AppendCaptureDeviceList(cur->handle);
                 cur = cur->next;
                 cur = cur->next;
             }
             }
-        }
-        break;
+            break;
     }
     }
 }
 }
 
 

+ 17 - 32
Engine/lib/openal-soft/Alc/backends/portaudio.c

@@ -26,6 +26,8 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "alconfig.h"
+#include "ringbuffer.h"
 #include "compat.h"
 #include "compat.h"
 
 
 #include "backends/base.h"
 #include "backends/base.h"
@@ -139,7 +141,6 @@ static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBu
 static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device);
 static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device);
 static void ALCportPlayback_Destruct(ALCportPlayback *self);
 static void ALCportPlayback_Destruct(ALCportPlayback *self);
 static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name);
 static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name);
-static void ALCportPlayback_close(ALCportPlayback *self);
 static ALCboolean ALCportPlayback_reset(ALCportPlayback *self);
 static ALCboolean ALCportPlayback_reset(ALCportPlayback *self);
 static ALCboolean ALCportPlayback_start(ALCportPlayback *self);
 static ALCboolean ALCportPlayback_start(ALCportPlayback *self);
 static void ALCportPlayback_stop(ALCportPlayback *self);
 static void ALCportPlayback_stop(ALCportPlayback *self);
@@ -163,8 +164,9 @@ static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
 
 
 static void ALCportPlayback_Destruct(ALCportPlayback *self)
 static void ALCportPlayback_Destruct(ALCportPlayback *self)
 {
 {
-    if(self->stream)
-        Pa_CloseStream(self->stream);
+    PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError;
+    if(err != paNoError)
+        ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
     self->stream = NULL;
     self->stream = NULL;
 
 
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
@@ -177,7 +179,9 @@ static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *
 {
 {
     ALCportPlayback *self = userData;
     ALCportPlayback *self = userData;
 
 
+    ALCportPlayback_lock(self);
     aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer);
     aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer);
+    ALCportPlayback_unlock(self);
     return 0;
     return 0;
 }
 }
 
 
@@ -243,20 +247,12 @@ retry_open:
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 
 
 }
 }
 
 
-static void ALCportPlayback_close(ALCportPlayback *self)
-{
-    PaError err = Pa_CloseStream(self->stream);
-    if(err != paNoError)
-        ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
-    self->stream = NULL;
-}
-
 static ALCboolean ALCportPlayback_reset(ALCportPlayback *self)
 static ALCboolean ALCportPlayback_reset(ALCportPlayback *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -334,7 +330,6 @@ static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuff
 static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device);
 static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device);
 static void ALCportCapture_Destruct(ALCportCapture *self);
 static void ALCportCapture_Destruct(ALCportCapture *self);
 static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name);
 static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name);
-static void ALCportCapture_close(ALCportCapture *self);
 static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset)
 static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset)
 static ALCboolean ALCportCapture_start(ALCportCapture *self);
 static ALCboolean ALCportCapture_start(ALCportCapture *self);
 static void ALCportCapture_stop(ALCportCapture *self);
 static void ALCportCapture_stop(ALCportCapture *self);
@@ -354,16 +349,17 @@ static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device)
     SET_VTABLE2(ALCportCapture, ALCbackend, self);
     SET_VTABLE2(ALCportCapture, ALCbackend, self);
 
 
     self->stream = NULL;
     self->stream = NULL;
+    self->ring = NULL;
 }
 }
 
 
 static void ALCportCapture_Destruct(ALCportCapture *self)
 static void ALCportCapture_Destruct(ALCportCapture *self)
 {
 {
-    if(self->stream)
-        Pa_CloseStream(self->stream);
+    PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError;
+    if(err != paNoError)
+        ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
     self->stream = NULL;
     self->stream = NULL;
 
 
-    if(self->ring)
-        ll_ringbuffer_free(self->ring);
+    ll_ringbuffer_free(self->ring);
     self->ring = NULL;
     self->ring = NULL;
 
 
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
@@ -397,9 +393,9 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
 
 
     samples = device->UpdateSize * device->NumUpdates;
     samples = device->UpdateSize * device->NumUpdates;
     samples = maxu(samples, 100 * device->Frequency / 1000);
     samples = maxu(samples, 100 * device->Frequency / 1000);
-    frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
-    self->ring = ll_ringbuffer_create(samples, frame_size);
+    self->ring = ll_ringbuffer_create(samples, frame_size, false);
     if(self->ring == NULL) return ALC_INVALID_VALUE;
     if(self->ring == NULL) return ALC_INVALID_VALUE;
 
 
     self->params.device = -1;
     self->params.device = -1;
@@ -431,7 +427,7 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
             ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
             ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
             return ALC_INVALID_VALUE;
             return ALC_INVALID_VALUE;
     }
     }
-    self->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
+    self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
 
 
     err = Pa_OpenStream(&self->stream, &self->params, NULL,
     err = Pa_OpenStream(&self->stream, &self->params, NULL,
         device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
         device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
@@ -443,22 +439,11 @@ static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCportCapture_close(ALCportCapture *self)
-{
-    PaError err = Pa_CloseStream(self->stream);
-    if(err != paNoError)
-        ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
-    self->stream = NULL;
-
-    ll_ringbuffer_free(self->ring);
-    self->ring = NULL;
-}
-
 
 
 static ALCboolean ALCportCapture_start(ALCportCapture *self)
 static ALCboolean ALCportCapture_start(ALCportCapture *self)
 {
 {

+ 203 - 131
Engine/lib/openal-soft/Alc/backends/pulseaudio.c

@@ -25,6 +25,7 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "alconfig.h"
 #include "threads.h"
 #include "threads.h"
 #include "compat.h"
 #include "compat.h"
 
 
@@ -182,6 +183,8 @@ static ALCboolean pulse_load(void)
 #ifdef HAVE_DYNLOAD
 #ifdef HAVE_DYNLOAD
     if(!pa_handle)
     if(!pa_handle)
     {
     {
+        al_string missing_funcs = AL_STRING_INIT_STATIC();
+
 #ifdef _WIN32
 #ifdef _WIN32
 #define PALIB "libpulse-0.dll"
 #define PALIB "libpulse-0.dll"
 #elif defined(__APPLE__) && defined(__MACH__)
 #elif defined(__APPLE__) && defined(__MACH__)
@@ -191,12 +194,16 @@ static ALCboolean pulse_load(void)
 #endif
 #endif
         pa_handle = LoadLib(PALIB);
         pa_handle = LoadLib(PALIB);
         if(!pa_handle)
         if(!pa_handle)
+        {
+            WARN("Failed to load %s\n", PALIB);
             return ALC_FALSE;
             return ALC_FALSE;
+        }
 
 
 #define LOAD_FUNC(x) do {                                                     \
 #define LOAD_FUNC(x) do {                                                     \
     p##x = GetSymbol(pa_handle, #x);                                          \
     p##x = GetSymbol(pa_handle, #x);                                          \
     if(!(p##x)) {                                                             \
     if(!(p##x)) {                                                             \
         ret = ALC_FALSE;                                                      \
         ret = ALC_FALSE;                                                      \
+        alstr_append_cstr(&missing_funcs, "\n" #x);                           \
     }                                                                         \
     }                                                                         \
 } while(0)
 } while(0)
         LOAD_FUNC(pa_context_unref);
         LOAD_FUNC(pa_context_unref);
@@ -270,9 +277,11 @@ static ALCboolean pulse_load(void)
 
 
         if(ret == ALC_FALSE)
         if(ret == ALC_FALSE)
         {
         {
+            WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs));
             CloseLib(pa_handle);
             CloseLib(pa_handle);
             pa_handle = NULL;
             pa_handle = NULL;
         }
         }
+        alstr_reset(&missing_funcs);
     }
     }
 #endif /* HAVE_DYNLOAD */
 #endif /* HAVE_DYNLOAD */
     return ret;
     return ret;
@@ -325,18 +334,20 @@ static void wait_for_operation(pa_operation *op, pa_threaded_mainloop *loop)
 static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent)
 static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent)
 {
 {
     const char *name = "OpenAL Soft";
     const char *name = "OpenAL Soft";
-    char path_name[PATH_MAX];
+    al_string binname = AL_STRING_INIT_STATIC();
     pa_context_state_t state;
     pa_context_state_t state;
     pa_context *context;
     pa_context *context;
     int err;
     int err;
 
 
-    if(pa_get_binary_name(path_name, sizeof(path_name)))
-        name = pa_path_get_filename(path_name);
+    GetProcBinary(NULL, &binname);
+    if(!alstr_empty(binname))
+        name = alstr_get_cstr(binname);
 
 
     context = pa_context_new(pa_threaded_mainloop_get_api(loop), name);
     context = pa_context_new(pa_threaded_mainloop_get_api(loop), name);
     if(!context)
     if(!context)
     {
     {
         ERR("pa_context_new() failed\n");
         ERR("pa_context_new() failed\n");
+        alstr_reset(&binname);
         return NULL;
         return NULL;
     }
     }
 
 
@@ -363,9 +374,10 @@ static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent)
         if(!silent)
         if(!silent)
             ERR("Context did not connect: %s\n", pa_strerror(err));
             ERR("Context did not connect: %s\n", pa_strerror(err));
         pa_context_unref(context);
         pa_context_unref(context);
-        return NULL;
+        context = NULL;
     }
     }
 
 
+    alstr_reset(&binname);
     return context;
     return context;
 }
 }
 
 
@@ -460,7 +472,7 @@ typedef struct ALCpulsePlayback {
     pa_stream *stream;
     pa_stream *stream;
     pa_context *context;
     pa_context *context;
 
 
-    volatile ALboolean killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCpulsePlayback;
 } ALCpulsePlayback;
 
 
@@ -483,7 +495,6 @@ static int ALCpulsePlayback_mixerProc(void *ptr);
 static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device);
 static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device);
 static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self);
 static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self);
 static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name);
 static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name);
-static void ALCpulsePlayback_close(ALCpulsePlayback *self);
 static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self);
 static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self);
 static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self);
 static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self);
 static void ALCpulsePlayback_stop(ALCpulsePlayback *self);
 static void ALCpulsePlayback_stop(ALCpulsePlayback *self);
@@ -502,11 +513,20 @@ static void ALCpulsePlayback_Construct(ALCpulsePlayback *self, ALCdevice *device
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCpulsePlayback, ALCbackend, self);
     SET_VTABLE2(ALCpulsePlayback, ALCbackend, self);
 
 
+    self->loop = NULL;
     AL_STRING_INIT(self->device_name);
     AL_STRING_INIT(self->device_name);
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
 }
 }
 
 
 static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self)
 static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self)
 {
 {
+    if(self->loop)
+    {
+        pulse_close(self->loop, self->context, self->stream);
+        self->loop = NULL;
+        self->context = NULL;
+        self->stream = NULL;
+    }
     AL_STRING_DEINIT(self->device_name);
     AL_STRING_DEINIT(self->device_name);
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
@@ -525,7 +545,7 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
         return;
         return;
     }
     }
 
 
-#define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0)
+#define MATCH_INFO_NAME(iter) (alstr_cmp_cstr((iter)->device_name, info->name) == 0)
     VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME);
     VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME);
     if(iter != VECTOR_END(PlaybackDevices)) return;
     if(iter != VECTOR_END(PlaybackDevices)) return;
 #undef MATCH_INFO_NAME
 #undef MATCH_INFO_NAME
@@ -533,27 +553,27 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.device_name);
     AL_STRING_INIT(entry.device_name);
 
 
-    al_string_copy_cstr(&entry.device_name, info->name);
+    alstr_copy_cstr(&entry.device_name, info->name);
 
 
     count = 0;
     count = 0;
     while(1)
     while(1)
     {
     {
-        al_string_copy_cstr(&entry.name, info->description);
+        alstr_copy_cstr(&entry.name, info->description);
         if(count != 0)
         if(count != 0)
         {
         {
             char str[64];
             char str[64];
             snprintf(str, sizeof(str), " #%d", count+1);
             snprintf(str, sizeof(str), " #%d", count+1);
-            al_string_append_cstr(&entry.name, str);
+            alstr_append_cstr(&entry.name, str);
         }
         }
 
 
-#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0)
         VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY);
         VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY);
         if(iter == VECTOR_END(PlaybackDevices)) break;
         if(iter == VECTOR_END(PlaybackDevices)) break;
 #undef MATCH_ENTRY
 #undef MATCH_ENTRY
         count++;
         count++;
     }
     }
 
 
-    TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name));
+    TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.device_name));
 
 
     VECTOR_PUSH_BACK(PlaybackDevices, entry);
     VECTOR_PUSH_BACK(PlaybackDevices, entry);
 }
 }
@@ -618,6 +638,11 @@ static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata)
 
 
     self->attr = *pa_stream_get_buffer_attr(stream);
     self->attr = *pa_stream_get_buffer_attr(stream);
     TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, self->attr.prebuf);
     TRACE("minreq=%d, tlength=%d, prebuf=%d\n", self->attr.minreq, self->attr.tlength, self->attr.prebuf);
+    /* FIXME: Update the device's UpdateSize (and/or NumUpdates) using the new
+     * buffer attributes? Changing UpdateSize will change the ALC_REFRESH
+     * property, which probably shouldn't change between device resets. But
+     * leaving it alone means ALC_REFRESH will be off.
+     */
 }
 }
 
 
 static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata)
 static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata)
@@ -626,7 +651,7 @@ static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pda
     if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
     if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
     {
     {
         ERR("Received context failure!\n");
         ERR("Received context failure!\n");
-        aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
+        aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback state failure");
     }
     }
     pa_threaded_mainloop_signal(self->loop, 0);
     pa_threaded_mainloop_signal(self->loop, 0);
 }
 }
@@ -637,7 +662,7 @@ static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata)
     if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
     if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
     {
     {
         ERR("Received stream failure!\n");
         ERR("Received stream failure!\n");
-        aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
+        aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Playback stream failure");
     }
     }
     pa_threaded_mainloop_signal(self->loop, 0);
     pa_threaded_mainloop_signal(self->loop, 0);
 }
 }
@@ -729,7 +754,7 @@ static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const
         return;
         return;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, info->description);
+    alstr_copy_cstr(&device->DeviceName, info->description);
 }
 }
 
 
 
 
@@ -737,9 +762,9 @@ static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata)
 {
 {
     ALCpulsePlayback *self = pdata;
     ALCpulsePlayback *self = pdata;
 
 
-    al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(stream));
+    alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(stream));
 
 
-    TRACE("Stream moved to %s\n", al_string_get_cstr(self->device_name));
+    TRACE("Stream moved to %s\n", alstr_get_cstr(self->device_name));
 }
 }
 
 
 
 
@@ -751,6 +776,13 @@ static pa_stream *ALCpulsePlayback_connectStream(const char *device_name,
     pa_stream_state_t state;
     pa_stream_state_t state;
     pa_stream *stream;
     pa_stream *stream;
 
 
+    if(!device_name)
+    {
+        device_name = getenv("ALSOFT_PULSE_DEFAULT");
+        if(device_name && !device_name[0])
+            device_name = NULL;
+    }
+
     stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter);
     stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter);
     if(!stream)
     if(!stream)
     {
     {
@@ -789,7 +821,6 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
     ALCpulsePlayback *self = ptr;
     ALCpulsePlayback *self = ptr;
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     ALuint buffer_size;
     ALuint buffer_size;
-    ALint update_size;
     size_t frame_size;
     size_t frame_size;
     ssize_t len;
     ssize_t len;
 
 
@@ -798,18 +829,35 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
 
 
     pa_threaded_mainloop_lock(self->loop);
     pa_threaded_mainloop_lock(self->loop);
     frame_size = pa_frame_size(&self->spec);
     frame_size = pa_frame_size(&self->spec);
-    update_size = device->UpdateSize * frame_size;
-
-    /* Sanitize buffer metrics, in case we actually have less than what we
-     * asked for. */
-    buffer_size = minu(update_size*device->NumUpdates, self->attr.tlength);
-    update_size = minu(update_size, buffer_size/2);
-    do {
-        len = pa_stream_writable_size(self->stream) - self->attr.tlength +
-              buffer_size;
-        if(len < update_size)
+
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
+    {
+        void *buf;
+        int ret;
+
+        len = pa_stream_writable_size(self->stream);
+        if(len < 0)
         {
         {
-            if(pa_stream_is_corked(self->stream) == 1)
+            ERR("Failed to get writable size: %ld", (long)len);
+            aluHandleDisconnect(device, "Failed to get writable size: %ld", (long)len);
+            break;
+        }
+
+        /* Make sure we're going to write at least 2 'periods' (minreqs), in
+         * case the server increased it since starting playback. Also round up
+         * the number of writable periods if it's not an integer count.
+         */
+        buffer_size = maxu((self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2) *
+                      self->attr.minreq;
+
+        /* NOTE: This assumes pa_stream_writable_size returns between 0 and
+         * tlength, else there will be more latency than intended.
+         */
+        len = mini(len - (ssize_t)self->attr.tlength, 0) + buffer_size;
+        if(len < (int32_t)self->attr.minreq)
+        {
+            if(pa_stream_is_corked(self->stream))
             {
             {
                 pa_operation *o;
                 pa_operation *o;
                 o = pa_stream_cork(self->stream, 0, NULL, NULL);
                 o = pa_stream_cork(self->stream, 0, NULL, NULL);
@@ -818,26 +866,17 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
             pa_threaded_mainloop_wait(self->loop);
             pa_threaded_mainloop_wait(self->loop);
             continue;
             continue;
         }
         }
-        len -= len%update_size;
 
 
-        while(len > 0)
-        {
-            size_t newlen = len;
-            void *buf;
-            pa_free_cb_t free_func = NULL;
+        len -= len%self->attr.minreq;
+        len -= len%frame_size;
 
 
-            if(pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
-            {
-                buf = pa_xmalloc(newlen);
-                free_func = pa_xfree;
-            }
+        buf = pa_xmalloc(len);
 
 
-            aluMixData(device, buf, newlen/frame_size);
+        aluMixData(device, buf, len/frame_size);
 
 
-            pa_stream_write(self->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
-            len -= newlen;
-        }
-    } while(!self->killNow && device->Connected);
+        ret = pa_stream_write(self->stream, buf, len, pa_xfree, 0, PA_SEEK_RELATIVE);
+        if(ret != PA_OK) ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret));
+    }
     pa_threaded_mainloop_unlock(self->loop);
     pa_threaded_mainloop_unlock(self->loop);
 
 
     return 0;
     return 0;
@@ -858,12 +897,12 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
         if(VECTOR_SIZE(PlaybackDevices) == 0)
         if(VECTOR_SIZE(PlaybackDevices) == 0)
             ALCpulsePlayback_probeDevices();
             ALCpulsePlayback_probeDevices();
 
 
-#define MATCH_NAME(iter) (al_string_cmp_cstr((iter)->name, name) == 0)
+#define MATCH_NAME(iter) (alstr_cmp_cstr((iter)->name, name) == 0)
         VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
         VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
 #undef MATCH_NAME
 #undef MATCH_NAME
         if(iter == VECTOR_END(PlaybackDevices))
         if(iter == VECTOR_END(PlaybackDevices))
             return ALC_INVALID_VALUE;
             return ALC_INVALID_VALUE;
-        pulse_name = al_string_get_cstr(iter->device_name);
+        pulse_name = alstr_get_cstr(iter->device_name);
         dev_name = iter->name;
         dev_name = iter->name;
     }
     }
 
 
@@ -894,11 +933,11 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
     }
     }
     pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
     pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
 
 
-    al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
-    if(al_string_empty(dev_name))
+    alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
+    if(alstr_empty(dev_name))
     {
     {
         pa_operation *o = pa_context_get_sink_info_by_name(
         pa_operation *o = pa_context_get_sink_info_by_name(
-            self->context, al_string_get_cstr(self->device_name),
+            self->context, alstr_get_cstr(self->device_name),
             ALCpulsePlayback_sinkNameCallback, self
             ALCpulsePlayback_sinkNameCallback, self
         );
         );
         wait_for_operation(o, self->loop);
         wait_for_operation(o, self->loop);
@@ -906,7 +945,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
     else
     else
     {
     {
         ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
         ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
-        al_string_copy(&device->DeviceName, dev_name);
+        alstr_copy(&device->DeviceName, dev_name);
     }
     }
 
 
     pa_threaded_mainloop_unlock(self->loop);
     pa_threaded_mainloop_unlock(self->loop);
@@ -914,16 +953,6 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCpulsePlayback_close(ALCpulsePlayback *self)
-{
-    pulse_close(self->loop, self->context, self->stream);
-    self->loop = NULL;
-    self->context = NULL;
-    self->stream = NULL;
-
-    al_string_clear(&self->device_name);
-}
-
 static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
 static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
@@ -931,7 +960,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
     const char *mapname = NULL;
     const char *mapname = NULL;
     pa_channel_map chanmap;
     pa_channel_map chanmap;
     pa_operation *o;
     pa_operation *o;
-    ALuint len;
 
 
     pa_threaded_mainloop_lock(self->loop);
     pa_threaded_mainloop_lock(self->loop);
 
 
@@ -946,11 +974,11 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
         self->stream = NULL;
         self->stream = NULL;
     }
     }
 
 
-    o = pa_context_get_sink_info_by_name(self->context, al_string_get_cstr(self->device_name),
+    o = pa_context_get_sink_info_by_name(self->context, alstr_get_cstr(self->device_name),
                                          ALCpulsePlayback_sinkInfoCallback, self);
                                          ALCpulsePlayback_sinkInfoCallback, self);
     wait_for_operation(o, self->loop);
     wait_for_operation(o, self->loop);
 
 
-    if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) ||
+    if(GetConfigValueBool(alstr_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) ||
        !(device->Flags&DEVICE_FREQUENCY_REQUEST))
        !(device->Flags&DEVICE_FREQUENCY_REQUEST))
         flags |= PA_STREAM_FIX_RATE;
         flags |= PA_STREAM_FIX_RATE;
     flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
     flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
@@ -984,7 +1012,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
             break;
             break;
     }
     }
     self->spec.rate = device->Frequency;
     self->spec.rate = device->Frequency;
-    self->spec.channels = ChannelsFromDevFmt(device->FmtChans);
+    self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
 
 
     if(pa_sample_spec_valid(&self->spec) == 0)
     if(pa_sample_spec_valid(&self->spec) == 0)
     {
     {
@@ -998,9 +1026,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
         case DevFmtMono:
         case DevFmtMono:
             mapname = "mono";
             mapname = "mono";
             break;
             break;
-        case DevFmtAmbi1:
-        case DevFmtAmbi2:
-        case DevFmtAmbi3:
+        case DevFmtAmbi3D:
             device->FmtChans = DevFmtStereo;
             device->FmtChans = DevFmtStereo;
             /*fall-through*/
             /*fall-through*/
         case DevFmtStereo:
         case DevFmtStereo:
@@ -1036,9 +1062,9 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
     self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2);
     self->attr.tlength = self->attr.minreq * maxu(device->NumUpdates, 2);
     self->attr.maxlength = -1;
     self->attr.maxlength = -1;
 
 
-    self->stream = ALCpulsePlayback_connectStream(al_string_get_cstr(self->device_name),
-                                                  self->loop, self->context, flags,
-                                                  &self->attr, &self->spec, &chanmap);
+    self->stream = ALCpulsePlayback_connectStream(alstr_get_cstr(self->device_name),
+        self->loop, self->context, flags, &self->attr, &self->spec, &chanmap
+    );
     if(!self->stream)
     if(!self->stream)
     {
     {
         pa_threaded_mainloop_unlock(self->loop);
         pa_threaded_mainloop_unlock(self->loop);
@@ -1072,11 +1098,10 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
     pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
     pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
     ALCpulsePlayback_bufferAttrCallback(self->stream, self);
     ALCpulsePlayback_bufferAttrCallback(self->stream, self);
 
 
-    len = self->attr.minreq / pa_frame_size(&self->spec);
-    device->NumUpdates = (ALuint)clampd(
-        (ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5, 2.0, 16.0
+    device->NumUpdates = (ALuint)clampu64(
+        (self->attr.tlength + self->attr.minreq/2) / self->attr.minreq, 2, 16
     );
     );
-    device->UpdateSize = len;
+    device->UpdateSize = self->attr.minreq / pa_frame_size(&self->spec);
 
 
     /* HACK: prebuf should be 0 as that's what we set it to. However on some
     /* HACK: prebuf should be 0 as that's what we set it to. However on some
      * systems it comes back as non-0, so we have to make sure the device will
      * systems it comes back as non-0, so we have to make sure the device will
@@ -1086,7 +1111,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
      */
      */
     if(self->attr.prebuf != 0)
     if(self->attr.prebuf != 0)
     {
     {
-        len = self->attr.prebuf / pa_frame_size(&self->spec);
+        ALuint len = self->attr.prebuf / pa_frame_size(&self->spec);
         if(len <= device->UpdateSize*device->NumUpdates)
         if(len <= device->UpdateSize*device->NumUpdates)
             ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n",
             ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n",
                 len, self->attr.prebuf, device->UpdateSize*device->NumUpdates);
                 len, self->attr.prebuf, device->UpdateSize*device->NumUpdates);
@@ -1104,7 +1129,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
 
 
 static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self)
 static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self)
 {
 {
-    self->killNow = AL_FALSE;
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
     if(althrd_create(&self->thread, ALCpulsePlayback_mixerProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCpulsePlayback_mixerProc, self) != althrd_success)
         return ALC_FALSE;
         return ALC_FALSE;
     return ALC_TRUE;
     return ALC_TRUE;
@@ -1115,10 +1140,9 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
     pa_operation *o;
     pa_operation *o;
     int res;
     int res;
 
 
-    if(!self->stream || self->killNow)
+    if(!self->stream || ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         return;
 
 
-    self->killNow = AL_TRUE;
     /* Signal the main loop in case PulseAudio isn't sending us audio requests
     /* 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
      * (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 mixer is between checking the killNow flag but before waiting for
@@ -1140,13 +1164,16 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
 
 
 static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self)
 static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self)
 {
 {
-    pa_usec_t latency = 0;
     ClockLatency ret;
     ClockLatency ret;
+    pa_usec_t latency;
     int neg, err;
     int neg, err;
 
 
     pa_threaded_mainloop_lock(self->loop);
     pa_threaded_mainloop_lock(self->loop);
     ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice);
     ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice);
-    if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0)
+    err = pa_stream_get_latency(self->stream, &latency, &neg);
+    pa_threaded_mainloop_unlock(self->loop);
+
+    if(UNLIKELY(err != 0))
     {
     {
         /* FIXME: if err = -PA_ERR_NODATA, it means we were called too soon
         /* FIXME: if err = -PA_ERR_NODATA, it means we were called too soon
          * after starting the stream and no timing info has been received from
          * after starting the stream and no timing info has been received from
@@ -1157,9 +1184,9 @@ static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self)
         latency = 0;
         latency = 0;
         neg = 0;
         neg = 0;
     }
     }
-    if(neg) latency = 0;
-    ret.Latency = minu64(latency, U64(0xffffffffffffffff)/1000) * 1000;
-    pa_threaded_mainloop_unlock(self->loop);
+    else if(UNLIKELY(neg))
+        latency = 0;
+    ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000;
 
 
     return ret;
     return ret;
 }
 }
@@ -1211,7 +1238,6 @@ static pa_stream *ALCpulseCapture_connectStream(const char *device_name,
 static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device);
 static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device);
 static void ALCpulseCapture_Destruct(ALCpulseCapture *self);
 static void ALCpulseCapture_Destruct(ALCpulseCapture *self);
 static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name);
 static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name);
-static void ALCpulseCapture_close(ALCpulseCapture *self);
 static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, ALCboolean, reset)
 static DECLARE_FORWARD(ALCpulseCapture, ALCbackend, ALCboolean, reset)
 static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self);
 static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self);
 static void ALCpulseCapture_stop(ALCpulseCapture *self);
 static void ALCpulseCapture_stop(ALCpulseCapture *self);
@@ -1230,11 +1256,19 @@ static void ALCpulseCapture_Construct(ALCpulseCapture *self, ALCdevice *device)
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
     SET_VTABLE2(ALCpulseCapture, ALCbackend, self);
     SET_VTABLE2(ALCpulseCapture, ALCbackend, self);
 
 
+    self->loop = NULL;
     AL_STRING_INIT(self->device_name);
     AL_STRING_INIT(self->device_name);
 }
 }
 
 
 static void ALCpulseCapture_Destruct(ALCpulseCapture *self)
 static void ALCpulseCapture_Destruct(ALCpulseCapture *self)
 {
 {
+    if(self->loop)
+    {
+        pulse_close(self->loop, self->context, self->stream);
+        self->loop = NULL;
+        self->context = NULL;
+        self->stream = NULL;
+    }
     AL_STRING_DEINIT(self->device_name);
     AL_STRING_DEINIT(self->device_name);
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
     ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 }
@@ -1253,7 +1287,7 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
         return;
         return;
     }
     }
 
 
-#define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0)
+#define MATCH_INFO_NAME(iter) (alstr_cmp_cstr((iter)->device_name, info->name) == 0)
     VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME);
     VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME);
     if(iter != VECTOR_END(CaptureDevices)) return;
     if(iter != VECTOR_END(CaptureDevices)) return;
 #undef MATCH_INFO_NAME
 #undef MATCH_INFO_NAME
@@ -1261,27 +1295,27 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.device_name);
     AL_STRING_INIT(entry.device_name);
 
 
-    al_string_copy_cstr(&entry.device_name, info->name);
+    alstr_copy_cstr(&entry.device_name, info->name);
 
 
     count = 0;
     count = 0;
     while(1)
     while(1)
     {
     {
-        al_string_copy_cstr(&entry.name, info->description);
+        alstr_copy_cstr(&entry.name, info->description);
         if(count != 0)
         if(count != 0)
         {
         {
             char str[64];
             char str[64];
             snprintf(str, sizeof(str), " #%d", count+1);
             snprintf(str, sizeof(str), " #%d", count+1);
-            al_string_append_cstr(&entry.name, str);
+            alstr_append_cstr(&entry.name, str);
         }
         }
 
 
-#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+#define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0)
         VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY);
         VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY);
         if(iter == VECTOR_END(CaptureDevices)) break;
         if(iter == VECTOR_END(CaptureDevices)) break;
 #undef MATCH_ENTRY
 #undef MATCH_ENTRY
         count++;
         count++;
     }
     }
 
 
-    TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name));
+    TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.device_name));
 
 
     VECTOR_PUSH_BACK(CaptureDevices, entry);
     VECTOR_PUSH_BACK(CaptureDevices, entry);
 }
 }
@@ -1346,7 +1380,7 @@ static void ALCpulseCapture_contextStateCallback(pa_context *context, void *pdat
     if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
     if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
     {
     {
         ERR("Received context failure!\n");
         ERR("Received context failure!\n");
-        aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
+        aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture state failure");
     }
     }
     pa_threaded_mainloop_signal(self->loop, 0);
     pa_threaded_mainloop_signal(self->loop, 0);
 }
 }
@@ -1357,7 +1391,7 @@ static void ALCpulseCapture_streamStateCallback(pa_stream *stream, void *pdata)
     if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
     if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
     {
     {
         ERR("Received stream failure!\n");
         ERR("Received stream failure!\n");
-        aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice);
+        aluHandleDisconnect(STATIC_CAST(ALCbackend,self)->mDevice, "Capture stream failure");
     }
     }
     pa_threaded_mainloop_signal(self->loop, 0);
     pa_threaded_mainloop_signal(self->loop, 0);
 }
 }
@@ -1374,7 +1408,7 @@ static void ALCpulseCapture_sourceNameCallback(pa_context *UNUSED(context), cons
         return;
         return;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, info->description);
+    alstr_copy_cstr(&device->DeviceName, info->description);
 }
 }
 
 
 
 
@@ -1382,9 +1416,9 @@ static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata)
 {
 {
     ALCpulseCapture *self = pdata;
     ALCpulseCapture *self = pdata;
 
 
-    al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(stream));
+    alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(stream));
 
 
-    TRACE("Stream moved to %s\n", al_string_get_cstr(self->device_name));
+    TRACE("Stream moved to %s\n", alstr_get_cstr(self->device_name));
 }
 }
 
 
 
 
@@ -1434,6 +1468,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     const char *pulse_name = NULL;
     const char *pulse_name = NULL;
     pa_stream_flags_t flags = 0;
     pa_stream_flags_t flags = 0;
+    const char *mapname = NULL;
     pa_channel_map chanmap;
     pa_channel_map chanmap;
     ALuint samples;
     ALuint samples;
 
 
@@ -1444,13 +1479,13 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
         if(VECTOR_SIZE(CaptureDevices) == 0)
         if(VECTOR_SIZE(CaptureDevices) == 0)
             ALCpulseCapture_probeDevices();
             ALCpulseCapture_probeDevices();
 
 
-#define MATCH_NAME(iter) (al_string_cmp_cstr((iter)->name, name) == 0)
+#define MATCH_NAME(iter) (alstr_cmp_cstr((iter)->name, name) == 0)
         VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
         VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
 #undef MATCH_NAME
 #undef MATCH_NAME
         if(iter == VECTOR_END(CaptureDevices))
         if(iter == VECTOR_END(CaptureDevices))
             return ALC_INVALID_VALUE;
             return ALC_INVALID_VALUE;
-        pulse_name = al_string_get_cstr(iter->device_name);
-        al_string_copy(&device->DeviceName, iter->name);
+        pulse_name = alstr_get_cstr(iter->device_name);
+        alstr_copy(&device->DeviceName, iter->name);
     }
     }
 
 
     if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self))
     if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self))
@@ -1458,9 +1493,6 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
 
 
     pa_threaded_mainloop_lock(self->loop);
     pa_threaded_mainloop_lock(self->loop);
 
 
-    self->spec.rate = device->Frequency;
-    self->spec.channels = ChannelsFromDevFmt(device->FmtChans);
-
     switch(device->FmtType)
     switch(device->FmtType)
     {
     {
         case DevFmtUByte:
         case DevFmtUByte:
@@ -1483,6 +1515,44 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
             goto fail;
             goto fail;
     }
     }
 
 
+    switch(device->FmtChans)
+    {
+        case DevFmtMono:
+            mapname = "mono";
+            break;
+        case DevFmtStereo:
+            mapname = "front-left,front-right";
+            break;
+        case DevFmtQuad:
+            mapname = "front-left,front-right,rear-left,rear-right";
+            break;
+        case DevFmtX51:
+            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;
+        case DevFmtX71:
+            mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right";
+            break;
+        case DevFmtAmbi3D:
+            ERR("%s capture samples not supported\n", DevFmtChannelsString(device->FmtChans));
+            pa_threaded_mainloop_unlock(self->loop);
+            goto fail;
+    }
+    if(!pa_channel_map_parse(&chanmap, mapname))
+    {
+        ERR("Failed to build channel map for %s\n", DevFmtChannelsString(device->FmtChans));
+        pa_threaded_mainloop_unlock(self->loop);
+        return ALC_FALSE;
+    }
+
+    self->spec.rate = device->Frequency;
+    self->spec.channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
+
     if(pa_sample_spec_valid(&self->spec) == 0)
     if(pa_sample_spec_valid(&self->spec) == 0)
     {
     {
         ERR("Invalid sample format\n");
         ERR("Invalid sample format\n");
@@ -1512,9 +1582,9 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
         flags |= PA_STREAM_DONT_MOVE;
         flags |= PA_STREAM_DONT_MOVE;
 
 
     TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
     TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
-    self->stream = ALCpulseCapture_connectStream(pulse_name, self->loop, self->context,
-                                                 flags, &self->attr, &self->spec,
-                                                 &chanmap);
+    self->stream = ALCpulseCapture_connectStream(pulse_name,
+        self->loop, self->context, flags, &self->attr, &self->spec, &chanmap
+    );
     if(!self->stream)
     if(!self->stream)
     {
     {
         pa_threaded_mainloop_unlock(self->loop);
         pa_threaded_mainloop_unlock(self->loop);
@@ -1523,11 +1593,11 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
     pa_stream_set_moved_callback(self->stream, ALCpulseCapture_streamMovedCallback, self);
     pa_stream_set_moved_callback(self->stream, ALCpulseCapture_streamMovedCallback, self);
     pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self);
     pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self);
 
 
-    al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
-    if(al_string_empty(device->DeviceName))
+    alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
+    if(alstr_empty(device->DeviceName))
     {
     {
         pa_operation *o = pa_context_get_source_info_by_name(
         pa_operation *o = pa_context_get_source_info_by_name(
-            self->context, al_string_get_cstr(self->device_name),
+            self->context, alstr_get_cstr(self->device_name),
             ALCpulseCapture_sourceNameCallback, self
             ALCpulseCapture_sourceNameCallback, self
         );
         );
         wait_for_operation(o, self->loop);
         wait_for_operation(o, self->loop);
@@ -1545,30 +1615,23 @@ fail:
     return ALC_INVALID_VALUE;
     return ALC_INVALID_VALUE;
 }
 }
 
 
-static void ALCpulseCapture_close(ALCpulseCapture *self)
-{
-    pulse_close(self->loop, self->context, self->stream);
-    self->loop = NULL;
-    self->context = NULL;
-    self->stream = NULL;
-
-    al_string_clear(&self->device_name);
-}
-
 static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self)
 static ALCboolean ALCpulseCapture_start(ALCpulseCapture *self)
 {
 {
     pa_operation *o;
     pa_operation *o;
+    pa_threaded_mainloop_lock(self->loop);
     o = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop);
     o = pa_stream_cork(self->stream, 0, stream_success_callback, self->loop);
     wait_for_operation(o, self->loop);
     wait_for_operation(o, self->loop);
-
+    pa_threaded_mainloop_unlock(self->loop);
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
 static void ALCpulseCapture_stop(ALCpulseCapture *self)
 static void ALCpulseCapture_stop(ALCpulseCapture *self)
 {
 {
     pa_operation *o;
     pa_operation *o;
+    pa_threaded_mainloop_lock(self->loop);
     o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop);
     o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop);
     wait_for_operation(o, self->loop);
     wait_for_operation(o, self->loop);
+    pa_threaded_mainloop_unlock(self->loop);
 }
 }
 
 
 static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples)
 static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples)
@@ -1579,6 +1642,7 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu
     /* Capture is done in fragment-sized chunks, so we loop until we get all
     /* Capture is done in fragment-sized chunks, so we loop until we get all
      * that's available */
      * that's available */
     self->last_readable -= todo;
     self->last_readable -= todo;
+    pa_threaded_mainloop_lock(self->loop);
     while(todo > 0)
     while(todo > 0)
     {
     {
         size_t rem = todo;
         size_t rem = todo;
@@ -1590,14 +1654,15 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu
             state = pa_stream_get_state(self->stream);
             state = pa_stream_get_state(self->stream);
             if(!PA_STREAM_IS_GOOD(state))
             if(!PA_STREAM_IS_GOOD(state))
             {
             {
-                aluHandleDisconnect(device);
+                aluHandleDisconnect(device, "Bad capture state: %u", state);
                 break;
                 break;
             }
             }
             if(pa_stream_peek(self->stream, &self->cap_store, &self->cap_len) < 0)
             if(pa_stream_peek(self->stream, &self->cap_store, &self->cap_len) < 0)
             {
             {
                 ERR("pa_stream_peek() failed: %s\n",
                 ERR("pa_stream_peek() failed: %s\n",
                     pa_strerror(pa_context_errno(self->context)));
                     pa_strerror(pa_context_errno(self->context)));
-                aluHandleDisconnect(device);
+                aluHandleDisconnect(device, "Failed retrieving capture samples: %s",
+                                    pa_strerror(pa_context_errno(self->context)));
                 break;
                 break;
             }
             }
             self->cap_remain = self->cap_len;
             self->cap_remain = self->cap_len;
@@ -1618,6 +1683,7 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu
             self->cap_len = 0;
             self->cap_len = 0;
         }
         }
     }
     }
+    pa_threaded_mainloop_unlock(self->loop);
     if(todo > 0)
     if(todo > 0)
         memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo);
         memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo);
 
 
@@ -1629,16 +1695,19 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self)
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     size_t readable = self->cap_remain;
     size_t readable = self->cap_remain;
 
 
-    if(device->Connected)
+    if(ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
     {
     {
-        ssize_t got = pa_stream_readable_size(self->stream);
+        ssize_t got;
+        pa_threaded_mainloop_lock(self->loop);
+        got = pa_stream_readable_size(self->stream);
         if(got < 0)
         if(got < 0)
         {
         {
             ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got));
             ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got));
-            aluHandleDisconnect(device);
+            aluHandleDisconnect(device, "Failed getting readable size: %s", pa_strerror(got));
         }
         }
         else if((size_t)got > self->cap_len)
         else if((size_t)got > self->cap_len)
             readable += got - self->cap_len;
             readable += got - self->cap_len;
+        pa_threaded_mainloop_unlock(self->loop);
     }
     }
 
 
     if(self->last_readable < readable)
     if(self->last_readable < readable)
@@ -1649,21 +1718,24 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self)
 
 
 static ClockLatency ALCpulseCapture_getClockLatency(ALCpulseCapture *self)
 static ClockLatency ALCpulseCapture_getClockLatency(ALCpulseCapture *self)
 {
 {
-    pa_usec_t latency = 0;
     ClockLatency ret;
     ClockLatency ret;
+    pa_usec_t latency;
     int neg, err;
     int neg, err;
 
 
     pa_threaded_mainloop_lock(self->loop);
     pa_threaded_mainloop_lock(self->loop);
     ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice);
     ret.ClockTime = GetDeviceClockTime(STATIC_CAST(ALCbackend,self)->mDevice);
-    if((err=pa_stream_get_latency(self->stream, &latency, &neg)) != 0)
+    err = pa_stream_get_latency(self->stream, &latency, &neg);
+    pa_threaded_mainloop_unlock(self->loop);
+
+    if(UNLIKELY(err != 0))
     {
     {
         ERR("Failed to get stream latency: 0x%x\n", err);
         ERR("Failed to get stream latency: 0x%x\n", err);
         latency = 0;
         latency = 0;
         neg = 0;
         neg = 0;
     }
     }
-    if(neg) latency = 0;
-    ret.Latency = minu64(latency, U64(0xffffffffffffffff)/1000) * 1000;
-    pa_threaded_mainloop_unlock(self->loop);
+    else if(UNLIKELY(neg))
+        latency = 0;
+    ret.Latency = (ALint64)minu64(latency, U64(0x7fffffffffffffff)/1000) * 1000;
 
 
     return ret;
     return ret;
 }
 }
@@ -1769,14 +1841,14 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e
     {
     {
         case ALL_DEVICE_PROBE:
         case ALL_DEVICE_PROBE:
             ALCpulsePlayback_probeDevices();
             ALCpulsePlayback_probeDevices();
-#define APPEND_ALL_DEVICES_LIST(e)  AppendAllDevicesList(al_string_get_cstr((e)->name))
+#define APPEND_ALL_DEVICES_LIST(e)  AppendAllDevicesList(alstr_get_cstr((e)->name))
             VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_ALL_DEVICES_LIST);
             VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_ALL_DEVICES_LIST);
 #undef APPEND_ALL_DEVICES_LIST
 #undef APPEND_ALL_DEVICES_LIST
             break;
             break;
 
 
         case CAPTURE_DEVICE_PROBE:
         case CAPTURE_DEVICE_PROBE:
             ALCpulseCapture_probeDevices();
             ALCpulseCapture_probeDevices();
-#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(al_string_get_cstr((e)->name))
+#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(alstr_get_cstr((e)->name))
             VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_CAPTURE_DEVICE_LIST);
             VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_CAPTURE_DEVICE_LIST);
 #undef APPEND_CAPTURE_DEVICE_LIST
 #undef APPEND_CAPTURE_DEVICE_LIST
             break;
             break;

+ 269 - 112
Engine/lib/openal-soft/Alc/backends/qsa.c

@@ -33,6 +33,8 @@
 #include "alu.h"
 #include "alu.h"
 #include "threads.h"
 #include "threads.h"
 
 
+#include "backends/base.h"
+
 
 
 typedef struct {
 typedef struct {
     snd_pcm_t* pcmHandle;
     snd_pcm_t* pcmHandle;
@@ -44,7 +46,7 @@ typedef struct {
     ALvoid* buffer;
     ALvoid* buffer;
     ALsizei size;
     ALsizei size;
 
 
-    volatile int killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } qsa_data;
 } qsa_data;
 
 
@@ -157,17 +159,39 @@ static void deviceList(int type, vector_DevMap *devmap)
 }
 }
 
 
 
 
-FORCE_ALIGN static int qsa_proc_playback(void* ptr)
+/* Wrappers to use an old-style backend with the new interface. */
+typedef struct PlaybackWrapper {
+    DERIVE_FROM_TYPE(ALCbackend);
+    qsa_data *ExtraData;
+} PlaybackWrapper;
+
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device);
+static void PlaybackWrapper_Destruct(PlaybackWrapper *self);
+static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name);
+static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self);
+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 DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
+DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper);
+
+
+FORCE_ALIGN static int qsa_proc_playback(void *ptr)
 {
 {
-    ALCdevice* device=(ALCdevice*)ptr;
-    qsa_data* data=(qsa_data*)device->ExtraData;
-    char* write_ptr;
-    int avail;
+    PlaybackWrapper *self = ptr;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+    qsa_data *data = self->ExtraData;
     snd_pcm_channel_status_t status;
     snd_pcm_channel_status_t status;
     struct sched_param param;
     struct sched_param param;
-    fd_set wfds;
-    int selectret;
     struct timeval timeout;
     struct timeval timeout;
+    char* write_ptr;
+    fd_set wfds;
+    ALint len;
+    int sret;
 
 
     SetRTPriority();
     SetRTPriority();
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
@@ -177,72 +201,69 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr)
     param.sched_priority=param.sched_curpriority+1;
     param.sched_priority=param.sched_curpriority+1;
     SchedSet(0, 0, SCHED_NOCHANGE, &param);
     SchedSet(0, 0, SCHED_NOCHANGE, &param);
 
 
-    ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    const ALint frame_size = FrameSizeFromDevFmt(
+        device->FmtChans, device->FmtType, device->AmbiOrder
+    );
 
 
-    while (!data->killNow)
+    V0(device->Backend,lock)();
+    while(!ATOMIC_LOAD(&data->killNow, almemory_order_acquire))
     {
     {
-        ALint len=data->size;
-        write_ptr=data->buffer;
-
-        avail=len/frame_size;
-        aluMixData(device, write_ptr, avail);
+        FD_ZERO(&wfds);
+        FD_SET(data->audio_fd, &wfds);
+        timeout.tv_sec=2;
+        timeout.tv_usec=0;
 
 
-        while (len>0 && !data->killNow)
+        /* Select also works like time slice to OS */
+        V0(device->Backend,unlock)();
+        sret = select(data->audio_fd+1, NULL, &wfds, NULL, &timeout);
+        V0(device->Backend,lock)();
+        if(sret == -1)
         {
         {
-            FD_ZERO(&wfds);
-            FD_SET(data->audio_fd, &wfds);
-            timeout.tv_sec=2;
-            timeout.tv_usec=0;
-
-            /* Select also works like time slice to OS */
-            selectret=select(data->audio_fd+1, NULL, &wfds, NULL, &timeout);
-            switch (selectret)
-            {
-                case -1:
-                     aluHandleDisconnect(device);
-                     return 1;
-                case 0:
-                     break;
-                default:
-                     if (FD_ISSET(data->audio_fd, &wfds))
-                     {
-                         break;
-                     }
-                     break;
-            }
-
-            int wrote=snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);
+            ERR("select error: %s\n", strerror(errno));
+            aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno));
+            break;
+        }
+        if(sret == 0)
+        {
+            ERR("select timeout\n");
+            continue;
+        }
 
 
-            if (wrote<=0)
+        len = data->size;
+        write_ptr = data->buffer;
+        aluMixData(device, write_ptr, len/frame_size);
+        while(len>0 && !ATOMIC_LOAD(&data->killNow, almemory_order_acquire))
+        {
+            int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);
+            if(wrote <= 0)
             {
             {
-                if ((errno==EAGAIN) || (errno==EWOULDBLOCK))
-                {
+                if(errno==EAGAIN || errno==EWOULDBLOCK)
                     continue;
                     continue;
-                }
 
 
-                memset(&status, 0, sizeof (status));
-                status.channel=SND_PCM_CHANNEL_PLAYBACK;
+                memset(&status, 0, sizeof(status));
+                status.channel = SND_PCM_CHANNEL_PLAYBACK;
 
 
                 snd_pcm_plugin_status(data->pcmHandle, &status);
                 snd_pcm_plugin_status(data->pcmHandle, &status);
 
 
                 /* we need to reinitialize the sound channel if we've underrun the buffer */
                 /* we need to reinitialize the sound channel if we've underrun the buffer */
-                if ((status.status==SND_PCM_STATUS_UNDERRUN) ||
-                    (status.status==SND_PCM_STATUS_READY))
+                if(status.status == SND_PCM_STATUS_UNDERRUN ||
+                   status.status == SND_PCM_STATUS_READY)
                 {
                 {
-                    if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0)
+                    if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0)
                     {
                     {
-                        aluHandleDisconnect(device);
+                        aluHandleDisconnect(device, "Playback recovery failed");
                         break;
                         break;
                     }
                     }
                 }
                 }
             }
             }
             else
             else
             {
             {
-                write_ptr+=wrote;
-                len-=wrote;
+                write_ptr += wrote;
+                len -= wrote;
             }
             }
         }
         }
     }
     }
+    V0(device->Backend,unlock)();
 
 
     return 0;
     return 0;
 }
 }
@@ -251,8 +272,9 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr)
 /* Playback */
 /* Playback */
 /************/
 /************/
 
 
-static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
+static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName)
 {
 {
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     qsa_data *data;
     qsa_data *data;
     int card, dev;
     int card, dev;
     int status;
     int status;
@@ -260,6 +282,7 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
     data = (qsa_data*)calloc(1, sizeof(qsa_data));
     data = (qsa_data*)calloc(1, sizeof(qsa_data));
     if(data == NULL)
     if(data == NULL)
         return ALC_OUT_OF_MEMORY;
         return ALC_OUT_OF_MEMORY;
+    ATOMIC_INIT(&data->killNow, AL_TRUE);
 
 
     if(!deviceName)
     if(!deviceName)
         deviceName = qsaDevice;
         deviceName = qsaDevice;
@@ -299,15 +322,15 @@ static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
         return ALC_INVALID_DEVICE;
         return ALC_INVALID_DEVICE;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
-    device->ExtraData = data;
+    alstr_copy_cstr(&device->DeviceName, deviceName);
+    self->ExtraData = data;
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void qsa_close_playback(ALCdevice* device)
+static void qsa_close_playback(PlaybackWrapper *self)
 {
 {
-    qsa_data* data=(qsa_data*)device->ExtraData;
+    qsa_data *data = self->ExtraData;
 
 
     if (data->buffer!=NULL)
     if (data->buffer!=NULL)
     {
     {
@@ -318,12 +341,13 @@ static void qsa_close_playback(ALCdevice* device)
     snd_pcm_close(data->pcmHandle);
     snd_pcm_close(data->pcmHandle);
     free(data);
     free(data);
 
 
-    device->ExtraData=NULL;
+    self->ExtraData = NULL;
 }
 }
 
 
-static ALCboolean qsa_reset_playback(ALCdevice* device)
+static ALCboolean qsa_reset_playback(PlaybackWrapper *self)
 {
 {
-    qsa_data* data=(qsa_data*)device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+    qsa_data *data = self->ExtraData;
     int32_t format=-1;
     int32_t format=-1;
 
 
     switch(device->FmtType)
     switch(device->FmtType)
@@ -364,14 +388,14 @@ static ALCboolean qsa_reset_playback(ALCdevice* device)
     data->cparams.start_mode=SND_PCM_START_FULL;
     data->cparams.start_mode=SND_PCM_START_FULL;
     data->cparams.stop_mode=SND_PCM_STOP_STOP;
     data->cparams.stop_mode=SND_PCM_STOP_STOP;
 
 
-    data->cparams.buf.block.frag_size=device->UpdateSize*
-        ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType);
+    data->cparams.buf.block.frag_size=device->UpdateSize *
+        FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
     data->cparams.buf.block.frags_max=device->NumUpdates;
     data->cparams.buf.block.frags_max=device->NumUpdates;
     data->cparams.buf.block.frags_min=device->NumUpdates;
     data->cparams.buf.block.frags_min=device->NumUpdates;
 
 
     data->cparams.format.interleave=1;
     data->cparams.format.interleave=1;
     data->cparams.format.rate=device->Frequency;
     data->cparams.format.rate=device->Frequency;
-    data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
+    data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
     data->cparams.format.format=format;
     data->cparams.format.format=format;
 
 
     if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
     if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
@@ -555,7 +579,7 @@ static ALCboolean qsa_reset_playback(ALCdevice* device)
     SetDefaultChannelOrder(device);
     SetDefaultChannelOrder(device);
 
 
     device->UpdateSize=data->csetup.buf.block.frag_size/
     device->UpdateSize=data->csetup.buf.block.frag_size/
-        (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType));
+        FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
     device->NumUpdates=data->csetup.buf.block.frags;
     device->NumUpdates=data->csetup.buf.block.frags;
 
 
     data->size=data->csetup.buf.block.frag_size;
     data->size=data->csetup.buf.block.frag_size;
@@ -568,35 +592,93 @@ static ALCboolean qsa_reset_playback(ALCdevice* device)
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-static ALCboolean qsa_start_playback(ALCdevice* device)
+static ALCboolean qsa_start_playback(PlaybackWrapper *self)
 {
 {
-    qsa_data *data = (qsa_data*)device->ExtraData;
+    qsa_data *data = self->ExtraData;
 
 
-    data->killNow = 0;
-    if(althrd_create(&data->thread, qsa_proc_playback, device) != althrd_success)
+    ATOMIC_STORE(&data->killNow, AL_FALSE, almemory_order_release);
+    if(althrd_create(&data->thread, qsa_proc_playback, self) != althrd_success)
         return ALC_FALSE;
         return ALC_FALSE;
 
 
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-static void qsa_stop_playback(ALCdevice* device)
+static void qsa_stop_playback(PlaybackWrapper *self)
 {
 {
-    qsa_data *data = (qsa_data*)device->ExtraData;
+    qsa_data *data = self->ExtraData;
     int res;
     int res;
 
 
-    if(data->killNow)
+    if(ATOMIC_EXCHANGE(&data->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         return;
-
-    data->killNow = 1;
     althrd_join(data->thread, &res);
     althrd_join(data->thread, &res);
 }
 }
 
 
+
+static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(PlaybackWrapper, ALCbackend, self);
+
+    self->ExtraData = NULL;
+}
+
+static void PlaybackWrapper_Destruct(PlaybackWrapper *self)
+{
+    if(self->ExtraData)
+        qsa_close_playback(self);
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name)
+{
+    return qsa_open_playback(self, name);
+}
+
+static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self)
+{
+    return qsa_reset_playback(self);
+}
+
+static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self)
+{
+    return qsa_start_playback(self);
+}
+
+static void PlaybackWrapper_stop(PlaybackWrapper *self)
+{
+    qsa_stop_playback(self);
+}
+
+
+
 /***********/
 /***********/
 /* Capture */
 /* Capture */
 /***********/
 /***********/
 
 
-static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
+typedef struct CaptureWrapper {
+    DERIVE_FROM_TYPE(ALCbackend);
+    qsa_data *ExtraData;
+} CaptureWrapper;
+
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device);
+static void CaptureWrapper_Destruct(CaptureWrapper *self);
+static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset)
+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 DECLARE_FORWARD(CaptureWrapper, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
+DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
+
+
+static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName)
 {
 {
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     qsa_data *data;
     qsa_data *data;
     int card, dev;
     int card, dev;
     int format=-1;
     int format=-1;
@@ -646,8 +728,8 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
         return ALC_INVALID_DEVICE;
         return ALC_INVALID_DEVICE;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
-    device->ExtraData = data;
+    alstr_copy_cstr(&device->DeviceName, deviceName);
+    self->ExtraData = data;
 
 
     switch (device->FmtType)
     switch (device->FmtType)
     {
     {
@@ -687,20 +769,19 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
     data->cparams.stop_mode=SND_PCM_STOP_STOP;
     data->cparams.stop_mode=SND_PCM_STOP_STOP;
 
 
     data->cparams.buf.block.frag_size=device->UpdateSize*
     data->cparams.buf.block.frag_size=device->UpdateSize*
-        ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType);
+        FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
     data->cparams.buf.block.frags_max=device->NumUpdates;
     data->cparams.buf.block.frags_max=device->NumUpdates;
     data->cparams.buf.block.frags_min=device->NumUpdates;
     data->cparams.buf.block.frags_min=device->NumUpdates;
 
 
     data->cparams.format.interleave=1;
     data->cparams.format.interleave=1;
     data->cparams.format.rate=device->Frequency;
     data->cparams.format.rate=device->Frequency;
-    data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
+    data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
     data->cparams.format.format=format;
     data->cparams.format.format=format;
 
 
     if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0)
     if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0)
     {
     {
         snd_pcm_close(data->pcmHandle);
         snd_pcm_close(data->pcmHandle);
         free(data);
         free(data);
-        device->ExtraData=NULL;
 
 
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
@@ -708,20 +789,20 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void qsa_close_capture(ALCdevice* device)
+static void qsa_close_capture(CaptureWrapper *self)
 {
 {
-    qsa_data* data=(qsa_data*)device->ExtraData;
+    qsa_data *data = self->ExtraData;
 
 
     if (data->pcmHandle!=NULL)
     if (data->pcmHandle!=NULL)
         snd_pcm_close(data->pcmHandle);
         snd_pcm_close(data->pcmHandle);
 
 
     free(data);
     free(data);
-    device->ExtraData=NULL;
+    self->ExtraData = NULL;
 }
 }
 
 
-static void qsa_start_capture(ALCdevice* device)
+static void qsa_start_capture(CaptureWrapper *self)
 {
 {
-    qsa_data* data=(qsa_data*)device->ExtraData;
+    qsa_data *data = self->ExtraData;
     int rstatus;
     int rstatus;
 
 
     if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
     if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
@@ -741,18 +822,18 @@ static void qsa_start_capture(ALCdevice* device)
     snd_pcm_capture_go(data->pcmHandle);
     snd_pcm_capture_go(data->pcmHandle);
 }
 }
 
 
-static void qsa_stop_capture(ALCdevice* device)
+static void qsa_stop_capture(CaptureWrapper *self)
 {
 {
-    qsa_data* data=(qsa_data*)device->ExtraData;
-
+    qsa_data *data = self->ExtraData;
     snd_pcm_capture_flush(data->pcmHandle);
     snd_pcm_capture_flush(data->pcmHandle);
 }
 }
 
 
-static ALCuint qsa_available_samples(ALCdevice* device)
+static ALCuint qsa_available_samples(CaptureWrapper *self)
 {
 {
-    qsa_data* data=(qsa_data*)device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+    qsa_data *data = self->ExtraData;
     snd_pcm_channel_status_t status;
     snd_pcm_channel_status_t status;
-    ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    ALint frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
     ALint free_size;
     ALint free_size;
     int rstatus;
     int rstatus;
 
 
@@ -765,7 +846,7 @@ static ALCuint qsa_available_samples(ALCdevice* device)
         if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
         if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
         {
         {
             ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
             ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
-            aluHandleDisconnect(device);
+            aluHandleDisconnect(device, "Failed capture recovery: %s", snd_strerror(rstatus));
             return 0;
             return 0;
         }
         }
 
 
@@ -779,16 +860,17 @@ static ALCuint qsa_available_samples(ALCdevice* device)
     return free_size/frame_size;
     return free_size/frame_size;
 }
 }
 
 
-static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples)
 {
 {
-    qsa_data* data=(qsa_data*)device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+    qsa_data *data = self->ExtraData;
     char* read_ptr;
     char* read_ptr;
     snd_pcm_channel_status_t status;
     snd_pcm_channel_status_t status;
     fd_set rfds;
     fd_set rfds;
     int selectret;
     int selectret;
     struct timeval timeout;
     struct timeval timeout;
     int bytes_read;
     int bytes_read;
-    ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
     ALint len=samples*frame_size;
     ALint len=samples*frame_size;
     int rstatus;
     int rstatus;
 
 
@@ -807,7 +889,7 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
         switch (selectret)
         switch (selectret)
         {
         {
             case -1:
             case -1:
-                 aluHandleDisconnect(device);
+                 aluHandleDisconnect(device, "Failed to check capture samples");
                  return ALC_INVALID_DEVICE;
                  return ALC_INVALID_DEVICE;
             case 0:
             case 0:
                  break;
                  break;
@@ -838,7 +920,8 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
                 if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
                 if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
                 {
                 {
                     ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
                     ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
-                    aluHandleDisconnect(device);
+                    aluHandleDisconnect(device, "Failed capture recovery: %s",
+                                        snd_strerror(rstatus));
                     return ALC_INVALID_DEVICE;
                     return ALC_INVALID_DEVICE;
                 }
                 }
                 snd_pcm_capture_go(data->pcmHandle);
                 snd_pcm_capture_go(data->pcmHandle);
@@ -854,27 +937,68 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static const BackendFuncs qsa_funcs= {
-    qsa_open_playback,
-    qsa_close_playback,
-    qsa_reset_playback,
-    qsa_start_playback,
-    qsa_stop_playback,
-    qsa_open_capture,
-    qsa_close_capture,
-    qsa_start_capture,
-    qsa_stop_capture,
-    qsa_capture_samples,
-    qsa_available_samples
-};
 
 
-ALCboolean alc_qsa_init(BackendFuncs* func_list)
+static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(CaptureWrapper, ALCbackend, self);
+
+    self->ExtraData = NULL;
+}
+
+static void CaptureWrapper_Destruct(CaptureWrapper *self)
+{
+    if(self->ExtraData)
+        qsa_close_capture(self);
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name)
 {
 {
-    *func_list = qsa_funcs;
+    return qsa_open_capture(self, name);
+}
+
+static ALCboolean CaptureWrapper_start(CaptureWrapper *self)
+{
+    qsa_start_capture(self);
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-void alc_qsa_deinit(void)
+static void CaptureWrapper_stop(CaptureWrapper *self)
+{
+    qsa_stop_capture(self);
+}
+
+static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples)
+{
+    return qsa_capture_samples(self, buffer, samples);
+}
+
+static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
+{
+    return qsa_available_samples(self);
+}
+
+
+typedef struct ALCqsaBackendFactory {
+    DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCqsaBackendFactory;
+#define ALCQSABACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCqsaBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self));
+static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self));
+static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type);
+static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type);
+static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCqsaBackendFactory);
+
+static ALCboolean ALCqsaBackendFactory_init(ALCqsaBackendFactory* UNUSED(self))
+{
+    return ALC_TRUE;
+}
+
+static void ALCqsaBackendFactory_deinit(ALCqsaBackendFactory* UNUSED(self))
 {
 {
 #define FREE_NAME(iter) free((iter)->name)
 #define FREE_NAME(iter) free((iter)->name)
     VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
     VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
@@ -885,7 +1009,14 @@ void alc_qsa_deinit(void)
 #undef FREE_NAME
 #undef FREE_NAME
 }
 }
 
 
-void alc_qsa_probe(enum DevProbe type)
+static ALCboolean ALCqsaBackendFactory_querySupport(ALCqsaBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+        return ALC_TRUE;
+    return ALC_FALSE;
+}
+
+static void ALCqsaBackendFactory_probe(ALCqsaBackendFactory* UNUSED(self), enum DevProbe type)
 {
 {
     switch (type)
     switch (type)
     {
     {
@@ -914,3 +1045,29 @@ void alc_qsa_probe(enum DevProbe type)
             break;
             break;
     }
     }
 }
 }
+
+static ALCbackend* ALCqsaBackendFactory_createBackend(ALCqsaBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+    {
+        PlaybackWrapper *backend;
+        NEW_OBJ(backend, PlaybackWrapper)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+    if(type == ALCbackend_Capture)
+    {
+        CaptureWrapper *backend;
+        NEW_OBJ(backend, CaptureWrapper)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+
+    return NULL;
+}
+
+ALCbackendFactory *ALCqsaBackendFactory_getFactory(void)
+{
+    static ALCqsaBackendFactory factory = ALCQSABACKENDFACTORY_INITIALIZER;
+    return STATIC_CAST(ALCbackendFactory, &factory);
+}

+ 287 - 0
Engine/lib/openal-soft/Alc/backends/sdl2.c

@@ -0,0 +1,287 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2018 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <SDL2/SDL.h>
+
+#include "alMain.h"
+#include "alu.h"
+#include "threads.h"
+#include "compat.h"
+
+#include "backends/base.h"
+
+
+#ifdef _WIN32
+#define DEVNAME_PREFIX "OpenAL Soft on "
+#else
+#define DEVNAME_PREFIX ""
+#endif
+
+typedef struct ALCsdl2Backend {
+    DERIVE_FROM_TYPE(ALCbackend);
+
+    SDL_AudioDeviceID deviceID;
+    ALsizei frameSize;
+
+    ALuint Frequency;
+    enum DevFmtChannels FmtChans;
+    enum DevFmtType     FmtType;
+    ALuint UpdateSize;
+} ALCsdl2Backend;
+
+static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device);
+static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self);
+static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name);
+static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self);
+static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self);
+static void ALCsdl2Backend_stop(ALCsdl2Backend *self);
+static DECLARE_FORWARD2(ALCsdl2Backend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCsdl2Backend, ALCbackend, ClockLatency, getClockLatency)
+static void ALCsdl2Backend_lock(ALCsdl2Backend *self);
+static void ALCsdl2Backend_unlock(ALCsdl2Backend *self);
+DECLARE_DEFAULT_ALLOCATORS(ALCsdl2Backend)
+
+DEFINE_ALCBACKEND_VTABLE(ALCsdl2Backend);
+
+static const ALCchar defaultDeviceName[] = DEVNAME_PREFIX "Default Device";
+
+static void ALCsdl2Backend_Construct(ALCsdl2Backend *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCsdl2Backend, ALCbackend, self);
+
+    self->deviceID = 0;
+    self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
+    self->Frequency = device->Frequency;
+    self->FmtChans = device->FmtChans;
+    self->FmtType = device->FmtType;
+    self->UpdateSize = device->UpdateSize;
+}
+
+static void ALCsdl2Backend_Destruct(ALCsdl2Backend *self)
+{
+    if(self->deviceID)
+        SDL_CloseAudioDevice(self->deviceID);
+    self->deviceID = 0;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+static void ALCsdl2Backend_audioCallback(void *ptr, Uint8 *stream, int len)
+{
+    ALCsdl2Backend *self = (ALCsdl2Backend*)ptr;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+
+    assert((len % self->frameSize) == 0);
+    aluMixData(device, stream, len / self->frameSize);
+}
+
+static ALCenum ALCsdl2Backend_open(ALCsdl2Backend *self, const ALCchar *name)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    SDL_AudioSpec want, have;
+
+    SDL_zero(want);
+    SDL_zero(have);
+
+    want.freq = device->Frequency;
+    switch(device->FmtType)
+    {
+        case DevFmtUByte: want.format = AUDIO_U8; break;
+        case DevFmtByte: want.format = AUDIO_S8; break;
+        case DevFmtUShort: want.format = AUDIO_U16SYS; break;
+        case DevFmtShort: want.format = AUDIO_S16SYS; break;
+        case DevFmtUInt: /* fall-through */
+        case DevFmtInt: want.format = AUDIO_S32SYS; break;
+        case DevFmtFloat: want.format = AUDIO_F32; break;
+    }
+    want.channels = (device->FmtChans == DevFmtMono) ? 1 : 2;
+    want.samples = device->UpdateSize;
+    want.callback = ALCsdl2Backend_audioCallback;
+    want.userdata = self;
+
+    /* Passing NULL to SDL_OpenAudioDevice opens a default, which isn't
+     * necessarily the first in the list.
+     */
+    if(!name || strcmp(name, defaultDeviceName) == 0)
+        self->deviceID = SDL_OpenAudioDevice(NULL, SDL_FALSE, &want, &have,
+                                             SDL_AUDIO_ALLOW_ANY_CHANGE);
+    else
+    {
+        const size_t prefix_len = strlen(DEVNAME_PREFIX);
+        if(strncmp(name, DEVNAME_PREFIX, prefix_len) == 0)
+            self->deviceID = SDL_OpenAudioDevice(name+prefix_len, SDL_FALSE, &want, &have,
+                                                 SDL_AUDIO_ALLOW_ANY_CHANGE);
+        else
+            self->deviceID = SDL_OpenAudioDevice(name, SDL_FALSE, &want, &have,
+                                                 SDL_AUDIO_ALLOW_ANY_CHANGE);
+    }
+    if(self->deviceID == 0)
+        return ALC_INVALID_VALUE;
+
+    device->Frequency = have.freq;
+    if(have.channels == 1)
+        device->FmtChans = DevFmtMono;
+    else if(have.channels == 2)
+        device->FmtChans = DevFmtStereo;
+    else
+    {
+        ERR("Got unhandled SDL channel count: %d\n", (int)have.channels);
+        return ALC_INVALID_VALUE;
+    }
+    switch(have.format)
+    {
+        case AUDIO_U8:     device->FmtType = DevFmtUByte;  break;
+        case AUDIO_S8:     device->FmtType = DevFmtByte;   break;
+        case AUDIO_U16SYS: device->FmtType = DevFmtUShort; break;
+        case AUDIO_S16SYS: device->FmtType = DevFmtShort;  break;
+        case AUDIO_S32SYS: device->FmtType = DevFmtInt;    break;
+        case AUDIO_F32SYS: device->FmtType = DevFmtFloat;  break;
+        default:
+            ERR("Got unsupported SDL format: 0x%04x\n", have.format);
+            return ALC_INVALID_VALUE;
+    }
+    device->UpdateSize = have.samples;
+    device->NumUpdates = 2; /* SDL always (tries to) use two periods. */
+
+    self->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
+    self->Frequency = device->Frequency;
+    self->FmtChans = device->FmtChans;
+    self->FmtType = device->FmtType;
+    self->UpdateSize = device->UpdateSize;
+
+    alstr_copy_cstr(&device->DeviceName, name ? name : defaultDeviceName);
+
+    return ALC_NO_ERROR;
+}
+
+static ALCboolean ALCsdl2Backend_reset(ALCsdl2Backend *self)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    device->Frequency = self->Frequency;
+    device->FmtChans = self->FmtChans;
+    device->FmtType = self->FmtType;
+    device->UpdateSize = self->UpdateSize;
+    device->NumUpdates = 2;
+    SetDefaultWFXChannelOrder(device);
+    return ALC_TRUE;
+}
+
+static ALCboolean ALCsdl2Backend_start(ALCsdl2Backend *self)
+{
+    SDL_PauseAudioDevice(self->deviceID, 0);
+    return ALC_TRUE;
+}
+
+static void ALCsdl2Backend_stop(ALCsdl2Backend *self)
+{
+    SDL_PauseAudioDevice(self->deviceID, 1);
+}
+
+static void ALCsdl2Backend_lock(ALCsdl2Backend *self)
+{
+    SDL_LockAudioDevice(self->deviceID);
+}
+
+static void ALCsdl2Backend_unlock(ALCsdl2Backend *self)
+{
+    SDL_UnlockAudioDevice(self->deviceID);
+}
+
+
+typedef struct ALCsdl2BackendFactory {
+    DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCsdl2BackendFactory;
+#define ALCsdl2BACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsdl2BackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void);
+
+static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory *self);
+static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory *self);
+static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory *self, ALCbackend_Type type);
+static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsdl2BackendFactory);
+
+
+ALCbackendFactory *ALCsdl2BackendFactory_getFactory(void)
+{
+    static ALCsdl2BackendFactory factory = ALCsdl2BACKENDFACTORY_INITIALIZER;
+    return STATIC_CAST(ALCbackendFactory, &factory);
+}
+
+
+static ALCboolean ALCsdl2BackendFactory_init(ALCsdl2BackendFactory* UNUSED(self))
+{
+    if(SDL_InitSubSystem(SDL_INIT_AUDIO) == 0)
+        return AL_TRUE;
+    return ALC_FALSE;
+}
+
+static void ALCsdl2BackendFactory_deinit(ALCsdl2BackendFactory* UNUSED(self))
+{
+    SDL_QuitSubSystem(SDL_INIT_AUDIO);
+}
+
+static ALCboolean ALCsdl2BackendFactory_querySupport(ALCsdl2BackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+        return ALC_TRUE;
+    return ALC_FALSE;
+}
+
+static void ALCsdl2BackendFactory_probe(ALCsdl2BackendFactory* UNUSED(self), enum DevProbe type)
+{
+    int num_devices, i;
+    al_string name;
+
+    if(type != ALL_DEVICE_PROBE)
+        return;
+
+    AL_STRING_INIT(name);
+    num_devices = SDL_GetNumAudioDevices(SDL_FALSE);
+
+    AppendAllDevicesList(defaultDeviceName);
+    for(i = 0;i < num_devices;++i)
+    {
+        alstr_copy_cstr(&name, DEVNAME_PREFIX);
+        alstr_append_cstr(&name, SDL_GetAudioDeviceName(i, SDL_FALSE));
+        AppendAllDevicesList(alstr_get_cstr(name));
+    }
+    alstr_reset(&name);
+}
+
+static ALCbackend* ALCsdl2BackendFactory_createBackend(ALCsdl2BackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+    {
+        ALCsdl2Backend *backend;
+        NEW_OBJ(backend, ALCsdl2Backend)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+
+    return NULL;
+}

+ 133 - 85
Engine/lib/openal-soft/Alc/backends/sndio.c

@@ -28,55 +28,98 @@
 #include "alu.h"
 #include "alu.h"
 #include "threads.h"
 #include "threads.h"
 
 
-#include <sndio.h>
+#include "backends/base.h"
 
 
+#include <sndio.h>
 
 
-static const ALCchar sndio_device[] = "SndIO Default";
 
 
 
 
-static ALCboolean sndio_load(void)
-{
-    return ALC_TRUE;
-}
 
 
+typedef struct ALCsndioBackend {
+    DERIVE_FROM_TYPE(ALCbackend);
 
 
-typedef struct {
     struct sio_hdl *sndHandle;
     struct sio_hdl *sndHandle;
 
 
     ALvoid *mix_data;
     ALvoid *mix_data;
     ALsizei data_size;
     ALsizei data_size;
 
 
-    volatile int killNow;
+    ATOMIC(int) killNow;
     althrd_t thread;
     althrd_t thread;
-} sndio_data;
+} ALCsndioBackend;
+
+static int ALCsndioBackend_mixerProc(void *ptr);
+
+static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device);
+static void ALCsndioBackend_Destruct(ALCsndioBackend *self);
+static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name);
+static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self);
+static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self);
+static void ALCsndioBackend_stop(ALCsndioBackend *self);
+static DECLARE_FORWARD2(ALCsndioBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, ClockLatency, getClockLatency)
+static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCsndioBackend, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCsndioBackend)
+
+DEFINE_ALCBACKEND_VTABLE(ALCsndioBackend);
+
+
+static const ALCchar sndio_device[] = "SndIO Default";
 
 
 
 
-static int sndio_proc(void *ptr)
+static void ALCsndioBackend_Construct(ALCsndioBackend *self, ALCdevice *device)
 {
 {
-    ALCdevice *device = ptr;
-    sndio_data *data = device->ExtraData;
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCsndioBackend, ALCbackend, self);
+
+    self->sndHandle = NULL;
+    self->mix_data = NULL;
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
+}
+
+static void ALCsndioBackend_Destruct(ALCsndioBackend *self)
+{
+    if(self->sndHandle)
+        sio_close(self->sndHandle);
+    self->sndHandle = NULL;
+
+    al_free(self->mix_data);
+    self->mix_data = NULL;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+static int ALCsndioBackend_mixerProc(void *ptr)
+{
+    ALCsndioBackend *self = (ALCsndioBackend*)ptr;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALsizei frameSize;
     ALsizei frameSize;
     size_t wrote;
     size_t wrote;
 
 
     SetRTPriority();
     SetRTPriority();
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
 
 
-    frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
-    while(!data->killNow && device->Connected)
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
     {
     {
-        ALsizei len = data->data_size;
-        ALubyte *WritePtr = data->mix_data;
+        ALsizei len = self->data_size;
+        ALubyte *WritePtr = self->mix_data;
 
 
+        ALCsndioBackend_lock(self);
         aluMixData(device, WritePtr, len/frameSize);
         aluMixData(device, WritePtr, len/frameSize);
-        while(len > 0 && !data->killNow)
+        ALCsndioBackend_unlock(self);
+        while(len > 0 && !ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
         {
         {
-            wrote = sio_write(data->sndHandle, WritePtr, len);
+            wrote = sio_write(self->sndHandle, WritePtr, len);
             if(wrote == 0)
             if(wrote == 0)
             {
             {
                 ERR("sio_write failed\n");
                 ERR("sio_write failed\n");
                 ALCdevice_Lock(device);
                 ALCdevice_Lock(device);
-                aluHandleDisconnect(device);
+                aluHandleDisconnect(device, "Failed to write playback samples");
                 ALCdevice_Unlock(device);
                 ALCdevice_Unlock(device);
                 break;
                 break;
             }
             }
@@ -90,45 +133,30 @@ static int sndio_proc(void *ptr)
 }
 }
 
 
 
 
-
-static ALCenum sndio_open_playback(ALCdevice *device, const ALCchar *deviceName)
+static ALCenum ALCsndioBackend_open(ALCsndioBackend *self, const ALCchar *name)
 {
 {
-    sndio_data *data;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
 
 
-    if(!deviceName)
-        deviceName = sndio_device;
-    else if(strcmp(deviceName, sndio_device) != 0)
+    if(!name)
+        name = sndio_device;
+    else if(strcmp(name, sndio_device) != 0)
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
 
 
-    data = calloc(1, sizeof(*data));
-    data->killNow = 0;
-
-    data->sndHandle = sio_open(NULL, SIO_PLAY, 0);
-    if(data->sndHandle == NULL)
+    self->sndHandle = sio_open(NULL, SIO_PLAY, 0);
+    if(self->sndHandle == NULL)
     {
     {
-        free(data);
         ERR("Could not open device\n");
         ERR("Could not open device\n");
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
     }
     }
 
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
-    device->ExtraData = data;
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void sndio_close_playback(ALCdevice *device)
-{
-    sndio_data *data = device->ExtraData;
-
-    sio_close(data->sndHandle);
-    free(data);
-    device->ExtraData = NULL;
-}
-
-static ALCboolean sndio_reset_playback(ALCdevice *device)
+static ALCboolean ALCsndioBackend_reset(ALCsndioBackend *self)
 {
 {
-    sndio_data *data = device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     struct sio_par par;
     struct sio_par par;
 
 
     sio_initpar(&par);
     sio_initpar(&par);
@@ -170,7 +198,7 @@ static ALCboolean sndio_reset_playback(ALCdevice *device)
     par.appbufsz = device->UpdateSize * (device->NumUpdates-1);
     par.appbufsz = device->UpdateSize * (device->NumUpdates-1);
     if(!par.appbufsz) par.appbufsz = device->UpdateSize;
     if(!par.appbufsz) par.appbufsz = device->UpdateSize;
 
 
-    if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par))
+    if(!sio_setpar(self->sndHandle, &par) || !sio_getpar(self->sndHandle, &par))
     {
     {
         ERR("Failed to set device parameters\n");
         ERR("Failed to set device parameters\n");
         return ALC_FALSE;
         return ALC_FALSE;
@@ -211,77 +239,84 @@ static ALCboolean sndio_reset_playback(ALCdevice *device)
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-static ALCboolean sndio_start_playback(ALCdevice *device)
+static ALCboolean ALCsndioBackend_start(ALCsndioBackend *self)
 {
 {
-    sndio_data *data = device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+
+    self->data_size = device->UpdateSize * FrameSizeFromDevFmt(
+        device->FmtChans, device->FmtType, device->AmbiOrder
+    );
+    al_free(self->mix_data);
+    self->mix_data = al_calloc(16, self->data_size);
 
 
-    if(!sio_start(data->sndHandle))
+    if(!sio_start(self->sndHandle))
     {
     {
         ERR("Error starting playback\n");
         ERR("Error starting playback\n");
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
 
 
-    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, sndio_proc, device) != althrd_success)
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
+    if(althrd_create(&self->thread, ALCsndioBackend_mixerProc, self) != althrd_success)
     {
     {
-        sio_stop(data->sndHandle);
-        free(data->mix_data);
-        data->mix_data = NULL;
+        sio_stop(self->sndHandle);
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
 
 
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-static void sndio_stop_playback(ALCdevice *device)
+static void ALCsndioBackend_stop(ALCsndioBackend *self)
 {
 {
-    sndio_data *data = device->ExtraData;
     int res;
     int res;
 
 
-    if(data->killNow)
+    if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         return;
+    althrd_join(self->thread, &res);
 
 
-    data->killNow = 1;
-    althrd_join(data->thread, &res);
-
-    if(!sio_stop(data->sndHandle))
+    if(!sio_stop(self->sndHandle))
         ERR("Error stopping device\n");
         ERR("Error stopping device\n");
 
 
-    free(data->mix_data);
-    data->mix_data = NULL;
+    al_free(self->mix_data);
+    self->mix_data = NULL;
 }
 }
 
 
 
 
-static const BackendFuncs sndio_funcs = {
-    sndio_open_playback,
-    sndio_close_playback,
-    sndio_reset_playback,
-    sndio_start_playback,
-    sndio_stop_playback,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
-
-ALCboolean alc_sndio_init(BackendFuncs *func_list)
+typedef struct ALCsndioBackendFactory {
+    DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCsndioBackendFactory;
+#define ALCSNDIOBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsndioBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCsndioBackendFactory_getFactory(void);
+
+static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory *self);
+static DECLARE_FORWARD(ALCsndioBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory *self, ALCbackend_Type type);
+static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsndioBackendFactory);
+
+
+ALCbackendFactory *ALCsndioBackendFactory_getFactory(void)
 {
 {
-    if(!sndio_load())
-        return ALC_FALSE;
-    *func_list = sndio_funcs;
+    static ALCsndioBackendFactory factory = ALCSNDIOBACKENDFACTORY_INITIALIZER;
+    return STATIC_CAST(ALCbackendFactory, &factory);
+}
+
+
+static ALCboolean ALCsndioBackendFactory_init(ALCsndioBackendFactory* UNUSED(self))
+{
+    /* No dynamic loading */
     return ALC_TRUE;
     return ALC_TRUE;
 }
 }
 
 
-void alc_sndio_deinit(void)
+static ALCboolean ALCsndioBackendFactory_querySupport(ALCsndioBackendFactory* UNUSED(self), ALCbackend_Type type)
 {
 {
+    if(type == ALCbackend_Playback)
+        return ALC_TRUE;
+    return ALC_FALSE;
 }
 }
 
 
-void alc_sndio_probe(enum DevProbe type)
+static void ALCsndioBackendFactory_probe(ALCsndioBackendFactory* UNUSED(self), enum DevProbe type)
 {
 {
     switch(type)
     switch(type)
     {
     {
@@ -292,3 +327,16 @@ void alc_sndio_probe(enum DevProbe type)
             break;
             break;
     }
     }
 }
 }
+
+static ALCbackend* ALCsndioBackendFactory_createBackend(ALCsndioBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+    {
+        ALCsndioBackend *backend;
+        NEW_OBJ(backend, ALCsndioBackend)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+
+    return NULL;
+}

+ 62 - 41
Engine/lib/openal-soft/Alc/backends/solaris.c

@@ -34,6 +34,7 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "alconfig.h"
 #include "threads.h"
 #include "threads.h"
 #include "compat.h"
 #include "compat.h"
 
 
@@ -50,7 +51,7 @@ typedef struct ALCsolarisBackend {
     ALubyte *mix_data;
     ALubyte *mix_data;
     int data_size;
     int data_size;
 
 
-    volatile int killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCsolarisBackend;
 } ALCsolarisBackend;
 
 
@@ -59,7 +60,6 @@ static int ALCsolarisBackend_mixerProc(void *ptr);
 static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device);
 static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device);
 static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self);
 static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self);
 static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name);
 static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name);
-static void ALCsolarisBackend_close(ALCsolarisBackend *self);
 static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self);
 static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self);
 static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self);
 static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self);
 static void ALCsolarisBackend_stop(ALCsolarisBackend *self);
 static void ALCsolarisBackend_stop(ALCsolarisBackend *self);
@@ -84,6 +84,8 @@ static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *devi
     SET_VTABLE2(ALCsolarisBackend, ALCbackend, self);
     SET_VTABLE2(ALCsolarisBackend, ALCbackend, self);
 
 
     self->fd = -1;
     self->fd = -1;
+    self->mix_data = NULL;
+    ATOMIC_INIT(&self->killNow, AL_FALSE);
 }
 }
 
 
 static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self)
 static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self)
@@ -103,43 +105,67 @@ static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self)
 static int ALCsolarisBackend_mixerProc(void *ptr)
 static int ALCsolarisBackend_mixerProc(void *ptr)
 {
 {
     ALCsolarisBackend *self = ptr;
     ALCsolarisBackend *self = ptr;
-    ALCdevice *Device = STATIC_CAST(ALCbackend,self)->mDevice;
-    ALint frameSize;
-    int wrote;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    struct timeval timeout;
+    ALubyte *write_ptr;
+    ALint frame_size;
+    ALint to_write;
+    ssize_t wrote;
+    fd_set wfds;
+    int sret;
 
 
     SetRTPriority();
     SetRTPriority();
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
 
 
-    frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
+    frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
-    while(!self->killNow && Device->Connected)
+    ALCsolarisBackend_lock(self);
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
     {
     {
-        ALint len = self->data_size;
-        ALubyte *WritePtr = self->mix_data;
+        FD_ZERO(&wfds);
+        FD_SET(self->fd, &wfds);
+        timeout.tv_sec = 1;
+        timeout.tv_usec = 0;
+
+        ALCsolarisBackend_unlock(self);
+        sret = select(self->fd+1, NULL, &wfds, NULL, &timeout);
+        ALCsolarisBackend_lock(self);
+        if(sret < 0)
+        {
+            if(errno == EINTR)
+                continue;
+            ERR("select failed: %s\n", strerror(errno));
+            aluHandleDisconnect(device, "Failed to wait for playback buffer: %s", strerror(errno));
+            break;
+        }
+        else if(sret == 0)
+        {
+            WARN("select timeout\n");
+            continue;
+        }
 
 
-        aluMixData(Device, WritePtr, len/frameSize);
-        while(len > 0 && !self->killNow)
+        write_ptr = self->mix_data;
+        to_write = self->data_size;
+        aluMixData(device, write_ptr, to_write/frame_size);
+        while(to_write > 0 && !ATOMIC_LOAD_SEQ(&self->killNow))
         {
         {
-            wrote = write(self->fd, WritePtr, len);
+            wrote = write(self->fd, write_ptr, to_write);
             if(wrote < 0)
             if(wrote < 0)
             {
             {
-                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
-                {
-                    ERR("write failed: %s\n", strerror(errno));
-                    ALCsolarisBackend_lock(self);
-                    aluHandleDisconnect(Device);
-                    ALCsolarisBackend_unlock(self);
-                    break;
-                }
-
-                al_nssleep(1000000);
-                continue;
+                if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+                    continue;
+                ERR("write failed: %s\n", strerror(errno));
+                aluHandleDisconnect(device, "Failed to write playback samples: %s",
+                                    strerror(errno));
+                break;
             }
             }
 
 
-            len -= wrote;
-            WritePtr += wrote;
+            to_write -= wrote;
+            write_ptr += wrote;
         }
         }
     }
     }
+    ALCsolarisBackend_unlock(self);
 
 
     return 0;
     return 0;
 }
 }
@@ -162,23 +188,17 @@ static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *na
     }
     }
 
 
     device = STATIC_CAST(ALCbackend,self)->mDevice;
     device = STATIC_CAST(ALCbackend,self)->mDevice;
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCsolarisBackend_close(ALCsolarisBackend *self)
-{
-    close(self->fd);
-    self->fd = -1;
-}
-
 static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
 static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     audio_info_t info;
     audio_info_t info;
-    ALuint frameSize;
-    int numChannels;
+    ALsizei frameSize;
+    ALsizei numChannels;
 
 
     AUDIO_INITINFO(&info);
     AUDIO_INITINFO(&info);
 
 
@@ -186,7 +206,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
 
 
     if(device->FmtChans != DevFmtMono)
     if(device->FmtChans != DevFmtMono)
         device->FmtChans = DevFmtStereo;
         device->FmtChans = DevFmtStereo;
-    numChannels = ChannelsFromDevFmt(device->FmtChans);
+    numChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
     info.play.channels = numChannels;
     info.play.channels = numChannels;
 
 
     switch(device->FmtType)
     switch(device->FmtType)
@@ -220,9 +240,9 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
 
 
-    if(ChannelsFromDevFmt(device->FmtChans) != info.play.channels)
+    if(ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder) != (ALsizei)info.play.channels)
     {
     {
-        ERR("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), info.play.channels);
+        ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), info.play.channels);
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
 
 
@@ -242,7 +262,9 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
     SetDefaultChannelOrder(device);
     SetDefaultChannelOrder(device);
 
 
     free(self->mix_data);
     free(self->mix_data);
-    self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    self->data_size = device->UpdateSize * FrameSizeFromDevFmt(
+        device->FmtChans, device->FmtType, device->AmbiOrder
+    );
     self->mix_data = calloc(1, self->data_size);
     self->mix_data = calloc(1, self->data_size);
 
 
     return ALC_TRUE;
     return ALC_TRUE;
@@ -250,7 +272,7 @@ static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
 
 
 static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self)
 static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self)
 {
 {
-    self->killNow = 0;
+    ATOMIC_STORE_SEQ(&self->killNow, AL_FALSE);
     if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success)
         return ALC_FALSE;
         return ALC_FALSE;
     return ALC_TRUE;
     return ALC_TRUE;
@@ -260,10 +282,9 @@ static void ALCsolarisBackend_stop(ALCsolarisBackend *self)
 {
 {
     int res;
     int res;
 
 
-    if(self->killNow)
+    if(ATOMIC_EXCHANGE_SEQ(&self->killNow, AL_TRUE))
         return;
         return;
 
 
-    self->killNow = 1;
     althrd_join(self->thread, &res);
     althrd_join(self->thread, &res);
 
 
     if(ioctl(self->fd, AUDIO_DRAIN) < 0)
     if(ioctl(self->fd, AUDIO_DRAIN) < 0)

Файловите разлики са ограничени, защото са твърде много
+ 301 - 218
Engine/lib/openal-soft/Alc/backends/wasapi.c


+ 39 - 32
Engine/lib/openal-soft/Alc/backends/wave.c

@@ -27,6 +27,7 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "alconfig.h"
 #include "threads.h"
 #include "threads.h"
 #include "compat.h"
 #include "compat.h"
 
 
@@ -76,16 +77,15 @@ typedef struct ALCwaveBackend {
     ALvoid *mBuffer;
     ALvoid *mBuffer;
     ALuint mSize;
     ALuint mSize;
 
 
-    volatile int killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCwaveBackend;
 } ALCwaveBackend;
 
 
 static int ALCwaveBackend_mixerProc(void *ptr);
 static int ALCwaveBackend_mixerProc(void *ptr);
 
 
 static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device);
 static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device);
-static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, Destruct)
+static void ALCwaveBackend_Destruct(ALCwaveBackend *self);
 static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name);
 static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name);
-static void ALCwaveBackend_close(ALCwaveBackend *self);
 static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self);
 static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self);
 static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self);
 static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self);
 static void ALCwaveBackend_stop(ALCwaveBackend *self);
 static void ALCwaveBackend_stop(ALCwaveBackend *self);
@@ -110,9 +110,17 @@ static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device)
     self->mBuffer = NULL;
     self->mBuffer = NULL;
     self->mSize = 0;
     self->mSize = 0;
 
 
-    self->killNow = 1;
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
 }
 }
 
 
+static void ALCwaveBackend_Destruct(ALCwaveBackend *self)
+{
+    if(self->mFile)
+        fclose(self->mFile);
+    self->mFile = NULL;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
 
 
 static int ALCwaveBackend_mixerProc(void *ptr)
 static int ALCwaveBackend_mixerProc(void *ptr)
 {
 {
@@ -127,7 +135,7 @@ static int ALCwaveBackend_mixerProc(void *ptr)
 
 
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
     althrd_setname(althrd_current(), MIXER_THREAD_NAME);
 
 
-    frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
     done = 0;
     done = 0;
     if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
     if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC)
@@ -135,7 +143,8 @@ static int ALCwaveBackend_mixerProc(void *ptr)
         ERR("Failed to get starting time\n");
         ERR("Failed to get starting time\n");
         return 1;
         return 1;
     }
     }
-    while(!self->killNow && device->Connected)
+    while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
+          ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
     {
     {
         if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
         if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
         {
         {
@@ -157,7 +166,9 @@ static int ALCwaveBackend_mixerProc(void *ptr)
             al_nssleep(restTime);
             al_nssleep(restTime);
         else while(avail-done >= device->UpdateSize)
         else while(avail-done >= device->UpdateSize)
         {
         {
+            ALCwaveBackend_lock(self);
             aluMixData(device, self->mBuffer, device->UpdateSize);
             aluMixData(device, self->mBuffer, device->UpdateSize);
+            ALCwaveBackend_unlock(self);
             done += device->UpdateSize;
             done += device->UpdateSize;
 
 
             if(!IS_LITTLE_ENDIAN)
             if(!IS_LITTLE_ENDIAN)
@@ -194,7 +205,7 @@ static int ALCwaveBackend_mixerProc(void *ptr)
             {
             {
                 ERR("Error writing to file\n");
                 ERR("Error writing to file\n");
                 ALCdevice_Lock(device);
                 ALCdevice_Lock(device);
-                aluHandleDisconnect(device);
+                aluHandleDisconnect(device, "Failed to write playback samples");
                 ALCdevice_Unlock(device);
                 ALCdevice_Unlock(device);
                 break;
                 break;
             }
             }
@@ -226,18 +237,11 @@ static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name)
     }
     }
 
 
     device = STATIC_CAST(ALCbackend, self)->mDevice;
     device = STATIC_CAST(ALCbackend, self)->mDevice;
-    al_string_copy_cstr(&device->DeviceName, name);
+    alstr_copy_cstr(&device->DeviceName, name);
 
 
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 }
 }
 
 
-static void ALCwaveBackend_close(ALCwaveBackend *self)
-{
-    if(self->mFile)
-        fclose(self->mFile);
-    self->mFile = NULL;
-}
-
 static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
 static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -249,7 +253,10 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
     clearerr(self->mFile);
     clearerr(self->mFile);
 
 
     if(GetConfigValueBool(NULL, "wave", "bformat", 0))
     if(GetConfigValueBool(NULL, "wave", "bformat", 0))
-        device->FmtChans = DevFmtAmbi1;
+    {
+        device->FmtChans = DevFmtAmbi3D;
+        device->AmbiOrder = 1;
+    }
 
 
     switch(device->FmtType)
     switch(device->FmtType)
     {
     {
@@ -277,24 +284,23 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
         case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
         case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
         case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; 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 DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
-        case DevFmtAmbi1:
-        case DevFmtAmbi2:
-        case DevFmtAmbi3:
+        case DevFmtAmbi3D:
             /* .amb output requires FuMa */
             /* .amb output requires FuMa */
-            device->AmbiFmt = AmbiFormat_FuMa;
+            device->AmbiLayout = AmbiLayout_FuMa;
+            device->AmbiScale = AmbiNorm_FuMa;
             isbformat = 1;
             isbformat = 1;
             chanmask = 0;
             chanmask = 0;
             break;
             break;
     }
     }
     bits = BytesFromDevFmt(device->FmtType) * 8;
     bits = BytesFromDevFmt(device->FmtType) * 8;
-    channels = ChannelsFromDevFmt(device->FmtChans);
+    channels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
 
 
-    fprintf(self->mFile, "RIFF");
+    fputs("RIFF", self->mFile);
     fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close
     fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close
 
 
-    fprintf(self->mFile, "WAVE");
+    fputs("WAVE", self->mFile);
 
 
-    fprintf(self->mFile, "fmt ");
+    fputs("fmt ", self->mFile);
     fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
     fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
 
 
     // 16-bit val, format type id (extensible: 0xFFFE)
     // 16-bit val, format type id (extensible: 0xFFFE)
@@ -316,11 +322,12 @@ static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
     // 32-bit val, channel mask
     // 32-bit val, channel mask
     fwrite32le(chanmask, self->mFile);
     fwrite32le(chanmask, self->mFile);
     // 16 byte GUID, sub-type format
     // 16 byte GUID, sub-type format
-    val = fwrite(((bits==32) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
-                               (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM)), 1, 16, self->mFile);
+    val = fwrite((device->FmtType == DevFmtFloat) ?
+                 (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
+                 (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM), 1, 16, self->mFile);
     (void)val;
     (void)val;
 
 
-    fprintf(self->mFile, "data");
+    fputs("data", self->mFile);
     fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close
     fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close
 
 
     if(ferror(self->mFile))
     if(ferror(self->mFile))
@@ -339,7 +346,9 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
 
 
-    self->mSize = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    self->mSize = device->UpdateSize * FrameSizeFromDevFmt(
+        device->FmtChans, device->FmtType, device->AmbiOrder
+    );
     self->mBuffer = malloc(self->mSize);
     self->mBuffer = malloc(self->mSize);
     if(!self->mBuffer)
     if(!self->mBuffer)
     {
     {
@@ -347,7 +356,7 @@ static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self)
         return ALC_FALSE;
         return ALC_FALSE;
     }
     }
 
 
-    self->killNow = 0;
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
     if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success)
     {
     {
         free(self->mBuffer);
         free(self->mBuffer);
@@ -365,10 +374,8 @@ static void ALCwaveBackend_stop(ALCwaveBackend *self)
     long size;
     long size;
     int res;
     int res;
 
 
-    if(self->killNow)
+    if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         return;
-
-    self->killNow = 1;
     althrd_join(self->thread, &res);
     althrd_join(self->thread, &res);
 
 
     free(self->mBuffer);
     free(self->mBuffer);

+ 64 - 75
Engine/lib/openal-soft/Alc/backends/winmm.c

@@ -29,6 +29,7 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "ringbuffer.h"
 #include "threads.h"
 #include "threads.h"
 
 
 #include "backends/base.h"
 #include "backends/base.h"
@@ -45,7 +46,7 @@ static vector_al_string CaptureDevices;
 
 
 static void clear_devlist(vector_al_string *list)
 static void clear_devlist(vector_al_string *list)
 {
 {
-    VECTOR_FOR_EACH(al_string, *list, al_string_deinit);
+    VECTOR_FOR_EACH(al_string, *list, alstr_reset);
     VECTOR_RESIZE(*list, 0, 0);
     VECTOR_RESIZE(*list, 0, 0);
 }
 }
 
 
@@ -71,23 +72,23 @@ static void ProbePlaybackDevices(void)
             ALuint count = 0;
             ALuint count = 0;
             while(1)
             while(1)
             {
             {
-                al_string_copy_cstr(&dname, DEVNAME_HEAD);
-                al_string_append_wcstr(&dname, WaveCaps.szPname);
+                alstr_copy_cstr(&dname, DEVNAME_HEAD);
+                alstr_append_wcstr(&dname, WaveCaps.szPname);
                 if(count != 0)
                 if(count != 0)
                 {
                 {
                     char str[64];
                     char str[64];
                     snprintf(str, sizeof(str), " #%d", count+1);
                     snprintf(str, sizeof(str), " #%d", count+1);
-                    al_string_append_cstr(&dname, str);
+                    alstr_append_cstr(&dname, str);
                 }
                 }
                 count++;
                 count++;
 
 
-#define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0)
+#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0)
                 VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY);
                 VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY);
                 if(iter == VECTOR_END(PlaybackDevices)) break;
                 if(iter == VECTOR_END(PlaybackDevices)) break;
 #undef MATCH_ENTRY
 #undef MATCH_ENTRY
             }
             }
 
 
-            TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
+            TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i);
         }
         }
         VECTOR_PUSH_BACK(PlaybackDevices, dname);
         VECTOR_PUSH_BACK(PlaybackDevices, dname);
     }
     }
@@ -114,23 +115,23 @@ static void ProbeCaptureDevices(void)
             ALuint count = 0;
             ALuint count = 0;
             while(1)
             while(1)
             {
             {
-                al_string_copy_cstr(&dname, DEVNAME_HEAD);
-                al_string_append_wcstr(&dname, WaveCaps.szPname);
+                alstr_copy_cstr(&dname, DEVNAME_HEAD);
+                alstr_append_wcstr(&dname, WaveCaps.szPname);
                 if(count != 0)
                 if(count != 0)
                 {
                 {
                     char str[64];
                     char str[64];
                     snprintf(str, sizeof(str), " #%d", count+1);
                     snprintf(str, sizeof(str), " #%d", count+1);
-                    al_string_append_cstr(&dname, str);
+                    alstr_append_cstr(&dname, str);
                 }
                 }
                 count++;
                 count++;
 
 
-#define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0)
+#define MATCH_ENTRY(i) (alstr_cmp(dname, *(i)) == 0)
                 VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY);
                 VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY);
                 if(iter == VECTOR_END(CaptureDevices)) break;
                 if(iter == VECTOR_END(CaptureDevices)) break;
 #undef MATCH_ENTRY
 #undef MATCH_ENTRY
             }
             }
 
 
-            TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i);
+            TRACE("Got device \"%s\", ID %u\n", alstr_get_cstr(dname), i);
         }
         }
         VECTOR_PUSH_BACK(CaptureDevices, dname);
         VECTOR_PUSH_BACK(CaptureDevices, dname);
     }
     }
@@ -147,7 +148,7 @@ typedef struct ALCwinmmPlayback {
 
 
     WAVEFORMATEX Format;
     WAVEFORMATEX Format;
 
 
-    volatile ALboolean killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCwinmmPlayback;
 } ALCwinmmPlayback;
 
 
@@ -158,7 +159,6 @@ static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWO
 static int ALCwinmmPlayback_mixerProc(void *arg);
 static int ALCwinmmPlayback_mixerProc(void *arg);
 
 
 static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name);
 static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name);
-static void ALCwinmmPlayback_close(ALCwinmmPlayback *self);
 static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self);
 static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self);
 static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self);
 static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self);
 static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self);
 static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self);
@@ -180,7 +180,7 @@ static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device
     InitRef(&self->WaveBuffersCommitted, 0);
     InitRef(&self->WaveBuffersCommitted, 0);
     self->OutHdl = NULL;
     self->OutHdl = NULL;
 
 
-    self->killNow = AL_TRUE;
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
 }
 }
 
 
 static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self)
 static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self)
@@ -224,7 +224,7 @@ FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg)
         if(msg.message != WOM_DONE)
         if(msg.message != WOM_DONE)
             continue;
             continue;
 
 
-        if(self->killNow)
+        if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
         {
         {
             if(ReadRef(&self->WaveBuffersCommitted) == 0)
             if(ReadRef(&self->WaveBuffersCommitted) == 0)
                 break;
                 break;
@@ -232,8 +232,10 @@ FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg)
         }
         }
 
 
         WaveHdr = ((WAVEHDR*)msg.lParam);
         WaveHdr = ((WAVEHDR*)msg.lParam);
+        ALCwinmmPlayback_lock(self);
         aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength /
         aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength /
                                             self->Format.nBlockAlign);
                                             self->Format.nBlockAlign);
+        ALCwinmmPlayback_unlock(self);
 
 
         // Send buffer back to play more data
         // Send buffer back to play more data
         waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR));
         waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR));
@@ -255,8 +257,8 @@ static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *devi
         ProbePlaybackDevices();
         ProbePlaybackDevices();
 
 
     // Find the Device ID matching the deviceName if valid
     // Find the Device ID matching the deviceName if valid
-#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && \
-                             (!deviceName || al_string_cmp_cstr(*(iter), deviceName) == 0))
+#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \
+                             (!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0))
     VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME);
     VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME);
     if(iter == VECTOR_END(PlaybackDevices))
     if(iter == VECTOR_END(PlaybackDevices))
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
@@ -298,7 +300,7 @@ retry_open:
         goto failure;
         goto failure;
     }
     }
 
 
-    al_string_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
+    alstr_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID));
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 
 
 failure:
 failure:
@@ -309,9 +311,6 @@ failure:
     return ALC_INVALID_VALUE;
     return ALC_INVALID_VALUE;
 }
 }
 
 
-static void ALCwinmmPlayback_close(ALCwinmmPlayback* UNUSED(self))
-{ }
-
 static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self)
 static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self)
 {
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
@@ -372,7 +371,7 @@ static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self)
     ALint BufferSize;
     ALint BufferSize;
     ALuint i;
     ALuint i;
 
 
-    self->killNow = AL_FALSE;
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
     if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success)
         return ALC_FALSE;
         return ALC_FALSE;
 
 
@@ -380,7 +379,7 @@ static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self)
 
 
     // Create 4 Buffers
     // Create 4 Buffers
     BufferSize  = device->UpdateSize*device->NumUpdates / 4;
     BufferSize  = device->UpdateSize*device->NumUpdates / 4;
-    BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
 
 
     BufferData = calloc(4, BufferSize);
     BufferData = calloc(4, BufferSize);
     for(i = 0;i < 4;i++)
     for(i = 0;i < 4;i++)
@@ -403,11 +402,8 @@ static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self)
     void *buffer = NULL;
     void *buffer = NULL;
     int i;
     int i;
 
 
-    if(self->killNow)
+    if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
         return;
         return;
-
-    // Set flag to stop processing headers
-    self->killNow = AL_TRUE;
     althrd_join(self->thread, &i);
     althrd_join(self->thread, &i);
 
 
     // Release the wave buffers
     // Release the wave buffers
@@ -434,7 +430,7 @@ typedef struct ALCwinmmCapture {
 
 
     WAVEFORMATEX Format;
     WAVEFORMATEX Format;
 
 
-    volatile ALboolean killNow;
+    ATOMIC(ALenum) killNow;
     althrd_t thread;
     althrd_t thread;
 } ALCwinmmCapture;
 } ALCwinmmCapture;
 
 
@@ -445,7 +441,6 @@ static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_
 static int ALCwinmmCapture_captureProc(void *arg);
 static int ALCwinmmCapture_captureProc(void *arg);
 
 
 static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name);
 static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name);
-static void ALCwinmmCapture_close(ALCwinmmCapture *self);
 static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset)
 static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset)
 static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self);
 static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self);
 static void ALCwinmmCapture_stop(ALCwinmmCapture *self);
 static void ALCwinmmCapture_stop(ALCwinmmCapture *self);
@@ -467,11 +462,38 @@ static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device)
     InitRef(&self->WaveBuffersCommitted, 0);
     InitRef(&self->WaveBuffersCommitted, 0);
     self->InHdl = NULL;
     self->InHdl = NULL;
 
 
-    self->killNow = AL_TRUE;
+    ATOMIC_INIT(&self->killNow, AL_TRUE);
 }
 }
 
 
 static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self)
 static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self)
 {
 {
+    void *buffer = NULL;
+    int i;
+
+    /* Tell the processing thread to quit and wait for it to do so. */
+    if(!ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
+    {
+        PostThreadMessage(self->thread, WM_QUIT, 0, 0);
+
+        althrd_join(self->thread, &i);
+
+        /* Make sure capture is stopped and all pending buffers are flushed. */
+        waveInReset(self->InHdl);
+
+        // Release the wave buffers
+        for(i = 0;i < 4;i++)
+        {
+            waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
+            if(i == 0) buffer = self->WaveBuffer[i].lpData;
+            self->WaveBuffer[i].lpData = NULL;
+        }
+        free(buffer);
+    }
+
+    ll_ringbuffer_free(self->Ring);
+    self->Ring = NULL;
+
+    // Close the Wave device
     if(self->InHdl)
     if(self->InHdl)
         waveInClose(self->InHdl);
         waveInClose(self->InHdl);
     self->InHdl = 0;
     self->InHdl = 0;
@@ -510,7 +532,7 @@ static int ALCwinmmCapture_captureProc(void *arg)
             continue;
             continue;
         /* Don't wait for other buffers to finish before quitting. We're
         /* Don't wait for other buffers to finish before quitting. We're
          * closing so we don't need them. */
          * closing so we don't need them. */
-        if(self->killNow)
+        if(ATOMIC_LOAD(&self->killNow, almemory_order_acquire))
             break;
             break;
 
 
         WaveHdr = ((WAVEHDR*)msg.lParam);
         WaveHdr = ((WAVEHDR*)msg.lParam);
@@ -542,7 +564,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
         ProbeCaptureDevices();
         ProbeCaptureDevices();
 
 
     // Find the Device ID matching the deviceName if valid
     // Find the Device ID matching the deviceName if valid
-#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) &&  (!name || al_string_cmp_cstr(*iter, name) == 0))
+#define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0))
     VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME);
     VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME);
     if(iter == VECTOR_END(CaptureDevices))
     if(iter == VECTOR_END(CaptureDevices))
         return ALC_INVALID_VALUE;
         return ALC_INVALID_VALUE;
@@ -561,9 +583,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
         case DevFmtX51Rear:
         case DevFmtX51Rear:
         case DevFmtX61:
         case DevFmtX61:
         case DevFmtX71:
         case DevFmtX71:
-        case DevFmtAmbi1:
-        case DevFmtAmbi2:
-        case DevFmtAmbi3:
+        case DevFmtAmbi3D:
             return ALC_INVALID_ENUM;
             return ALC_INVALID_ENUM;
     }
     }
 
 
@@ -584,7 +604,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
     memset(&self->Format, 0, sizeof(WAVEFORMATEX));
     memset(&self->Format, 0, sizeof(WAVEFORMATEX));
     self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ?
     self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ?
                                WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
                                WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM);
-    self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
+    self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
     self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
     self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
     self->Format.nBlockAlign = self->Format.wBitsPerSample *
     self->Format.nBlockAlign = self->Format.wBitsPerSample *
                                self->Format.nChannels / 8;
                                self->Format.nChannels / 8;
@@ -606,7 +626,7 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
     if(CapturedDataSize < (self->Format.nSamplesPerSec / 10))
     if(CapturedDataSize < (self->Format.nSamplesPerSec / 10))
         CapturedDataSize = self->Format.nSamplesPerSec / 10;
         CapturedDataSize = self->Format.nSamplesPerSec / 10;
 
 
-    self->Ring = ll_ringbuffer_create(CapturedDataSize+1, self->Format.nBlockAlign);
+    self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false);
     if(!self->Ring) goto failure;
     if(!self->Ring) goto failure;
 
 
     InitRef(&self->WaveBuffersCommitted, 0);
     InitRef(&self->WaveBuffersCommitted, 0);
@@ -632,11 +652,11 @@ static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name)
         IncrementRef(&self->WaveBuffersCommitted);
         IncrementRef(&self->WaveBuffersCommitted);
     }
     }
 
 
-    self->killNow = AL_FALSE;
+    ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
     if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success)
     if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success)
         goto failure;
         goto failure;
 
 
-    al_string_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
+    alstr_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID));
     return ALC_NO_ERROR;
     return ALC_NO_ERROR;
 
 
 failure:
 failure:
@@ -657,37 +677,6 @@ failure:
     return ALC_INVALID_VALUE;
     return ALC_INVALID_VALUE;
 }
 }
 
 
-static void ALCwinmmCapture_close(ALCwinmmCapture *self)
-{
-    void *buffer = NULL;
-    int i;
-
-    /* Tell the processing thread to quit and wait for it to do so. */
-    self->killNow = AL_TRUE;
-    PostThreadMessage(self->thread, WM_QUIT, 0, 0);
-
-    althrd_join(self->thread, &i);
-
-    /* Make sure capture is stopped and all pending buffers are flushed. */
-    waveInReset(self->InHdl);
-
-    // Release the wave buffers
-    for(i = 0;i < 4;i++)
-    {
-        waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR));
-        if(i == 0) buffer = self->WaveBuffer[i].lpData;
-        self->WaveBuffer[i].lpData = NULL;
-    }
-    free(buffer);
-
-    ll_ringbuffer_free(self->Ring);
-    self->Ring = NULL;
-
-    // Close the Wave device
-    waveInClose(self->InHdl);
-    self->InHdl = NULL;
-}
-
 static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self)
 static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self)
 {
 {
     waveInStart(self->InHdl);
     waveInStart(self->InHdl);
@@ -707,19 +696,19 @@ static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *bu
 
 
 static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self)
 static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self)
 {
 {
-    return ll_ringbuffer_read_space(self->Ring);
+    return (ALCuint)ll_ringbuffer_read_space(self->Ring);
 }
 }
 
 
 
 
 static inline void AppendAllDevicesList2(const al_string *name)
 static inline void AppendAllDevicesList2(const al_string *name)
 {
 {
-    if(!al_string_empty(*name))
-        AppendAllDevicesList(al_string_get_cstr(*name));
+    if(!alstr_empty(*name))
+        AppendAllDevicesList(alstr_get_cstr(*name));
 }
 }
 static inline void AppendCaptureDeviceList2(const al_string *name)
 static inline void AppendCaptureDeviceList2(const al_string *name)
 {
 {
-    if(!al_string_empty(*name))
-        AppendCaptureDeviceList(al_string_get_cstr(*name));
+    if(!alstr_empty(*name))
+        AppendCaptureDeviceList(alstr_get_cstr(*name));
 }
 }
 
 
 typedef struct ALCwinmmBackendFactory {
 typedef struct ALCwinmmBackendFactory {

+ 182 - 360
Engine/lib/openal-soft/Alc/bformatdec.c

@@ -3,82 +3,22 @@
 
 
 #include "bformatdec.h"
 #include "bformatdec.h"
 #include "ambdec.h"
 #include "ambdec.h"
-#include "mixer_defs.h"
+#include "filters/splitter.h"
 #include "alu.h"
 #include "alu.h"
 
 
+#include "bool.h"
 #include "threads.h"
 #include "threads.h"
 #include "almalloc.h"
 #include "almalloc.h"
 
 
 
 
-void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult)
-{
-    ALfloat w = freq_mult * F_TAU;
-    ALfloat cw = cosf(w);
-    if(cw > FLT_EPSILON)
-        splitter->coeff = (sinf(w) - 1.0f) / cw;
-    else
-        splitter->coeff = cw * -0.5f;
-
-    splitter->lp_z1 = 0.0f;
-    splitter->lp_z2 = 0.0f;
-    splitter->hp_z1 = 0.0f;
-}
-
-void bandsplit_clear(BandSplitter *splitter)
-{
-    splitter->lp_z1 = 0.0f;
-    splitter->lp_z2 = 0.0f;
-    splitter->hp_z1 = 0.0f;
-}
-
-void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
-                       const ALfloat *input, ALuint count)
-{
-    ALfloat coeff, d, x;
-    ALfloat z1, z2;
-    ALuint i;
-
-    coeff = splitter->coeff*0.5f + 0.5f;
-    z1 = splitter->lp_z1;
-    z2 = splitter->lp_z2;
-    for(i = 0;i < count;i++)
-    {
-        x = input[i];
-
-        d = (x - z1) * coeff;
-        x = z1 + d;
-        z1 = x + d;
-
-        d = (x - z2) * coeff;
-        x = z2 + d;
-        z2 = x + d;
-
-        lpout[i] = x;
-    }
-    splitter->lp_z1 = z1;
-    splitter->lp_z2 = z2;
-
-    coeff = splitter->coeff;
-    z1 = splitter->hp_z1;
-    for(i = 0;i < count;i++)
-    {
-        x = input[i];
-
-        d = x - coeff*z1;
-        x = z1 + coeff*d;
-        z1 = d;
-
-        hpout[i] = x - lpout[i];
-    }
-    splitter->hp_z1 = z1;
-}
-
-
-static const ALfloat UnitScale[MAX_AMBI_COEFFS] = {
+/* NOTE: These are scale factors as applied to Ambisonics content. Decoder
+ * coefficients should be divided by these values to get proper N3D scalings.
+ */
+const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS] = {
     1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
     1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
 };
 };
-static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
+const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
     1.000000000f, /* ACN  0 (W), sqrt(1) */
     1.000000000f, /* ACN  0 (W), sqrt(1) */
     1.732050808f, /* ACN  1 (Y), sqrt(3) */
     1.732050808f, /* ACN  1 (Y), sqrt(3) */
     1.732050808f, /* ACN  2 (Z), sqrt(3) */
     1.732050808f, /* ACN  2 (Z), sqrt(3) */
@@ -96,7 +36,7 @@ static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
     2.645751311f, /* ACN 14 (N), sqrt(7) */
     2.645751311f, /* ACN 14 (N), sqrt(7) */
     2.645751311f, /* ACN 15 (P), sqrt(7) */
     2.645751311f, /* ACN 15 (P), sqrt(7) */
 };
 };
-static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
+const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
     1.414213562f, /* ACN  0 (W), sqrt(2) */
     1.414213562f, /* ACN  0 (W), sqrt(2) */
     1.732050808f, /* ACN  1 (Y), sqrt(3) */
     1.732050808f, /* ACN  1 (Y), sqrt(3) */
     1.732050808f, /* ACN  2 (Z), sqrt(3) */
     1.732050808f, /* ACN  2 (Z), sqrt(3) */
@@ -116,26 +56,9 @@ static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
 };
 };
 
 
 
 
-enum FreqBand {
-    FB_HighFreq,
-    FB_LowFreq,
-    FB_Max
-};
-
-/* These points are in AL coordinates! */
-static const ALfloat Ambi2DPoints[4][3] = {
-    { -0.707106781f,  0.0f, -0.707106781f },
-    {  0.707106781f,  0.0f, -0.707106781f },
-    { -0.707106781f,  0.0f,  0.707106781f },
-    {  0.707106781f,  0.0f,  0.707106781f },
-};
-static const ALfloat Ambi2DDecoder[4][FB_Max][MAX_AMBI_COEFFS] = {
-    { { 0.353553f,  0.204094f, 0.0f,  0.204094f }, { 0.25f,  0.204094f, 0.0f,  0.204094f } },
-    { { 0.353553f, -0.204094f, 0.0f,  0.204094f }, { 0.25f, -0.204094f, 0.0f,  0.204094f } },
-    { { 0.353553f,  0.204094f, 0.0f, -0.204094f }, { 0.25f,  0.204094f, 0.0f, -0.204094f } },
-    { { 0.353553f, -0.204094f, 0.0f, -0.204094f }, { 0.25f, -0.204094f, 0.0f, -0.204094f } },
-};
-static ALfloat Ambi2DEncoder[4][MAX_AMBI_COEFFS];
+#define HF_BAND 0
+#define LF_BAND 1
+#define NUM_BANDS 2
 
 
 /* These points are in AL coordinates! */
 /* These points are in AL coordinates! */
 static const ALfloat Ambi3DPoints[8][3] = {
 static const ALfloat Ambi3DPoints[8][3] = {
@@ -148,57 +71,28 @@ static const ALfloat Ambi3DPoints[8][3] = {
     { -0.577350269f, -0.577350269f,  0.577350269f },
     { -0.577350269f, -0.577350269f,  0.577350269f },
     {  0.577350269f, -0.577350269f,  0.577350269f },
     {  0.577350269f, -0.577350269f,  0.577350269f },
 };
 };
-static const ALfloat Ambi3DDecoder[8][FB_Max][MAX_AMBI_COEFFS] = {
-    { { 0.25f,  0.1443375672f,  0.1443375672f,  0.1443375672f }, { 0.125f,  0.125f,  0.125f,  0.125f } },
-    { { 0.25f, -0.1443375672f,  0.1443375672f,  0.1443375672f }, { 0.125f, -0.125f,  0.125f,  0.125f } },
-    { { 0.25f,  0.1443375672f,  0.1443375672f, -0.1443375672f }, { 0.125f,  0.125f,  0.125f, -0.125f } },
-    { { 0.25f, -0.1443375672f,  0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f,  0.125f, -0.125f } },
-    { { 0.25f,  0.1443375672f, -0.1443375672f,  0.1443375672f }, { 0.125f,  0.125f, -0.125f,  0.125f } },
-    { { 0.25f, -0.1443375672f, -0.1443375672f,  0.1443375672f }, { 0.125f, -0.125f, -0.125f,  0.125f } },
-    { { 0.25f,  0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f,  0.125f, -0.125f, -0.125f } },
-    { { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } },
+static const ALfloat Ambi3DDecoder[8][MAX_AMBI_COEFFS] = {
+    { 0.125f,  0.125f,  0.125f,  0.125f },
+    { 0.125f, -0.125f,  0.125f,  0.125f },
+    { 0.125f,  0.125f,  0.125f, -0.125f },
+    { 0.125f, -0.125f,  0.125f, -0.125f },
+    { 0.125f,  0.125f, -0.125f,  0.125f },
+    { 0.125f, -0.125f, -0.125f,  0.125f },
+    { 0.125f,  0.125f, -0.125f, -0.125f },
+    { 0.125f, -0.125f, -0.125f, -0.125f },
+};
+static const ALfloat Ambi3DDecoderHFScale[MAX_AMBI_COEFFS] = {
+    2.0f,
+    1.15470054f, 1.15470054f, 1.15470054f
 };
 };
-static ALfloat Ambi3DEncoder[8][MAX_AMBI_COEFFS];
-
-
-static RowMixerFunc MixMatrixRow = MixRow_C;
-
-
-static alonce_flag bformatdec_inited = AL_ONCE_FLAG_INIT;
-
-static void init_bformatdec(void)
-{
-    ALuint i, j;
-
-    MixMatrixRow = SelectRowMixer();
-
-    for(i = 0;i < COUNTOF(Ambi3DPoints);i++)
-        CalcDirectionCoeffs(Ambi3DPoints[i], 0.0f, Ambi3DEncoder[i]);
-
-    for(i = 0;i < COUNTOF(Ambi2DPoints);i++)
-    {
-        CalcDirectionCoeffs(Ambi2DPoints[i], 0.0f, Ambi2DEncoder[i]);
-
-        /* Remove the skipped height-related coefficients for 2D rendering. */
-        Ambi2DEncoder[i][2] = Ambi2DEncoder[i][3];
-        Ambi2DEncoder[i][3] = Ambi2DEncoder[i][4];
-        Ambi2DEncoder[i][4] = Ambi2DEncoder[i][8];
-        Ambi2DEncoder[i][5] = Ambi2DEncoder[i][9];
-        Ambi2DEncoder[i][6] = Ambi2DEncoder[i][15];
-        for(j = 7;j < MAX_AMBI_COEFFS;j++)
-            Ambi2DEncoder[i][j] = 0.0f;
-    }
-}
-
 
 
-#define MAX_DELAY_LENGTH 128
 
 
 /* NOTE: BandSplitter filters are unused with single-band decoding */
 /* NOTE: BandSplitter filters are unused with single-band decoding */
 typedef struct BFormatDec {
 typedef struct BFormatDec {
-    ALboolean Enabled[MAX_OUTPUT_CHANNELS];
+    ALuint Enabled; /* Bitfield of enabled channels. */
 
 
     union {
     union {
-        alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][FB_Max][MAX_AMBI_COEFFS];
+        alignas(16) ALfloat Dual[MAX_OUTPUT_CHANNELS][NUM_BANDS][MAX_AMBI_COEFFS];
         alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
         alignas(16) ALfloat Single[MAX_OUTPUT_CHANNELS][MAX_AMBI_COEFFS];
     } Matrix;
     } Matrix;
 
 
@@ -212,67 +106,42 @@ typedef struct BFormatDec {
     alignas(16) ALfloat ChannelMix[BUFFERSIZE];
     alignas(16) ALfloat ChannelMix[BUFFERSIZE];
 
 
     struct {
     struct {
-        alignas(16) ALfloat Buffer[MAX_DELAY_LENGTH];
-        ALuint Length; /* Valid range is [0...MAX_DELAY_LENGTH). */
-    } Delay[MAX_OUTPUT_CHANNELS];
+        BandSplitter XOver;
+        ALfloat Gains[NUM_BANDS];
+    } UpSampler[4];
 
 
-    struct {
-        BandSplitter XOver[4];
-
-        ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max];
-    } UpSampler;
-
-    ALuint NumChannels;
+    ALsizei NumChannels;
     ALboolean DualBand;
     ALboolean DualBand;
-    ALboolean Periphonic;
 } BFormatDec;
 } BFormatDec;
 
 
 BFormatDec *bformatdec_alloc()
 BFormatDec *bformatdec_alloc()
 {
 {
-    alcall_once(&bformatdec_inited, init_bformatdec);
     return al_calloc(16, sizeof(BFormatDec));
     return al_calloc(16, sizeof(BFormatDec));
 }
 }
 
 
-void bformatdec_free(BFormatDec *dec)
+void bformatdec_free(BFormatDec **dec)
 {
 {
-    if(dec)
+    if(dec && *dec)
     {
     {
-        al_free(dec->Samples);
-        dec->Samples = NULL;
-        dec->SamplesHF = NULL;
-        dec->SamplesLF = NULL;
-
-        memset(dec, 0, sizeof(*dec));
-        al_free(dec);
-    }
-}
+        al_free((*dec)->Samples);
+        (*dec)->Samples = NULL;
+        (*dec)->SamplesHF = NULL;
+        (*dec)->SamplesLF = NULL;
 
 
-int bformatdec_getOrder(const struct BFormatDec *dec)
-{
-    if(dec->Periphonic)
-    {
-        if(dec->NumChannels > 9) return 3;
-        if(dec->NumChannels > 4) return 2;
-        if(dec->NumChannels > 1) return 1;
+        al_free(*dec);
+        *dec = NULL;
     }
     }
-    else
-    {
-        if(dec->NumChannels > 5) return 3;
-        if(dec->NumChannels > 3) return 2;
-        if(dec->NumChannels > 1) return 1;
-    }
-    return 0;
 }
 }
 
 
-void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags)
+void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS])
 {
 {
-    static const ALuint map2DTo3D[MAX_AMBI2D_COEFFS] = {
+    static const ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = {
         0,  1, 3,  4, 8,  9, 15
         0,  1, 3,  4, 8,  9, 15
     };
     };
-    const ALfloat *coeff_scale = UnitScale;
-    ALfloat distgain[MAX_OUTPUT_CHANNELS];
-    ALfloat maxdist, ratio;
-    ALuint i, j, k;
+    const ALfloat *coeff_scale = N3D2N3DScale;
+    bool periphonic;
+    ALfloat ratio;
+    ALsizei i;
 
 
     al_free(dec->Samples);
     al_free(dec->Samples);
     dec->Samples = NULL;
     dec->Samples = NULL;
@@ -284,91 +153,48 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount,
     dec->SamplesHF = dec->Samples;
     dec->SamplesHF = dec->Samples;
     dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
     dec->SamplesLF = dec->SamplesHF + dec->NumChannels;
 
 
-    for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
-        dec->Enabled[i] = AL_FALSE;
+    dec->Enabled = 0;
     for(i = 0;i < conf->NumSpeakers;i++)
     for(i = 0;i < conf->NumSpeakers;i++)
-        dec->Enabled[chanmap[i]] = AL_TRUE;
+        dec->Enabled |= 1 << chanmap[i];
 
 
     if(conf->CoeffScale == ADS_SN3D)
     if(conf->CoeffScale == ADS_SN3D)
         coeff_scale = SN3D2N3DScale;
         coeff_scale = SN3D2N3DScale;
     else if(conf->CoeffScale == ADS_FuMa)
     else if(conf->CoeffScale == ADS_FuMa)
         coeff_scale = FuMa2N3DScale;
         coeff_scale = FuMa2N3DScale;
 
 
+    memset(dec->UpSampler, 0, sizeof(dec->UpSampler));
     ratio = 400.0f / (ALfloat)srate;
     ratio = 400.0f / (ALfloat)srate;
     for(i = 0;i < 4;i++)
     for(i = 0;i < 4;i++)
-        bandsplit_init(&dec->UpSampler.XOver[i], ratio);
-    memset(dec->UpSampler.Gains, 0, sizeof(dec->UpSampler.Gains));
+        bandsplit_init(&dec->UpSampler[i].XOver, ratio);
     if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
     if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
     {
     {
-        /* Combine the matrices that do the in->virt and virt->out conversions
-         * so we get a single in->out conversion.
-         */
-        for(i = 0;i < 4;i++)
-        {
-            for(j = 0;j < dec->NumChannels;j++)
-            {
-                ALfloat *gains = dec->UpSampler.Gains[i][j];
-                for(k = 0;k < COUNTOF(Ambi3DDecoder);k++)
-                {
-                    gains[FB_HighFreq] += Ambi3DDecoder[k][FB_HighFreq][i]*Ambi3DEncoder[k][j];
-                    gains[FB_LowFreq] += Ambi3DDecoder[k][FB_LowFreq][i]*Ambi3DEncoder[k][j];
-                }
-            }
-        }
+        periphonic = true;
 
 
-        dec->Periphonic = AL_TRUE;
-    }
-    else
-    {
-        for(i = 0;i < 4;i++)
+        dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H3P :
+                                           (conf->ChanMask > 0xf) ? W_SCALE_2H2P : 1.0f;
+        dec->UpSampler[0].Gains[LF_BAND] = 1.0f;
+        for(i = 1;i < 4;i++)
         {
         {
-            for(j = 0;j < dec->NumChannels;j++)
-            {
-                ALfloat *gains = dec->UpSampler.Gains[i][j];
-                for(k = 0;k < COUNTOF(Ambi2DDecoder);k++)
-                {
-                    gains[FB_HighFreq] += Ambi2DDecoder[k][FB_HighFreq][i]*Ambi2DEncoder[k][j];
-                    gains[FB_LowFreq] += Ambi2DDecoder[k][FB_LowFreq][i]*Ambi2DEncoder[k][j];
-                }
-            }
+            dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H3P :
+                                               (conf->ChanMask > 0xf) ? XYZ_SCALE_2H2P : 1.0f;
+            dec->UpSampler[i].Gains[LF_BAND] = 1.0f;
         }
         }
-
-        dec->Periphonic = AL_FALSE;
     }
     }
-
-    maxdist = 0.0f;
-    for(i = 0;i < conf->NumSpeakers;i++)
+    else
     {
     {
-        maxdist = maxf(maxdist, conf->Speakers[i].Distance);
-        distgain[i] = 1.0f;
-    }
+        periphonic = false;
 
 
-    memset(dec->Delay, 0, sizeof(dec->Delay));
-    if((flags&BFDF_DistanceComp) && maxdist > 0.0f)
-    {
-        for(i = 0;i < conf->NumSpeakers;i++)
+        dec->UpSampler[0].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? W_SCALE_3H0P :
+                                           (conf->ChanMask > 0xf) ? W_SCALE_2H0P : 1.0f;
+        dec->UpSampler[0].Gains[LF_BAND] = 1.0f;
+        for(i = 1;i < 3;i++)
         {
         {
-            ALuint chan = chanmap[i];
-            ALfloat delay;
-
-            /* Distance compensation only delays in steps of the sample rate.
-             * This is a bit less accurate since the delay time falls to the
-             * nearest sample time, but it's far simpler as it doesn't have to
-             * deal with phase offsets. This means at 48khz, for instance, the
-             * distance delay will be in steps of about 7 millimeters.
-             */
-            delay = floorf((maxdist-conf->Speakers[i].Distance) / SPEEDOFSOUNDMETRESPERSEC *
-                           (ALfloat)srate + 0.5f);
-            if(delay >= (ALfloat)MAX_DELAY_LENGTH)
-                ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n",
-                    al_string_get_cstr(conf->Speakers[i].Name), delay, MAX_DELAY_LENGTH);
-
-            dec->Delay[chan].Length = (ALuint)clampf(delay, 0.0f, (ALfloat)(MAX_DELAY_LENGTH-1));
-            distgain[i] = conf->Speakers[i].Distance / maxdist;
-            TRACE("Channel %u \"%s\" distance compensation: %u samples, %f gain\n", chan,
-                al_string_get_cstr(conf->Speakers[i].Name), dec->Delay[chan].Length, distgain[i]
-            );
+            dec->UpSampler[i].Gains[HF_BAND] = (conf->ChanMask > 0x1ff) ? XYZ_SCALE_3H0P :
+                                               (conf->ChanMask > 0xf) ? XYZ_SCALE_2H0P : 1.0f;
+            dec->UpSampler[i].Gains[LF_BAND] = 1.0f;
         }
         }
+        dec->UpSampler[3].Gains[HF_BAND] = 0.0f;
+        dec->UpSampler[3].Gains[LF_BAND] = 0.0f;
     }
     }
 
 
     memset(&dec->Matrix, 0, sizeof(dec->Matrix));
     memset(&dec->Matrix, 0, sizeof(dec->Matrix));
@@ -377,22 +203,22 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount,
         dec->DualBand = AL_FALSE;
         dec->DualBand = AL_FALSE;
         for(i = 0;i < conf->NumSpeakers;i++)
         for(i = 0;i < conf->NumSpeakers;i++)
         {
         {
-            ALuint chan = chanmap[i];
+            ALsizei chan = chanmap[i];
             ALfloat gain;
             ALfloat gain;
-            ALuint j, k;
+            ALsizei j, k;
 
 
-            if(!dec->Periphonic)
+            if(!periphonic)
             {
             {
                 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
                 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
                 {
                 {
-                    ALuint l = map2DTo3D[j];
+                    ALsizei l = map2DTo3D[j];
                     if(j == 0) gain = conf->HFOrderGain[0];
                     if(j == 0) gain = conf->HFOrderGain[0];
                     else if(j == 1) gain = conf->HFOrderGain[1];
                     else if(j == 1) gain = conf->HFOrderGain[1];
                     else if(j == 3) gain = conf->HFOrderGain[2];
                     else if(j == 3) gain = conf->HFOrderGain[2];
                     else if(j == 5) gain = conf->HFOrderGain[3];
                     else if(j == 5) gain = conf->HFOrderGain[3];
                     if((conf->ChanMask&(1<<l)))
                     if((conf->ChanMask&(1<<l)))
                         dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
                         dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[l] *
-                                                      gain * distgain[i];
+                                                      gain;
                 }
                 }
             }
             }
             else
             else
@@ -405,7 +231,7 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount,
                     else if(j == 9) gain = conf->HFOrderGain[3];
                     else if(j == 9) gain = conf->HFOrderGain[3];
                     if((conf->ChanMask&(1<<j)))
                     if((conf->ChanMask&(1<<j)))
                         dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
                         dec->Matrix.Single[chan][j] = conf->HFMatrix[i][k++] / coeff_scale[j] *
-                                                      gain * distgain[i];
+                                                      gain;
                 }
                 }
             }
             }
         }
         }
@@ -421,35 +247,33 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount,
         ratio = powf(10.0f, conf->XOverRatio / 40.0f);
         ratio = powf(10.0f, conf->XOverRatio / 40.0f);
         for(i = 0;i < conf->NumSpeakers;i++)
         for(i = 0;i < conf->NumSpeakers;i++)
         {
         {
-            ALuint chan = chanmap[i];
+            ALsizei chan = chanmap[i];
             ALfloat gain;
             ALfloat gain;
-            ALuint j, k;
+            ALsizei j, k;
 
 
-            if(!dec->Periphonic)
+            if(!periphonic)
             {
             {
                 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
                 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
                 {
                 {
-                    ALuint l = map2DTo3D[j];
+                    ALsizei l = map2DTo3D[j];
                     if(j == 0) gain = conf->HFOrderGain[0] * ratio;
                     if(j == 0) gain = conf->HFOrderGain[0] * ratio;
                     else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
                     else if(j == 1) gain = conf->HFOrderGain[1] * ratio;
                     else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
                     else if(j == 3) gain = conf->HFOrderGain[2] * ratio;
                     else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
                     else if(j == 5) gain = conf->HFOrderGain[3] * ratio;
                     if((conf->ChanMask&(1<<l)))
                     if((conf->ChanMask&(1<<l)))
-                        dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
-                                                                 coeff_scale[l] * gain *
-                                                                 distgain[i];
+                        dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] /
+                                                             coeff_scale[l] * gain;
                 }
                 }
                 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
                 for(j = 0,k = 0;j < MAX_AMBI2D_COEFFS;j++)
                 {
                 {
-                    ALuint l = map2DTo3D[j];
+                    ALsizei l = map2DTo3D[j];
                     if(j == 0) gain = conf->LFOrderGain[0] / ratio;
                     if(j == 0) gain = conf->LFOrderGain[0] / ratio;
                     else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
                     else if(j == 1) gain = conf->LFOrderGain[1] / ratio;
                     else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
                     else if(j == 3) gain = conf->LFOrderGain[2] / ratio;
                     else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
                     else if(j == 5) gain = conf->LFOrderGain[3] / ratio;
                     if((conf->ChanMask&(1<<l)))
                     if((conf->ChanMask&(1<<l)))
-                        dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
-                                                                coeff_scale[l] * gain *
-                                                                distgain[i];
+                        dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] /
+                                                             coeff_scale[l] * gain;
                 }
                 }
             }
             }
             else
             else
@@ -461,9 +285,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount,
                     else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
                     else if(j == 4) gain = conf->HFOrderGain[2] * ratio;
                     else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
                     else if(j == 9) gain = conf->HFOrderGain[3] * ratio;
                     if((conf->ChanMask&(1<<j)))
                     if((conf->ChanMask&(1<<j)))
-                        dec->Matrix.Dual[chan][FB_HighFreq][j] = conf->HFMatrix[i][k++] /
-                                                                 coeff_scale[j] * gain *
-                                                                 distgain[i];
+                        dec->Matrix.Dual[chan][HF_BAND][j] = conf->HFMatrix[i][k++] /
+                                                             coeff_scale[j] * gain;
                 }
                 }
                 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
                 for(j = 0,k = 0;j < MAX_AMBI_COEFFS;j++)
                 {
                 {
@@ -472,9 +295,8 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount,
                     else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
                     else if(j == 4) gain = conf->LFOrderGain[2] / ratio;
                     else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
                     else if(j == 9) gain = conf->LFOrderGain[3] / ratio;
                     if((conf->ChanMask&(1<<j)))
                     if((conf->ChanMask&(1<<j)))
-                        dec->Matrix.Dual[chan][FB_LowFreq][j] = conf->LFMatrix[i][k++] /
-                                                                coeff_scale[j] * gain *
-                                                                distgain[i];
+                        dec->Matrix.Dual[chan][LF_BAND][j] = conf->LFMatrix[i][k++] /
+                                                             coeff_scale[j] * gain;
                 }
                 }
             }
             }
         }
         }
@@ -482,10 +304,11 @@ void bformatdec_reset(BFormatDec *dec, const AmbDecConf *conf, ALuint chancount,
 }
 }
 
 
 
 
-void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo)
+void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
 {
 {
-    ALuint chan, i;
+    ALsizei chan, i;
 
 
+    OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
     if(dec->DualBand)
     if(dec->DualBand)
     {
     {
         for(i = 0;i < dec->NumChannels;i++)
         for(i = 0;i < dec->NumChannels;i++)
@@ -494,42 +317,18 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU
 
 
         for(chan = 0;chan < OutChannels;chan++)
         for(chan = 0;chan < OutChannels;chan++)
         {
         {
-            if(!dec->Enabled[chan])
+            if(!(dec->Enabled&(1<<chan)))
                 continue;
                 continue;
 
 
             memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
             memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
-            MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_HighFreq],
-                SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesHF), dec->NumChannels, 0,
-                SamplesToDo
+            MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][HF_BAND],
+                dec->SamplesHF, dec->NumChannels, 0, SamplesToDo
             );
             );
-            MixMatrixRow(dec->ChannelMix, dec->Matrix.Dual[chan][FB_LowFreq],
-                SAFE_CONST(ALfloatBUFFERSIZE*,dec->SamplesLF), dec->NumChannels, 0,
-                SamplesToDo
+            MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND],
+                dec->SamplesLF, dec->NumChannels, 0, SamplesToDo
             );
             );
 
 
-            if(dec->Delay[chan].Length > 0)
-            {
-                const ALuint base = dec->Delay[chan].Length;
-                if(SamplesToDo >= base)
-                {
-                    for(i = 0;i < base;i++)
-                        OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
-                    for(;i < SamplesToDo;i++)
-                        OutBuffer[chan][i] += dec->ChannelMix[i-base];
-                    memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base],
-                           base*sizeof(ALfloat));
-                }
-                else
-                {
-                    for(i = 0;i < SamplesToDo;i++)
-                        OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
-                    memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo,
-                            base - SamplesToDo);
-                    memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix,
-                           SamplesToDo*sizeof(ALfloat));
-                }
-            }
-            else for(i = 0;i < SamplesToDo;i++)
+            for(i = 0;i < SamplesToDo;i++)
                 OutBuffer[chan][i] += dec->ChannelMix[i];
                 OutBuffer[chan][i] += dec->ChannelMix[i];
         }
         }
     }
     }
@@ -537,134 +336,157 @@ void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BU
     {
     {
         for(chan = 0;chan < OutChannels;chan++)
         for(chan = 0;chan < OutChannels;chan++)
         {
         {
-            if(!dec->Enabled[chan])
+            if(!(dec->Enabled&(1<<chan)))
                 continue;
                 continue;
 
 
             memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
             memset(dec->ChannelMix, 0, SamplesToDo*sizeof(ALfloat));
-            MixMatrixRow(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
-                         dec->NumChannels, 0, SamplesToDo);
+            MixRowSamples(dec->ChannelMix, dec->Matrix.Single[chan], InSamples,
+                          dec->NumChannels, 0, SamplesToDo);
 
 
-            if(dec->Delay[chan].Length > 0)
-            {
-                const ALuint base = dec->Delay[chan].Length;
-                if(SamplesToDo >= base)
-                {
-                    for(i = 0;i < base;i++)
-                        OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
-                    for(;i < SamplesToDo;i++)
-                        OutBuffer[chan][i] += dec->ChannelMix[i-base];
-                    memcpy(dec->Delay[chan].Buffer, &dec->ChannelMix[SamplesToDo-base],
-                           base*sizeof(ALfloat));
-                }
-                else
-                {
-                    for(i = 0;i < SamplesToDo;i++)
-                        OutBuffer[chan][i] += dec->Delay[chan].Buffer[i];
-                    memmove(dec->Delay[chan].Buffer, dec->Delay[chan].Buffer+SamplesToDo,
-                            base - SamplesToDo);
-                    memcpy(dec->Delay[chan].Buffer+base-SamplesToDo, dec->ChannelMix,
-                           SamplesToDo*sizeof(ALfloat));
-                }
-            }
-            else for(i = 0;i < SamplesToDo;i++)
+            for(i = 0;i < SamplesToDo;i++)
                 OutBuffer[chan][i] += dec->ChannelMix[i];
                 OutBuffer[chan][i] += dec->ChannelMix[i];
         }
         }
     }
     }
 }
 }
 
 
 
 
-void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo)
+void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo)
 {
 {
-    ALuint i, j;
-
-    /* This up-sampler is very simplistic. It essentially decodes the first-
-     * order content to a square channel array (or cube if height is desired),
-     * then encodes those points onto the higher order soundfield. The decoder
-     * and encoder matrices have been combined to directly convert each input
-     * channel to the output, without the need for storing the virtual channel
-     * array.
+    ALsizei i;
+
+    /* This up-sampler leverages the differences observed in dual-band second-
+     * and third-order decoder matrices compared to first-order. For the same
+     * output channel configuration, the low-frequency matrix has identical
+     * coefficients in the shared input channels, while the high-frequency
+     * matrix has extra scalars applied to the W channel and X/Y/Z channels.
+     * Mixing the first-order content into the higher-order stream with the
+     * appropriate counter-scales applied to the HF response results in the
+     * subsequent higher-order decode generating the same response as a first-
+     * order decode.
      */
      */
     for(i = 0;i < InChannels;i++)
     for(i = 0;i < InChannels;i++)
     {
     {
         /* First, split the first-order components into low and high frequency
         /* First, split the first-order components into low and high frequency
          * bands.
          * bands.
          */
          */
-        bandsplit_process(&dec->UpSampler.XOver[i],
-            dec->Samples[FB_HighFreq], dec->Samples[FB_LowFreq],
+        bandsplit_process(&dec->UpSampler[i].XOver,
+            dec->Samples[HF_BAND], dec->Samples[LF_BAND],
             InSamples[i], SamplesToDo
             InSamples[i], SamplesToDo
         );
         );
 
 
         /* Now write each band to the output. */
         /* Now write each band to the output. */
-        for(j = 0;j < dec->NumChannels;j++)
-            MixMatrixRow(OutBuffer[j], dec->UpSampler.Gains[i][j],
-                SAFE_CONST(ALfloatBUFFERSIZE*,dec->Samples), FB_Max, 0,
-                SamplesToDo
-            );
+        MixRowSamples(OutBuffer[i], dec->UpSampler[i].Gains,
+            dec->Samples, NUM_BANDS, 0, SamplesToDo
+        );
     }
     }
 }
 }
 
 
 
 
+#define INVALID_UPSAMPLE_INDEX INT_MAX
+
+static ALsizei GetACNIndex(const BFChannelConfig *chans, ALsizei numchans, ALsizei acn)
+{
+    ALsizei i;
+    for(i = 0;i < numchans;i++)
+    {
+        if(chans[i].Index == acn)
+            return i;
+    }
+    return INVALID_UPSAMPLE_INDEX;
+}
+#define GetChannelForACN(b, a) GetACNIndex((b).Ambi.Map, (b).NumChannels, (a))
+
 typedef struct AmbiUpsampler {
 typedef struct AmbiUpsampler {
-    alignas(16) ALfloat Samples[FB_Max][BUFFERSIZE];
+    alignas(16) ALfloat Samples[NUM_BANDS][BUFFERSIZE];
 
 
     BandSplitter XOver[4];
     BandSplitter XOver[4];
 
 
-    ALfloat Gains[4][MAX_OUTPUT_CHANNELS][FB_Max];
+    ALfloat Gains[4][MAX_OUTPUT_CHANNELS][NUM_BANDS];
 } AmbiUpsampler;
 } AmbiUpsampler;
 
 
 AmbiUpsampler *ambiup_alloc()
 AmbiUpsampler *ambiup_alloc()
 {
 {
-    alcall_once(&bformatdec_inited, init_bformatdec);
     return al_calloc(16, sizeof(AmbiUpsampler));
     return al_calloc(16, sizeof(AmbiUpsampler));
 }
 }
 
 
-void ambiup_free(struct AmbiUpsampler *ambiup)
+void ambiup_free(struct AmbiUpsampler **ambiup)
 {
 {
-    al_free(ambiup);
+    if(ambiup)
+    {
+        al_free(*ambiup);
+        *ambiup = NULL;
+    }
 }
 }
 
 
-void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device)
+void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale)
 {
 {
-    ALfloat gains[8][MAX_OUTPUT_CHANNELS];
     ALfloat ratio;
     ALfloat ratio;
-    ALuint i, j, k;
+    ALsizei i;
 
 
     ratio = 400.0f / (ALfloat)device->Frequency;
     ratio = 400.0f / (ALfloat)device->Frequency;
     for(i = 0;i < 4;i++)
     for(i = 0;i < 4;i++)
         bandsplit_init(&ambiup->XOver[i], ratio);
         bandsplit_init(&ambiup->XOver[i], ratio);
 
 
-    for(i = 0;i < COUNTOF(Ambi3DEncoder);i++)
-        ComputePanningGains(device->Dry, Ambi3DEncoder[i], 1.0f, gains[i]);
-
     memset(ambiup->Gains, 0, sizeof(ambiup->Gains));
     memset(ambiup->Gains, 0, sizeof(ambiup->Gains));
-    for(i = 0;i < 4;i++)
+    if(device->Dry.CoeffCount > 0)
     {
     {
-        for(j = 0;j < device->Dry.NumChannels;j++)
+        ALfloat encgains[8][MAX_OUTPUT_CHANNELS];
+        ALsizei j;
+        size_t k;
+
+        for(k = 0;k < COUNTOF(Ambi3DPoints);k++)
+        {
+            ALfloat coeffs[MAX_AMBI_COEFFS] = { 0.0f };
+            CalcDirectionCoeffs(Ambi3DPoints[k], 0.0f, coeffs);
+            ComputeDryPanGains(&device->Dry, coeffs, 1.0f, encgains[k]);
+        }
+
+        /* Combine the matrices that do the in->virt and virt->out conversions
+         * so we get a single in->out conversion. NOTE: the Encoder matrix
+         * (encgains) and output are transposed, so the input channels line up
+         * with the rows and the output channels line up with the columns.
+         */
+        for(i = 0;i < 4;i++)
+        {
+            for(j = 0;j < device->Dry.NumChannels;j++)
+            {
+                ALfloat gain=0.0f;
+                for(k = 0;k < COUNTOF(Ambi3DDecoder);k++)
+                    gain += Ambi3DDecoder[k][i] * encgains[k][j];
+                ambiup->Gains[i][j][HF_BAND] = gain * Ambi3DDecoderHFScale[i];
+                ambiup->Gains[i][j][LF_BAND] = gain;
+            }
+        }
+    }
+    else
+    {
+        for(i = 0;i < 4;i++)
         {
         {
-            for(k = 0;k < COUNTOF(Ambi3DDecoder);k++)
+            ALsizei index = GetChannelForACN(device->Dry, i);
+            if(index != INVALID_UPSAMPLE_INDEX)
             {
             {
-                ambiup->Gains[i][j][FB_HighFreq] += Ambi3DDecoder[k][FB_HighFreq][i]*gains[k][j];
-                ambiup->Gains[i][j][FB_LowFreq] += Ambi3DDecoder[k][FB_LowFreq][i]*gains[k][j];
+                ALfloat scale = device->Dry.Ambi.Map[index].Scale;
+                ambiup->Gains[i][index][HF_BAND] = scale * ((i==0) ? w_scale : xyz_scale);
+                ambiup->Gains[i][index][LF_BAND] = scale;
             }
             }
         }
         }
     }
     }
 }
 }
 
 
-void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo)
+void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
 {
 {
-    ALuint i, j;
+    ALsizei i, j;
 
 
     for(i = 0;i < 4;i++)
     for(i = 0;i < 4;i++)
     {
     {
         bandsplit_process(&ambiup->XOver[i],
         bandsplit_process(&ambiup->XOver[i],
-            ambiup->Samples[FB_HighFreq], ambiup->Samples[FB_LowFreq],
+            ambiup->Samples[HF_BAND], ambiup->Samples[LF_BAND],
             InSamples[i], SamplesToDo
             InSamples[i], SamplesToDo
         );
         );
 
 
         for(j = 0;j < OutChannels;j++)
         for(j = 0;j < OutChannels;j++)
-            MixMatrixRow(OutBuffer[j], ambiup->Gains[i][j],
-                SAFE_CONST(ALfloatBUFFERSIZE*,ambiup->Samples), FB_Max, 0,
-                SamplesToDo
+            MixRowSamples(OutBuffer[j], ambiup->Gains[i][j],
+                ambiup->Samples, NUM_BANDS, 0, SamplesToDo
             );
             );
     }
     }
 }
 }

+ 34 - 26
Engine/lib/openal-soft/Alc/bformatdec.h

@@ -3,47 +3,55 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 
 
+
+/* These are the necessary scales for first-order HF responses to play over
+ * higher-order 2D (non-periphonic) decoders.
+ */
+#define W_SCALE_2H0P   1.224744871f /* sqrt(1.5) */
+#define XYZ_SCALE_2H0P 1.0f
+#define W_SCALE_3H0P   1.414213562f /* sqrt(2) */
+#define XYZ_SCALE_3H0P 1.082392196f
+
+/* These are the necessary scales for first-order HF responses to play over
+ * higher-order 3D (periphonic) decoders.
+ */
+#define W_SCALE_2H2P   1.341640787f /* sqrt(1.8) */
+#define XYZ_SCALE_2H2P 1.0f
+#define W_SCALE_3H3P   1.695486018f
+#define XYZ_SCALE_3H3P 1.136697713f
+
+
+/* NOTE: These are scale factors as applied to Ambisonics content. Decoder
+ * coefficients should be divided by these values to get proper N3D scalings.
+ */
+const ALfloat N3D2N3DScale[MAX_AMBI_COEFFS];
+const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS];
+const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS];
+
+
 struct AmbDecConf;
 struct AmbDecConf;
 struct BFormatDec;
 struct BFormatDec;
 struct AmbiUpsampler;
 struct AmbiUpsampler;
 
 
-enum BFormatDecFlags {
-    BFDF_DistanceComp = 1<<0
-};
 
 
 struct BFormatDec *bformatdec_alloc();
 struct BFormatDec *bformatdec_alloc();
-void bformatdec_free(struct BFormatDec *dec);
-int bformatdec_getOrder(const struct BFormatDec *dec);
-void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALuint chancount, ALuint srate, const ALuint chanmap[MAX_OUTPUT_CHANNELS], int flags);
+void bformatdec_free(struct BFormatDec **dec);
+void bformatdec_reset(struct BFormatDec *dec, const struct AmbDecConf *conf, ALsizei chancount, ALuint srate, const ALsizei chanmap[MAX_OUTPUT_CHANNELS]);
 
 
 /* Decodes the ambisonic input to the given output channels. */
 /* Decodes the ambisonic input to the given output channels. */
-void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo);
+void bformatdec_process(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo);
 
 
 /* Up-samples a first-order input to the decoder's configuration. */
 /* Up-samples a first-order input to the decoder's configuration. */
-void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint InChannels, ALuint SamplesToDo);
+void bformatdec_upSample(struct BFormatDec *dec, ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei InChannels, ALsizei SamplesToDo);
 
 
 
 
 /* Stand-alone first-order upsampler. Kept here because it shares some stuff
 /* Stand-alone first-order upsampler. Kept here because it shares some stuff
- * with bformatdec.
+ * with bformatdec. Assumes a periphonic (4-channel) input mix!
  */
  */
 struct AmbiUpsampler *ambiup_alloc();
 struct AmbiUpsampler *ambiup_alloc();
-void ambiup_free(struct AmbiUpsampler *ambiup);
-void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device);
-
-void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo);
-
-
-/* Band splitter. Splits a signal into two phase-matching frequency bands. */
-typedef struct BandSplitter {
-    ALfloat coeff;
-    ALfloat lp_z1;
-    ALfloat lp_z2;
-    ALfloat hp_z1;
-} BandSplitter;
+void ambiup_free(struct AmbiUpsampler **ambiup);
+void ambiup_reset(struct AmbiUpsampler *ambiup, const ALCdevice *device, ALfloat w_scale, ALfloat xyz_scale);
 
 
-void bandsplit_init(BandSplitter *splitter, ALfloat freq_mult);
-void bandsplit_clear(BandSplitter *splitter);
-void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
-                       const ALfloat *input, ALuint count);
+void ambiup_process(struct AmbiUpsampler *ambiup, ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALsizei OutChannels, const ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo);
 
 
 #endif /* BFORMATDEC_H */
 #endif /* BFORMATDEC_H */

+ 4 - 4
Engine/lib/openal-soft/Alc/bs2b.c

@@ -129,16 +129,16 @@ void bs2b_clear(struct bs2b *bs2b)
     memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample));
     memset(&bs2b->last_sample, 0, sizeof(bs2b->last_sample));
 } /* bs2b_clear */
 } /* bs2b_clear */
 
 
-void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, unsigned int SamplesToDo)
+void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo)
 {
 {
     float lsamples[128][2];
     float lsamples[128][2];
     float rsamples[128][2];
     float rsamples[128][2];
-    unsigned int base;
+    int base;
 
 
     for(base = 0;base < SamplesToDo;)
     for(base = 0;base < SamplesToDo;)
     {
     {
-        unsigned int todo = minu(128, SamplesToDo-base);
-        unsigned int i;
+        int todo = mini(128, SamplesToDo-base);
+        int i;
 
 
         /* Process left input */
         /* Process left input */
         lsamples[0][0] = bs2b->a0_lo*Left[0] +
         lsamples[0][0] = bs2b->a0_lo*Left[0] +

+ 0 - 981
Engine/lib/openal-soft/Alc/bsinc.c

@@ -1,981 +0,0 @@
-
-#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
-};

+ 17 - 1
Engine/lib/openal-soft/Alc/compat.h

@@ -3,6 +3,10 @@
 
 
 #include "alstring.h"
 #include "alstring.h"
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef _WIN32
 #ifdef _WIN32
 
 
 #define WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
@@ -38,7 +42,7 @@ struct FileMapping {
 struct FileMapping MapFileToMem(const char *fname);
 struct FileMapping MapFileToMem(const char *fname);
 void UnmapFileMem(const struct FileMapping *mapping);
 void UnmapFileMem(const struct FileMapping *mapping);
 
 
-al_string GetProcPath(void);
+void GetProcBinary(al_string *path, al_string *fname);
 
 
 #ifdef HAVE_DYNLOAD
 #ifdef HAVE_DYNLOAD
 void *LoadLib(const char *name);
 void *LoadLib(const char *name);
@@ -46,4 +50,16 @@ void CloseLib(void *handle);
 void *GetSymbol(void *handle, const char *name);
 void *GetSymbol(void *handle, const char *name);
 #endif
 #endif
 
 
+#ifdef __ANDROID__
+#define JCALL(obj, func)  ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
+#define JCALL0(obj, func)  ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
+
+/** Returns a JNIEnv*. */
+void *Android_GetJNIEnv(void);
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
 #endif /* AL_COMPAT_H */
 #endif /* AL_COMPAT_H */

+ 468 - 0
Engine/lib/openal-soft/Alc/converter.c

@@ -0,0 +1,468 @@
+
+#include "config.h"
+
+#include "converter.h"
+
+#include "fpu_modes.h"
+#include "mixer/defs.h"
+
+
+SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate)
+{
+    SampleConverter *converter;
+    ALsizei step;
+
+    if(numchans <= 0 || srcRate <= 0 || dstRate <= 0)
+        return NULL;
+
+    converter = al_calloc(16, FAM_SIZE(SampleConverter, Chan, numchans));
+    converter->mSrcType = srcType;
+    converter->mDstType = dstType;
+    converter->mNumChannels = numchans;
+    converter->mSrcTypeSize = BytesFromDevFmt(srcType);
+    converter->mDstTypeSize = BytesFromDevFmt(dstType);
+
+    converter->mSrcPrepCount = 0;
+    converter->mFracOffset = 0;
+
+    /* Have to set the mixer FPU mode since that's what the resampler code expects. */
+    START_MIXER_MODE();
+    step = (ALsizei)mind(((ALdouble)srcRate/dstRate*FRACTIONONE) + 0.5,
+                         MAX_PITCH * FRACTIONONE);
+    converter->mIncrement = maxi(step, 1);
+    if(converter->mIncrement == FRACTIONONE)
+        converter->mResample = Resample_copy_C;
+    else
+    {
+        /* TODO: Allow other resamplers. */
+        BsincPrepare(converter->mIncrement, &converter->mState.bsinc, &bsinc12);
+        converter->mResample = SelectResampler(BSinc12Resampler);
+    }
+    END_MIXER_MODE();
+
+    return converter;
+}
+
+void DestroySampleConverter(SampleConverter **converter)
+{
+    if(converter)
+    {
+        al_free(*converter);
+        *converter = NULL;
+    }
+}
+
+
+static inline ALfloat Sample_ALbyte(ALbyte val)
+{ return val * (1.0f/128.0f); }
+static inline ALfloat Sample_ALubyte(ALubyte val)
+{ return Sample_ALbyte((ALint)val - 128); }
+
+static inline ALfloat Sample_ALshort(ALshort val)
+{ return val * (1.0f/32768.0f); }
+static inline ALfloat Sample_ALushort(ALushort val)
+{ return Sample_ALshort((ALint)val - 32768); }
+
+static inline ALfloat Sample_ALint(ALint val)
+{ return (val>>7) * (1.0f/16777216.0f); }
+static inline ALfloat Sample_ALuint(ALuint val)
+{ return Sample_ALint(val - INT_MAX - 1); }
+
+static inline ALfloat Sample_ALfloat(ALfloat val)
+{ return val; }
+
+#define DECL_TEMPLATE(T)                                                      \
+static inline void Load_##T(ALfloat *restrict dst, const T *restrict src,     \
+                            ALint srcstep, ALsizei samples)                   \
+{                                                                             \
+    ALsizei i;                                                                \
+    for(i = 0;i < samples;i++)                                                \
+        dst[i] = Sample_##T(src[i*srcstep]);                                  \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+
+#undef DECL_TEMPLATE
+
+static void LoadSamples(ALfloat *dst, const ALvoid *src, ALint srcstep, enum DevFmtType srctype, ALsizei samples)
+{
+    switch(srctype)
+    {
+        case DevFmtByte:
+            Load_ALbyte(dst, src, srcstep, samples);
+            break;
+        case DevFmtUByte:
+            Load_ALubyte(dst, src, srcstep, samples);
+            break;
+        case DevFmtShort:
+            Load_ALshort(dst, src, srcstep, samples);
+            break;
+        case DevFmtUShort:
+            Load_ALushort(dst, src, srcstep, samples);
+            break;
+        case DevFmtInt:
+            Load_ALint(dst, src, srcstep, samples);
+            break;
+        case DevFmtUInt:
+            Load_ALuint(dst, src, srcstep, samples);
+            break;
+        case DevFmtFloat:
+            Load_ALfloat(dst, src, srcstep, samples);
+            break;
+    }
+}
+
+
+static inline ALbyte ALbyte_Sample(ALfloat val)
+{ return fastf2i(clampf(val*128.0f, -128.0f, 127.0f)); }
+static inline ALubyte ALubyte_Sample(ALfloat val)
+{ return ALbyte_Sample(val)+128; }
+
+static inline ALshort ALshort_Sample(ALfloat val)
+{ return fastf2i(clampf(val*32768.0f, -32768.0f, 32767.0f)); }
+static inline ALushort ALushort_Sample(ALfloat val)
+{ return ALshort_Sample(val)+32768; }
+
+static inline ALint ALint_Sample(ALfloat val)
+{ return fastf2i(clampf(val*16777216.0f, -16777216.0f, 16777215.0f)) << 7; }
+static inline ALuint ALuint_Sample(ALfloat val)
+{ return ALint_Sample(val)+INT_MAX+1; }
+
+static inline ALfloat ALfloat_Sample(ALfloat val)
+{ return val; }
+
+#define DECL_TEMPLATE(T)                                                      \
+static inline void Store_##T(T *restrict dst, const ALfloat *restrict src,    \
+                             ALint dststep, ALsizei samples)                  \
+{                                                                             \
+    ALsizei i;                                                                \
+    for(i = 0;i < samples;i++)                                                \
+        dst[i*dststep] = T##_Sample(src[i]);                                  \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+
+#undef DECL_TEMPLATE
+
+static void StoreSamples(ALvoid *dst, const ALfloat *src, ALint dststep, enum DevFmtType dsttype, ALsizei samples)
+{
+    switch(dsttype)
+    {
+        case DevFmtByte:
+            Store_ALbyte(dst, src, dststep, samples);
+            break;
+        case DevFmtUByte:
+            Store_ALubyte(dst, src, dststep, samples);
+            break;
+        case DevFmtShort:
+            Store_ALshort(dst, src, dststep, samples);
+            break;
+        case DevFmtUShort:
+            Store_ALushort(dst, src, dststep, samples);
+            break;
+        case DevFmtInt:
+            Store_ALint(dst, src, dststep, samples);
+            break;
+        case DevFmtUInt:
+            Store_ALuint(dst, src, dststep, samples);
+            break;
+        case DevFmtFloat:
+            Store_ALfloat(dst, src, dststep, samples);
+            break;
+    }
+}
+
+
+ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes)
+{
+    ALint prepcount = converter->mSrcPrepCount;
+    ALsizei increment = converter->mIncrement;
+    ALsizei DataPosFrac = converter->mFracOffset;
+    ALuint64 DataSize64;
+
+    if(prepcount < 0)
+    {
+        /* Negative prepcount means we need to skip that many input samples. */
+        if(-prepcount >= srcframes)
+            return 0;
+        srcframes += prepcount;
+        prepcount = 0;
+    }
+
+    if(srcframes < 1)
+    {
+        /* No output samples if there's no input samples. */
+        return 0;
+    }
+
+    if(prepcount < MAX_RESAMPLE_PADDING*2 &&
+       MAX_RESAMPLE_PADDING*2 - prepcount >= srcframes)
+    {
+        /* Not enough input samples to generate an output sample. */
+        return 0;
+    }
+
+    DataSize64  = prepcount;
+    DataSize64 += srcframes;
+    DataSize64 -= MAX_RESAMPLE_PADDING*2;
+    DataSize64 <<= FRACTIONBITS;
+    DataSize64 -= DataPosFrac;
+
+    /* If we have a full prep, we can generate at least one sample. */
+    return (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE);
+}
+
+
+ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes)
+{
+    const ALsizei SrcFrameSize = converter->mNumChannels * converter->mSrcTypeSize;
+    const ALsizei DstFrameSize = converter->mNumChannels * converter->mDstTypeSize;
+    const ALsizei increment = converter->mIncrement;
+    ALsizei pos = 0;
+
+    START_MIXER_MODE();
+    while(pos < dstframes && *srcframes > 0)
+    {
+        ALfloat *restrict SrcData = ASSUME_ALIGNED(converter->mSrcSamples, 16);
+        ALfloat *restrict DstData = ASSUME_ALIGNED(converter->mDstSamples, 16);
+        ALint prepcount = converter->mSrcPrepCount;
+        ALsizei DataPosFrac = converter->mFracOffset;
+        ALuint64 DataSize64;
+        ALsizei DstSize;
+        ALint toread;
+        ALsizei chan;
+
+        if(prepcount < 0)
+        {
+            /* Negative prepcount means we need to skip that many input samples. */
+            if(-prepcount >= *srcframes)
+            {
+                converter->mSrcPrepCount = prepcount + *srcframes;
+                *srcframes = 0;
+                break;
+            }
+            *src = (const ALbyte*)*src + SrcFrameSize*-prepcount;
+            *srcframes += prepcount;
+            converter->mSrcPrepCount = 0;
+            continue;
+        }
+        toread = mini(*srcframes, BUFFERSIZE - MAX_RESAMPLE_PADDING*2);
+
+        if(prepcount < MAX_RESAMPLE_PADDING*2 &&
+           MAX_RESAMPLE_PADDING*2 - prepcount >= toread)
+        {
+            /* Not enough input samples to generate an output sample. Store
+             * what we're given for later.
+             */
+            for(chan = 0;chan < converter->mNumChannels;chan++)
+                LoadSamples(&converter->Chan[chan].mPrevSamples[prepcount],
+                    (const ALbyte*)*src + converter->mSrcTypeSize*chan,
+                    converter->mNumChannels, converter->mSrcType, toread
+                );
+
+            converter->mSrcPrepCount = prepcount + toread;
+            *srcframes = 0;
+            break;
+        }
+
+        DataSize64  = prepcount;
+        DataSize64 += toread;
+        DataSize64 -= MAX_RESAMPLE_PADDING*2;
+        DataSize64 <<= FRACTIONBITS;
+        DataSize64 -= DataPosFrac;
+
+        /* If we have a full prep, we can generate at least one sample. */
+        DstSize = (ALsizei)clampu64((DataSize64 + increment-1)/increment, 1, BUFFERSIZE);
+        DstSize = mini(DstSize, dstframes-pos);
+
+        for(chan = 0;chan < converter->mNumChannels;chan++)
+        {
+            const ALbyte *SrcSamples = (const ALbyte*)*src + converter->mSrcTypeSize*chan;
+            ALbyte *DstSamples = (ALbyte*)dst + converter->mDstTypeSize*chan;
+            const ALfloat *ResampledData;
+            ALsizei SrcDataEnd;
+
+            /* Load the previous samples into the source data first, then the
+             * new samples from the input buffer.
+             */
+            memcpy(SrcData, converter->Chan[chan].mPrevSamples,
+                   prepcount*sizeof(ALfloat));
+            LoadSamples(SrcData + prepcount, SrcSamples,
+                converter->mNumChannels, converter->mSrcType, toread
+            );
+
+            /* Store as many prep samples for next time as possible, given the
+             * number of output samples being generated.
+             */
+            SrcDataEnd = (DataPosFrac + increment*DstSize)>>FRACTIONBITS;
+            if(SrcDataEnd >= prepcount+toread)
+                memset(converter->Chan[chan].mPrevSamples, 0,
+                       sizeof(converter->Chan[chan].mPrevSamples));
+            else
+            {
+                size_t len = mini(MAX_RESAMPLE_PADDING*2, prepcount+toread-SrcDataEnd);
+                memcpy(converter->Chan[chan].mPrevSamples, &SrcData[SrcDataEnd],
+                       len*sizeof(ALfloat));
+                memset(converter->Chan[chan].mPrevSamples+len, 0,
+                       sizeof(converter->Chan[chan].mPrevSamples) - len*sizeof(ALfloat));
+            }
+
+            /* Now resample, and store the result in the output buffer. */
+            ResampledData = converter->mResample(&converter->mState,
+                SrcData+MAX_RESAMPLE_PADDING, DataPosFrac, increment,
+                DstData, DstSize
+            );
+
+            StoreSamples(DstSamples, ResampledData, converter->mNumChannels,
+                         converter->mDstType, DstSize);
+        }
+
+        /* Update the number of prep samples still available, as well as the
+         * fractional offset.
+         */
+        DataPosFrac += increment*DstSize;
+        converter->mSrcPrepCount = mini(prepcount + toread - (DataPosFrac>>FRACTIONBITS),
+                                        MAX_RESAMPLE_PADDING*2);
+        converter->mFracOffset = DataPosFrac & FRACTIONMASK;
+
+        /* Update the src and dst pointers in case there's still more to do. */
+        *src = (const ALbyte*)*src + SrcFrameSize*(DataPosFrac>>FRACTIONBITS);
+        *srcframes -= mini(*srcframes, (DataPosFrac>>FRACTIONBITS));
+
+        dst = (ALbyte*)dst + DstFrameSize*DstSize;
+        pos += DstSize;
+    }
+    END_MIXER_MODE();
+
+    return pos;
+}
+
+
+ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans)
+{
+    ChannelConverter *converter;
+
+    if(srcChans != dstChans && !((srcChans == DevFmtMono && dstChans == DevFmtStereo) ||
+                                 (srcChans == DevFmtStereo && dstChans == DevFmtMono)))
+        return NULL;
+
+    converter = al_calloc(DEF_ALIGN, sizeof(*converter));
+    converter->mSrcType = srcType;
+    converter->mSrcChans = srcChans;
+    converter->mDstChans = dstChans;
+
+    return converter;
+}
+
+void DestroyChannelConverter(ChannelConverter **converter)
+{
+    if(converter)
+    {
+        al_free(*converter);
+        *converter = NULL;
+    }
+}
+
+
+#define DECL_TEMPLATE(T)                                                       \
+static void Mono2Stereo##T(ALfloat *restrict dst, const T *src, ALsizei frames)\
+{                                                                              \
+    ALsizei i;                                                                 \
+    for(i = 0;i < frames;i++)                                                  \
+        dst[i*2 + 1] = dst[i*2 + 0] = Sample_##T(src[i]) * 0.707106781187f;    \
+}                                                                              \
+                                                                               \
+static void Stereo2Mono##T(ALfloat *restrict dst, const T *src, ALsizei frames)\
+{                                                                              \
+    ALsizei i;                                                                 \
+    for(i = 0;i < frames;i++)                                                  \
+        dst[i] = (Sample_##T(src[i*2 + 0])+Sample_##T(src[i*2 + 1])) *         \
+                 0.707106781187f;                                              \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+
+#undef DECL_TEMPLATE
+
+void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames)
+{
+    if(converter->mSrcChans == converter->mDstChans)
+    {
+        LoadSamples(dst, src, 1, converter->mSrcType,
+                    frames*ChannelsFromDevFmt(converter->mSrcChans, 0));
+        return;
+    }
+
+    if(converter->mSrcChans == DevFmtStereo && converter->mDstChans == DevFmtMono)
+    {
+        switch(converter->mSrcType)
+        {
+            case DevFmtByte:
+                Stereo2MonoALbyte(dst, src, frames);
+                break;
+            case DevFmtUByte:
+                Stereo2MonoALubyte(dst, src, frames);
+                break;
+            case DevFmtShort:
+                Stereo2MonoALshort(dst, src, frames);
+                break;
+            case DevFmtUShort:
+                Stereo2MonoALushort(dst, src, frames);
+                break;
+            case DevFmtInt:
+                Stereo2MonoALint(dst, src, frames);
+                break;
+            case DevFmtUInt:
+                Stereo2MonoALuint(dst, src, frames);
+                break;
+            case DevFmtFloat:
+                Stereo2MonoALfloat(dst, src, frames);
+                break;
+        }
+    }
+    else /*if(converter->mSrcChans == DevFmtMono && converter->mDstChans == DevFmtStereo)*/
+    {
+        switch(converter->mSrcType)
+        {
+            case DevFmtByte:
+                Mono2StereoALbyte(dst, src, frames);
+                break;
+            case DevFmtUByte:
+                Mono2StereoALubyte(dst, src, frames);
+                break;
+            case DevFmtShort:
+                Mono2StereoALshort(dst, src, frames);
+                break;
+            case DevFmtUShort:
+                Mono2StereoALushort(dst, src, frames);
+                break;
+            case DevFmtInt:
+                Mono2StereoALint(dst, src, frames);
+                break;
+            case DevFmtUInt:
+                Mono2StereoALuint(dst, src, frames);
+                break;
+            case DevFmtFloat:
+                Mono2StereoALfloat(dst, src, frames);
+                break;
+        }
+    }
+}

+ 55 - 0
Engine/lib/openal-soft/Alc/converter.h

@@ -0,0 +1,55 @@
+#ifndef CONVERTER_H
+#define CONVERTER_H
+
+#include "alMain.h"
+#include "alu.h"
+
+#ifdef __cpluspluc
+extern "C" {
+#endif
+
+typedef struct SampleConverter {
+    enum DevFmtType mSrcType;
+    enum DevFmtType mDstType;
+    ALsizei mNumChannels;
+    ALsizei mSrcTypeSize;
+    ALsizei mDstTypeSize;
+
+    ALint mSrcPrepCount;
+
+    ALsizei mFracOffset;
+    ALsizei mIncrement;
+    InterpState mState;
+    ResamplerFunc mResample;
+
+    alignas(16) ALfloat mSrcSamples[BUFFERSIZE];
+    alignas(16) ALfloat mDstSamples[BUFFERSIZE];
+
+    struct {
+        alignas(16) ALfloat mPrevSamples[MAX_RESAMPLE_PADDING*2];
+    } Chan[];
+} SampleConverter;
+
+SampleConverter *CreateSampleConverter(enum DevFmtType srcType, enum DevFmtType dstType, ALsizei numchans, ALsizei srcRate, ALsizei dstRate);
+void DestroySampleConverter(SampleConverter **converter);
+
+ALsizei SampleConverterInput(SampleConverter *converter, const ALvoid **src, ALsizei *srcframes, ALvoid *dst, ALsizei dstframes);
+ALsizei SampleConverterAvailableOut(SampleConverter *converter, ALsizei srcframes);
+
+
+typedef struct ChannelConverter {
+    enum DevFmtType mSrcType;
+    enum DevFmtChannels mSrcChans;
+    enum DevFmtChannels mDstChans;
+} ChannelConverter;
+
+ChannelConverter *CreateChannelConverter(enum DevFmtType srcType, enum DevFmtChannels srcChans, enum DevFmtChannels dstChans);
+void DestroyChannelConverter(ChannelConverter **converter);
+
+void ChannelConverterInput(ChannelConverter *converter, const ALvoid *src, ALfloat *dst, ALsizei frames);
+
+#ifdef __cpluspluc
+}
+#endif
+
+#endif /* CONVERTER_H */

+ 15 - 0
Engine/lib/openal-soft/Alc/cpu_caps.h

@@ -0,0 +1,15 @@
+#ifndef CPU_CAPS_H
+#define CPU_CAPS_H
+
+extern int CPUCapFlags;
+enum {
+    CPU_CAP_SSE    = 1<<0,
+    CPU_CAP_SSE2   = 1<<1,
+    CPU_CAP_SSE3   = 1<<2,
+    CPU_CAP_SSE4_1 = 1<<3,
+    CPU_CAP_NEON   = 1<<4,
+};
+
+void FillCPUCaps(int capfilter);
+
+#endif /* CPU_CAPS_H */

+ 299 - 156
Engine/lib/openal-soft/Alc/effects/chorus.c

@@ -24,32 +24,40 @@
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "alMain.h"
 #include "alMain.h"
-#include "alFilter.h"
 #include "alAuxEffectSlot.h"
 #include "alAuxEffectSlot.h"
 #include "alError.h"
 #include "alError.h"
 #include "alu.h"
 #include "alu.h"
+#include "filters/defs.h"
 
 
 
 
-enum ChorusWaveForm {
-    CWF_Triangle = AL_CHORUS_WAVEFORM_TRIANGLE,
-    CWF_Sinusoid = AL_CHORUS_WAVEFORM_SINUSOID
+static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch");
+static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
+
+enum WaveForm {
+    WF_Sinusoid,
+    WF_Triangle
 };
 };
 
 
 typedef struct ALchorusState {
 typedef struct ALchorusState {
     DERIVE_FROM_TYPE(ALeffectState);
     DERIVE_FROM_TYPE(ALeffectState);
 
 
-    ALfloat *SampleBuffer[2];
-    ALuint BufferLength;
-    ALuint offset;
-    ALuint lfo_range;
+    ALfloat *SampleBuffer;
+    ALsizei BufferLength;
+    ALsizei offset;
+
+    ALsizei lfo_offset;
+    ALsizei lfo_range;
     ALfloat lfo_scale;
     ALfloat lfo_scale;
     ALint lfo_disp;
     ALint lfo_disp;
 
 
     /* Gains for left and right sides */
     /* Gains for left and right sides */
-    ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
+    struct {
+        ALfloat Current[MAX_OUTPUT_CHANNELS];
+        ALfloat Target[MAX_OUTPUT_CHANNELS];
+    } Gains[2];
 
 
     /* effect parameters */
     /* effect parameters */
-    enum ChorusWaveForm waveform;
+    enum WaveForm waveform;
     ALint delay;
     ALint delay;
     ALfloat depth;
     ALfloat depth;
     ALfloat feedback;
     ALfloat feedback;
@@ -57,8 +65,8 @@ typedef struct ALchorusState {
 
 
 static ALvoid ALchorusState_Destruct(ALchorusState *state);
 static ALvoid ALchorusState_Destruct(ALchorusState *state);
 static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device);
 static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device);
-static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
-static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
+static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props);
+static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
 DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
 DECLARE_DEFAULT_ALLOCATORS(ALchorusState)
 
 
 DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
 DEFINE_ALEFFECTSTATE_VTABLE(ALchorusState);
@@ -70,54 +78,51 @@ static void ALchorusState_Construct(ALchorusState *state)
     SET_VTABLE2(ALchorusState, ALeffectState, state);
     SET_VTABLE2(ALchorusState, ALeffectState, state);
 
 
     state->BufferLength = 0;
     state->BufferLength = 0;
-    state->SampleBuffer[0] = NULL;
-    state->SampleBuffer[1] = NULL;
+    state->SampleBuffer = NULL;
     state->offset = 0;
     state->offset = 0;
+    state->lfo_offset = 0;
     state->lfo_range = 1;
     state->lfo_range = 1;
-    state->waveform = CWF_Triangle;
+    state->waveform = WF_Triangle;
 }
 }
 
 
 static ALvoid ALchorusState_Destruct(ALchorusState *state)
 static ALvoid ALchorusState_Destruct(ALchorusState *state)
 {
 {
-    al_free(state->SampleBuffer[0]);
-    state->SampleBuffer[0] = NULL;
-    state->SampleBuffer[1] = NULL;
+    al_free(state->SampleBuffer);
+    state->SampleBuffer = NULL;
 
 
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
 }
 }
 
 
 static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
 static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Device)
 {
 {
-    ALuint maxlen;
-    ALuint it;
+    const ALfloat max_delay = maxf(AL_CHORUS_MAX_DELAY, AL_FLANGER_MAX_DELAY);
+    ALsizei maxlen;
 
 
-    maxlen = fastf2u(AL_CHORUS_MAX_DELAY * 3.0f * Device->Frequency) + 1;
-    maxlen = NextPowerOf2(maxlen);
+    maxlen = NextPowerOf2(float2int(max_delay*2.0f*Device->Frequency) + 1u);
+    if(maxlen <= 0) return AL_FALSE;
 
 
     if(maxlen != state->BufferLength)
     if(maxlen != state->BufferLength)
     {
     {
-        void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2);
+        void *temp = al_calloc(16, maxlen * sizeof(ALfloat));
         if(!temp) return AL_FALSE;
         if(!temp) return AL_FALSE;
 
 
-        al_free(state->SampleBuffer[0]);
-        state->SampleBuffer[0] = temp;
-        state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
+        al_free(state->SampleBuffer);
+        state->SampleBuffer = temp;
 
 
         state->BufferLength = maxlen;
         state->BufferLength = maxlen;
     }
     }
 
 
-    for(it = 0;it < state->BufferLength;it++)
-    {
-        state->SampleBuffer[0][it] = 0.0f;
-        state->SampleBuffer[1][it] = 0.0f;
-    }
+    memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat));
+    memset(state->Gains, 0, sizeof(state->Gains));
 
 
     return AL_TRUE;
     return AL_TRUE;
 }
 }
 
 
-static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
+static ALvoid ALchorusState_update(ALchorusState *state, const ALCcontext *Context, const ALeffectslot *Slot, const ALeffectProps *props)
 {
 {
-    ALfloat frequency = (ALfloat)Device->Frequency;
+    const ALsizei mindelay = MAX_RESAMPLE_PADDING << FRACTIONBITS;
+    const ALCdevice *device = Context->Device;
+    ALfloat frequency = (ALfloat)device->Frequency;
     ALfloat coeffs[MAX_AMBI_COEFFS];
     ALfloat coeffs[MAX_AMBI_COEFFS];
     ALfloat rate;
     ALfloat rate;
     ALint phase;
     ALint phase;
@@ -125,156 +130,166 @@ static ALvoid ALchorusState_update(ALchorusState *state, const ALCdevice *Device
     switch(props->Chorus.Waveform)
     switch(props->Chorus.Waveform)
     {
     {
         case AL_CHORUS_WAVEFORM_TRIANGLE:
         case AL_CHORUS_WAVEFORM_TRIANGLE:
-            state->waveform = CWF_Triangle;
+            state->waveform = WF_Triangle;
             break;
             break;
         case AL_CHORUS_WAVEFORM_SINUSOID:
         case AL_CHORUS_WAVEFORM_SINUSOID:
-            state->waveform = CWF_Sinusoid;
+            state->waveform = WF_Sinusoid;
             break;
             break;
     }
     }
-    state->depth = props->Chorus.Depth;
+
+    /* The LFO depth is scaled to be relative to the sample delay. Clamp the
+     * delay and depth to allow enough padding for resampling.
+     */
+    state->delay = maxi(float2int(props->Chorus.Delay*frequency*FRACTIONONE + 0.5f),
+                        mindelay);
+    state->depth = minf(props->Chorus.Depth * state->delay,
+                        (ALfloat)(state->delay - mindelay));
+
     state->feedback = props->Chorus.Feedback;
     state->feedback = props->Chorus.Feedback;
-    state->delay = fastf2i(props->Chorus.Delay * frequency);
 
 
     /* Gains for left and right sides */
     /* Gains for left and right sides */
-    CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs);
-    ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
-    CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs);
-    ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
+    CalcAngleCoeffs(-F_PI_2, 0.0f, 0.0f, coeffs);
+    ComputeDryPanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[0].Target);
+    CalcAngleCoeffs( F_PI_2, 0.0f, 0.0f, coeffs);
+    ComputeDryPanGains(&device->Dry, coeffs, Slot->Params.Gain, state->Gains[1].Target);
 
 
     phase = props->Chorus.Phase;
     phase = props->Chorus.Phase;
     rate = props->Chorus.Rate;
     rate = props->Chorus.Rate;
     if(!(rate > 0.0f))
     if(!(rate > 0.0f))
     {
     {
-        state->lfo_scale = 0.0f;
+        state->lfo_offset = 0;
         state->lfo_range = 1;
         state->lfo_range = 1;
+        state->lfo_scale = 0.0f;
         state->lfo_disp = 0;
         state->lfo_disp = 0;
     }
     }
     else
     else
     {
     {
-        /* Calculate LFO coefficient */
-        state->lfo_range = fastf2u(frequency/rate + 0.5f);
+        /* Calculate LFO coefficient (number of samples per cycle). Limit the
+         * max range to avoid overflow when calculating the displacement.
+         */
+        ALsizei lfo_range = float2int(minf(frequency/rate + 0.5f, (ALfloat)(INT_MAX/360 - 180)));
+
+        state->lfo_offset = float2int((ALfloat)state->lfo_offset/state->lfo_range*
+                                      lfo_range + 0.5f) % lfo_range;
+        state->lfo_range = lfo_range;
         switch(state->waveform)
         switch(state->waveform)
         {
         {
-            case CWF_Triangle:
+            case WF_Triangle:
                 state->lfo_scale = 4.0f / state->lfo_range;
                 state->lfo_scale = 4.0f / state->lfo_range;
                 break;
                 break;
-            case CWF_Sinusoid:
+            case WF_Sinusoid:
                 state->lfo_scale = F_TAU / state->lfo_range;
                 state->lfo_scale = F_TAU / state->lfo_range;
                 break;
                 break;
         }
         }
 
 
         /* Calculate lfo phase displacement */
         /* Calculate lfo phase displacement */
-        state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
+        if(phase < 0) phase = 360 + phase;
+        state->lfo_disp = (state->lfo_range*phase + 180) / 360;
     }
     }
 }
 }
 
 
-static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state)
+static void GetTriangleDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
+                              const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
+                              const ALsizei todo)
 {
 {
-    ALfloat lfo_value;
-
-    lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
-    lfo_value *= state->depth * state->delay;
-    *delay_left = fastf2i(lfo_value) + state->delay;
-
-    offset += state->lfo_disp;
-    lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
-    lfo_value *= state->depth * state->delay;
-    *delay_right = fastf2i(lfo_value) + state->delay;
+    ALsizei i;
+    for(i = 0;i < todo;i++)
+    {
+        delays[i] = fastf2i((1.0f - fabsf(2.0f - lfo_scale*offset)) * depth) + delay;
+        offset = (offset+1)%lfo_range;
+    }
 }
 }
 
 
-static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALchorusState *state)
+static void GetSinusoidDelays(ALint *restrict delays, ALsizei offset, const ALsizei lfo_range,
+                              const ALfloat lfo_scale, const ALfloat depth, const ALsizei delay,
+                              const ALsizei todo)
 {
 {
-    ALfloat lfo_value;
-
-    lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
-    lfo_value *= state->depth * state->delay;
-    *delay_left = fastf2i(lfo_value) + state->delay;
-
-    offset += state->lfo_disp;
-    lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
-    lfo_value *= state->depth * state->delay;
-    *delay_right = fastf2i(lfo_value) + state->delay;
-}
-
-#define DECL_TEMPLATE(Func)                                                   \
-static void Process##Func(ALchorusState *state, const ALuint SamplesToDo,     \
-  const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2])              \
-{                                                                             \
-    const ALuint bufmask = state->BufferLength-1;                             \
-    ALfloat *restrict leftbuf = state->SampleBuffer[0];                       \
-    ALfloat *restrict rightbuf = state->SampleBuffer[1];                      \
-    ALuint offset = state->offset;                                            \
-    const ALfloat feedback = state->feedback;                                 \
-    ALuint it;                                                                \
-                                                                              \
-    for(it = 0;it < SamplesToDo;it++)                                         \
-    {                                                                         \
-        ALint delay_left, delay_right;                                        \
-        Func(&delay_left, &delay_right, offset, state);                       \
-                                                                              \
-        out[it][0] = leftbuf[(offset-delay_left)&bufmask];                    \
-        leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback;      \
-                                                                              \
-        out[it][1] = rightbuf[(offset-delay_right)&bufmask];                  \
-        rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback;     \
-                                                                              \
-        offset++;                                                             \
-    }                                                                         \
-    state->offset = offset;                                                   \
+    ALsizei i;
+    for(i = 0;i < todo;i++)
+    {
+        delays[i] = fastf2i(sinf(lfo_scale*offset) * depth) + delay;
+        offset = (offset+1)%lfo_range;
+    }
 }
 }
 
 
-DECL_TEMPLATE(Triangle)
-DECL_TEMPLATE(Sinusoid)
-
-#undef DECL_TEMPLATE
 
 
-static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
+static ALvoid ALchorusState_process(ALchorusState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
 {
 {
-    ALuint it, kt;
-    ALuint base;
+    const ALsizei bufmask = state->BufferLength-1;
+    const ALfloat feedback = state->feedback;
+    const ALsizei avgdelay = (state->delay + (FRACTIONONE>>1)) >> FRACTIONBITS;
+    ALfloat *restrict delaybuf = state->SampleBuffer;
+    ALsizei offset = state->offset;
+    ALsizei i, c;
+    ALsizei base;
 
 
     for(base = 0;base < SamplesToDo;)
     for(base = 0;base < SamplesToDo;)
     {
     {
-        ALfloat temps[128][2];
-        ALuint td = minu(128, SamplesToDo-base);
+        const ALsizei todo = mini(256, SamplesToDo-base);
+        ALint moddelays[2][256];
+        alignas(16) ALfloat temps[2][256];
 
 
-        switch(state->waveform)
+        if(state->waveform == WF_Sinusoid)
         {
         {
-            case CWF_Triangle:
-                ProcessTriangle(state, td, SamplesIn[0]+base, temps);
-                break;
-            case CWF_Sinusoid:
-                ProcessSinusoid(state, td, SamplesIn[0]+base, temps);
-                break;
+            GetSinusoidDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale,
+                              state->depth, state->delay, todo);
+            GetSinusoidDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range,
+                              state->lfo_range, state->lfo_scale, state->depth, state->delay,
+                              todo);
         }
         }
+        else /*if(state->waveform == WF_Triangle)*/
+        {
+            GetTriangleDelays(moddelays[0], state->lfo_offset, state->lfo_range, state->lfo_scale,
+                              state->depth, state->delay, todo);
+            GetTriangleDelays(moddelays[1], (state->lfo_offset+state->lfo_disp)%state->lfo_range,
+                              state->lfo_range, state->lfo_scale, state->depth, state->delay,
+                              todo);
+        }
+        state->lfo_offset = (state->lfo_offset+todo) % state->lfo_range;
 
 
-        for(kt = 0;kt < NumChannels;kt++)
+        for(i = 0;i < todo;i++)
         {
         {
-            ALfloat gain = state->Gain[0][kt];
-            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(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
-            {
-                for(it = 0;it < td;it++)
-                    SamplesOut[kt][it+base] += temps[it][1] * gain;
-            }
+            ALint delay;
+            ALfloat mu;
+
+            // Feed the buffer's input first (necessary for delays < 1).
+            delaybuf[offset&bufmask] = SamplesIn[0][base+i];
+
+            // Tap for the left output.
+            delay = offset - (moddelays[0][i]>>FRACTIONBITS);
+            mu = (moddelays[0][i]&FRACTIONMASK) * (1.0f/FRACTIONONE);
+            temps[0][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay  ) & bufmask],
+                                delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask],
+                                mu);
+
+            // Tap for the right output.
+            delay = offset - (moddelays[1][i]>>FRACTIONBITS);
+            mu = (moddelays[1][i]&FRACTIONMASK) * (1.0f/FRACTIONONE);
+            temps[1][i] = cubic(delaybuf[(delay+1) & bufmask], delaybuf[(delay  ) & bufmask],
+                                delaybuf[(delay-1) & bufmask], delaybuf[(delay-2) & bufmask],
+                                mu);
+
+            // Accumulate feedback from the average delay of the taps.
+            delaybuf[offset&bufmask] += delaybuf[(offset-avgdelay) & bufmask] * feedback;
+            offset++;
         }
         }
 
 
-        base += td;
+        for(c = 0;c < 2;c++)
+            MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current,
+                       state->Gains[c].Target, SamplesToDo-base, base, todo);
+
+        base += todo;
     }
     }
+
+    state->offset = offset;
 }
 }
 
 
 
 
-typedef struct ALchorusStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALchorusStateFactory;
+typedef struct ChorusStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} ChorusStateFactory;
 
 
-static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(factory))
+static ALeffectState *ChorusStateFactory_create(ChorusStateFactory *UNUSED(factory))
 {
 {
     ALchorusState *state;
     ALchorusState *state;
 
 
@@ -284,14 +299,14 @@ static ALeffectState *ALchorusStateFactory_create(ALchorusStateFactory *UNUSED(f
     return STATIC_CAST(ALeffectState, state);
     return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALchorusStateFactory);
+DEFINE_EFFECTSTATEFACTORY_VTABLE(ChorusStateFactory);
 
 
 
 
-ALeffectStateFactory *ALchorusStateFactory_getFactory(void)
+EffectStateFactory *ChorusStateFactory_getFactory(void)
 {
 {
-    static ALchorusStateFactory ChorusFactory = { { GET_VTABLE2(ALchorusStateFactory, ALeffectStateFactory) } };
+    static ChorusStateFactory ChorusFactory = { { GET_VTABLE2(ChorusStateFactory, EffectStateFactory) } };
 
 
-    return STATIC_CAST(ALeffectStateFactory, &ChorusFactory);
+    return STATIC_CAST(EffectStateFactory, &ChorusFactory);
 }
 }
 
 
 
 
@@ -302,24 +317,22 @@ void ALchorus_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALi
     {
     {
         case AL_CHORUS_WAVEFORM:
         case AL_CHORUS_WAVEFORM:
             if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM))
             if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid chorus waveform");
             props->Chorus.Waveform = val;
             props->Chorus.Waveform = val;
             break;
             break;
 
 
         case AL_CHORUS_PHASE:
         case AL_CHORUS_PHASE:
             if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
             if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus phase out of range");
             props->Chorus.Phase = val;
             props->Chorus.Phase = val;
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param);
     }
     }
 }
 }
 void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
 void ALchorus_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
-    ALchorus_setParami(effect, context, param, vals[0]);
-}
+{ ALchorus_setParami(effect, context, param, vals[0]); }
 void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 {
 {
     ALeffectProps *props = &effect->Props;
     ALeffectProps *props = &effect->Props;
@@ -327,36 +340,34 @@ void ALchorus_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALf
     {
     {
         case AL_CHORUS_RATE:
         case AL_CHORUS_RATE:
             if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
             if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus rate out of range");
             props->Chorus.Rate = val;
             props->Chorus.Rate = val;
             break;
             break;
 
 
         case AL_CHORUS_DEPTH:
         case AL_CHORUS_DEPTH:
             if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
             if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus depth out of range");
             props->Chorus.Depth = val;
             props->Chorus.Depth = val;
             break;
             break;
 
 
         case AL_CHORUS_FEEDBACK:
         case AL_CHORUS_FEEDBACK:
             if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
             if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus feedback out of range");
             props->Chorus.Feedback = val;
             props->Chorus.Feedback = val;
             break;
             break;
 
 
         case AL_CHORUS_DELAY:
         case AL_CHORUS_DELAY:
             if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
             if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Chorus delay out of range");
             props->Chorus.Delay = val;
             props->Chorus.Delay = val;
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param);
     }
     }
 }
 }
 void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
 void ALchorus_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
-    ALchorus_setParamf(effect, context, param, vals[0]);
-}
+{ ALchorus_setParamf(effect, context, param, vals[0]); }
 
 
 void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
 void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
 {
 {
@@ -372,13 +383,11 @@ void ALchorus_getParami(const ALeffect *effect, ALCcontext *context, ALenum para
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid chorus integer property 0x%04x", param);
     }
     }
 }
 }
 void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
 void ALchorus_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
-    ALchorus_getParami(effect, context, param, vals);
-}
+{ ALchorus_getParami(effect, context, param, vals); }
 void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 {
 {
     const ALeffectProps *props = &effect->Props;
     const ALeffectProps *props = &effect->Props;
@@ -401,12 +410,146 @@ void ALchorus_getParamf(const ALeffect *effect, ALCcontext *context, ALenum para
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid chorus float property 0x%04x", param);
     }
     }
 }
 }
 void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
 void ALchorus_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{ ALchorus_getParamf(effect, context, param, vals); }
+
+DEFINE_ALEFFECT_VTABLE(ALchorus);
+
+
+/* Flanger is basically a chorus with a really short delay. They can both use
+ * the same processing functions, so piggyback flanger on the chorus functions.
+ */
+typedef struct FlangerStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} FlangerStateFactory;
+
+ALeffectState *FlangerStateFactory_create(FlangerStateFactory *UNUSED(factory))
 {
 {
-    ALchorus_getParamf(effect, context, param, vals);
+    ALchorusState *state;
+
+    NEW_OBJ0(state, ALchorusState)();
+    if(!state) return NULL;
+
+    return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-DEFINE_ALEFFECT_VTABLE(ALchorus);
+DEFINE_EFFECTSTATEFACTORY_VTABLE(FlangerStateFactory);
+
+EffectStateFactory *FlangerStateFactory_getFactory(void)
+{
+    static FlangerStateFactory FlangerFactory = { { GET_VTABLE2(FlangerStateFactory, EffectStateFactory) } };
+
+    return STATIC_CAST(EffectStateFactory, &FlangerFactory);
+}
+
+
+void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
+{
+    ALeffectProps *props = &effect->Props;
+    switch(param)
+    {
+        case AL_FLANGER_WAVEFORM:
+            if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid flanger waveform");
+            props->Chorus.Waveform = val;
+            break;
+
+        case AL_FLANGER_PHASE:
+            if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger phase out of range");
+            props->Chorus.Phase = val;
+            break;
+
+        default:
+            alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param);
+    }
+}
+void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{ ALflanger_setParami(effect, context, param, vals[0]); }
+void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
+{
+    ALeffectProps *props = &effect->Props;
+    switch(param)
+    {
+        case AL_FLANGER_RATE:
+            if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger rate out of range");
+            props->Chorus.Rate = val;
+            break;
+
+        case AL_FLANGER_DEPTH:
+            if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger depth out of range");
+            props->Chorus.Depth = val;
+            break;
+
+        case AL_FLANGER_FEEDBACK:
+            if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger feedback out of range");
+            props->Chorus.Feedback = val;
+            break;
+
+        case AL_FLANGER_DELAY:
+            if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Flanger delay out of range");
+            props->Chorus.Delay = val;
+            break;
+
+        default:
+            alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param);
+    }
+}
+void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
+{ ALflanger_setParamf(effect, context, param, vals[0]); }
+
+void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
+{
+    const ALeffectProps *props = &effect->Props;
+    switch(param)
+    {
+        case AL_FLANGER_WAVEFORM:
+            *val = props->Chorus.Waveform;
+            break;
+
+        case AL_FLANGER_PHASE:
+            *val = props->Chorus.Phase;
+            break;
+
+        default:
+            alSetError(context, AL_INVALID_ENUM, "Invalid flanger integer property 0x%04x", param);
+    }
+}
+void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{ ALflanger_getParami(effect, context, param, vals); }
+void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
+{
+    const ALeffectProps *props = &effect->Props;
+    switch(param)
+    {
+        case AL_FLANGER_RATE:
+            *val = props->Chorus.Rate;
+            break;
+
+        case AL_FLANGER_DEPTH:
+            *val = props->Chorus.Depth;
+            break;
+
+        case AL_FLANGER_FEEDBACK:
+            *val = props->Chorus.Feedback;
+            break;
+
+        case AL_FLANGER_DELAY:
+            *val = props->Chorus.Delay;
+            break;
+
+        default:
+            alSetError(context, AL_INVALID_ENUM, "Invalid flanger float property 0x%04x", param);
+    }
+}
+void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
+{ ALflanger_getParamf(effect, context, param, vals); }
+
+DEFINE_ALEFFECT_VTABLE(ALflanger);

+ 34 - 38
Engine/lib/openal-soft/Alc/effects/compressor.c

@@ -42,8 +42,8 @@ typedef struct ALcompressorState {
 
 
 static ALvoid ALcompressorState_Destruct(ALcompressorState *state);
 static ALvoid ALcompressorState_Destruct(ALcompressorState *state);
 static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device);
 static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdevice *device);
-static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
-static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
+static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
+static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
 DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
 DECLARE_DEFAULT_ALLOCATORS(ALcompressorState)
 
 
 DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
 DEFINE_ALEFFECTSTATE_VTABLE(ALcompressorState);
@@ -76,8 +76,9 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev
     return AL_TRUE;
     return AL_TRUE;
 }
 }
 
 
-static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
+static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
 {
 {
+    const ALCdevice *device = context->Device;
     ALuint i;
     ALuint i;
 
 
     state->Enabled = props->Compressor.OnOff;
     state->Enabled = props->Compressor.OnOff;
@@ -85,19 +86,19 @@ static ALvoid ALcompressorState_update(ALcompressorState *state, const ALCdevice
     STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
     STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
     STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
     STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
     for(i = 0;i < 4;i++)
     for(i = 0;i < 4;i++)
-        ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i],
+        ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i],
                                slot->Params.Gain, state->Gain[i]);
                                slot->Params.Gain, state->Gain[i]);
 }
 }
 
 
-static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
+static ALvoid ALcompressorState_process(ALcompressorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
 {
 {
-    ALuint i, j, k;
-    ALuint base;
+    ALsizei i, j, k;
+    ALsizei base;
 
 
     for(base = 0;base < SamplesToDo;)
     for(base = 0;base < SamplesToDo;)
     {
     {
         ALfloat temps[64][4];
         ALfloat temps[64][4];
-        ALuint td = minu(64, SamplesToDo-base);
+        ALsizei td = mini(64, SamplesToDo-base);
 
 
         /* Load samples into the temp buffer first. */
         /* Load samples into the temp buffer first. */
         for(j = 0;j < 4;j++)
         for(j = 0;j < 4;j++)
@@ -178,11 +179,11 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples
 }
 }
 
 
 
 
-typedef struct ALcompressorStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALcompressorStateFactory;
+typedef struct CompressorStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} CompressorStateFactory;
 
 
-static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *UNUSED(factory))
+static ALeffectState *CompressorStateFactory_create(CompressorStateFactory *UNUSED(factory))
 {
 {
     ALcompressorState *state;
     ALcompressorState *state;
 
 
@@ -192,13 +193,13 @@ static ALeffectState *ALcompressorStateFactory_create(ALcompressorStateFactory *
     return STATIC_CAST(ALeffectState, state);
     return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALcompressorStateFactory);
+DEFINE_EFFECTSTATEFACTORY_VTABLE(CompressorStateFactory);
 
 
-ALeffectStateFactory *ALcompressorStateFactory_getFactory(void)
+EffectStateFactory *CompressorStateFactory_getFactory(void)
 {
 {
-    static ALcompressorStateFactory CompressorFactory = { { GET_VTABLE2(ALcompressorStateFactory, ALeffectStateFactory) } };
+    static CompressorStateFactory CompressorFactory = { { GET_VTABLE2(CompressorStateFactory, EffectStateFactory) } };
 
 
-    return STATIC_CAST(ALeffectStateFactory, &CompressorFactory);
+    return STATIC_CAST(EffectStateFactory, &CompressorFactory);
 }
 }
 
 
 
 
@@ -209,24 +210,21 @@ void ALcompressor_setParami(ALeffect *effect, ALCcontext *context, ALenum param,
     {
     {
         case AL_COMPRESSOR_ONOFF:
         case AL_COMPRESSOR_ONOFF:
             if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
             if(!(val >= AL_COMPRESSOR_MIN_ONOFF && val <= AL_COMPRESSOR_MAX_ONOFF))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Compressor state out of range");
             props->Compressor.OnOff = val;
             props->Compressor.OnOff = val;
             break;
             break;
 
 
-    default:
-        SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+        default:
+            alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x",
+                       param);
     }
     }
 }
 }
 void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
 void ALcompressor_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
-    ALcompressor_setParami(effect, context, param, vals[0]);
-}
-void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALcompressor_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
-    ALcompressor_setParamf(effect, context, param, vals[0]);
-}
+{ ALcompressor_setParami(effect, context, param, vals[0]); }
+void ALcompressor_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); }
+void ALcompressor_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); }
 
 
 void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
 void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
 { 
 { 
@@ -236,19 +234,17 @@ void ALcompressor_getParami(const ALeffect *effect, ALCcontext *context, ALenum
         case AL_COMPRESSOR_ONOFF:
         case AL_COMPRESSOR_ONOFF:
             *val = props->Compressor.OnOff;
             *val = props->Compressor.OnOff;
             break;
             break;
+
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid compressor integer property 0x%04x",
+                       param);
     }
     }
 }
 }
 void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
 void ALcompressor_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
-    ALcompressor_getParami(effect, context, param, vals);
-}
-void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALfloat *UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALcompressor_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
-    ALcompressor_getParamf(effect, context, param, vals);
-}
+{ ALcompressor_getParami(effect, context, param, vals); }
+void ALcompressor_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float property 0x%04x", param); }
+void ALcompressor_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid compressor float-vector property 0x%04x", param); }
 
 
 DEFINE_ALEFFECT_VTABLE(ALcompressor);
 DEFINE_ALEFFECT_VTABLE(ALcompressor);

+ 46 - 63
Engine/lib/openal-soft/Alc/effects/dedicated.c

@@ -23,22 +23,23 @@
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "alMain.h"
 #include "alMain.h"
-#include "alFilter.h"
 #include "alAuxEffectSlot.h"
 #include "alAuxEffectSlot.h"
 #include "alError.h"
 #include "alError.h"
 #include "alu.h"
 #include "alu.h"
+#include "filters/defs.h"
 
 
 
 
 typedef struct ALdedicatedState {
 typedef struct ALdedicatedState {
     DERIVE_FROM_TYPE(ALeffectState);
     DERIVE_FROM_TYPE(ALeffectState);
 
 
-    ALfloat gains[MAX_OUTPUT_CHANNELS];
+    ALfloat CurrentGains[MAX_OUTPUT_CHANNELS];
+    ALfloat TargetGains[MAX_OUTPUT_CHANNELS];
 } ALdedicatedState;
 } ALdedicatedState;
 
 
 static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state);
 static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state);
 static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device);
 static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *device);
-static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props);
-static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
+static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
+static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
 DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState)
 DECLARE_DEFAULT_ALLOCATORS(ALdedicatedState)
 
 
 DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
 DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
@@ -46,13 +47,8 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALdedicatedState);
 
 
 static void ALdedicatedState_Construct(ALdedicatedState *state)
 static void ALdedicatedState_Construct(ALdedicatedState *state)
 {
 {
-    ALsizei s;
-
     ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
     ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
     SET_VTABLE2(ALdedicatedState, ALeffectState, state);
     SET_VTABLE2(ALdedicatedState, ALeffectState, state);
-
-    for(s = 0;s < MAX_OUTPUT_CHANNELS;s++)
-        state->gains[s] = 0.0f;
 }
 }
 
 
 static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state)
 static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state)
@@ -60,74 +56,69 @@ static ALvoid ALdedicatedState_Destruct(ALdedicatedState *state)
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
 }
 }
 
 
-static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), ALCdevice *UNUSED(device))
+static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *state, ALCdevice *UNUSED(device))
 {
 {
+    ALsizei i;
+    for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+        state->CurrentGains[i] = 0.0f;
     return AL_TRUE;
     return AL_TRUE;
 }
 }
 
 
-static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCdevice *device, const ALeffectslot *Slot, const ALeffectProps *props)
+static ALvoid ALdedicatedState_update(ALdedicatedState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
 {
 {
+    const ALCdevice *device = context->Device;
     ALfloat Gain;
     ALfloat Gain;
-    ALuint i;
+    ALsizei i;
 
 
     for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
     for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
-        state->gains[i] = 0.0f;
+        state->TargetGains[i] = 0.0f;
 
 
-    Gain = Slot->Params.Gain * props->Dedicated.Gain;
-    if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
+    Gain = slot->Params.Gain * props->Dedicated.Gain;
+    if(slot->Params.EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
     {
     {
         int idx;
         int idx;
-        if((idx=GetChannelIdxByName(device->RealOut, LFE)) != -1)
+        if((idx=GetChannelIdxByName(&device->RealOut, LFE)) != -1)
         {
         {
             STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer;
             STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer;
             STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels;
             STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels;
-            state->gains[idx] = Gain;
+            state->TargetGains[idx] = Gain;
         }
         }
     }
     }
-    else if(Slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
+    else if(slot->Params.EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
     {
     {
         int idx;
         int idx;
         /* Dialog goes to the front-center speaker if it exists, otherwise it
         /* Dialog goes to the front-center speaker if it exists, otherwise it
          * plays from the front-center location. */
          * plays from the front-center location. */
-        if((idx=GetChannelIdxByName(device->RealOut, FrontCenter)) != -1)
+        if((idx=GetChannelIdxByName(&device->RealOut, FrontCenter)) != -1)
         {
         {
             STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer;
             STATIC_CAST(ALeffectState,state)->OutBuffer = device->RealOut.Buffer;
             STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels;
             STATIC_CAST(ALeffectState,state)->OutChannels = device->RealOut.NumChannels;
-            state->gains[idx] = Gain;
+            state->TargetGains[idx] = Gain;
         }
         }
         else
         else
         {
         {
             ALfloat coeffs[MAX_AMBI_COEFFS];
             ALfloat coeffs[MAX_AMBI_COEFFS];
-            CalcXYZCoeffs(0.0f, 0.0f, -1.0f, 0.0f, coeffs);
+            CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
 
 
             STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer;
             STATIC_CAST(ALeffectState,state)->OutBuffer = device->Dry.Buffer;
             STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels;
             STATIC_CAST(ALeffectState,state)->OutChannels = device->Dry.NumChannels;
-            ComputePanningGains(device->Dry, coeffs, Gain, state->gains);
+            ComputeDryPanGains(&device->Dry, coeffs, Gain, state->TargetGains);
         }
         }
     }
     }
 }
 }
 
 
-static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
+static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
 {
 {
-    const ALfloat *gains = state->gains;
-    ALuint i, c;
-
-    for(c = 0;c < NumChannels;c++)
-    {
-        if(!(fabsf(gains[c]) > GAIN_SILENCE_THRESHOLD))
-            continue;
-
-        for(i = 0;i < SamplesToDo;i++)
-            SamplesOut[c][i] += SamplesIn[0][i] * gains[c];
-    }
+    MixSamples(SamplesIn[0], NumChannels, SamplesOut, state->CurrentGains,
+               state->TargetGains, SamplesToDo, 0, SamplesToDo);
 }
 }
 
 
 
 
-typedef struct ALdedicatedStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALdedicatedStateFactory;
+typedef struct DedicatedStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} DedicatedStateFactory;
 
 
-ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(factory))
+ALeffectState *DedicatedStateFactory_create(DedicatedStateFactory *UNUSED(factory))
 {
 {
     ALdedicatedState *state;
     ALdedicatedState *state;
 
 
@@ -137,23 +128,21 @@ ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(fa
     return STATIC_CAST(ALeffectState, state);
     return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdedicatedStateFactory);
+DEFINE_EFFECTSTATEFACTORY_VTABLE(DedicatedStateFactory);
 
 
 
 
-ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void)
+EffectStateFactory *DedicatedStateFactory_getFactory(void)
 {
 {
-    static ALdedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(ALdedicatedStateFactory, ALeffectStateFactory) } };
+    static DedicatedStateFactory DedicatedFactory = { { GET_VTABLE2(DedicatedStateFactory, EffectStateFactory) } };
 
 
-    return STATIC_CAST(ALeffectStateFactory, &DedicatedFactory);
+    return STATIC_CAST(EffectStateFactory, &DedicatedFactory);
 }
 }
 
 
 
 
-void ALdedicated_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALdedicated_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
-    ALdedicated_setParami(effect, context, param, vals[0]);
-}
+void ALdedicated_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); }
+void ALdedicated_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); }
 void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 {
 {
     ALeffectProps *props = &effect->Props;
     ALeffectProps *props = &effect->Props;
@@ -161,25 +150,21 @@ void ALdedicated_setParamf(ALeffect *effect, ALCcontext *context, ALenum param,
     {
     {
         case AL_DEDICATED_GAIN:
         case AL_DEDICATED_GAIN:
             if(!(val >= 0.0f && isfinite(val)))
             if(!(val >= 0.0f && isfinite(val)))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Dedicated gain out of range");
             props->Dedicated.Gain = val;
             props->Dedicated.Gain = val;
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param);
     }
     }
 }
 }
 void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
 void ALdedicated_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
-    ALdedicated_setParamf(effect, context, param, vals[0]);
-}
+{ ALdedicated_setParamf(effect, context, param, vals[0]); }
 
 
-void ALdedicated_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALdedicated_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
-    ALdedicated_getParami(effect, context, param, vals);
-}
+void ALdedicated_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer property 0x%04x", param); }
+void ALdedicated_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid dedicated integer-vector property 0x%04x", param); }
 void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 {
 {
     const ALeffectProps *props = &effect->Props;
     const ALeffectProps *props = &effect->Props;
@@ -190,12 +175,10 @@ void ALdedicated_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid dedicated float property 0x%04x", param);
     }
     }
 }
 }
 void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
 void ALdedicated_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
-    ALdedicated_getParamf(effect, context, param, vals);
-}
+{ ALdedicated_getParamf(effect, context, param, vals); }
 
 
 DEFINE_ALEFFECT_VTABLE(ALdedicated);
 DEFINE_ALEFFECT_VTABLE(ALdedicated);

+ 96 - 107
Engine/lib/openal-soft/Alc/effects/distortion.c

@@ -24,10 +24,10 @@
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "alMain.h"
 #include "alMain.h"
-#include "alFilter.h"
 #include "alAuxEffectSlot.h"
 #include "alAuxEffectSlot.h"
 #include "alError.h"
 #include "alError.h"
 #include "alu.h"
 #include "alu.h"
+#include "filters/defs.h"
 
 
 
 
 typedef struct ALdistortionState {
 typedef struct ALdistortionState {
@@ -37,16 +37,18 @@ typedef struct ALdistortionState {
     ALfloat Gain[MAX_OUTPUT_CHANNELS];
     ALfloat Gain[MAX_OUTPUT_CHANNELS];
 
 
     /* Effect parameters */
     /* Effect parameters */
-    ALfilterState lowpass;
-    ALfilterState bandpass;
+    BiquadFilter lowpass;
+    BiquadFilter bandpass;
     ALfloat attenuation;
     ALfloat attenuation;
     ALfloat edge_coeff;
     ALfloat edge_coeff;
+
+    ALfloat Buffer[2][BUFFERSIZE];
 } ALdistortionState;
 } ALdistortionState;
 
 
 static ALvoid ALdistortionState_Destruct(ALdistortionState *state);
 static ALvoid ALdistortionState_Destruct(ALdistortionState *state);
 static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device);
 static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *device);
-static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
-static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
+static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
+static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
 DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
 DECLARE_DEFAULT_ALLOCATORS(ALdistortionState)
 
 
 DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
 DEFINE_ALEFFECTSTATE_VTABLE(ALdistortionState);
@@ -56,9 +58,6 @@ static void ALdistortionState_Construct(ALdistortionState *state)
 {
 {
     ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
     ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
     SET_VTABLE2(ALdistortionState, ALeffectState, state);
     SET_VTABLE2(ALdistortionState, ALeffectState, state);
-
-    ALfilterState_clear(&state->lowpass);
-    ALfilterState_clear(&state->bandpass);
 }
 }
 
 
 static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
 static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
@@ -66,125 +65,121 @@ static ALvoid ALdistortionState_Destruct(ALdistortionState *state)
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
 }
 }
 
 
-static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *UNUSED(state), ALCdevice *UNUSED(device))
+static ALboolean ALdistortionState_deviceUpdate(ALdistortionState *state, ALCdevice *UNUSED(device))
 {
 {
+    BiquadFilter_clear(&state->lowpass);
+    BiquadFilter_clear(&state->bandpass);
     return AL_TRUE;
     return AL_TRUE;
 }
 }
 
 
-static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
+static ALvoid ALdistortionState_update(ALdistortionState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
 {
 {
-    ALfloat frequency = (ALfloat)Device->Frequency;
+    const ALCdevice *device = context->Device;
+    ALfloat frequency = (ALfloat)device->Frequency;
+    ALfloat coeffs[MAX_AMBI_COEFFS];
     ALfloat bandwidth;
     ALfloat bandwidth;
     ALfloat cutoff;
     ALfloat cutoff;
     ALfloat edge;
     ALfloat edge;
 
 
-    /* Store distorted signal attenuation settings */
-    state->attenuation = props->Distortion.Gain;
-
-    /* Store waveshaper edge settings */
+    /* Store waveshaper edge settings. */
     edge = sinf(props->Distortion.Edge * (F_PI_2));
     edge = sinf(props->Distortion.Edge * (F_PI_2));
     edge = minf(edge, 0.99f);
     edge = minf(edge, 0.99f);
     state->edge_coeff = 2.0f * edge / (1.0f-edge);
     state->edge_coeff = 2.0f * edge / (1.0f-edge);
 
 
-    /* Lowpass filter */
     cutoff = props->Distortion.LowpassCutoff;
     cutoff = props->Distortion.LowpassCutoff;
-    /* Bandwidth value is constant in octaves */
+    /* Bandwidth value is constant in octaves. */
     bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
     bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
-    ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
+    /* Multiply sampling frequency by the amount of oversampling done during
+     * processing.
+     */
+    BiquadFilter_setParams(&state->lowpass, BiquadType_LowPass, 1.0f,
         cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
         cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
     );
     );
 
 
-    /* Bandpass filter */
     cutoff = props->Distortion.EQCenter;
     cutoff = props->Distortion.EQCenter;
-    /* Convert bandwidth in Hz to octaves */
+    /* Convert bandwidth in Hz to octaves. */
     bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f);
     bandwidth = props->Distortion.EQBandwidth / (cutoff * 0.67f);
-    ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
+    BiquadFilter_setParams(&state->bandpass, BiquadType_BandPass, 1.0f,
         cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
         cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
     );
     );
 
 
-    ComputeAmbientGains(Device->Dry, Slot->Params.Gain, state->Gain);
+    CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
+    ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain * props->Distortion.Gain,
+                       state->Gain);
 }
 }
 
 
-static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
+static ALvoid ALdistortionState_process(ALdistortionState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
 {
 {
+    ALfloat (*restrict buffer)[BUFFERSIZE] = state->Buffer;
     const ALfloat fc = state->edge_coeff;
     const ALfloat fc = state->edge_coeff;
-    ALuint base;
-    ALuint it;
-    ALuint ot;
-    ALuint kt;
+    ALsizei base;
+    ALsizei i, k;
 
 
     for(base = 0;base < SamplesToDo;)
     for(base = 0;base < SamplesToDo;)
     {
     {
-        float buffer[2][64 * 4];
-        ALuint td = minu(64, SamplesToDo-base);
-
-        /* Perform 4x oversampling to avoid aliasing.   */
-        /* Oversampling greatly improves distortion     */
-        /* quality and allows to implement lowpass and  */
-        /* bandpass filters using high frequencies, at  */
-        /* which classic IIR filters became unstable.   */
-
-        /* Fill oversample buffer using zero stuffing */
-        for(it = 0;it < td;it++)
-        {
-            buffer[0][it*4 + 0] = SamplesIn[0][it+base];
-            buffer[0][it*4 + 1] = 0.0f;
-            buffer[0][it*4 + 2] = 0.0f;
-            buffer[0][it*4 + 3] = 0.0f;
-        }
-
-        /* First step, do lowpass filtering of original signal,  */
-        /* additionally perform buffer interpolation and lowpass */
-        /* cutoff for oversampling (which is fortunately first   */
-        /* step of distortion). So combine three operations into */
-        /* the one.                                              */
-        ALfilterState_process(&state->lowpass, buffer[1], buffer[0], td*4);
-
-        /* Second step, do distortion using waveshaper function  */
-        /* to emulate signal processing during tube overdriving. */
-        /* Three steps of waveshaping are intended to modify     */
-        /* waveform without boost/clipping/attenuation process.  */
-        for(it = 0;it < td;it++)
+        /* Perform 4x oversampling to avoid aliasing. Oversampling greatly
+         * improves distortion quality and allows to implement lowpass and
+         * bandpass filters using high frequencies, at which classic IIR
+         * filters became unstable.
+         */
+        ALsizei todo = mini(BUFFERSIZE, (SamplesToDo-base) * 4);
+
+        /* Fill oversample buffer using zero stuffing. Multiply the sample by
+         * the amount of oversampling to maintain the signal's power.
+         */
+        for(i = 0;i < todo;i++)
+            buffer[0][i] = !(i&3) ? SamplesIn[0][(i>>2)+base] * 4.0f : 0.0f;
+
+        /* First step, do lowpass filtering of original signal. Additionally
+         * perform buffer interpolation and lowpass cutoff for oversampling
+         * (which is fortunately first step of distortion). So combine three
+         * operations into the one.
+         */
+        BiquadFilter_process(&state->lowpass, buffer[1], buffer[0], todo);
+
+        /* Second step, do distortion using waveshaper function to emulate
+         * signal processing during tube overdriving. Three steps of
+         * waveshaping are intended to modify waveform without boost/clipping/
+         * attenuation process.
+         */
+        for(i = 0;i < todo;i++)
         {
         {
-            for(ot = 0;ot < 4;ot++)
-            {
-                /* Restore signal power by multiplying sample by amount of oversampling */
-                ALfloat smp = buffer[1][it*4 + ot] * 4.0f;
+            ALfloat smp = buffer[1][i];
 
 
-                smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
-                smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f;
-                smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
+            smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
+            smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp)) * -1.0f;
+            smp = (1.0f + fc) * smp/(1.0f + fc*fabsf(smp));
 
 
-                buffer[1][it*4 + ot] = smp;
-            }
+            buffer[0][i] = smp;
         }
         }
 
 
-        /* Third step, do bandpass filtering of distorted signal */
-        ALfilterState_process(&state->bandpass, buffer[0], buffer[1], td*4);
+        /* Third step, do bandpass filtering of distorted signal. */
+        BiquadFilter_process(&state->bandpass, buffer[1], buffer[0], todo);
 
 
-        for(kt = 0;kt < NumChannels;kt++)
+        todo >>= 2;
+        for(k = 0;k < NumChannels;k++)
         {
         {
             /* Fourth step, final, do attenuation and perform decimation,
             /* Fourth step, final, do attenuation and perform decimation,
-             * store only one sample out of 4.
+             * storing only one sample out of four.
              */
              */
-            ALfloat gain = state->Gain[kt] * state->attenuation;
+            ALfloat gain = state->Gain[k];
             if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
             if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
                 continue;
                 continue;
 
 
-            for(it = 0;it < td;it++)
-                SamplesOut[kt][base+it] += gain * buffer[0][it*4];
+            for(i = 0;i < todo;i++)
+                SamplesOut[k][base+i] += gain * buffer[1][i*4];
         }
         }
 
 
-        base += td;
+        base += todo;
     }
     }
 }
 }
 
 
 
 
-typedef struct ALdistortionStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALdistortionStateFactory;
+typedef struct DistortionStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} DistortionStateFactory;
 
 
-static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *UNUSED(factory))
+static ALeffectState *DistortionStateFactory_create(DistortionStateFactory *UNUSED(factory))
 {
 {
     ALdistortionState *state;
     ALdistortionState *state;
 
 
@@ -194,23 +189,21 @@ static ALeffectState *ALdistortionStateFactory_create(ALdistortionStateFactory *
     return STATIC_CAST(ALeffectState, state);
     return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALdistortionStateFactory);
+DEFINE_EFFECTSTATEFACTORY_VTABLE(DistortionStateFactory);
 
 
 
 
-ALeffectStateFactory *ALdistortionStateFactory_getFactory(void)
+EffectStateFactory *DistortionStateFactory_getFactory(void)
 {
 {
-    static ALdistortionStateFactory DistortionFactory = { { GET_VTABLE2(ALdistortionStateFactory, ALeffectStateFactory) } };
+    static DistortionStateFactory DistortionFactory = { { GET_VTABLE2(DistortionStateFactory, EffectStateFactory) } };
 
 
-    return STATIC_CAST(ALeffectStateFactory, &DistortionFactory);
+    return STATIC_CAST(EffectStateFactory, &DistortionFactory);
 }
 }
 
 
 
 
-void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALdistortion_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
-    ALdistortion_setParami(effect, context, param, vals[0]);
-}
+void ALdistortion_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); }
+void ALdistortion_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); }
 void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 {
 {
     ALeffectProps *props = &effect->Props;
     ALeffectProps *props = &effect->Props;
@@ -218,49 +211,46 @@ void ALdistortion_setParamf(ALeffect *effect, ALCcontext *context, ALenum param,
     {
     {
         case AL_DISTORTION_EDGE:
         case AL_DISTORTION_EDGE:
             if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
             if(!(val >= AL_DISTORTION_MIN_EDGE && val <= AL_DISTORTION_MAX_EDGE))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion edge out of range");
             props->Distortion.Edge = val;
             props->Distortion.Edge = val;
             break;
             break;
 
 
         case AL_DISTORTION_GAIN:
         case AL_DISTORTION_GAIN:
             if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
             if(!(val >= AL_DISTORTION_MIN_GAIN && val <= AL_DISTORTION_MAX_GAIN))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion gain out of range");
             props->Distortion.Gain = val;
             props->Distortion.Gain = val;
             break;
             break;
 
 
         case AL_DISTORTION_LOWPASS_CUTOFF:
         case AL_DISTORTION_LOWPASS_CUTOFF:
             if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
             if(!(val >= AL_DISTORTION_MIN_LOWPASS_CUTOFF && val <= AL_DISTORTION_MAX_LOWPASS_CUTOFF))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion low-pass cutoff out of range");
             props->Distortion.LowpassCutoff = val;
             props->Distortion.LowpassCutoff = val;
             break;
             break;
 
 
         case AL_DISTORTION_EQCENTER:
         case AL_DISTORTION_EQCENTER:
             if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
             if(!(val >= AL_DISTORTION_MIN_EQCENTER && val <= AL_DISTORTION_MAX_EQCENTER))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ center out of range");
             props->Distortion.EQCenter = val;
             props->Distortion.EQCenter = val;
             break;
             break;
 
 
         case AL_DISTORTION_EQBANDWIDTH:
         case AL_DISTORTION_EQBANDWIDTH:
             if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
             if(!(val >= AL_DISTORTION_MIN_EQBANDWIDTH && val <= AL_DISTORTION_MAX_EQBANDWIDTH))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Distortion EQ bandwidth out of range");
             props->Distortion.EQBandwidth = val;
             props->Distortion.EQBandwidth = val;
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x",
+                       param);
     }
     }
 }
 }
 void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
 void ALdistortion_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
-    ALdistortion_setParamf(effect, context, param, vals[0]);
-}
+{ ALdistortion_setParamf(effect, context, param, vals[0]); }
 
 
-void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALdistortion_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
-    ALdistortion_getParami(effect, context, param, vals);
-}
+void ALdistortion_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer property 0x%04x", param); }
+void ALdistortion_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid distortion integer-vector property 0x%04x", param); }
 void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 {
 {
     const ALeffectProps *props = &effect->Props;
     const ALeffectProps *props = &effect->Props;
@@ -287,12 +277,11 @@ void ALdistortion_getParamf(const ALeffect *effect, ALCcontext *context, ALenum
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid distortion float property 0x%04x",
+                       param);
     }
     }
 }
 }
 void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
 void ALdistortion_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
-    ALdistortion_getParamf(effect, context, param, vals);
-}
+{ ALdistortion_getParamf(effect, context, param, vals); }
 
 
 DEFINE_ALEFFECT_VTABLE(ALdistortion);
 DEFINE_ALEFFECT_VTABLE(ALdistortion);

+ 94 - 110
Engine/lib/openal-soft/Alc/effects/echo.c

@@ -28,32 +28,37 @@
 #include "alAuxEffectSlot.h"
 #include "alAuxEffectSlot.h"
 #include "alError.h"
 #include "alError.h"
 #include "alu.h"
 #include "alu.h"
+#include "filters/defs.h"
 
 
 
 
 typedef struct ALechoState {
 typedef struct ALechoState {
     DERIVE_FROM_TYPE(ALeffectState);
     DERIVE_FROM_TYPE(ALeffectState);
 
 
     ALfloat *SampleBuffer;
     ALfloat *SampleBuffer;
-    ALuint BufferLength;
+    ALsizei BufferLength;
 
 
     // The echo is two tap. The delay is the number of samples from before the
     // The echo is two tap. The delay is the number of samples from before the
     // current offset
     // current offset
     struct {
     struct {
-        ALuint delay;
+        ALsizei delay;
     } Tap[2];
     } Tap[2];
-    ALuint Offset;
+    ALsizei Offset;
+
     /* The panning gains for the two taps */
     /* The panning gains for the two taps */
-    ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
+    struct {
+        ALfloat Current[MAX_OUTPUT_CHANNELS];
+        ALfloat Target[MAX_OUTPUT_CHANNELS];
+    } Gains[2];
 
 
     ALfloat FeedGain;
     ALfloat FeedGain;
 
 
-    ALfilterState Filter;
+    BiquadFilter Filter;
 } ALechoState;
 } ALechoState;
 
 
 static ALvoid ALechoState_Destruct(ALechoState *state);
 static ALvoid ALechoState_Destruct(ALechoState *state);
 static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device);
 static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device);
-static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
-static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
+static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
+static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
 DECLARE_DEFAULT_ALLOCATORS(ALechoState)
 DECLARE_DEFAULT_ALLOCATORS(ALechoState)
 
 
 DEFINE_ALEFFECTSTATE_VTABLE(ALechoState);
 DEFINE_ALEFFECTSTATE_VTABLE(ALechoState);
@@ -71,7 +76,7 @@ static void ALechoState_Construct(ALechoState *state)
     state->Tap[1].delay = 0;
     state->Tap[1].delay = 0;
     state->Offset = 0;
     state->Offset = 0;
 
 
-    ALfilterState_clear(&state->Filter);
+    BiquadFilter_clear(&state->Filter);
 }
 }
 
 
 static ALvoid ALechoState_Destruct(ALechoState *state)
 static ALvoid ALechoState_Destruct(ALechoState *state)
@@ -83,13 +88,14 @@ static ALvoid ALechoState_Destruct(ALechoState *state)
 
 
 static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
 static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
 {
 {
-    ALuint maxlen, i;
+    ALsizei maxlen;
 
 
     // Use the next power of 2 for the buffer length, so the tap offsets can be
     // Use the next power of 2 for the buffer length, so the tap offsets can be
     // wrapped using a mask instead of a modulo
     // wrapped using a mask instead of a modulo
-    maxlen  = fastf2u(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
-    maxlen += fastf2u(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
-    maxlen  = NextPowerOf2(maxlen);
+    maxlen = float2int(AL_ECHO_MAX_DELAY*Device->Frequency + 0.5f) +
+             float2int(AL_ECHO_MAX_LRDELAY*Device->Frequency + 0.5f);
+    maxlen = NextPowerOf2(maxlen);
+    if(maxlen <= 0) return AL_FALSE;
 
 
     if(maxlen != state->BufferLength)
     if(maxlen != state->BufferLength)
     {
     {
@@ -100,20 +106,22 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
         state->SampleBuffer = temp;
         state->SampleBuffer = temp;
         state->BufferLength = maxlen;
         state->BufferLength = maxlen;
     }
     }
-    for(i = 0;i < state->BufferLength;i++)
-        state->SampleBuffer[i] = 0.0f;
+
+    memset(state->SampleBuffer, 0, state->BufferLength*sizeof(ALfloat));
+    memset(state->Gains, 0, sizeof(state->Gains));
 
 
     return AL_TRUE;
     return AL_TRUE;
 }
 }
 
 
-static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
+static ALvoid ALechoState_update(ALechoState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
 {
 {
-    ALuint frequency = Device->Frequency;
+    const ALCdevice *device = context->Device;
+    ALuint frequency = device->Frequency;
     ALfloat coeffs[MAX_AMBI_COEFFS];
     ALfloat coeffs[MAX_AMBI_COEFFS];
-    ALfloat gain, lrpan, spread;
+    ALfloat gainhf, lrpan, spread;
 
 
-    state->Tap[0].delay = fastf2u(props->Echo.Delay * frequency) + 1;
-    state->Tap[1].delay = fastf2u(props->Echo.LRDelay * frequency);
+    state->Tap[0].delay = maxi(float2int(props->Echo.Delay*frequency + 0.5f), 1);
+    state->Tap[1].delay = float2int(props->Echo.LRDelay*frequency + 0.5f);
     state->Tap[1].delay += state->Tap[0].delay;
     state->Tap[1].delay += state->Tap[0].delay;
 
 
     spread = props->Echo.Spread;
     spread = props->Echo.Spread;
@@ -126,94 +134,78 @@ static ALvoid ALechoState_update(ALechoState *state, const ALCdevice *Device, co
 
 
     state->FeedGain = props->Echo.Feedback;
     state->FeedGain = props->Echo.Feedback;
 
 
-    gain = minf(1.0f - props->Echo.Damping, 0.01f);
-    ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
-                            gain, LOWPASSFREQREF/frequency,
-                            calc_rcpQ_from_slope(gain, 0.75f));
-
-    gain = Slot->Params.Gain;
+    gainhf = maxf(1.0f - props->Echo.Damping, 0.0625f); /* Limit -24dB */
+    BiquadFilter_setParams(&state->Filter, BiquadType_HighShelf,
+        gainhf, LOWPASSFREQREF/frequency, calc_rcpQ_from_slope(gainhf, 1.0f)
+    );
 
 
     /* First tap panning */
     /* First tap panning */
-    CalcXYZCoeffs(-lrpan, 0.0f, 0.0f, spread, coeffs);
-    ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[0]);
+    CalcAngleCoeffs(-F_PI_2*lrpan, 0.0f, spread, coeffs);
+    ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[0].Target);
 
 
     /* Second tap panning */
     /* Second tap panning */
-    CalcXYZCoeffs( lrpan, 0.0f, 0.0f, spread, coeffs);
-    ComputePanningGains(Device->Dry, coeffs, gain, state->Gain[1]);
+    CalcAngleCoeffs( F_PI_2*lrpan, 0.0f, spread, coeffs);
+    ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->Gains[1].Target);
 }
 }
 
 
-static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
+static ALvoid ALechoState_process(ALechoState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
 {
 {
-    const ALuint mask = state->BufferLength-1;
-    const ALuint tap1 = state->Tap[0].delay;
-    const ALuint tap2 = state->Tap[1].delay;
-    ALuint offset = state->Offset;
-    ALfloat x[2], y[2], in, out;
-    ALuint base;
-    ALuint i, k;
-
-    x[0] = state->Filter.x[0];
-    x[1] = state->Filter.x[1];
-    y[0] = state->Filter.y[0];
-    y[1] = state->Filter.y[1];
+    const ALsizei mask = state->BufferLength-1;
+    const ALsizei tap1 = state->Tap[0].delay;
+    const ALsizei tap2 = state->Tap[1].delay;
+    ALfloat *restrict delaybuf = state->SampleBuffer;
+    ALsizei offset = state->Offset;
+    ALfloat z1, z2, in, out;
+    ALsizei base;
+    ALsizei c, i;
+
+    z1 = state->Filter.z1;
+    z2 = state->Filter.z2;
     for(base = 0;base < SamplesToDo;)
     for(base = 0;base < SamplesToDo;)
     {
     {
-        ALfloat temps[128][2];
-        ALuint td = minu(128, SamplesToDo-base);
+        alignas(16) ALfloat temps[2][128];
+        ALsizei td = mini(128, SamplesToDo-base);
 
 
         for(i = 0;i < td;i++)
         for(i = 0;i < td;i++)
         {
         {
+            /* Feed the delay buffer's input first. */
+            delaybuf[offset&mask] = SamplesIn[0][i+base];
+
             /* First tap */
             /* First tap */
-            temps[i][0] = state->SampleBuffer[(offset-tap1) & mask];
+            temps[0][i] = delaybuf[(offset-tap1) & mask];
             /* Second tap */
             /* Second tap */
-            temps[i][1] = state->SampleBuffer[(offset-tap2) & mask];
-
-            // Apply damping and feedback gain to the second tap, and mix in the
-            // new sample
-            in = temps[i][1] + SamplesIn[0][i+base];
-            out = in*state->Filter.b0 +
-                  x[0]*state->Filter.b1 + x[1]*state->Filter.b2 -
-                  y[0]*state->Filter.a1 - y[1]*state->Filter.a2;
-            x[1] = x[0]; x[0] = in;
-            y[1] = y[0]; y[0] = out;
-
-            state->SampleBuffer[offset&mask] = out * state->FeedGain;
+            temps[1][i] = delaybuf[(offset-tap2) & mask];
+
+            /* Apply damping to the second tap, then add it to the buffer with
+             * feedback attenuation.
+             */
+            in = temps[1][i];
+            out = in*state->Filter.b0 + z1;
+            z1 = in*state->Filter.b1 - out*state->Filter.a1 + z2;
+            z2 = in*state->Filter.b2 - out*state->Filter.a2;
+
+            delaybuf[offset&mask] += out * state->FeedGain;
             offset++;
             offset++;
         }
         }
 
 
-        for(k = 0;k < NumChannels;k++)
-        {
-            ALfloat gain = state->Gain[0][k];
-            if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
-            {
-                for(i = 0;i < td;i++)
-                    SamplesOut[k][i+base] += temps[i][0] * gain;
-            }
-
-            gain = state->Gain[1][k];
-            if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
-            {
-                for(i = 0;i < td;i++)
-                    SamplesOut[k][i+base] += temps[i][1] * gain;
-            }
-        }
+        for(c = 0;c < 2;c++)
+            MixSamples(temps[c], NumChannels, SamplesOut, state->Gains[c].Current,
+                       state->Gains[c].Target, SamplesToDo-base, base, td);
 
 
         base += td;
         base += td;
     }
     }
-    state->Filter.x[0] = x[0];
-    state->Filter.x[1] = x[1];
-    state->Filter.y[0] = y[0];
-    state->Filter.y[1] = y[1];
+    state->Filter.z1 = z1;
+    state->Filter.z2 = z2;
 
 
     state->Offset = offset;
     state->Offset = offset;
 }
 }
 
 
 
 
-typedef struct ALechoStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALechoStateFactory;
+typedef struct EchoStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} EchoStateFactory;
 
 
-ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory))
+ALeffectState *EchoStateFactory_create(EchoStateFactory *UNUSED(factory))
 {
 {
     ALechoState *state;
     ALechoState *state;
 
 
@@ -223,22 +215,20 @@ ALeffectState *ALechoStateFactory_create(ALechoStateFactory *UNUSED(factory))
     return STATIC_CAST(ALeffectState, state);
     return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALechoStateFactory);
+DEFINE_EFFECTSTATEFACTORY_VTABLE(EchoStateFactory);
 
 
-ALeffectStateFactory *ALechoStateFactory_getFactory(void)
+EffectStateFactory *EchoStateFactory_getFactory(void)
 {
 {
-    static ALechoStateFactory EchoFactory = { { GET_VTABLE2(ALechoStateFactory, ALeffectStateFactory) } };
+    static EchoStateFactory EchoFactory = { { GET_VTABLE2(EchoStateFactory, EffectStateFactory) } };
 
 
-    return STATIC_CAST(ALeffectStateFactory, &EchoFactory);
+    return STATIC_CAST(EffectStateFactory, &EchoFactory);
 }
 }
 
 
 
 
-void ALecho_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALecho_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
-    ALecho_setParami(effect, context, param, vals[0]);
-}
+void ALecho_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); }
+void ALecho_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); }
 void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 {
 {
     ALeffectProps *props = &effect->Props;
     ALeffectProps *props = &effect->Props;
@@ -246,49 +236,45 @@ void ALecho_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALflo
     {
     {
         case AL_ECHO_DELAY:
         case AL_ECHO_DELAY:
             if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
             if(!(val >= AL_ECHO_MIN_DELAY && val <= AL_ECHO_MAX_DELAY))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo delay out of range");
             props->Echo.Delay = val;
             props->Echo.Delay = val;
             break;
             break;
 
 
         case AL_ECHO_LRDELAY:
         case AL_ECHO_LRDELAY:
             if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
             if(!(val >= AL_ECHO_MIN_LRDELAY && val <= AL_ECHO_MAX_LRDELAY))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo LR delay out of range");
             props->Echo.LRDelay = val;
             props->Echo.LRDelay = val;
             break;
             break;
 
 
         case AL_ECHO_DAMPING:
         case AL_ECHO_DAMPING:
             if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
             if(!(val >= AL_ECHO_MIN_DAMPING && val <= AL_ECHO_MAX_DAMPING))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo damping out of range");
             props->Echo.Damping = val;
             props->Echo.Damping = val;
             break;
             break;
 
 
         case AL_ECHO_FEEDBACK:
         case AL_ECHO_FEEDBACK:
             if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
             if(!(val >= AL_ECHO_MIN_FEEDBACK && val <= AL_ECHO_MAX_FEEDBACK))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo feedback out of range");
             props->Echo.Feedback = val;
             props->Echo.Feedback = val;
             break;
             break;
 
 
         case AL_ECHO_SPREAD:
         case AL_ECHO_SPREAD:
             if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
             if(!(val >= AL_ECHO_MIN_SPREAD && val <= AL_ECHO_MAX_SPREAD))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Echo spread out of range");
             props->Echo.Spread = val;
             props->Echo.Spread = val;
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param);
     }
     }
 }
 }
 void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
 void ALecho_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
-    ALecho_setParamf(effect, context, param, vals[0]);
-}
+{ ALecho_setParamf(effect, context, param, vals[0]); }
 
 
-void ALecho_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALecho_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
-    ALecho_getParami(effect, context, param, vals);
-}
+void ALecho_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param); }
+void ALecho_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid echo integer-vector property 0x%04x", param); }
 void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 {
 {
     const ALeffectProps *props = &effect->Props;
     const ALeffectProps *props = &effect->Props;
@@ -315,12 +301,10 @@ void ALecho_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param,
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid echo float property 0x%04x", param);
     }
     }
 }
 }
 void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
 void ALecho_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
-    ALecho_getParamf(effect, context, param, vals);
-}
+{ ALecho_getParamf(effect, context, param, vals); }
 
 
 DEFINE_ALEFFECT_VTABLE(ALecho);
 DEFINE_ALEFFECT_VTABLE(ALecho);

+ 93 - 142
Engine/lib/openal-soft/Alc/effects/equalizer.c

@@ -24,10 +24,10 @@
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "alMain.h"
 #include "alMain.h"
-#include "alFilter.h"
 #include "alAuxEffectSlot.h"
 #include "alAuxEffectSlot.h"
 #include "alError.h"
 #include "alError.h"
 #include "alu.h"
 #include "alu.h"
+#include "filters/defs.h"
 
 
 
 
 /*  The document  "Effects Extension Guide.pdf"  says that low and high  *
 /*  The document  "Effects Extension Guide.pdf"  says that low and high  *
@@ -72,25 +72,25 @@
  * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt                   */
  * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt                   */
 
 
 
 
-/* The maximum number of sample frames per update. */
-#define MAX_UPDATE_SAMPLES 256
-
 typedef struct ALequalizerState {
 typedef struct ALequalizerState {
     DERIVE_FROM_TYPE(ALeffectState);
     DERIVE_FROM_TYPE(ALeffectState);
 
 
-    /* Effect gains for each channel */
-    ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
+    struct {
+        /* Effect gains for each channel */
+        ALfloat CurrentGains[MAX_OUTPUT_CHANNELS];
+        ALfloat TargetGains[MAX_OUTPUT_CHANNELS];
 
 
-    /* Effect parameters */
-    ALfilterState filter[4][MAX_EFFECT_CHANNELS];
+        /* Effect parameters */
+        BiquadFilter filter[4];
+    } Chans[MAX_EFFECT_CHANNELS];
 
 
-    ALfloat SampleBuffer[4][MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES];
+    ALfloat SampleBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
 } ALequalizerState;
 } ALequalizerState;
 
 
 static ALvoid ALequalizerState_Destruct(ALequalizerState *state);
 static ALvoid ALequalizerState_Destruct(ALequalizerState *state);
 static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device);
 static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *device);
-static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
-static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
+static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
+static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
 DECLARE_DEFAULT_ALLOCATORS(ALequalizerState)
 DECLARE_DEFAULT_ALLOCATORS(ALequalizerState)
 
 
 DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
 DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
@@ -98,18 +98,8 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALequalizerState);
 
 
 static void ALequalizerState_Construct(ALequalizerState *state)
 static void ALequalizerState_Construct(ALequalizerState *state)
 {
 {
-    int it, ft;
-
     ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
     ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
     SET_VTABLE2(ALequalizerState, ALeffectState, state);
     SET_VTABLE2(ALequalizerState, ALeffectState, state);
-
-    /* Initialize sample history only on filter creation to avoid */
-    /* sound clicks if filter settings were changed in runtime.   */
-    for(it = 0; it < 4; it++)
-    {
-        for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
-            ALfilterState_clear(&state->filter[it][ft]);
-    }
 }
 }
 
 
 static ALvoid ALequalizerState_Destruct(ALequalizerState *state)
 static ALvoid ALequalizerState_Destruct(ALequalizerState *state)
@@ -117,131 +107,100 @@ static ALvoid ALequalizerState_Destruct(ALequalizerState *state)
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
 }
 }
 
 
-static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), ALCdevice *UNUSED(device))
+static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *state, ALCdevice *UNUSED(device))
 {
 {
+    ALsizei i, j;
+
+    for(i = 0; i < MAX_EFFECT_CHANNELS;i++)
+    {
+        for(j = 0;j < 4;j++)
+            BiquadFilter_clear(&state->Chans[i].filter[j]);
+        for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
+            state->Chans[i].CurrentGains[j] = 0.0f;
+    }
     return AL_TRUE;
     return AL_TRUE;
 }
 }
 
 
-static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props)
+static ALvoid ALequalizerState_update(ALequalizerState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
 {
 {
+    const ALCdevice *device = context->Device;
     ALfloat frequency = (ALfloat)device->Frequency;
     ALfloat frequency = (ALfloat)device->Frequency;
-    ALfloat gain, freq_mult;
+    ALfloat gain, f0norm;
     ALuint i;
     ALuint i;
 
 
     STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
     STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
     STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
     STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
     for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
     for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
-        ComputeFirstOrderGains(device->FOAOut, IdentityMatrixf.m[i],
-                               slot->Params.Gain, state->Gain[i]);
+        ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i],
+                               slot->Params.Gain, state->Chans[i].TargetGains);
 
 
     /* Calculate coefficients for the each type of filter. Note that the shelf
     /* Calculate coefficients for the each type of filter. Note that the shelf
      * filters' gain is for the reference frequency, which is the centerpoint
      * filters' gain is for the reference frequency, which is the centerpoint
      * of the transition band.
      * of the transition band.
      */
      */
-    gain = sqrtf(props->Equalizer.LowGain);
-    freq_mult = props->Equalizer.LowCutoff/frequency;
-    ALfilterState_setParams(&state->filter[0][0], ALfilterType_LowShelf,
-        gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
+    gain = maxf(sqrtf(props->Equalizer.LowGain), 0.0625f); /* Limit -24dB */
+    f0norm = props->Equalizer.LowCutoff/frequency;
+    BiquadFilter_setParams(&state->Chans[0].filter[0], BiquadType_LowShelf,
+        gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f)
     );
     );
-    /* Copy the filter coefficients for the other input channels. */
-    for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
-    {
-        state->filter[0][i].a1 = state->filter[0][0].a1;
-        state->filter[0][i].a2 = state->filter[0][0].a2;
-        state->filter[0][i].b0 = state->filter[0][0].b0;
-        state->filter[0][i].b1 = state->filter[0][0].b1;
-        state->filter[0][i].b2 = state->filter[0][0].b2;
-    }
 
 
-    gain = props->Equalizer.Mid1Gain;
-    freq_mult = props->Equalizer.Mid1Center/frequency;
-    ALfilterState_setParams(&state->filter[1][0], ALfilterType_Peaking,
-        gain, freq_mult, calc_rcpQ_from_bandwidth(
-            freq_mult, props->Equalizer.Mid1Width
+    gain = maxf(props->Equalizer.Mid1Gain, 0.0625f);
+    f0norm = props->Equalizer.Mid1Center/frequency;
+    BiquadFilter_setParams(&state->Chans[0].filter[1], BiquadType_Peaking,
+        gain, f0norm, calc_rcpQ_from_bandwidth(
+            f0norm, props->Equalizer.Mid1Width
         )
         )
     );
     );
-    for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
-    {
-        state->filter[1][i].a1 = state->filter[1][0].a1;
-        state->filter[1][i].a2 = state->filter[1][0].a2;
-        state->filter[1][i].b0 = state->filter[1][0].b0;
-        state->filter[1][i].b1 = state->filter[1][0].b1;
-        state->filter[1][i].b2 = state->filter[1][0].b2;
-    }
 
 
-    gain = props->Equalizer.Mid2Gain;
-    freq_mult = props->Equalizer.Mid2Center/frequency;
-    ALfilterState_setParams(&state->filter[2][0], ALfilterType_Peaking,
-        gain, freq_mult, calc_rcpQ_from_bandwidth(
-            freq_mult, props->Equalizer.Mid2Width
+    gain = maxf(props->Equalizer.Mid2Gain, 0.0625f);
+    f0norm = props->Equalizer.Mid2Center/frequency;
+    BiquadFilter_setParams(&state->Chans[0].filter[2], BiquadType_Peaking,
+        gain, f0norm, calc_rcpQ_from_bandwidth(
+            f0norm, props->Equalizer.Mid2Width
         )
         )
     );
     );
-    for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
-    {
-        state->filter[2][i].a1 = state->filter[2][0].a1;
-        state->filter[2][i].a2 = state->filter[2][0].a2;
-        state->filter[2][i].b0 = state->filter[2][0].b0;
-        state->filter[2][i].b1 = state->filter[2][0].b1;
-        state->filter[2][i].b2 = state->filter[2][0].b2;
-    }
 
 
-    gain = sqrtf(props->Equalizer.HighGain);
-    freq_mult = props->Equalizer.HighCutoff/frequency;
-    ALfilterState_setParams(&state->filter[3][0], ALfilterType_HighShelf,
-        gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
+    gain = maxf(sqrtf(props->Equalizer.HighGain), 0.0625f);
+    f0norm = props->Equalizer.HighCutoff/frequency;
+    BiquadFilter_setParams(&state->Chans[0].filter[3], BiquadType_HighShelf,
+        gain, f0norm, calc_rcpQ_from_slope(gain, 0.75f)
     );
     );
+
+    /* Copy the filter coefficients for the other input channels. */
     for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
     for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
     {
     {
-        state->filter[3][i].a1 = state->filter[3][0].a1;
-        state->filter[3][i].a2 = state->filter[3][0].a2;
-        state->filter[3][i].b0 = state->filter[3][0].b0;
-        state->filter[3][i].b1 = state->filter[3][0].b1;
-        state->filter[3][i].b2 = state->filter[3][0].b2;
+        BiquadFilter_copyParams(&state->Chans[i].filter[0], &state->Chans[0].filter[0]);
+        BiquadFilter_copyParams(&state->Chans[i].filter[1], &state->Chans[0].filter[1]);
+        BiquadFilter_copyParams(&state->Chans[i].filter[2], &state->Chans[0].filter[2]);
+        BiquadFilter_copyParams(&state->Chans[i].filter[3], &state->Chans[0].filter[3]);
     }
     }
 }
 }
 
 
-static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
+static ALvoid ALequalizerState_process(ALequalizerState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
 {
 {
-    ALfloat (*Samples)[MAX_EFFECT_CHANNELS][MAX_UPDATE_SAMPLES] = state->SampleBuffer;
-    ALuint it, kt, ft;
-    ALuint base;
+    ALfloat (*restrict temps)[BUFFERSIZE] = state->SampleBuffer;
+    ALsizei c;
 
 
-    for(base = 0;base < SamplesToDo;)
+    for(c = 0;c < MAX_EFFECT_CHANNELS;c++)
     {
     {
-        ALuint td = minu(MAX_UPDATE_SAMPLES, SamplesToDo-base);
-
-        for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
-            ALfilterState_process(&state->filter[0][ft], Samples[0][ft], &SamplesIn[ft][base], td);
-        for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
-            ALfilterState_process(&state->filter[1][ft], Samples[1][ft], Samples[0][ft], td);
-        for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
-            ALfilterState_process(&state->filter[2][ft], Samples[2][ft], Samples[1][ft], td);
-        for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
-            ALfilterState_process(&state->filter[3][ft], Samples[3][ft], Samples[2][ft], td);
-
-        for(ft = 0;ft < MAX_EFFECT_CHANNELS;ft++)
-        {
-            for(kt = 0;kt < NumChannels;kt++)
-            {
-                ALfloat gain = state->Gain[ft][kt];
-                if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
-                    continue;
-
-                for(it = 0;it < td;it++)
-                    SamplesOut[kt][base+it] += gain * Samples[3][ft][it];
-            }
-        }
-
-        base += td;
+        BiquadFilter_process(&state->Chans[c].filter[0], temps[0], SamplesIn[c], SamplesToDo);
+        BiquadFilter_process(&state->Chans[c].filter[1], temps[1], temps[0], SamplesToDo);
+        BiquadFilter_process(&state->Chans[c].filter[2], temps[2], temps[1], SamplesToDo);
+        BiquadFilter_process(&state->Chans[c].filter[3], temps[3], temps[2], SamplesToDo);
+
+        MixSamples(temps[3], NumChannels, SamplesOut,
+            state->Chans[c].CurrentGains, state->Chans[c].TargetGains,
+            SamplesToDo, 0, SamplesToDo
+        );
     }
     }
 }
 }
 
 
 
 
-typedef struct ALequalizerStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALequalizerStateFactory;
+typedef struct EqualizerStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} EqualizerStateFactory;
 
 
-ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(factory))
+ALeffectState *EqualizerStateFactory_create(EqualizerStateFactory *UNUSED(factory))
 {
 {
     ALequalizerState *state;
     ALequalizerState *state;
 
 
@@ -251,22 +210,20 @@ ALeffectState *ALequalizerStateFactory_create(ALequalizerStateFactory *UNUSED(fa
     return STATIC_CAST(ALeffectState, state);
     return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALequalizerStateFactory);
+DEFINE_EFFECTSTATEFACTORY_VTABLE(EqualizerStateFactory);
 
 
-ALeffectStateFactory *ALequalizerStateFactory_getFactory(void)
+EffectStateFactory *EqualizerStateFactory_getFactory(void)
 {
 {
-    static ALequalizerStateFactory EqualizerFactory = { { GET_VTABLE2(ALequalizerStateFactory, ALeffectStateFactory) } };
+    static EqualizerStateFactory EqualizerFactory = { { GET_VTABLE2(EqualizerStateFactory, EffectStateFactory) } };
 
 
-    return STATIC_CAST(ALeffectStateFactory, &EqualizerFactory);
+    return STATIC_CAST(EffectStateFactory, &EqualizerFactory);
 }
 }
 
 
 
 
-void ALequalizer_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALequalizer_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
-    ALequalizer_setParami(effect, context, param, vals[0]);
-}
+void ALequalizer_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); }
+void ALequalizer_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); }
 void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
 {
 {
     ALeffectProps *props = &effect->Props;
     ALeffectProps *props = &effect->Props;
@@ -274,79 +231,75 @@ void ALequalizer_setParamf(ALeffect *effect, ALCcontext *context, ALenum param,
     {
     {
         case AL_EQUALIZER_LOW_GAIN:
         case AL_EQUALIZER_LOW_GAIN:
             if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN))
             if(!(val >= AL_EQUALIZER_MIN_LOW_GAIN && val <= AL_EQUALIZER_MAX_LOW_GAIN))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band gain out of range");
             props->Equalizer.LowGain = val;
             props->Equalizer.LowGain = val;
             break;
             break;
 
 
         case AL_EQUALIZER_LOW_CUTOFF:
         case AL_EQUALIZER_LOW_CUTOFF:
             if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
             if(!(val >= AL_EQUALIZER_MIN_LOW_CUTOFF && val <= AL_EQUALIZER_MAX_LOW_CUTOFF))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer low-band cutoff out of range");
             props->Equalizer.LowCutoff = val;
             props->Equalizer.LowCutoff = val;
             break;
             break;
 
 
         case AL_EQUALIZER_MID1_GAIN:
         case AL_EQUALIZER_MID1_GAIN:
             if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
             if(!(val >= AL_EQUALIZER_MIN_MID1_GAIN && val <= AL_EQUALIZER_MAX_MID1_GAIN))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band gain out of range");
             props->Equalizer.Mid1Gain = val;
             props->Equalizer.Mid1Gain = val;
             break;
             break;
 
 
         case AL_EQUALIZER_MID1_CENTER:
         case AL_EQUALIZER_MID1_CENTER:
             if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
             if(!(val >= AL_EQUALIZER_MIN_MID1_CENTER && val <= AL_EQUALIZER_MAX_MID1_CENTER))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band center out of range");
             props->Equalizer.Mid1Center = val;
             props->Equalizer.Mid1Center = val;
             break;
             break;
 
 
         case AL_EQUALIZER_MID1_WIDTH:
         case AL_EQUALIZER_MID1_WIDTH:
             if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
             if(!(val >= AL_EQUALIZER_MIN_MID1_WIDTH && val <= AL_EQUALIZER_MAX_MID1_WIDTH))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid1-band width out of range");
             props->Equalizer.Mid1Width = val;
             props->Equalizer.Mid1Width = val;
             break;
             break;
 
 
         case AL_EQUALIZER_MID2_GAIN:
         case AL_EQUALIZER_MID2_GAIN:
             if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
             if(!(val >= AL_EQUALIZER_MIN_MID2_GAIN && val <= AL_EQUALIZER_MAX_MID2_GAIN))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band gain out of range");
             props->Equalizer.Mid2Gain = val;
             props->Equalizer.Mid2Gain = val;
             break;
             break;
 
 
         case AL_EQUALIZER_MID2_CENTER:
         case AL_EQUALIZER_MID2_CENTER:
             if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
             if(!(val >= AL_EQUALIZER_MIN_MID2_CENTER && val <= AL_EQUALIZER_MAX_MID2_CENTER))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band center out of range");
             props->Equalizer.Mid2Center = val;
             props->Equalizer.Mid2Center = val;
             break;
             break;
 
 
         case AL_EQUALIZER_MID2_WIDTH:
         case AL_EQUALIZER_MID2_WIDTH:
             if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
             if(!(val >= AL_EQUALIZER_MIN_MID2_WIDTH && val <= AL_EQUALIZER_MAX_MID2_WIDTH))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer mid2-band width out of range");
             props->Equalizer.Mid2Width = val;
             props->Equalizer.Mid2Width = val;
             break;
             break;
 
 
         case AL_EQUALIZER_HIGH_GAIN:
         case AL_EQUALIZER_HIGH_GAIN:
             if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
             if(!(val >= AL_EQUALIZER_MIN_HIGH_GAIN && val <= AL_EQUALIZER_MAX_HIGH_GAIN))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band gain out of range");
             props->Equalizer.HighGain = val;
             props->Equalizer.HighGain = val;
             break;
             break;
 
 
         case AL_EQUALIZER_HIGH_CUTOFF:
         case AL_EQUALIZER_HIGH_CUTOFF:
             if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
             if(!(val >= AL_EQUALIZER_MIN_HIGH_CUTOFF && val <= AL_EQUALIZER_MAX_HIGH_CUTOFF))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Equalizer high-band cutoff out of range");
             props->Equalizer.HighCutoff = val;
             props->Equalizer.HighCutoff = val;
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param);
     }
     }
 }
 }
 void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
 void ALequalizer_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
-    ALequalizer_setParamf(effect, context, param, vals[0]);
-}
+{ ALequalizer_setParamf(effect, context, param, vals[0]); }
 
 
-void ALequalizer_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val))
-{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }
-void ALequalizer_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
-    ALequalizer_getParami(effect, context, param, vals);
-}
+void ALequalizer_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(val))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer property 0x%04x", param); }
+void ALequalizer_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint *UNUSED(vals))
+{ alSetError(context, AL_INVALID_ENUM, "Invalid equalizer integer-vector property 0x%04x", param); }
 void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 {
 {
     const ALeffectProps *props = &effect->Props;
     const ALeffectProps *props = &effect->Props;
@@ -393,12 +346,10 @@ void ALequalizer_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid equalizer float property 0x%04x", param);
     }
     }
 }
 }
 void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
 void ALequalizer_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
-    ALequalizer_getParamf(effect, context, param, vals);
-}
+{ ALequalizer_getParamf(effect, context, param, vals); }
 
 
 DEFINE_ALEFFECT_VTABLE(ALequalizer);
 DEFINE_ALEFFECT_VTABLE(ALequalizer);

+ 0 - 411
Engine/lib/openal-soft/Alc/effects/flanger.c

@@ -1,411 +0,0 @@
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 2013 by Mike Gorchak
- * This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- * Or go to http://www.gnu.org/copyleft/lgpl.html
- */
-
-#include "config.h"
-
-#include <math.h>
-#include <stdlib.h>
-
-#include "alMain.h"
-#include "alFilter.h"
-#include "alAuxEffectSlot.h"
-#include "alError.h"
-#include "alu.h"
-
-
-enum FlangerWaveForm {
-    FWF_Triangle = AL_FLANGER_WAVEFORM_TRIANGLE,
-    FWF_Sinusoid = AL_FLANGER_WAVEFORM_SINUSOID
-};
-
-typedef struct ALflangerState {
-    DERIVE_FROM_TYPE(ALeffectState);
-
-    ALfloat *SampleBuffer[2];
-    ALuint BufferLength;
-    ALuint offset;
-    ALuint lfo_range;
-    ALfloat lfo_scale;
-    ALint lfo_disp;
-
-    /* Gains for left and right sides */
-    ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
-
-    /* effect parameters */
-    enum FlangerWaveForm waveform;
-    ALint delay;
-    ALfloat depth;
-    ALfloat feedback;
-} ALflangerState;
-
-static ALvoid ALflangerState_Destruct(ALflangerState *state);
-static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device);
-static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
-static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
-DECLARE_DEFAULT_ALLOCATORS(ALflangerState)
-
-DEFINE_ALEFFECTSTATE_VTABLE(ALflangerState);
-
-
-static void ALflangerState_Construct(ALflangerState *state)
-{
-    ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
-    SET_VTABLE2(ALflangerState, ALeffectState, state);
-
-    state->BufferLength = 0;
-    state->SampleBuffer[0] = NULL;
-    state->SampleBuffer[1] = NULL;
-    state->offset = 0;
-    state->lfo_range = 1;
-    state->waveform = FWF_Triangle;
-}
-
-static ALvoid ALflangerState_Destruct(ALflangerState *state)
-{
-    al_free(state->SampleBuffer[0]);
-    state->SampleBuffer[0] = NULL;
-    state->SampleBuffer[1] = NULL;
-
-    ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
-}
-
-static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *Device)
-{
-    ALuint maxlen;
-    ALuint it;
-
-    maxlen = fastf2u(AL_FLANGER_MAX_DELAY * 3.0f * Device->Frequency) + 1;
-    maxlen = NextPowerOf2(maxlen);
-
-    if(maxlen != state->BufferLength)
-    {
-        void *temp = al_calloc(16, maxlen * sizeof(ALfloat) * 2);
-        if(!temp) return AL_FALSE;
-
-        al_free(state->SampleBuffer[0]);
-        state->SampleBuffer[0] = temp;
-        state->SampleBuffer[1] = state->SampleBuffer[0] + maxlen;
-
-        state->BufferLength = maxlen;
-    }
-
-    for(it = 0;it < state->BufferLength;it++)
-    {
-        state->SampleBuffer[0][it] = 0.0f;
-        state->SampleBuffer[1][it] = 0.0f;
-    }
-
-    return AL_TRUE;
-}
-
-static ALvoid ALflangerState_update(ALflangerState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
-{
-    ALfloat frequency = (ALfloat)Device->Frequency;
-    ALfloat coeffs[MAX_AMBI_COEFFS];
-    ALfloat rate;
-    ALint phase;
-
-    switch(props->Flanger.Waveform)
-    {
-        case AL_FLANGER_WAVEFORM_TRIANGLE:
-            state->waveform = FWF_Triangle;
-            break;
-        case AL_FLANGER_WAVEFORM_SINUSOID:
-            state->waveform = FWF_Sinusoid;
-            break;
-    }
-    state->depth = props->Flanger.Depth;
-    state->feedback = props->Flanger.Feedback;
-    state->delay = fastf2i(props->Flanger.Delay * frequency);
-
-    /* Gains for left and right sides */
-    CalcXYZCoeffs(-1.0f, 0.0f, 0.0f, 0.0f, coeffs);
-    ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[0]);
-    CalcXYZCoeffs( 1.0f, 0.0f, 0.0f, 0.0f, coeffs);
-    ComputePanningGains(Device->Dry, coeffs, Slot->Params.Gain, state->Gain[1]);
-
-    phase = props->Flanger.Phase;
-    rate = props->Flanger.Rate;
-    if(!(rate > 0.0f))
-    {
-        state->lfo_scale = 0.0f;
-        state->lfo_range = 1;
-        state->lfo_disp = 0;
-    }
-    else
-    {
-        /* Calculate LFO coefficient */
-        state->lfo_range = fastf2u(frequency/rate + 0.5f);
-        switch(state->waveform)
-        {
-            case FWF_Triangle:
-                state->lfo_scale = 4.0f / state->lfo_range;
-                break;
-            case FWF_Sinusoid:
-                state->lfo_scale = F_TAU / state->lfo_range;
-                break;
-        }
-
-        /* Calculate lfo phase displacement */
-        state->lfo_disp = fastf2i(state->lfo_range * (phase/360.0f));
-    }
-}
-
-static inline void Triangle(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
-{
-    ALfloat lfo_value;
-
-    lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
-    lfo_value *= state->depth * state->delay;
-    *delay_left = fastf2i(lfo_value) + state->delay;
-
-    offset += state->lfo_disp;
-    lfo_value = 2.0f - fabsf(2.0f - state->lfo_scale*(offset%state->lfo_range));
-    lfo_value *= state->depth * state->delay;
-    *delay_right = fastf2i(lfo_value) + state->delay;
-}
-
-static inline void Sinusoid(ALint *delay_left, ALint *delay_right, ALuint offset, const ALflangerState *state)
-{
-    ALfloat lfo_value;
-
-    lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
-    lfo_value *= state->depth * state->delay;
-    *delay_left = fastf2i(lfo_value) + state->delay;
-
-    offset += state->lfo_disp;
-    lfo_value = 1.0f + sinf(state->lfo_scale*(offset%state->lfo_range));
-    lfo_value *= state->depth * state->delay;
-    *delay_right = fastf2i(lfo_value) + state->delay;
-}
-
-#define DECL_TEMPLATE(Func)                                                   \
-static void Process##Func(ALflangerState *state, const ALuint SamplesToDo,    \
-  const ALfloat *restrict SamplesIn, ALfloat (*restrict out)[2])              \
-{                                                                             \
-    const ALuint bufmask = state->BufferLength-1;                             \
-    ALfloat *restrict leftbuf = state->SampleBuffer[0];                       \
-    ALfloat *restrict rightbuf = state->SampleBuffer[1];                      \
-    ALuint offset = state->offset;                                            \
-    const ALfloat feedback = state->feedback;                                 \
-    ALuint it;                                                                \
-                                                                              \
-    for(it = 0;it < SamplesToDo;it++)                                         \
-    {                                                                         \
-        ALint delay_left, delay_right;                                        \
-        Func(&delay_left, &delay_right, offset, state);                       \
-                                                                              \
-        out[it][0] = leftbuf[(offset-delay_left)&bufmask];                    \
-        leftbuf[offset&bufmask] = (out[it][0]+SamplesIn[it]) * feedback;      \
-                                                                              \
-        out[it][1] = rightbuf[(offset-delay_right)&bufmask];                  \
-        rightbuf[offset&bufmask] = (out[it][1]+SamplesIn[it]) * feedback;     \
-                                                                              \
-        offset++;                                                             \
-    }                                                                         \
-    state->offset = offset;                                                   \
-}
-
-DECL_TEMPLATE(Triangle)
-DECL_TEMPLATE(Sinusoid)
-
-#undef DECL_TEMPLATE
-
-static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
-{
-    ALuint it, kt;
-    ALuint base;
-
-    for(base = 0;base < SamplesToDo;)
-    {
-        ALfloat temps[128][2];
-        ALuint td = minu(128, SamplesToDo-base);
-
-        switch(state->waveform)
-        {
-            case FWF_Triangle:
-                ProcessTriangle(state, td, SamplesIn[0]+base, temps);
-                break;
-            case FWF_Sinusoid:
-                ProcessSinusoid(state, td, SamplesIn[0]+base, temps);
-                break;
-        }
-
-        for(kt = 0;kt < NumChannels;kt++)
-        {
-            ALfloat gain = state->Gain[0][kt];
-            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(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
-            {
-                for(it = 0;it < td;it++)
-                    SamplesOut[kt][it+base] += temps[it][1] * gain;
-            }
-        }
-
-        base += td;
-    }
-}
-
-
-typedef struct ALflangerStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALflangerStateFactory;
-
-ALeffectState *ALflangerStateFactory_create(ALflangerStateFactory *UNUSED(factory))
-{
-    ALflangerState *state;
-
-    NEW_OBJ0(state, ALflangerState)();
-    if(!state) return NULL;
-
-    return STATIC_CAST(ALeffectState, state);
-}
-
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALflangerStateFactory);
-
-ALeffectStateFactory *ALflangerStateFactory_getFactory(void)
-{
-    static ALflangerStateFactory FlangerFactory = { { GET_VTABLE2(ALflangerStateFactory, ALeffectStateFactory) } };
-
-    return STATIC_CAST(ALeffectStateFactory, &FlangerFactory);
-}
-
-
-void ALflanger_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
-{
-    ALeffectProps *props = &effect->Props;
-    switch(param)
-    {
-        case AL_FLANGER_WAVEFORM:
-            if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
-            props->Flanger.Waveform = val;
-            break;
-
-        case AL_FLANGER_PHASE:
-            if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
-            props->Flanger.Phase = val;
-            break;
-
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
-    }
-}
-void ALflanger_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
-    ALflanger_setParami(effect, context, param, vals[0]);
-}
-void ALflanger_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val)
-{
-    ALeffectProps *props = &effect->Props;
-    switch(param)
-    {
-        case AL_FLANGER_RATE:
-            if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
-            props->Flanger.Rate = val;
-            break;
-
-        case AL_FLANGER_DEPTH:
-            if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
-            props->Flanger.Depth = val;
-            break;
-
-        case AL_FLANGER_FEEDBACK:
-            if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
-            props->Flanger.Feedback = val;
-            break;
-
-        case AL_FLANGER_DELAY:
-            if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
-            props->Flanger.Delay = val;
-            break;
-
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
-    }
-}
-void ALflanger_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
-    ALflanger_setParamf(effect, context, param, vals[0]);
-}
-
-void ALflanger_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
-{
-    const ALeffectProps *props = &effect->Props;
-    switch(param)
-    {
-        case AL_FLANGER_WAVEFORM:
-            *val = props->Flanger.Waveform;
-            break;
-
-        case AL_FLANGER_PHASE:
-            *val = props->Flanger.Phase;
-            break;
-
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
-    }
-}
-void ALflanger_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
-    ALflanger_getParami(effect, context, param, vals);
-}
-void ALflanger_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
-{
-    const ALeffectProps *props = &effect->Props;
-    switch(param)
-    {
-        case AL_FLANGER_RATE:
-            *val = props->Flanger.Rate;
-            break;
-
-        case AL_FLANGER_DEPTH:
-            *val = props->Flanger.Depth;
-            break;
-
-        case AL_FLANGER_FEEDBACK:
-            *val = props->Flanger.Feedback;
-            break;
-
-        case AL_FLANGER_DELAY:
-            *val = props->Flanger.Delay;
-            break;
-
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
-    }
-}
-void ALflanger_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
-    ALflanger_getParamf(effect, context, param, vals);
-}
-
-DEFINE_ALEFFECT_VTABLE(ALflanger);

+ 87 - 95
Engine/lib/openal-soft/Alc/effects/modulator.c

@@ -24,29 +24,36 @@
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "alMain.h"
 #include "alMain.h"
-#include "alFilter.h"
 #include "alAuxEffectSlot.h"
 #include "alAuxEffectSlot.h"
 #include "alError.h"
 #include "alError.h"
 #include "alu.h"
 #include "alu.h"
+#include "filters/defs.h"
 
 
 
 
+#define MAX_UPDATE_SAMPLES 128
+
 typedef struct ALmodulatorState {
 typedef struct ALmodulatorState {
     DERIVE_FROM_TYPE(ALeffectState);
     DERIVE_FROM_TYPE(ALeffectState);
 
 
-    void (*Process)(ALfloat*, const ALfloat*, ALuint, const ALuint, ALuint);
+    void (*GetSamples)(ALfloat*, ALsizei, const ALsizei, ALsizei);
+
+    ALsizei index;
+    ALsizei step;
 
 
-    ALuint index;
-    ALuint step;
+    alignas(16) ALfloat ModSamples[MAX_UPDATE_SAMPLES];
 
 
-    ALfloat Gain[MAX_EFFECT_CHANNELS][MAX_OUTPUT_CHANNELS];
+    struct {
+        BiquadFilter Filter;
 
 
-    ALfilterState Filter[MAX_EFFECT_CHANNELS];
+        ALfloat CurrentGains[MAX_OUTPUT_CHANNELS];
+        ALfloat TargetGains[MAX_OUTPUT_CHANNELS];
+    } Chans[MAX_EFFECT_CHANNELS];
 } ALmodulatorState;
 } ALmodulatorState;
 
 
 static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state);
 static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state);
 static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device);
 static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *device);
-static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props);
-static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels);
+static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
+static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
 DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState)
 DECLARE_DEFAULT_ALLOCATORS(ALmodulatorState)
 
 
 DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
 DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
@@ -56,31 +63,31 @@ DEFINE_ALEFFECTSTATE_VTABLE(ALmodulatorState);
 #define WAVEFORM_FRACONE   (1<<WAVEFORM_FRACBITS)
 #define WAVEFORM_FRACONE   (1<<WAVEFORM_FRACBITS)
 #define WAVEFORM_FRACMASK  (WAVEFORM_FRACONE-1)
 #define WAVEFORM_FRACMASK  (WAVEFORM_FRACONE-1)
 
 
-static inline ALfloat Sin(ALuint index)
+static inline ALfloat Sin(ALsizei index)
 {
 {
     return sinf(index*(F_TAU/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)
+static inline ALfloat Saw(ALsizei index)
 {
 {
     return (ALfloat)index / WAVEFORM_FRACONE;
     return (ALfloat)index / WAVEFORM_FRACONE;
 }
 }
 
 
-static inline ALfloat Square(ALuint index)
+static inline ALfloat Square(ALsizei index)
 {
 {
     return (ALfloat)((index >> (WAVEFORM_FRACBITS - 1)) & 1);
     return (ALfloat)((index >> (WAVEFORM_FRACBITS - 1)) & 1);
 }
 }
 
 
 #define DECL_TEMPLATE(func)                                                   \
 #define DECL_TEMPLATE(func)                                                   \
-static void Modulate##func(ALfloat *restrict dst, const ALfloat *restrict src,\
-                           ALuint index, const ALuint step, ALuint todo)      \
+static void Modulate##func(ALfloat *restrict dst, ALsizei index,              \
+                           const ALsizei step, ALsizei todo)                  \
 {                                                                             \
 {                                                                             \
-    ALuint i;                                                                 \
+    ALsizei i;                                                                \
     for(i = 0;i < todo;i++)                                                   \
     for(i = 0;i < todo;i++)                                                   \
     {                                                                         \
     {                                                                         \
         index += step;                                                        \
         index += step;                                                        \
         index &= WAVEFORM_FRACMASK;                                           \
         index &= WAVEFORM_FRACMASK;                                           \
-        dst[i] = src[i] * func(index);                                        \
+        dst[i] = func(index);                                                 \
     }                                                                         \
     }                                                                         \
 }
 }
 
 
@@ -93,16 +100,11 @@ DECL_TEMPLATE(Square)
 
 
 static void ALmodulatorState_Construct(ALmodulatorState *state)
 static void ALmodulatorState_Construct(ALmodulatorState *state)
 {
 {
-    ALuint i;
-
     ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
     ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
     SET_VTABLE2(ALmodulatorState, ALeffectState, state);
     SET_VTABLE2(ALmodulatorState, ALeffectState, state);
 
 
     state->index = 0;
     state->index = 0;
     state->step = 1;
     state->step = 1;
-
-    for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
-        ALfilterState_clear(&state->Filter[i]);
 }
 }
 
 
 static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state)
 static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state)
@@ -110,91 +112,89 @@ static ALvoid ALmodulatorState_Destruct(ALmodulatorState *state)
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
     ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
 }
 }
 
 
-static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), ALCdevice *UNUSED(device))
+static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *state, ALCdevice *UNUSED(device))
 {
 {
+    ALsizei i, j;
+    for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
+    {
+        BiquadFilter_clear(&state->Chans[i].Filter);
+        for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
+            state->Chans[i].CurrentGains[j] = 0.0f;
+    }
     return AL_TRUE;
     return AL_TRUE;
 }
 }
 
 
-static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCdevice *Device, const ALeffectslot *Slot, const ALeffectProps *props)
+static ALvoid ALmodulatorState_update(ALmodulatorState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
 {
 {
+    const ALCdevice *device = context->Device;
     ALfloat cw, a;
     ALfloat cw, a;
-    ALuint i;
+    ALsizei i;
 
 
     if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
     if(props->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
-        state->Process = ModulateSin;
+        state->GetSamples = ModulateSin;
     else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
     else if(props->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
-        state->Process = ModulateSaw;
+        state->GetSamples = ModulateSaw;
     else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
     else /*if(Slot->Params.EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SQUARE)*/
-        state->Process = ModulateSquare;
+        state->GetSamples = ModulateSquare;
 
 
-    state->step = fastf2u(props->Modulator.Frequency*WAVEFORM_FRACONE /
-                          Device->Frequency);
-    if(state->step == 0) state->step = 1;
+    state->step = float2int(props->Modulator.Frequency*WAVEFORM_FRACONE/device->Frequency + 0.5f);
+    state->step = clampi(state->step, 1, WAVEFORM_FRACONE-1);
 
 
     /* Custom filter coeffs, which match the old version instead of a low-shelf. */
     /* Custom filter coeffs, which match the old version instead of a low-shelf. */
-    cw = cosf(F_TAU * props->Modulator.HighPassCutoff / Device->Frequency);
+    cw = cosf(F_TAU * props->Modulator.HighPassCutoff / device->Frequency);
     a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
     a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
 
 
-    for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
-    {
-        state->Filter[i].a1 = -a;
-        state->Filter[i].a2 = 0.0f;
-        state->Filter[i].b0 = a;
-        state->Filter[i].b1 = -a;
-        state->Filter[i].b2 = 0.0f;
-    }
+    state->Chans[0].Filter.b0 = a;
+    state->Chans[0].Filter.b1 = -a;
+    state->Chans[0].Filter.b2 = 0.0f;
+    state->Chans[0].Filter.a1 = -a;
+    state->Chans[0].Filter.a2 = 0.0f;
+    for(i = 1;i < MAX_EFFECT_CHANNELS;i++)
+        BiquadFilter_copyParams(&state->Chans[i].Filter, &state->Chans[0].Filter);
 
 
-    STATIC_CAST(ALeffectState,state)->OutBuffer = Device->FOAOut.Buffer;
-    STATIC_CAST(ALeffectState,state)->OutChannels = Device->FOAOut.NumChannels;
+    STATIC_CAST(ALeffectState,state)->OutBuffer = device->FOAOut.Buffer;
+    STATIC_CAST(ALeffectState,state)->OutChannels = device->FOAOut.NumChannels;
     for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
     for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
-        ComputeFirstOrderGains(Device->FOAOut, IdentityMatrixf.m[i],
-                               Slot->Params.Gain, state->Gain[i]);
+        ComputeFirstOrderGains(&device->FOAOut, IdentityMatrixf.m[i],
+                               slot->Params.Gain, state->Chans[i].TargetGains);
 }
 }
 
 
-static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
+static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
 {
 {
-    const ALuint step = state->step;
-    ALuint index = state->index;
-    ALuint base;
+    ALfloat *restrict modsamples = ASSUME_ALIGNED(state->ModSamples, 16);
+    const ALsizei step = state->step;
+    ALsizei base;
 
 
     for(base = 0;base < SamplesToDo;)
     for(base = 0;base < SamplesToDo;)
     {
     {
-        ALfloat temps[2][128];
-        ALuint td = minu(128, SamplesToDo-base);
-        ALuint i, j, k;
+        alignas(16) ALfloat temps[2][MAX_UPDATE_SAMPLES];
+        ALsizei td = mini(MAX_UPDATE_SAMPLES, SamplesToDo-base);
+        ALsizei c, i;
 
 
-        for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
-        {
-            ALfilterState_process(&state->Filter[j], temps[0], &SamplesIn[j][base], td);
-            state->Process(temps[1], temps[0], index, step, td);
-
-            for(k = 0;k < NumChannels;k++)
-            {
-                ALfloat gain = state->Gain[j][k];
-                if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
-                    continue;
-
-                for(i = 0;i < td;i++)
-                    SamplesOut[k][base+i] += gain * temps[1][i];
-            }
-        }
+        state->GetSamples(modsamples, state->index, step, td);
+        state->index += (step*td) & WAVEFORM_FRACMASK;
+        state->index &= WAVEFORM_FRACMASK;
 
 
-        for(i = 0;i < td;i++)
+        for(c = 0;c < MAX_EFFECT_CHANNELS;c++)
         {
         {
-            index += step;
-            index &= WAVEFORM_FRACMASK;
+            BiquadFilter_process(&state->Chans[c].Filter, temps[0], &SamplesIn[c][base], td);
+            for(i = 0;i < td;i++)
+                temps[1][i] = temps[0][i] * modsamples[i];
+
+            MixSamples(temps[1], NumChannels, SamplesOut, state->Chans[c].CurrentGains,
+                       state->Chans[c].TargetGains, SamplesToDo-base, base, td);
         }
         }
+
         base += td;
         base += td;
     }
     }
-    state->index = index;
 }
 }
 
 
 
 
-typedef struct ALmodulatorStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALmodulatorStateFactory;
+typedef struct ModulatorStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} ModulatorStateFactory;
 
 
-static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UNUSED(factory))
+static ALeffectState *ModulatorStateFactory_create(ModulatorStateFactory *UNUSED(factory))
 {
 {
     ALmodulatorState *state;
     ALmodulatorState *state;
 
 
@@ -204,13 +204,13 @@ static ALeffectState *ALmodulatorStateFactory_create(ALmodulatorStateFactory *UN
     return STATIC_CAST(ALeffectState, state);
     return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALmodulatorStateFactory);
+DEFINE_EFFECTSTATEFACTORY_VTABLE(ModulatorStateFactory);
 
 
-ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void)
+EffectStateFactory *ModulatorStateFactory_getFactory(void)
 {
 {
-    static ALmodulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ALmodulatorStateFactory, ALeffectStateFactory) } };
+    static ModulatorStateFactory ModulatorFactory = { { GET_VTABLE2(ModulatorStateFactory, EffectStateFactory) } };
 
 
-    return STATIC_CAST(ALeffectStateFactory, &ModulatorFactory);
+    return STATIC_CAST(EffectStateFactory, &ModulatorFactory);
 }
 }
 
 
 
 
@@ -221,24 +221,22 @@ void ALmodulator_setParamf(ALeffect *effect, ALCcontext *context, ALenum param,
     {
     {
         case AL_RING_MODULATOR_FREQUENCY:
         case AL_RING_MODULATOR_FREQUENCY:
             if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
             if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator frequency out of range");
             props->Modulator.Frequency = val;
             props->Modulator.Frequency = val;
             break;
             break;
 
 
         case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
         case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
             if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
             if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Modulator high-pass cutoff out of range");
             props->Modulator.HighPassCutoff = val;
             props->Modulator.HighPassCutoff = val;
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param);
     }
     }
 }
 }
 void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
 void ALmodulator_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals)
-{
-    ALmodulator_setParamf(effect, context, param, vals[0]);
-}
+{ ALmodulator_setParamf(effect, context, param, vals[0]); }
 void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
 void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
 {
 {
     ALeffectProps *props = &effect->Props;
     ALeffectProps *props = &effect->Props;
@@ -251,18 +249,16 @@ void ALmodulator_setParami(ALeffect *effect, ALCcontext *context, ALenum param,
 
 
         case AL_RING_MODULATOR_WAVEFORM:
         case AL_RING_MODULATOR_WAVEFORM:
             if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM))
             if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM))
-                SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE);
+                SETERR_RETURN(context, AL_INVALID_VALUE,, "Invalid modulator waveform");
             props->Modulator.Waveform = val;
             props->Modulator.Waveform = val;
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param);
     }
     }
 }
 }
 void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
 void ALmodulator_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
-{
-    ALmodulator_setParami(effect, context, param, vals[0]);
-}
+{ ALmodulator_setParami(effect, context, param, vals[0]); }
 
 
 void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
 void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
 {
 {
@@ -280,13 +276,11 @@ void ALmodulator_getParami(const ALeffect *effect, ALCcontext *context, ALenum p
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid modulator integer property 0x%04x", param);
     }
     }
 }
 }
 void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
 void ALmodulator_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
-{
-    ALmodulator_getParami(effect, context, param, vals);
-}
+{ ALmodulator_getParami(effect, context, param, vals); }
 void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val)
 {
 {
     const ALeffectProps *props = &effect->Props;
     const ALeffectProps *props = &effect->Props;
@@ -300,12 +294,10 @@ void ALmodulator_getParamf(const ALeffect *effect, ALCcontext *context, ALenum p
             break;
             break;
 
 
         default:
         default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+            alSetError(context, AL_INVALID_ENUM, "Invalid modulator float property 0x%04x", param);
     }
     }
 }
 }
 void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
 void ALmodulator_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals)
-{
-    ALmodulator_getParamf(effect, context, param, vals);
-}
+{ ALmodulator_getParamf(effect, context, param, vals); }
 
 
 DEFINE_ALEFFECT_VTABLE(ALmodulator);
 DEFINE_ALEFFECT_VTABLE(ALmodulator);

+ 37 - 37
Engine/lib/openal-soft/Alc/effects/null.c

@@ -16,8 +16,8 @@ typedef struct ALnullState {
 /* Forward-declare "virtual" functions to define the vtable with. */
 /* Forward-declare "virtual" functions to define the vtable with. */
 static ALvoid ALnullState_Destruct(ALnullState *state);
 static ALvoid ALnullState_Destruct(ALnullState *state);
 static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device);
 static ALboolean ALnullState_deviceUpdate(ALnullState *state, ALCdevice *device);
-static ALvoid ALnullState_update(ALnullState *state, const ALCdevice *device, const ALeffectslot *slot, const ALeffectProps *props);
-static ALvoid ALnullState_process(ALnullState *state, ALuint samplesToDo, const ALfloatBUFFERSIZE*restrict samplesIn, ALfloatBUFFERSIZE*restrict samplesOut, ALuint NumChannels);
+static ALvoid ALnullState_update(ALnullState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
+static ALvoid ALnullState_process(ALnullState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei mumChannels);
 static void *ALnullState_New(size_t size);
 static void *ALnullState_New(size_t size);
 static void ALnullState_Delete(void *ptr);
 static void ALnullState_Delete(void *ptr);
 
 
@@ -56,7 +56,7 @@ static ALboolean ALnullState_deviceUpdate(ALnullState* UNUSED(state), ALCdevice*
 /* This updates the effect state. This is called any time the effect is
 /* This updates the effect state. This is called any time the effect is
  * (re)loaded into a slot.
  * (re)loaded into a slot.
  */
  */
-static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UNUSED(device), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props))
+static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCcontext* UNUSED(context), const ALeffectslot* UNUSED(slot), const ALeffectProps* UNUSED(props))
 {
 {
 }
 }
 
 
@@ -64,7 +64,7 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), const ALCdevice* UN
  * input to the output buffer. The result should be added to the output buffer,
  * input to the output buffer. The result should be added to the output buffer,
  * not replace it.
  * not replace it.
  */
  */
-static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels))
+static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALsizei UNUSED(samplesToDo), const ALfloatBUFFERSIZE*restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALsizei UNUSED(numChannels))
 {
 {
 }
 }
 
 
@@ -85,12 +85,12 @@ static void ALnullState_Delete(void *ptr)
 }
 }
 
 
 
 
-typedef struct ALnullStateFactory {
-    DERIVE_FROM_TYPE(ALeffectStateFactory);
-} ALnullStateFactory;
+typedef struct NullStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} NullStateFactory;
 
 
 /* Creates ALeffectState objects of the appropriate type. */
 /* Creates ALeffectState objects of the appropriate type. */
-ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory))
+ALeffectState *NullStateFactory_create(NullStateFactory *UNUSED(factory))
 {
 {
     ALnullState *state;
     ALnullState *state;
 
 
@@ -100,79 +100,79 @@ ALeffectState *ALnullStateFactory_create(ALnullStateFactory *UNUSED(factory))
     return STATIC_CAST(ALeffectState, state);
     return STATIC_CAST(ALeffectState, state);
 }
 }
 
 
-/* Define the ALeffectStateFactory vtable for this type. */
-DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALnullStateFactory);
+/* Define the EffectStateFactory vtable for this type. */
+DEFINE_EFFECTSTATEFACTORY_VTABLE(NullStateFactory);
 
 
-ALeffectStateFactory *ALnullStateFactory_getFactory(void)
+EffectStateFactory *NullStateFactory_getFactory(void)
 {
 {
-    static ALnullStateFactory NullFactory = { { GET_VTABLE2(ALnullStateFactory, ALeffectStateFactory) } };
-    return STATIC_CAST(ALeffectStateFactory, &NullFactory);
+    static NullStateFactory NullFactory = { { GET_VTABLE2(NullStateFactory, EffectStateFactory) } };
+    return STATIC_CAST(EffectStateFactory, &NullFactory);
 }
 }
 
 
 
 
-void ALnull_setParami(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
+void ALnull_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint UNUSED(val))
 {
 {
     switch(param)
     switch(param)
     {
     {
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+    default:
+        alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param);
     }
     }
 }
 }
-void ALnull_setParamiv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals))
+void ALnull_setParamiv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALint* UNUSED(vals))
 {
 {
     switch(param)
     switch(param)
     {
     {
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+    default:
+        alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer-vector property 0x%04x", param);
     }
     }
 }
 }
-void ALnull_setParamf(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
+void ALnull_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
 {
 {
     switch(param)
     switch(param)
     {
     {
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+    default:
+        alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param);
     }
     }
 }
 }
-void ALnull_setParamfv(ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals))
+void ALnull_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat* UNUSED(vals))
 {
 {
     switch(param)
     switch(param)
     {
     {
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+    default:
+        alSetError(context, AL_INVALID_ENUM, "Invalid null effect float-vector property 0x%04x", param);
     }
     }
 }
 }
 
 
-void ALnull_getParami(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val))
+void ALnull_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(val))
 {
 {
     switch(param)
     switch(param)
     {
     {
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+    default:
+        alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer property 0x%04x", param);
     }
     }
 }
 }
-void ALnull_getParamiv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals))
+void ALnull_getParamiv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALint* UNUSED(vals))
 {
 {
     switch(param)
     switch(param)
     {
     {
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+    default:
+        alSetError(context, AL_INVALID_ENUM, "Invalid null effect integer-vector property 0x%04x", param);
     }
     }
 }
 }
-void ALnull_getParamf(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val))
+void ALnull_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(val))
 {
 {
     switch(param)
     switch(param)
     {
     {
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+    default:
+        alSetError(context, AL_INVALID_ENUM, "Invalid null effect float property 0x%04x", param);
     }
     }
 }
 }
-void ALnull_getParamfv(const ALeffect* UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals))
+void ALnull_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat* UNUSED(vals))
 {
 {
     switch(param)
     switch(param)
     {
     {
-        default:
-            SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM);
+    default:
+        alSetError(context, AL_INVALID_ENUM, "Invalid null effect float-vector property 0x%04x", param);
     }
     }
 }
 }
 
 

+ 526 - 0
Engine/lib/openal-soft/Alc/effects/pshifter.c

@@ -0,0 +1,526 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2018 by Raul Herraiz.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+#include "filters/defs.h"
+
+
+#define STFT_SIZE      1024
+#define STFT_HALF_SIZE (STFT_SIZE>>1)
+#define OVERSAMP       (1<<2)
+
+#define STFT_STEP    (STFT_SIZE / OVERSAMP)
+#define FIFO_LATENCY (STFT_STEP * (OVERSAMP-1))
+
+typedef struct ALcomplex {
+    ALdouble Real;
+    ALdouble Imag;
+} ALcomplex;
+
+typedef struct ALphasor {
+    ALdouble Amplitude;
+    ALdouble Phase;
+} ALphasor;
+
+typedef struct ALFrequencyDomain {
+    ALdouble Amplitude;
+    ALdouble Frequency;
+} ALfrequencyDomain;
+
+typedef struct ALpshifterState {
+    DERIVE_FROM_TYPE(ALeffectState);
+
+    /* Effect parameters */
+    ALsizei count;
+    ALsizei PitchShiftI;
+    ALfloat PitchShift;
+    ALfloat FreqPerBin;
+
+    /*Effects buffers*/
+    ALfloat InFIFO[STFT_SIZE];
+    ALfloat OutFIFO[STFT_STEP];
+    ALdouble LastPhase[STFT_HALF_SIZE+1];
+    ALdouble SumPhase[STFT_HALF_SIZE+1];
+    ALdouble OutputAccum[STFT_SIZE];
+
+    ALcomplex FFTbuffer[STFT_SIZE];
+
+    ALfrequencyDomain Analysis_buffer[STFT_HALF_SIZE+1];
+    ALfrequencyDomain Syntesis_buffer[STFT_HALF_SIZE+1];
+
+    alignas(16) ALfloat BufferOut[BUFFERSIZE];
+
+    /* Effect gains for each output channel */
+    ALfloat CurrentGains[MAX_OUTPUT_CHANNELS];
+    ALfloat TargetGains[MAX_OUTPUT_CHANNELS];
+} ALpshifterState;
+
+static ALvoid ALpshifterState_Destruct(ALpshifterState *state);
+static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device);
+static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props);
+static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels);
+DECLARE_DEFAULT_ALLOCATORS(ALpshifterState)
+
+DEFINE_ALEFFECTSTATE_VTABLE(ALpshifterState);
+
+
+/* Define a Hann window, used to filter the STFT input and output. */
+alignas(16) static ALdouble HannWindow[STFT_SIZE];
+
+static void InitHannWindow(void)
+{
+    ALsizei i;
+
+    /* Create lookup table of the Hann window for the desired size, i.e. STFT_SIZE */
+    for(i = 0;i < STFT_SIZE>>1;i++)
+    {
+        ALdouble val = sin(M_PI * (ALdouble)i / (ALdouble)(STFT_SIZE-1));
+        HannWindow[i] = HannWindow[STFT_SIZE-1-i] = val * val;
+    }
+}
+static alonce_flag HannInitOnce = AL_ONCE_FLAG_INIT;
+
+
+/* Fast double-to-int conversion. Assumes the FPU is already in round-to-zero
+ * mode. */
+static inline ALint fastd2i(ALdouble d)
+{
+    /* NOTE: SSE2 is required for the efficient double-to-int opcodes on x86.
+     * Otherwise, we need to rely on x87's fistp opcode with it already in
+     * round-to-zero mode. x86-64 guarantees SSE2 support.
+     */
+#if (defined(__i386__) && !defined(__SSE2_MATH__)) || (defined(_M_IX86_FP) && (_M_IX86_FP < 2))
+#ifdef HAVE_LRINTF
+    return lrint(d);
+#elif defined(_MSC_VER) && defined(_M_IX86)
+    ALint i;
+    __asm fld d
+    __asm fistp i
+    return i;
+#else
+    return (ALint)d;
+#endif
+#else
+    return (ALint)d;
+#endif
+}
+
+
+/* Converts ALcomplex to ALphasor */
+static inline ALphasor rect2polar(ALcomplex number)
+{
+    ALphasor polar;
+
+    polar.Amplitude = sqrt(number.Real*number.Real + number.Imag*number.Imag);
+    polar.Phase     = atan2(number.Imag, number.Real);
+
+    return polar;
+}
+
+/* Converts ALphasor to ALcomplex */
+static inline ALcomplex polar2rect(ALphasor  number)
+{
+    ALcomplex cartesian;
+
+    cartesian.Real = number.Amplitude * cos(number.Phase);
+    cartesian.Imag = number.Amplitude * sin(number.Phase);
+
+    return cartesian;
+}
+
+/* Addition of two complex numbers (ALcomplex format) */
+static inline ALcomplex complex_add(ALcomplex a, ALcomplex b)
+{
+    ALcomplex result;
+
+    result.Real = a.Real + b.Real;
+    result.Imag = a.Imag + b.Imag;
+
+    return result;
+}
+
+/* Subtraction of two complex numbers (ALcomplex format) */
+static inline ALcomplex complex_sub(ALcomplex a, ALcomplex b)
+{
+    ALcomplex result;
+
+    result.Real = a.Real - b.Real;
+    result.Imag = a.Imag - b.Imag;
+
+    return result;
+}
+
+/* Multiplication of two complex numbers (ALcomplex format) */
+static inline ALcomplex complex_mult(ALcomplex a, ALcomplex b)
+{
+    ALcomplex result;
+
+    result.Real = a.Real*b.Real - a.Imag*b.Imag;
+    result.Imag = a.Imag*b.Real + a.Real*b.Imag;
+
+    return result;
+}
+
+/* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is
+ * FFT and 1 is iFFT (inverse). Fills FFTBuffer[0...FFTSize-1] with the
+ * Discrete Fourier Transform (DFT) of the time domain data stored in
+ * FFTBuffer[0...FFTSize-1]. FFTBuffer is an array of complex numbers
+ * (ALcomplex), FFTSize MUST BE power of two.
+ */
+static inline ALvoid FFT(ALcomplex *FFTBuffer, ALsizei FFTSize, ALdouble Sign)
+{
+    ALsizei i, j, k, mask, step, step2;
+    ALcomplex temp, u, w;
+    ALdouble arg;
+
+    /* Bit-reversal permutation applied to a sequence of FFTSize items */
+    for(i = 1;i < FFTSize-1;i++)
+    {
+        for(mask = 0x1, j = 0;mask < FFTSize;mask <<= 1)
+        {
+            if((i&mask) != 0)
+                j++;
+            j <<= 1;
+        }
+        j >>= 1;
+
+        if(i < j)
+        {
+            temp         = FFTBuffer[i];
+            FFTBuffer[i] = FFTBuffer[j];
+            FFTBuffer[j] = temp;
+        }
+    }
+
+    /* Iterative form of Danielson–Lanczos lemma */
+    for(i = 1, step = 2;i < FFTSize;i<<=1, step<<=1)
+    {
+        step2 = step >> 1;
+        arg   = M_PI / step2;
+
+        w.Real = cos(arg);
+        w.Imag = sin(arg) * Sign;
+
+        u.Real = 1.0;
+        u.Imag = 0.0;
+
+        for(j = 0;j < step2;j++)
+        {
+            for(k = j;k < FFTSize;k+=step)
+            {
+                temp               = complex_mult(FFTBuffer[k+step2], u);
+                FFTBuffer[k+step2] = complex_sub(FFTBuffer[k], temp);
+                FFTBuffer[k]       = complex_add(FFTBuffer[k], temp);
+            }
+
+            u = complex_mult(u, w);
+        }
+    }
+}
+
+
+static void ALpshifterState_Construct(ALpshifterState *state)
+{
+    ALeffectState_Construct(STATIC_CAST(ALeffectState, state));
+    SET_VTABLE2(ALpshifterState, ALeffectState, state);
+
+    alcall_once(&HannInitOnce, InitHannWindow);
+}
+
+static ALvoid ALpshifterState_Destruct(ALpshifterState *state)
+{
+    ALeffectState_Destruct(STATIC_CAST(ALeffectState,state));
+}
+
+static ALboolean ALpshifterState_deviceUpdate(ALpshifterState *state, ALCdevice *device)
+{
+    /* (Re-)initializing parameters and clear the buffers. */
+    state->count       = FIFO_LATENCY;
+    state->PitchShiftI = FRACTIONONE;
+    state->PitchShift  = 1.0f;
+    state->FreqPerBin  = device->Frequency / (ALfloat)STFT_SIZE;
+
+    memset(state->InFIFO,          0, sizeof(state->InFIFO));
+    memset(state->OutFIFO,         0, sizeof(state->OutFIFO));
+    memset(state->FFTbuffer,       0, sizeof(state->FFTbuffer));
+    memset(state->LastPhase,       0, sizeof(state->LastPhase));
+    memset(state->SumPhase,        0, sizeof(state->SumPhase));
+    memset(state->OutputAccum,     0, sizeof(state->OutputAccum));
+    memset(state->Analysis_buffer, 0, sizeof(state->Analysis_buffer));
+    memset(state->Syntesis_buffer, 0, sizeof(state->Syntesis_buffer));
+
+    memset(state->CurrentGains, 0, sizeof(state->CurrentGains));
+    memset(state->TargetGains,  0, sizeof(state->TargetGains));
+
+    return AL_TRUE;
+}
+
+static ALvoid ALpshifterState_update(ALpshifterState *state, const ALCcontext *context, const ALeffectslot *slot, const ALeffectProps *props)
+{
+    const ALCdevice *device = context->Device;
+    ALfloat coeffs[MAX_AMBI_COEFFS];
+    float pitch;
+
+    pitch = powf(2.0f,
+        (ALfloat)(props->Pshifter.CoarseTune*100 + props->Pshifter.FineTune) / 1200.0f
+    );
+    state->PitchShiftI = (ALsizei)(pitch*FRACTIONONE + 0.5f);
+    state->PitchShift = state->PitchShiftI * (1.0f/FRACTIONONE);
+
+    CalcAngleCoeffs(0.0f, 0.0f, 0.0f, coeffs);
+    ComputeDryPanGains(&device->Dry, coeffs, slot->Params.Gain, state->TargetGains);
+}
+
+static ALvoid ALpshifterState_process(ALpshifterState *state, ALsizei SamplesToDo, const ALfloat (*restrict SamplesIn)[BUFFERSIZE], ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALsizei NumChannels)
+{
+    /* Pitch shifter engine based on the work of Stephan Bernsee.
+     * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/
+     */
+
+    static const ALdouble expected = M_PI*2.0 / OVERSAMP;
+    const ALdouble freq_per_bin = state->FreqPerBin;
+    ALfloat *restrict bufferOut = state->BufferOut;
+    ALsizei count = state->count;
+    ALsizei i, j, k;
+
+    for(i = 0;i < SamplesToDo;)
+    {
+        do {
+            /* Fill FIFO buffer with samples data */
+            state->InFIFO[count] = SamplesIn[0][i];
+            bufferOut[i] = state->OutFIFO[count - FIFO_LATENCY];
+
+            count++;
+        } while(++i < SamplesToDo && count < STFT_SIZE);
+
+        /* Check whether FIFO buffer is filled */
+        if(count < STFT_SIZE) break;
+        count = FIFO_LATENCY;
+
+        /* Real signal windowing and store in FFTbuffer */
+        for(k = 0;k < STFT_SIZE;k++)
+        {
+            state->FFTbuffer[k].Real = state->InFIFO[k] * HannWindow[k];
+            state->FFTbuffer[k].Imag = 0.0;
+        }
+
+        /* ANALYSIS */
+        /* Apply FFT to FFTbuffer data */
+        FFT(state->FFTbuffer, STFT_SIZE, -1.0);
+
+        /* Analyze the obtained data. Since the real FFT is symmetric, only
+         * STFT_HALF_SIZE+1 samples are needed.
+         */
+        for(k = 0;k < STFT_HALF_SIZE+1;k++)
+        {
+            ALphasor component;
+            ALdouble tmp;
+            ALint qpd;
+
+            /* Compute amplitude and phase */
+            component = rect2polar(state->FFTbuffer[k]);
+
+            /* Compute phase difference and subtract expected phase difference */
+            tmp = (component.Phase - state->LastPhase[k]) - k*expected;
+
+            /* Map delta phase into +/- Pi interval */
+            qpd = fastd2i(tmp / M_PI);
+            tmp -= M_PI * (qpd + (qpd%2));
+
+            /* Get deviation from bin frequency from the +/- Pi interval */
+            tmp /= expected;
+
+            /* Compute the k-th partials' true frequency, twice the amplitude
+             * for maintain the gain (because half of bins are used) and store
+             * amplitude and true frequency in analysis buffer.
+             */
+            state->Analysis_buffer[k].Amplitude = 2.0 * component.Amplitude;
+            state->Analysis_buffer[k].Frequency = (k + tmp) * freq_per_bin;
+
+            /* Store actual phase[k] for the calculations in the next frame*/
+            state->LastPhase[k] = component.Phase;
+        }
+
+        /* PROCESSING */
+        /* pitch shifting */
+        for(k = 0;k < STFT_HALF_SIZE+1;k++)
+        {
+            state->Syntesis_buffer[k].Amplitude = 0.0;
+            state->Syntesis_buffer[k].Frequency = 0.0;
+        }
+
+        for(k = 0;k < STFT_HALF_SIZE+1;k++)
+        {
+            j = (k*state->PitchShiftI) >> FRACTIONBITS;
+            if(j >= STFT_HALF_SIZE+1) break;
+
+            state->Syntesis_buffer[j].Amplitude += state->Analysis_buffer[k].Amplitude;
+            state->Syntesis_buffer[j].Frequency  = state->Analysis_buffer[k].Frequency *
+                                                   state->PitchShift;
+        }
+
+        /* SYNTHESIS */
+        /* Synthesis the processing data */
+        for(k = 0;k < STFT_HALF_SIZE+1;k++)
+        {
+            ALphasor component;
+            ALdouble tmp;
+
+            /* Compute bin deviation from scaled freq */
+            tmp = state->Syntesis_buffer[k].Frequency/freq_per_bin - k;
+
+            /* Calculate actual delta phase and accumulate it to get bin phase */
+            state->SumPhase[k] += (k + tmp) * expected;
+
+            component.Amplitude = state->Syntesis_buffer[k].Amplitude;
+            component.Phase     = state->SumPhase[k];
+
+            /* Compute phasor component to cartesian complex number and storage it into FFTbuffer*/
+            state->FFTbuffer[k] = polar2rect(component);
+        }
+        /* zero negative frequencies for recontruct a real signal */
+        for(k = STFT_HALF_SIZE+1;k < STFT_SIZE;k++)
+        {
+            state->FFTbuffer[k].Real = 0.0;
+            state->FFTbuffer[k].Imag = 0.0;
+        }
+
+        /* Apply iFFT to buffer data */
+        FFT(state->FFTbuffer, STFT_SIZE, 1.0);
+
+        /* Windowing and add to output */
+        for(k = 0;k < STFT_SIZE;k++)
+            state->OutputAccum[k] += HannWindow[k] * state->FFTbuffer[k].Real /
+                                     (0.5 * STFT_HALF_SIZE * OVERSAMP);
+
+        /* Shift accumulator, input & output FIFO */
+        for(k = 0;k < STFT_STEP;k++) state->OutFIFO[k] = (ALfloat)state->OutputAccum[k];
+        for(j = 0;k < STFT_SIZE;k++,j++) state->OutputAccum[j] = state->OutputAccum[k];
+        for(;j < STFT_SIZE;j++) state->OutputAccum[j] = 0.0;
+        for(k = 0;k < FIFO_LATENCY;k++)
+            state->InFIFO[k] = state->InFIFO[k+STFT_STEP];
+    }
+    state->count = count;
+
+    /* Now, mix the processed sound data to the output. */
+    MixSamples(bufferOut, NumChannels, SamplesOut, state->CurrentGains, state->TargetGains,
+               maxi(SamplesToDo, 512), 0, SamplesToDo);
+}
+
+typedef struct PshifterStateFactory {
+    DERIVE_FROM_TYPE(EffectStateFactory);
+} PshifterStateFactory;
+
+static ALeffectState *PshifterStateFactory_create(PshifterStateFactory *UNUSED(factory))
+{
+    ALpshifterState *state;
+
+    NEW_OBJ0(state, ALpshifterState)();
+    if(!state) return NULL;
+
+    return STATIC_CAST(ALeffectState, state);
+}
+
+DEFINE_EFFECTSTATEFACTORY_VTABLE(PshifterStateFactory);
+
+EffectStateFactory *PshifterStateFactory_getFactory(void)
+{
+    static PshifterStateFactory PshifterFactory = { { GET_VTABLE2(PshifterStateFactory, EffectStateFactory) } };
+
+    return STATIC_CAST(EffectStateFactory, &PshifterFactory);
+}
+
+
+void ALpshifter_setParamf(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat UNUSED(val))
+{
+    alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param );
+}
+
+void ALpshifter_setParamfv(ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, const ALfloat *UNUSED(vals))
+{
+    alSetError( context, AL_INVALID_ENUM, "Invalid pitch shifter float-vector property 0x%04x", param );
+}
+
+void ALpshifter_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val)
+{
+    ALeffectProps *props = &effect->Props;
+    switch(param)
+    {
+        case AL_PITCH_SHIFTER_COARSE_TUNE:
+            if(!(val >= AL_PITCH_SHIFTER_MIN_COARSE_TUNE && val <= AL_PITCH_SHIFTER_MAX_COARSE_TUNE))
+                SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter coarse tune out of range");
+            props->Pshifter.CoarseTune = val;
+            break;
+
+        case AL_PITCH_SHIFTER_FINE_TUNE:
+            if(!(val >= AL_PITCH_SHIFTER_MIN_FINE_TUNE && val <= AL_PITCH_SHIFTER_MAX_FINE_TUNE))
+                SETERR_RETURN(context, AL_INVALID_VALUE,,"Pitch shifter fine tune out of range");
+            props->Pshifter.FineTune = val;
+            break;
+
+        default:
+            alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param);
+    }
+}
+void ALpshifter_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals)
+{
+    ALpshifter_setParami(effect, context, param, vals[0]);
+}
+
+void ALpshifter_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val)
+{
+    const ALeffectProps *props = &effect->Props;
+    switch(param)
+    {
+        case AL_PITCH_SHIFTER_COARSE_TUNE:
+            *val = (ALint)props->Pshifter.CoarseTune;
+            break;
+        case AL_PITCH_SHIFTER_FINE_TUNE:
+            *val = (ALint)props->Pshifter.FineTune;
+            break;
+
+        default:
+            alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter integer property 0x%04x", param);
+    }
+}
+void ALpshifter_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals)
+{
+    ALpshifter_getParami(effect, context, param, vals);
+}
+
+void ALpshifter_getParamf(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(val))
+{
+    alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float property 0x%04x", param);
+}
+
+void ALpshifter_getParamfv(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum param, ALfloat *UNUSED(vals))
+{
+    alSetError(context, AL_INVALID_ENUM, "Invalid pitch shifter float vector-property 0x%04x", param);
+}
+
+DEFINE_ALEFFECT_VTABLE(ALpshifter);

Файловите разлики са ограничени, защото са твърде много
+ 924 - 700
Engine/lib/openal-soft/Alc/effects/reverb.c


+ 112 - 0
Engine/lib/openal-soft/Alc/filters/defs.h

@@ -0,0 +1,112 @@
+#ifndef ALC_FILTER_H
+#define ALC_FILTER_H
+
+#include "AL/al.h"
+#include "math_defs.h"
+
+/* Filters implementation is based on the "Cookbook formulae for audio
+ * EQ biquad filter coefficients" by Robert Bristow-Johnson
+ * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+ */
+/* Implementation note: For the shelf filters, the specified gain is for the
+ * reference frequency, which is the centerpoint of the transition band. This
+ * better matches EFX filter design. To set the gain for the shelf itself, use
+ * the square root of the desired linear gain (or halve the dB gain).
+ */
+
+typedef enum BiquadType {
+    /** EFX-style low-pass filter, specifying a gain and reference frequency. */
+    BiquadType_HighShelf,
+    /** EFX-style high-pass filter, specifying a gain and reference frequency. */
+    BiquadType_LowShelf,
+    /** Peaking filter, specifying a gain and reference frequency. */
+    BiquadType_Peaking,
+
+    /** Low-pass cut-off filter, specifying a cut-off frequency. */
+    BiquadType_LowPass,
+    /** High-pass cut-off filter, specifying a cut-off frequency. */
+    BiquadType_HighPass,
+    /** Band-pass filter, specifying a center frequency. */
+    BiquadType_BandPass,
+} BiquadType;
+
+typedef struct BiquadFilter {
+    ALfloat z1, z2; /* Last two delayed components for direct form II. */
+    ALfloat b0, b1, b2; /* Transfer function coefficients "b" (numerator) */
+    ALfloat a1, a2; /* Transfer function coefficients "a" (denominator; a0 is
+                     * pre-applied). */
+} BiquadFilter;
+/* Currently only a C-based filter process method is implemented. */
+#define BiquadFilter_process BiquadFilter_processC
+
+/**
+ * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the
+ * reference gain and shelf slope parameter.
+ * \param gain 0 < gain
+ * \param slope 0 < slope <= 1
+ */
+inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope)
+{
+    return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f);
+}
+/**
+ * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the normalized
+ * reference frequency and bandwidth.
+ * \param f0norm 0 < f0norm < 0.5.
+ * \param bandwidth 0 < bandwidth
+ */
+inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth)
+{
+    ALfloat w0 = F_TAU * f0norm;
+    return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0));
+}
+
+inline void BiquadFilter_clear(BiquadFilter *filter)
+{
+    filter->z1 = 0.0f;
+    filter->z2 = 0.0f;
+}
+
+/**
+ * Sets up the filter state for the specified filter type and its parameters.
+ *
+ * \param filter The filter object to prepare.
+ * \param type The type of filter for the object to apply.
+ * \param gain The gain for the reference frequency response. Only used by the
+ *             Shelf and Peaking filter types.
+ * \param f0norm The normalized reference frequency (ref_freq / sample_rate).
+ *               This is the center point for the Shelf, Peaking, and BandPass
+ *               filter types, or the cutoff frequency for the LowPass and
+ *               HighPass filter types.
+ * \param rcpQ The reciprocal of the Q coefficient for the filter's transition
+ *             band. Can be generated from calc_rcpQ_from_slope or
+ *             calc_rcpQ_from_bandwidth depending on the available data.
+ */
+void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ);
+
+inline void BiquadFilter_copyParams(BiquadFilter *restrict dst, const BiquadFilter *restrict src)
+{
+    dst->b0 = src->b0;
+    dst->b1 = src->b1;
+    dst->b2 = src->b2;
+    dst->a1 = src->a1;
+    dst->a2 = src->a2;
+}
+
+void BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples);
+
+inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples)
+{
+    if(LIKELY(numsamples >= 2))
+    {
+        filter->z1 = 0.0f;
+        filter->z2 = 0.0f;
+    }
+    else if(numsamples == 1)
+    {
+        filter->z1 = filter->z2;
+        filter->z2 = 0.0f;
+    }
+}
+
+#endif /* ALC_FILTER_H */

+ 129 - 0
Engine/lib/openal-soft/Alc/filters/filter.c

@@ -0,0 +1,129 @@
+
+#include "config.h"
+
+#include "AL/alc.h"
+#include "AL/al.h"
+
+#include "alMain.h"
+#include "defs.h"
+
+extern inline void BiquadFilter_clear(BiquadFilter *filter);
+extern inline void BiquadFilter_copyParams(BiquadFilter *restrict dst, const BiquadFilter *restrict src);
+extern inline void BiquadFilter_passthru(BiquadFilter *filter, ALsizei numsamples);
+extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
+extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat f0norm, ALfloat bandwidth);
+
+
+void BiquadFilter_setParams(BiquadFilter *filter, BiquadType type, ALfloat gain, ALfloat f0norm, ALfloat rcpQ)
+{
+    ALfloat alpha, sqrtgain_alpha_2;
+    ALfloat w0, sin_w0, cos_w0;
+    ALfloat a[3] = { 1.0f, 0.0f, 0.0f };
+    ALfloat b[3] = { 1.0f, 0.0f, 0.0f };
+
+    // Limit gain to -100dB
+    assert(gain > 0.00001f);
+
+    w0 = F_TAU * f0norm;
+    sin_w0 = sinf(w0);
+    cos_w0 = cosf(w0);
+    alpha = sin_w0/2.0f * rcpQ;
+
+    /* Calculate filter coefficients depending on filter type */
+    switch(type)
+    {
+        case BiquadType_HighShelf:
+            sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
+            b[0] =       gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
+            b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0                   );
+            b[2] =       gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
+            a[0] =             (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
+            a[1] =  2.0f*     ((gain-1.0f) - (gain+1.0f)*cos_w0                   );
+            a[2] =             (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
+            break;
+        case BiquadType_LowShelf:
+            sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
+            b[0] =       gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
+            b[1] =  2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0                   );
+            b[2] =       gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
+            a[0] =             (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
+            a[1] = -2.0f*     ((gain-1.0f) + (gain+1.0f)*cos_w0                   );
+            a[2] =             (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
+            break;
+        case BiquadType_Peaking:
+            gain = sqrtf(gain);
+            b[0] =  1.0f + alpha * gain;
+            b[1] = -2.0f * cos_w0;
+            b[2] =  1.0f - alpha * gain;
+            a[0] =  1.0f + alpha / gain;
+            a[1] = -2.0f * cos_w0;
+            a[2] =  1.0f - alpha / gain;
+            break;
+
+        case BiquadType_LowPass:
+            b[0] = (1.0f - cos_w0) / 2.0f;
+            b[1] =  1.0f - cos_w0;
+            b[2] = (1.0f - cos_w0) / 2.0f;
+            a[0] =  1.0f + alpha;
+            a[1] = -2.0f * cos_w0;
+            a[2] =  1.0f - alpha;
+            break;
+        case BiquadType_HighPass:
+            b[0] =  (1.0f + cos_w0) / 2.0f;
+            b[1] = -(1.0f + cos_w0);
+            b[2] =  (1.0f + cos_w0) / 2.0f;
+            a[0] =   1.0f + alpha;
+            a[1] =  -2.0f * cos_w0;
+            a[2] =   1.0f - alpha;
+            break;
+        case BiquadType_BandPass:
+            b[0] =  alpha;
+            b[1] =  0;
+            b[2] = -alpha;
+            a[0] =  1.0f + alpha;
+            a[1] = -2.0f * cos_w0;
+            a[2] =  1.0f - alpha;
+            break;
+    }
+
+    filter->a1 = a[1] / a[0];
+    filter->a2 = a[2] / a[0];
+    filter->b0 = b[0] / a[0];
+    filter->b1 = b[1] / a[0];
+    filter->b2 = b[2] / a[0];
+}
+
+
+void BiquadFilter_processC(BiquadFilter *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALsizei numsamples)
+{
+    const ALfloat a1 = filter->a1;
+    const ALfloat a2 = filter->a2;
+    const ALfloat b0 = filter->b0;
+    const ALfloat b1 = filter->b1;
+    const ALfloat b2 = filter->b2;
+    ALfloat z1 = filter->z1;
+    ALfloat z2 = filter->z2;
+    ALsizei i;
+
+    ASSUME(numsamples > 0);
+
+    /* Processing loop is Transposed Direct Form II. This requires less storage
+     * compared to Direct Form I (only two delay components, instead of a four-
+     * sample history; the last two inputs and outputs), and works better for
+     * floating-point which favors summing similarly-sized values while being
+     * less bothered by overflow.
+     *
+     * See: http://www.earlevel.com/main/2003/02/28/biquads/
+     */
+    for(i = 0;i < numsamples;i++)
+    {
+        ALfloat input = src[i];
+        ALfloat output = input*b0 + z1;
+        z1 = input*b1 - output*a1 + z2;
+        z2 = input*b2 - output*a2;
+        dst[i] = output;
+    }
+
+    filter->z1 = z1;
+    filter->z2 = z2;
+}

+ 426 - 0
Engine/lib/openal-soft/Alc/filters/nfc.c

@@ -0,0 +1,426 @@
+
+#include "config.h"
+
+#include "nfc.h"
+#include "alMain.h"
+
+#include <string.h>
+
+
+/* Near-field control filters are the basis for handling the near-field effect.
+ * The near-field effect is a bass-boost present in the directional components
+ * of a recorded signal, created as a result of the wavefront curvature (itself
+ * a function of sound distance). Proper reproduction dictates this be
+ * compensated for using a bass-cut given the playback speaker distance, to
+ * avoid excessive bass in the playback.
+ *
+ * For real-time rendered audio, emulating the near-field effect based on the
+ * sound source's distance, and subsequently compensating for it at output
+ * based on the speaker distances, can create a more realistic perception of
+ * sound distance beyond a simple 1/r attenuation.
+ *
+ * These filters do just that. Each one applies a low-shelf filter, created as
+ * the combination of a bass-boost for a given sound source distance (near-
+ * field emulation) along with a bass-cut for a given control/speaker distance
+ * (near-field compensation).
+ *
+ * Note that it is necessary to apply a cut along with the boost, since the
+ * boost alone is unstable in higher-order ambisonics as it causes an infinite
+ * DC gain (even first-order ambisonics requires there to be no DC offset for
+ * the boost to work). Consequently, ambisonics requires a control parameter to
+ * be used to avoid an unstable boost-only filter. NFC-HOA defines this control
+ * as a reference delay, calculated with:
+ *
+ * reference_delay = control_distance / speed_of_sound
+ *
+ * This means w0 (for input) or w1 (for output) should be set to:
+ *
+ * wN = 1 / (reference_delay * sample_rate)
+ *
+ * when dealing with NFC-HOA content. For FOA input content, which does not
+ * specify a reference_delay variable, w0 should be set to 0 to apply only
+ * near-field compensation for output. It's important that w1 be a finite,
+ * positive, non-0 value or else the bass-boost will become unstable again.
+ * Also, w0 should not be too large compared to w1, to avoid excessively loud
+ * low frequencies.
+ */
+
+static const float B[4][3] = {
+    {    0.0f                             },
+    {    1.0f                             },
+    {    3.0f,     3.0f                   },
+    { 3.6778f,  6.4595f, 2.3222f          },
+  /*{ 4.2076f, 11.4877f, 5.7924f, 9.1401f }*/
+};
+
+static void NfcFilterCreate1(struct NfcFilter1 *nfc, const float w0, const float w1)
+{
+    float b_00, g_0;
+    float r;
+
+    nfc->base_gain = 1.0f;
+    nfc->gain = 1.0f;
+
+    /* Calculate bass-boost coefficients. */
+    r = 0.5f * w0;
+    b_00 = B[1][0] * r;
+    g_0 = 1.0f + b_00;
+
+    nfc->gain *= g_0;
+    nfc->b1 = 2.0f * b_00 / g_0;
+
+    /* Calculate bass-cut coefficients. */
+    r = 0.5f * w1;
+    b_00 = B[1][0] * r;
+    g_0 = 1.0f + b_00;
+
+    nfc->base_gain /= g_0;
+    nfc->gain /= g_0;
+    nfc->a1 = 2.0f * b_00 / g_0;
+}
+
+static void NfcFilterAdjust1(struct NfcFilter1 *nfc, const float w0)
+{
+    float b_00, g_0;
+    float r;
+
+    r = 0.5f * w0;
+    b_00 = B[1][0] * r;
+    g_0 = 1.0f + b_00;
+
+    nfc->gain = nfc->base_gain * g_0;
+    nfc->b1 = 2.0f * b_00 / g_0;
+}
+
+
+static void NfcFilterCreate2(struct NfcFilter2 *nfc, const float w0, const float w1)
+{
+    float b_10, b_11, g_1;
+    float r;
+
+    nfc->base_gain = 1.0f;
+    nfc->gain = 1.0f;
+
+    /* Calculate bass-boost coefficients. */
+    r = 0.5f * w0;
+    b_10 = B[2][0] * r;
+    b_11 = B[2][1] * r * r;
+    g_1 = 1.0f + b_10 + b_11;
+
+    nfc->gain *= g_1;
+    nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1;
+    nfc->b2 = 4.0f * b_11 / g_1;
+
+    /* Calculate bass-cut coefficients. */
+    r = 0.5f * w1;
+    b_10 = B[2][0] * r;
+    b_11 = B[2][1] * r * r;
+    g_1 = 1.0f + b_10 + b_11;
+
+    nfc->base_gain /= g_1;
+    nfc->gain /= g_1;
+    nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1;
+    nfc->a2 = 4.0f * b_11 / g_1;
+}
+
+static void NfcFilterAdjust2(struct NfcFilter2 *nfc, const float w0)
+{
+    float b_10, b_11, g_1;
+    float r;
+
+    r = 0.5f * w0;
+    b_10 = B[2][0] * r;
+    b_11 = B[2][1] * r * r;
+    g_1 = 1.0f + b_10 + b_11;
+
+    nfc->gain = nfc->base_gain * g_1;
+    nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1;
+    nfc->b2 = 4.0f * b_11 / g_1;
+}
+
+
+static void NfcFilterCreate3(struct NfcFilter3 *nfc, const float w0, const float w1)
+{
+    float b_10, b_11, g_1;
+    float b_00, g_0;
+    float r;
+
+    nfc->base_gain = 1.0f;
+    nfc->gain = 1.0f;
+
+    /* Calculate bass-boost coefficients. */
+    r = 0.5f * w0;
+    b_10 = B[3][0] * r;
+    b_11 = B[3][1] * r * r;
+    g_1 = 1.0f + b_10 + b_11;
+
+    nfc->gain *= g_1;
+    nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1;
+    nfc->b2 = 4.0f * b_11 / g_1;
+
+    b_00 = B[3][2] * r;
+    g_0 = 1.0f + b_00;
+
+    nfc->gain *= g_0;
+    nfc->b3 = 2.0f * b_00 / g_0;
+
+    /* Calculate bass-cut coefficients. */
+    r = 0.5f * w1;
+    b_10 = B[3][0] * r;
+    b_11 = B[3][1] * r * r;
+    g_1 = 1.0f + b_10 + b_11;
+
+    nfc->base_gain /= g_1;
+    nfc->gain /= g_1;
+    nfc->a1 = (2.0f*b_10 + 4.0f*b_11) / g_1;
+    nfc->a2 = 4.0f * b_11 / g_1;
+
+    b_00 = B[3][2] * r;
+    g_0 = 1.0f + b_00;
+
+    nfc->base_gain /= g_0;
+    nfc->gain /= g_0;
+    nfc->a3 = 2.0f * b_00 / g_0;
+}
+
+static void NfcFilterAdjust3(struct NfcFilter3 *nfc, const float w0)
+{
+    float b_10, b_11, g_1;
+    float b_00, g_0;
+    float r;
+
+    r = 0.5f * w0;
+    b_10 = B[3][0] * r;
+    b_11 = B[3][1] * r * r;
+    g_1 = 1.0f + b_10 + b_11;
+
+    nfc->gain = nfc->base_gain * g_1;
+    nfc->b1 = (2.0f*b_10 + 4.0f*b_11) / g_1;
+    nfc->b2 = 4.0f * b_11 / g_1;
+
+    b_00 = B[3][2] * r;
+    g_0 = 1.0f + b_00;
+
+    nfc->gain *= g_0;
+    nfc->b3 = 2.0f * b_00 / g_0;
+}
+
+
+void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1)
+{
+    memset(nfc, 0, sizeof(*nfc));
+    NfcFilterCreate1(&nfc->first, w0, w1);
+    NfcFilterCreate2(&nfc->second, w0, w1);
+    NfcFilterCreate3(&nfc->third, w0, w1);
+}
+
+void NfcFilterAdjust(NfcFilter *nfc, const float w0)
+{
+    NfcFilterAdjust1(&nfc->first, w0);
+    NfcFilterAdjust2(&nfc->second, w0);
+    NfcFilterAdjust3(&nfc->third, w0);
+}
+
+
+void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count)
+{
+    const float gain = nfc->first.gain;
+    const float b1 = nfc->first.b1;
+    const float a1 = nfc->first.a1;
+    float z1 = nfc->first.z[0];
+    int i;
+
+    ASSUME(count > 0);
+
+    for(i = 0;i < count;i++)
+    {
+        float y = src[i]*gain - a1*z1;
+        float out = y + b1*z1;
+        z1 += y;
+
+        dst[i] = out;
+    }
+    nfc->first.z[0] = z1;
+}
+
+void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count)
+{
+    const float gain = nfc->second.gain;
+    const float b1 = nfc->second.b1;
+    const float b2 = nfc->second.b2;
+    const float a1 = nfc->second.a1;
+    const float a2 = nfc->second.a2;
+    float z1 = nfc->second.z[0];
+    float z2 = nfc->second.z[1];
+    int i;
+
+    ASSUME(count > 0);
+
+    for(i = 0;i < count;i++)
+    {
+        float y = src[i]*gain - a1*z1 - a2*z2;
+        float out = y + b1*z1 + b2*z2;
+        z2 += z1;
+        z1 += y;
+
+        dst[i] = out;
+    }
+    nfc->second.z[0] = z1;
+    nfc->second.z[1] = z2;
+}
+
+void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count)
+{
+    const float gain = nfc->third.gain;
+    const float b1 = nfc->third.b1;
+    const float b2 = nfc->third.b2;
+    const float b3 = nfc->third.b3;
+    const float a1 = nfc->third.a1;
+    const float a2 = nfc->third.a2;
+    const float a3 = nfc->third.a3;
+    float z1 = nfc->third.z[0];
+    float z2 = nfc->third.z[1];
+    float z3 = nfc->third.z[2];
+    int i;
+
+    ASSUME(count > 0);
+
+    for(i = 0;i < count;i++)
+    {
+        float y = src[i]*gain - a1*z1 - a2*z2;
+        float out = y + b1*z1 + b2*z2;
+        z2 += z1;
+        z1 += y;
+
+        y = out - a3*z3;
+        out = y + b3*z3;
+        z3 += y;
+
+        dst[i] = out;
+    }
+    nfc->third.z[0] = z1;
+    nfc->third.z[1] = z2;
+    nfc->third.z[2] = z3;
+}
+
+#if 0 /* Original methods the above are derived from. */
+static void NfcFilterCreate(NfcFilter *nfc, const ALsizei order, const float src_dist, const float ctl_dist, const float rate)
+{
+    static const float B[4][5] = {
+        {                                     },
+        {    1.0f                             },
+        {    3.0f,     3.0f                   },
+        { 3.6778f,  6.4595f, 2.3222f          },
+        { 4.2076f, 11.4877f, 5.7924f, 9.1401f }
+    };
+    float w0 = SPEEDOFSOUNDMETRESPERSEC / (src_dist * rate);
+    float w1 = SPEEDOFSOUNDMETRESPERSEC / (ctl_dist * rate);
+    ALsizei i;
+    float r;
+
+    nfc->g = 1.0f;
+    nfc->coeffs[0] = 1.0f;
+
+    /* NOTE: Slight adjustment from the literature to raise the center
+     * frequency a bit (0.5 -> 1.0).
+     */
+    r = 1.0f * w0;
+    for(i = 0; i < (order-1);i += 2)
+    {
+        float b_10 = B[order][i  ] * r;
+        float b_11 = B[order][i+1] * r * r;
+        float g_1 = 1.0f + b_10 + b_11;
+
+        nfc->b[i] = b_10;
+        nfc->b[i + 1] = b_11;
+        nfc->coeffs[0] *= g_1;
+        nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
+        nfc->coeffs[i+2] = (4.0f * b_11) / g_1;
+    }
+    if(i < order)
+    {
+        float b_00 = B[order][i] * r;
+        float g_0 = 1.0f + b_00;
+
+        nfc->b[i] = b_00;
+        nfc->coeffs[0] *= g_0;
+        nfc->coeffs[i+1] = (2.0f * b_00) / g_0;
+    }
+
+    r = 1.0f * w1;
+    for(i = 0;i < (order-1);i += 2)
+    {
+        float b_10 = B[order][i  ] * r;
+        float b_11 = B[order][i+1] * r * r;
+        float g_1 = 1.0f + b_10 + b_11;
+
+        nfc->g /= g_1;
+        nfc->coeffs[0] /= g_1;
+        nfc->coeffs[order+i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
+        nfc->coeffs[order+i+2] = (4.0f * b_11) / g_1;
+    }
+    if(i < order)
+    {
+        float b_00 = B[order][i] * r;
+        float g_0 = 1.0f + b_00;
+
+        nfc->g /= g_0;
+        nfc->coeffs[0] /= g_0;
+        nfc->coeffs[order+i+1] = (2.0f * b_00) / g_0;
+    }
+
+    for(i = 0; i < MAX_AMBI_ORDER; i++)
+        nfc->history[i] = 0.0f;
+}
+
+static void NfcFilterAdjust(NfcFilter *nfc, const float distance)
+{
+    int i;
+
+    nfc->coeffs[0] = nfc->g;
+
+    for(i = 0;i < (nfc->order-1);i += 2)
+    {
+        float b_10 = nfc->b[i] / distance;
+        float b_11 = nfc->b[i+1] / (distance * distance);
+        float g_1 = 1.0f + b_10 + b_11;
+
+        nfc->coeffs[0] *= g_1;
+        nfc->coeffs[i+1] = ((2.0f * b_10) + (4.0f * b_11)) / g_1;
+        nfc->coeffs[i+2] = (4.0f * b_11) / g_1;
+    }
+    if(i < nfc->order)
+    {
+        float b_00 = nfc->b[i] / distance;
+        float g_0 = 1.0f + b_00;
+
+        nfc->coeffs[0] *= g_0;
+        nfc->coeffs[i+1] = (2.0f * b_00) / g_0;
+    }
+}
+
+static float NfcFilterProcess(const float in, NfcFilter *nfc)
+{
+    int i;
+    float out = in * nfc->coeffs[0];
+
+    for(i = 0;i < (nfc->order-1);i += 2)
+    {
+        float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) -
+                        (nfc->coeffs[nfc->order+i+2] * nfc->history[i+1]) + 1.0e-30f;
+        out = y + (nfc->coeffs[i+1]*nfc->history[i]) + (nfc->coeffs[i+2]*nfc->history[i+1]);
+
+        nfc->history[i+1] += nfc->history[i];
+        nfc->history[i] += y;
+    }
+    if(i < nfc->order)
+    {
+        float y = out - (nfc->coeffs[nfc->order+i+1] * nfc->history[i]) + 1.0e-30f;
+
+        out = y + (nfc->coeffs[i+1] * nfc->history[i]);
+        nfc->history[i] += y;
+    }
+
+    return out;
+}
+#endif

+ 49 - 0
Engine/lib/openal-soft/Alc/filters/nfc.h

@@ -0,0 +1,49 @@
+#ifndef FILTER_NFC_H
+#define FILTER_NFC_H
+
+struct NfcFilter1 {
+    float base_gain, gain;
+    float b1, a1;
+    float z[1];
+};
+struct NfcFilter2 {
+    float base_gain, gain;
+    float b1, b2, a1, a2;
+    float z[2];
+};
+struct NfcFilter3 {
+    float base_gain, gain;
+    float b1, b2, b3, a1, a2, a3;
+    float z[3];
+};
+
+typedef struct NfcFilter {
+    struct NfcFilter1 first;
+    struct NfcFilter2 second;
+    struct NfcFilter3 third;
+} NfcFilter;
+
+
+/* NOTE:
+ * w0 = speed_of_sound / (source_distance * sample_rate);
+ * w1 = speed_of_sound / (control_distance * sample_rate);
+ *
+ * Generally speaking, the control distance should be approximately the average
+ * speaker distance, or based on the reference delay if outputing NFC-HOA. It
+ * must not be negative, 0, or infinite. The source distance should not be too
+ * small relative to the control distance.
+ */
+
+void NfcFilterCreate(NfcFilter *nfc, const float w0, const float w1);
+void NfcFilterAdjust(NfcFilter *nfc, const float w0);
+
+/* Near-field control filter for first-order ambisonic channels (1-3). */
+void NfcFilterProcess1(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count);
+
+/* Near-field control filter for second-order ambisonic channels (4-8). */
+void NfcFilterProcess2(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count);
+
+/* Near-field control filter for third-order ambisonic channels (9-15). */
+void NfcFilterProcess3(NfcFilter *nfc, float *restrict dst, const float *restrict src, const int count);
+
+#endif /* FILTER_NFC_H */

+ 109 - 0
Engine/lib/openal-soft/Alc/filters/splitter.c

@@ -0,0 +1,109 @@
+
+#include "config.h"
+
+#include "splitter.h"
+
+#include "math_defs.h"
+
+
+void bandsplit_init(BandSplitter *splitter, ALfloat f0norm)
+{
+    ALfloat w = f0norm * F_TAU;
+    ALfloat cw = cosf(w);
+    if(cw > FLT_EPSILON)
+        splitter->coeff = (sinf(w) - 1.0f) / cw;
+    else
+        splitter->coeff = cw * -0.5f;
+
+    splitter->lp_z1 = 0.0f;
+    splitter->lp_z2 = 0.0f;
+    splitter->hp_z1 = 0.0f;
+}
+
+void bandsplit_clear(BandSplitter *splitter)
+{
+    splitter->lp_z1 = 0.0f;
+    splitter->lp_z2 = 0.0f;
+    splitter->hp_z1 = 0.0f;
+}
+
+void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
+                       const ALfloat *input, ALsizei count)
+{
+    ALfloat lp_coeff, hp_coeff, lp_y, hp_y, d;
+    ALfloat lp_z1, lp_z2, hp_z1;
+    ALsizei i;
+
+    ASSUME(count > 0);
+
+    hp_coeff = splitter->coeff;
+    lp_coeff = splitter->coeff*0.5f + 0.5f;
+    lp_z1 = splitter->lp_z1;
+    lp_z2 = splitter->lp_z2;
+    hp_z1 = splitter->hp_z1;
+    for(i = 0;i < count;i++)
+    {
+        ALfloat in = input[i];
+
+        /* Low-pass sample processing. */
+        d = (in - lp_z1) * lp_coeff;
+        lp_y = lp_z1 + d;
+        lp_z1 = lp_y + d;
+
+        d = (lp_y - lp_z2) * lp_coeff;
+        lp_y = lp_z2 + d;
+        lp_z2 = lp_y + d;
+
+        lpout[i] = lp_y;
+
+        /* All-pass sample processing. */
+        hp_y = in*hp_coeff + hp_z1;
+        hp_z1 = in - hp_y*hp_coeff;
+
+        /* High-pass generated from removing low-passed output. */
+        hpout[i] = hp_y - lp_y;
+    }
+    splitter->lp_z1 = lp_z1;
+    splitter->lp_z2 = lp_z2;
+    splitter->hp_z1 = hp_z1;
+}
+
+
+void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm)
+{
+    ALfloat w = f0norm * F_TAU;
+    ALfloat cw = cosf(w);
+    if(cw > FLT_EPSILON)
+        splitter->coeff = (sinf(w) - 1.0f) / cw;
+    else
+        splitter->coeff = cw * -0.5f;
+
+    splitter->z1 = 0.0f;
+}
+
+void splitterap_clear(SplitterAllpass *splitter)
+{
+    splitter->z1 = 0.0f;
+}
+
+void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count)
+{
+    ALfloat coeff, in, out;
+    ALfloat z1;
+    ALsizei i;
+
+    ASSUME(count > 0);
+
+    coeff = splitter->coeff;
+    z1 = splitter->z1;
+    for(i = 0;i < count;i++)
+    {
+        in = samples[i];
+
+        out = in*coeff + z1;
+        z1 = in - out*coeff;
+
+        samples[i] = out;
+    }
+    splitter->z1 = z1;
+}

+ 40 - 0
Engine/lib/openal-soft/Alc/filters/splitter.h

@@ -0,0 +1,40 @@
+#ifndef FILTER_SPLITTER_H
+#define FILTER_SPLITTER_H
+
+#include "alMain.h"
+
+
+/* Band splitter. Splits a signal into two phase-matching frequency bands. */
+typedef struct BandSplitter {
+    ALfloat coeff;
+    ALfloat lp_z1;
+    ALfloat lp_z2;
+    ALfloat hp_z1;
+} BandSplitter;
+
+void bandsplit_init(BandSplitter *splitter, ALfloat f0norm);
+void bandsplit_clear(BandSplitter *splitter);
+void bandsplit_process(BandSplitter *splitter, ALfloat *restrict hpout, ALfloat *restrict lpout,
+                       const ALfloat *input, ALsizei count);
+
+/* The all-pass portion of the band splitter. Applies the same phase shift
+ * without splitting the signal.
+ */
+typedef struct SplitterAllpass {
+    ALfloat coeff;
+    ALfloat z1;
+} SplitterAllpass;
+
+void splitterap_init(SplitterAllpass *splitter, ALfloat f0norm);
+void splitterap_clear(SplitterAllpass *splitter);
+void splitterap_process(SplitterAllpass *splitter, ALfloat *restrict samples, ALsizei count);
+
+
+typedef struct FrontStablizer {
+    SplitterAllpass APFilter[MAX_OUTPUT_CHANNELS];
+    BandSplitter LFilter, RFilter;
+    alignas(16) ALfloat LSplit[2][BUFFERSIZE];
+    alignas(16) ALfloat RSplit[2][BUFFERSIZE];
+} FrontStablizer;
+
+#endif /* FILTER_SPLITTER_H */

+ 34 - 0
Engine/lib/openal-soft/Alc/fpu_modes.h

@@ -0,0 +1,34 @@
+#ifndef FPU_MODES_H
+#define FPU_MODES_H
+
+#ifdef HAVE_FENV_H
+#include <fenv.h>
+#endif
+
+
+typedef struct FPUCtl {
+#if defined(__GNUC__) && defined(HAVE_SSE)
+    unsigned int sse_state;
+#elif defined(HAVE___CONTROL87_2)
+    unsigned int state;
+    unsigned int sse_state;
+#elif defined(HAVE__CONTROLFP)
+    unsigned int state;
+#endif
+} FPUCtl;
+void SetMixerFPUMode(FPUCtl *ctl);
+void RestoreFPUMode(const FPUCtl *ctl);
+
+#ifdef __GNUC__
+/* Use an alternate macro set with GCC to avoid accidental continue or break
+ * statements within the mixer mode.
+ */
+#define START_MIXER_MODE() __extension__({ FPUCtl _oldMode; SetMixerFPUMode(&_oldMode)
+#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); })
+#else
+#define START_MIXER_MODE() do { FPUCtl _oldMode; SetMixerFPUMode(&_oldMode)
+#define END_MIXER_MODE() RestoreFPUMode(&_oldMode); } while(0)
+#endif
+#define LEAVE_MIXER_MODE() RestoreFPUMode(&_oldMode)
+
+#endif /* FPU_MODES_H */

+ 282 - 229
Engine/lib/openal-soft/Alc/helpers.c

@@ -39,6 +39,14 @@
 #ifdef HAVE_DIRENT_H
 #ifdef HAVE_DIRENT_H
 #include <dirent.h>
 #include <dirent.h>
 #endif
 #endif
+#ifdef HAVE_PROC_PIDPATH
+#include <libproc.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
 
 
 #ifndef AL_NO_UID_DEFS
 #ifndef AL_NO_UID_DEFS
 #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
 #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
@@ -61,7 +69,7 @@ DEFINE_GUID(IID_IAudioClient,         0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc
 DEFINE_GUID(IID_IAudioRenderClient,   0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
 DEFINE_GUID(IID_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);
 DEFINE_GUID(IID_IAudioCaptureClient,  0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17);
 
 
-#ifdef HAVE_MMDEVAPI
+#ifdef HAVE_WASAPI
 #include <wtypes.h>
 #include <wtypes.h>
 #include <devpropdef.h>
 #include <devpropdef.h>
 #include <propkeydef.h>
 #include <propkeydef.h>
@@ -103,6 +111,8 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
+#include "cpu_caps.h"
+#include "fpu_modes.h"
 #include "atomic.h"
 #include "atomic.h"
 #include "uintmap.h"
 #include "uintmap.h"
 #include "vector.h"
 #include "vector.h"
@@ -112,71 +122,50 @@ DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x
 
 
 
 
 extern inline ALuint NextPowerOf2(ALuint value);
 extern inline ALuint NextPowerOf2(ALuint value);
+extern inline size_t RoundUp(size_t value, size_t r);
 extern inline ALint fastf2i(ALfloat f);
 extern inline ALint fastf2i(ALfloat f);
-extern inline ALuint fastf2u(ALfloat f);
+extern inline int float2int(float f);
+#ifndef __GNUC__
+#if defined(HAVE_BITSCANFORWARD64_INTRINSIC)
+extern inline int msvc64_ctz64(ALuint64 v);
+#elif defined(HAVE_BITSCANFORWARD_INTRINSIC)
+extern inline int msvc_ctz64(ALuint64 v);
+#else
+extern inline int fallback_popcnt64(ALuint64 v);
+extern inline int fallback_ctz64(ALuint64 value);
+#endif
+#endif
 
 
 
 
-ALuint CPUCapFlags = 0;
+#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \
+                                    defined(_M_IX86) || defined(_M_X64))
+typedef unsigned int reg_type;
+static inline void get_cpuid(int f, reg_type *regs)
+{ __get_cpuid(f, &regs[0], &regs[1], &regs[2], &regs[3]); }
+#define CAN_GET_CPUID
+#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \
+                                        defined(_M_IX86) || defined(_M_X64))
+typedef int reg_type;
+static inline void get_cpuid(int f, reg_type *regs)
+{ (__cpuid)(regs, f); }
+#define CAN_GET_CPUID
+#endif
 
 
+int CPUCapFlags = 0;
 
 
-void FillCPUCaps(ALuint capfilter)
+void FillCPUCaps(int capfilter)
 {
 {
-    ALuint caps = 0;
+    int caps = 0;
 
 
 /* FIXME: We really should get this for all available CPUs in case different
 /* FIXME: We really should get this for all available CPUs in case different
  * CPUs have different caps (is that possible on one machine?). */
  * CPUs have different caps (is that possible on one machine?). */
-#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \
-                                    defined(_M_IX86) || defined(_M_X64))
+#ifdef CAN_GET_CPUID
     union {
     union {
-        unsigned int regs[4];
-        char str[sizeof(unsigned int[4])];
-    } cpuinf[3];
+        reg_type regs[4];
+        char str[sizeof(reg_type[4])];
+    } cpuinf[3] = {{ { 0, 0, 0, 0 } }};
 
 
-    if(!__get_cpuid(0, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]))
-        ERR("Failed to get CPUID\n");
-    else
-    {
-        unsigned int maxfunc = cpuinf[0].regs[0];
-        unsigned int maxextfunc = 0;
-
-        if(__get_cpuid(0x80000000, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]))
-            maxextfunc = cpuinf[0].regs[0];
-        TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc);
-
-        TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8);
-        if(maxextfunc >= 0x80000004 &&
-           __get_cpuid(0x80000002, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]) &&
-           __get_cpuid(0x80000003, &cpuinf[1].regs[0], &cpuinf[1].regs[1], &cpuinf[1].regs[2], &cpuinf[1].regs[3]) &&
-           __get_cpuid(0x80000004, &cpuinf[2].regs[0], &cpuinf[2].regs[1], &cpuinf[2].regs[2], &cpuinf[2].regs[3]))
-            TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str);
-
-        if(maxfunc >= 1 &&
-           __get_cpuid(1, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]))
-        {
-            if((cpuinf[0].regs[3]&(1<<25)))
-            {
-                caps |= CPU_CAP_SSE;
-                if((cpuinf[0].regs[3]&(1<<26)))
-                {
-                    caps |= CPU_CAP_SSE2;
-                    if((cpuinf[0].regs[2]&(1<<0)))
-                    {
-                        caps |= CPU_CAP_SSE3;
-                        if((cpuinf[0].regs[2]&(1<<19)))
-                            caps |= CPU_CAP_SSE4_1;
-                    }
-                }
-            }
-        }
-    }
-#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \
-                                        defined(_M_IX86) || defined(_M_X64))
-    union {
-        int regs[4];
-        char str[sizeof(int[4])];
-    } cpuinf[3];
-
-    (__cpuid)(cpuinf[0].regs, 0);
+    get_cpuid(0, cpuinf[0].regs);
     if(cpuinf[0].regs[0] == 0)
     if(cpuinf[0].regs[0] == 0)
         ERR("Failed to get CPUID\n");
         ERR("Failed to get CPUID\n");
     else
     else
@@ -184,7 +173,7 @@ void FillCPUCaps(ALuint capfilter)
         unsigned int maxfunc = cpuinf[0].regs[0];
         unsigned int maxfunc = cpuinf[0].regs[0];
         unsigned int maxextfunc;
         unsigned int maxextfunc;
 
 
-        (__cpuid)(cpuinf[0].regs, 0x80000000);
+        get_cpuid(0x80000000, cpuinf[0].regs);
         maxextfunc = cpuinf[0].regs[0];
         maxextfunc = cpuinf[0].regs[0];
 
 
         TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc);
         TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc);
@@ -192,29 +181,23 @@ void FillCPUCaps(ALuint capfilter)
         TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8);
         TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8);
         if(maxextfunc >= 0x80000004)
         if(maxextfunc >= 0x80000004)
         {
         {
-            (__cpuid)(cpuinf[0].regs, 0x80000002);
-            (__cpuid)(cpuinf[1].regs, 0x80000003);
-            (__cpuid)(cpuinf[2].regs, 0x80000004);
+            get_cpuid(0x80000002, cpuinf[0].regs);
+            get_cpuid(0x80000003, cpuinf[1].regs);
+            get_cpuid(0x80000004, cpuinf[2].regs);
             TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str);
             TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str);
         }
         }
 
 
         if(maxfunc >= 1)
         if(maxfunc >= 1)
         {
         {
-            (__cpuid)(cpuinf[0].regs, 1);
+            get_cpuid(1, cpuinf[0].regs);
             if((cpuinf[0].regs[3]&(1<<25)))
             if((cpuinf[0].regs[3]&(1<<25)))
-            {
                 caps |= CPU_CAP_SSE;
                 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;
-                    }
-                }
-            }
+            if((caps&CPU_CAP_SSE) && (cpuinf[0].regs[3]&(1<<26)))
+                caps |= CPU_CAP_SSE2;
+            if((caps&CPU_CAP_SSE2) && (cpuinf[0].regs[2]&(1<<0)))
+                caps |= CPU_CAP_SSE3;
+            if((caps&CPU_CAP_SSE3) && (cpuinf[0].regs[2]&(1<<19)))
+                caps |= CPU_CAP_SSE4_1;
         }
         }
     }
     }
 #else
 #else
@@ -242,11 +225,16 @@ void FillCPUCaps(ALuint capfilter)
         char buf[256];
         char buf[256];
         while(fgets(buf, sizeof(buf), file) != NULL)
         while(fgets(buf, sizeof(buf), file) != NULL)
         {
         {
+            size_t len;
             char *str;
             char *str;
 
 
             if(strncmp(buf, "Features\t:", 10) != 0)
             if(strncmp(buf, "Features\t:", 10) != 0)
                 continue;
                 continue;
 
 
+            len = strlen(buf);
+            while(len > 0 && isspace(buf[len-1]))
+                buf[--len] = 0;
+
             TRACE("Got features string:%s\n", buf+10);
             TRACE("Got features string:%s\n", buf+10);
 
 
             str = buf;
             str = buf;
@@ -272,7 +260,7 @@ void FillCPUCaps(ALuint capfilter)
         ((capfilter&CPU_CAP_SSE2)   ? ((caps&CPU_CAP_SSE2)   ? " +SSE2"   : " -SSE2")   : ""),
         ((capfilter&CPU_CAP_SSE2)   ? ((caps&CPU_CAP_SSE2)   ? " +SSE2"   : " -SSE2")   : ""),
         ((capfilter&CPU_CAP_SSE3)   ? ((caps&CPU_CAP_SSE3)   ? " +SSE3"   : " -SSE3")   : ""),
         ((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_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
-        ((capfilter&CPU_CAP_NEON)   ? ((caps&CPU_CAP_NEON)   ? " +Neon"   : " -Neon")   : ""),
+        ((capfilter&CPU_CAP_NEON)   ? ((caps&CPU_CAP_NEON)   ? " +NEON"   : " -NEON")   : ""),
         ((!capfilter) ? " -none-" : "")
         ((!capfilter) ? " -none-" : "")
     );
     );
     CPUCapFlags = caps & capfilter;
     CPUCapFlags = caps & capfilter;
@@ -281,78 +269,51 @@ void FillCPUCaps(ALuint capfilter)
 
 
 void SetMixerFPUMode(FPUCtl *ctl)
 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
-
-#ifdef FE_TOWARDZERO
-    fesetround(FE_TOWARDZERO);
-#endif
 #if defined(__GNUC__) && defined(HAVE_SSE)
 #if defined(__GNUC__) && defined(HAVE_SSE)
     if((CPUCapFlags&CPU_CAP_SSE))
     if((CPUCapFlags&CPU_CAP_SSE))
     {
     {
-        int sseState = ctl->sse_state;
-        sseState |= 0x6000; /* set round-to-zero */
+        __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state));
+        unsigned int sseState = ctl->sse_state;
         sseState |= 0x8000; /* set flush-to-zero */
         sseState |= 0x8000; /* set flush-to-zero */
         if((CPUCapFlags&CPU_CAP_SSE2))
         if((CPUCapFlags&CPU_CAP_SSE2))
             sseState |= 0x0040; /* set denormals-are-zero */
             sseState |= 0x0040; /* set denormals-are-zero */
         __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState));
         __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState));
     }
     }
-#endif
 
 
 #elif defined(HAVE___CONTROL87_2)
 #elif defined(HAVE___CONTROL87_2)
 
 
-    int mode;
-    __control87_2(0, 0, &ctl->state, NULL);
-    __control87_2(_RC_CHOP, _MCW_RC, &mode, NULL);
-#ifdef HAVE_SSE
-    if((CPUCapFlags&CPU_CAP_SSE))
-    {
-        __control87_2(0, 0, NULL, &ctl->sse_state);
-        __control87_2(_RC_CHOP|_DN_FLUSH, _MCW_RC|_MCW_DN, NULL, &mode);
-    }
-#endif
+    __control87_2(0, 0, &ctl->state, &ctl->sse_state);
+    _control87(_DN_FLUSH, _MCW_DN);
 
 
 #elif defined(HAVE__CONTROLFP)
 #elif defined(HAVE__CONTROLFP)
 
 
     ctl->state = _controlfp(0, 0);
     ctl->state = _controlfp(0, 0);
-    (void)_controlfp(_RC_CHOP, _MCW_RC);
+    _controlfp(_DN_FLUSH, _MCW_DN);
 #endif
 #endif
 }
 }
 
 
 void RestoreFPUMode(const FPUCtl *ctl)
 void RestoreFPUMode(const FPUCtl *ctl)
 {
 {
-#ifdef HAVE_FENV_H
-    fesetenv(STATIC_CAST(fenv_t, ctl));
 #if defined(__GNUC__) && defined(HAVE_SSE)
 #if defined(__GNUC__) && defined(HAVE_SSE)
     if((CPUCapFlags&CPU_CAP_SSE))
     if((CPUCapFlags&CPU_CAP_SSE))
         __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state));
         __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state));
-#endif
 
 
 #elif defined(HAVE___CONTROL87_2)
 #elif defined(HAVE___CONTROL87_2)
 
 
     int mode;
     int mode;
-    __control87_2(ctl->state, _MCW_RC, &mode, NULL);
-#ifdef HAVE_SSE
-    if((CPUCapFlags&CPU_CAP_SSE))
-        __control87_2(ctl->sse_state, _MCW_RC|_MCW_DN, NULL, &mode);
-#endif
+    __control87_2(ctl->state, _MCW_DN, &mode, NULL);
+    __control87_2(ctl->sse_state, _MCW_DN, NULL, &mode);
 
 
 #elif defined(HAVE__CONTROLFP)
 #elif defined(HAVE__CONTROLFP)
 
 
-    _controlfp(ctl->state, _MCW_RC);
+    _controlfp(ctl->state, _MCW_DN);
 #endif
 #endif
 }
 }
 
 
 
 
 static int StringSortCompare(const void *str1, const void *str2)
 static int StringSortCompare(const void *str1, const void *str2)
 {
 {
-    return al_string_cmp(*(const_al_string*)str1, *(const_al_string*)str2);
+    return alstr_cmp(*(const_al_string*)str1, *(const_al_string*)str2);
 }
 }
 
 
 #ifdef _WIN32
 #ifdef _WIN32
@@ -369,9 +330,8 @@ static WCHAR *strrchrW(WCHAR *str, WCHAR ch)
     return ret;
     return ret;
 }
 }
 
 
-al_string GetProcPath(void)
+void GetProcBinary(al_string *path, al_string *fname)
 {
 {
-    al_string ret = AL_STRING_INIT_STATIC();
     WCHAR *pathname, *sep;
     WCHAR *pathname, *sep;
     DWORD pathlen;
     DWORD pathlen;
     DWORD len;
     DWORD len;
@@ -388,23 +348,34 @@ al_string GetProcPath(void)
     {
     {
         free(pathname);
         free(pathname);
         ERR("Failed to get process name: error %lu\n", GetLastError());
         ERR("Failed to get process name: error %lu\n", GetLastError());
-        return ret;
+        return;
     }
     }
 
 
     pathname[len] = 0;
     pathname[len] = 0;
-    if((sep = strrchrW(pathname, '\\')))
+    if((sep=strrchrW(pathname, '\\')) != NULL)
+    {
+        WCHAR *sep2 = strrchrW(sep+1, '/');
+        if(sep2) sep = sep2;
+    }
+    else
+        sep = strrchrW(pathname, '/');
+
+    if(sep)
     {
     {
-        WCHAR *sep2 = strrchrW(pathname, '/');
-        if(sep2) *sep2 = 0;
-        else *sep = 0;
+        if(path) alstr_copy_wrange(path, pathname, sep);
+        if(fname) alstr_copy_wcstr(fname, sep+1);
+    }
+    else
+    {
+        if(path) alstr_clear(path);
+        if(fname) alstr_copy_wcstr(fname, pathname);
     }
     }
-    else if((sep = strrchrW(pathname, '/')))
-        *sep = 0;
-    al_string_copy_wcstr(&ret, pathname);
     free(pathname);
     free(pathname);
 
 
-    TRACE("Got: %s\n", al_string_get_cstr(ret));
-    return ret;
+    if(path && fname)
+        TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname));
+    else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path));
+    else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname));
 }
 }
 
 
 
 
@@ -520,13 +491,13 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string
     WCHAR *wpath;
     WCHAR *wpath;
     HANDLE hdl;
     HANDLE hdl;
 
 
-    al_string_copy_cstr(&pathstr, path);
-    al_string_append_cstr(&pathstr, "\\*");
-    al_string_append_cstr(&pathstr, ext);
+    alstr_copy_cstr(&pathstr, path);
+    alstr_append_cstr(&pathstr, "\\*");
+    alstr_append_cstr(&pathstr, ext);
 
 
-    TRACE("Searching %s\n", al_string_get_cstr(pathstr));
+    TRACE("Searching %s\n", alstr_get_cstr(pathstr));
 
 
-    wpath = FromUTF8(al_string_get_cstr(pathstr));
+    wpath = FromUTF8(alstr_get_cstr(pathstr));
 
 
     hdl = FindFirstFileW(wpath, &fdata);
     hdl = FindFirstFileW(wpath, &fdata);
     if(hdl != INVALID_HANDLE_VALUE)
     if(hdl != INVALID_HANDLE_VALUE)
@@ -534,10 +505,10 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string
         size_t base = VECTOR_SIZE(*results);
         size_t base = VECTOR_SIZE(*results);
         do {
         do {
             al_string str = AL_STRING_INIT_STATIC();
             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));
+            alstr_copy_cstr(&str, path);
+            alstr_append_char(&str, '\\');
+            alstr_append_wcstr(&str, fdata.cFileName);
+            TRACE("Got result %s\n", alstr_get_cstr(str));
             VECTOR_PUSH_BACK(*results, str);
             VECTOR_PUSH_BACK(*results, str);
         } while(FindNextFileW(hdl, &fdata));
         } while(FindNextFileW(hdl, &fdata));
         FindClose(hdl);
         FindClose(hdl);
@@ -548,7 +519,7 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string
     }
     }
 
 
     free(wpath);
     free(wpath);
-    al_string_deinit(&pathstr);
+    alstr_reset(&pathstr);
 }
 }
 
 
 vector_al_string SearchDataFiles(const char *ext, const char *subdir)
 vector_al_string SearchDataFiles(const char *ext, const char *subdir)
@@ -558,21 +529,21 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir)
     vector_al_string results = VECTOR_INIT_STATIC();
     vector_al_string results = VECTOR_INIT_STATIC();
     size_t i;
     size_t i;
 
 
-    while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
+    while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1) == 1)
         althrd_yield();
         althrd_yield();
 
 
     /* If the path is absolute, use it directly. */
     /* If the path is absolute, use it directly. */
     if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2]))
     if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2]))
     {
     {
         al_string path = AL_STRING_INIT_STATIC();
         al_string path = AL_STRING_INIT_STATIC();
-        al_string_copy_cstr(&path, subdir);
+        alstr_copy_cstr(&path, subdir);
 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
         VECTOR_FOR_EACH(char, path, FIX_SLASH);
         VECTOR_FOR_EACH(char, path, FIX_SLASH);
 #undef FIX_SLASH
 #undef FIX_SLASH
 
 
-        DirectorySearch(al_string_get_cstr(path), ext, &results);
+        DirectorySearch(alstr_get_cstr(path), ext, &results);
 
 
-        al_string_deinit(&path);
+        alstr_reset(&path);
     }
     }
     else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\')
     else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\')
         DirectorySearch(subdir, ext, &results);
         DirectorySearch(subdir, ext, &results);
@@ -584,7 +555,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir)
         /* Search the app-local directory. */
         /* Search the app-local directory. */
         if((cwdbuf=_wgetenv(L"ALSOFT_LOCAL_PATH")) && *cwdbuf != '\0')
         if((cwdbuf=_wgetenv(L"ALSOFT_LOCAL_PATH")) && *cwdbuf != '\0')
         {
         {
-            al_string_copy_wcstr(&path, cwdbuf);
+            alstr_copy_wcstr(&path, cwdbuf);
             if(is_slash(VECTOR_BACK(path)))
             if(is_slash(VECTOR_BACK(path)))
             {
             {
                 VECTOR_POP_BACK(path);
                 VECTOR_POP_BACK(path);
@@ -592,10 +563,10 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir)
             }
             }
         }
         }
         else if(!(cwdbuf=_wgetcwd(NULL, 0)))
         else if(!(cwdbuf=_wgetcwd(NULL, 0)))
-            al_string_copy_cstr(&path, ".");
+            alstr_copy_cstr(&path, ".");
         else
         else
         {
         {
-            al_string_copy_wcstr(&path, cwdbuf);
+            alstr_copy_wcstr(&path, cwdbuf);
             if(is_slash(VECTOR_BACK(path)))
             if(is_slash(VECTOR_BACK(path)))
             {
             {
                 VECTOR_POP_BACK(path);
                 VECTOR_POP_BACK(path);
@@ -606,30 +577,30 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir)
 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
         VECTOR_FOR_EACH(char, path, FIX_SLASH);
         VECTOR_FOR_EACH(char, path, FIX_SLASH);
 #undef FIX_SLASH
 #undef FIX_SLASH
-        DirectorySearch(al_string_get_cstr(path), ext, &results);
+        DirectorySearch(alstr_get_cstr(path), ext, &results);
 
 
         /* Search the local and global data dirs. */
         /* Search the local and global data dirs. */
         for(i = 0;i < COUNTOF(ids);i++)
         for(i = 0;i < COUNTOF(ids);i++)
         {
         {
-            WCHAR buffer[PATH_MAX];
+            WCHAR buffer[MAX_PATH];
             if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE)
             if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE)
             {
             {
-                al_string_copy_wcstr(&path, buffer);
+                alstr_copy_wcstr(&path, buffer);
                 if(!is_slash(VECTOR_BACK(path)))
                 if(!is_slash(VECTOR_BACK(path)))
-                    al_string_append_char(&path, '\\');
-                al_string_append_cstr(&path, subdir);
+                    alstr_append_char(&path, '\\');
+                alstr_append_cstr(&path, subdir);
 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
 #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
                 VECTOR_FOR_EACH(char, path, FIX_SLASH);
                 VECTOR_FOR_EACH(char, path, FIX_SLASH);
 #undef FIX_SLASH
 #undef FIX_SLASH
 
 
-                DirectorySearch(al_string_get_cstr(path), ext, &results);
+                DirectorySearch(alstr_get_cstr(path), ext, &results);
             }
             }
         }
         }
 
 
-        al_string_deinit(&path);
+        alstr_reset(&path);
     }
     }
 
 
-    ATOMIC_STORE(&search_lock, 0);
+    ATOMIC_STORE_SEQ(&search_lock, 0);
 
 
     return results;
     return results;
 }
 }
@@ -698,49 +669,103 @@ void UnmapFileMem(const struct FileMapping *mapping)
 
 
 #else
 #else
 
 
-al_string GetProcPath(void)
+void GetProcBinary(al_string *path, al_string *fname)
 {
 {
-    al_string ret = AL_STRING_INIT_STATIC();
-    const char *fname;
-    char *pathname, *sep;
+    char *pathname = NULL;
     size_t pathlen;
     size_t pathlen;
-    ssize_t len;
 
 
-    pathlen = 256;
-    pathname = malloc(pathlen);
-
-    fname = "/proc/self/exe";
-    len = readlink(fname, pathname, pathlen);
-    if(len == -1 && errno == ENOENT)
+#ifdef __FreeBSD__
+    int mib[4] = { CTL_KERN, KERN_PROC_ARGS, getpid() };
+    if(sysctl(mib, 3, NULL, &pathlen, NULL, 0) == -1)
+        WARN("Failed to sysctl kern.procargs.%d: %s\n", mib[2], strerror(errno));
+    else
     {
     {
-        fname = "/proc/self/file";
-        len = readlink(fname, pathname, pathlen);
+        pathname = malloc(pathlen + 1);
+        sysctl(mib, 3, (void*)pathname, &pathlen, NULL, 0);
+        pathname[pathlen] = 0;
     }
     }
-
-    while(len > 0 && (size_t)len == pathlen)
+#endif
+#ifdef HAVE_PROC_PIDPATH
+    if(!pathname)
     {
     {
-        free(pathname);
-        pathlen <<= 1;
-        pathname = malloc(pathlen);
-        len = readlink(fname, pathname, pathlen);
+        const pid_t pid = getpid();
+        char procpath[PROC_PIDPATHINFO_MAXSIZE];
+        int ret;
+
+        ret = proc_pidpath(pid, procpath, sizeof(procpath));
+        if(ret < 1)
+        {
+            WARN("proc_pidpath(%d, ...) failed: %s\n", pid, strerror(errno));
+            free(pathname);
+            pathname = NULL;
+        }
+        else
+        {
+            pathlen = strlen(procpath);
+            pathname = strdup(procpath);
+        }
     }
     }
-    if(len <= 0)
+#endif
+    if(!pathname)
     {
     {
-        free(pathname);
-        WARN("Failed to readlink %s: %s\n", fname, strerror(errno));
-        return ret;
+        const char *selfname;
+        ssize_t len;
+
+        pathlen = 256;
+        pathname = malloc(pathlen);
+
+        selfname = "/proc/self/exe";
+        len = readlink(selfname, pathname, pathlen);
+        if(len == -1 && errno == ENOENT)
+        {
+            selfname = "/proc/self/file";
+            len = readlink(selfname, pathname, pathlen);
+        }
+        if(len == -1 && errno == ENOENT)
+        {
+            selfname = "/proc/curproc/exe";
+            len = readlink(selfname, pathname, pathlen);
+        }
+        if(len == -1 && errno == ENOENT)
+        {
+            selfname = "/proc/curproc/file";
+            len = readlink(selfname, pathname, pathlen);
+        }
+
+        while(len > 0 && (size_t)len == pathlen)
+        {
+            free(pathname);
+            pathlen <<= 1;
+            pathname = malloc(pathlen);
+            len = readlink(selfname, pathname, pathlen);
+        }
+        if(len <= 0)
+        {
+            free(pathname);
+            WARN("Failed to readlink %s: %s\n", selfname, strerror(errno));
+            return;
+        }
+
+        pathname[len] = 0;
     }
     }
 
 
-    pathname[len] = 0;
-    sep = strrchr(pathname, '/');
+    char *sep = strrchr(pathname, '/');
     if(sep)
     if(sep)
-        al_string_copy_range(&ret, pathname, sep);
+    {
+        if(path) alstr_copy_range(path, pathname, sep);
+        if(fname) alstr_copy_cstr(fname, sep+1);
+    }
     else
     else
-        al_string_copy_cstr(&ret, pathname);
+    {
+        if(path) alstr_clear(path);
+        if(fname) alstr_copy_cstr(fname, pathname);
+    }
     free(pathname);
     free(pathname);
 
 
-    TRACE("Got: %s\n", al_string_get_cstr(ret));
-    return ret;
+    if(path && fname)
+        TRACE("Got: %s, %s\n", alstr_get_cstr(*path), alstr_get_cstr(*fname));
+    else if(path) TRACE("Got path: %s\n", alstr_get_cstr(*path));
+    else if(fname) TRACE("Got filename: %s\n", alstr_get_cstr(*fname));
 }
 }
 
 
 
 
@@ -814,11 +839,11 @@ static void DirectorySearch(const char *path, const char *ext, vector_al_string
                 continue;
                 continue;
 
 
             AL_STRING_INIT(str);
             AL_STRING_INIT(str);
-            al_string_copy_cstr(&str, path);
+            alstr_copy_cstr(&str, path);
             if(VECTOR_BACK(str) != '/')
             if(VECTOR_BACK(str) != '/')
-                al_string_append_char(&str, '/');
-            al_string_append_cstr(&str, dirent->d_name);
-            TRACE("Got result %s\n", al_string_get_cstr(str));
+                alstr_append_char(&str, '/');
+            alstr_append_cstr(&str, dirent->d_name);
+            TRACE("Got result %s\n", alstr_get_cstr(str));
             VECTOR_PUSH_BACK(*results, str);
             VECTOR_PUSH_BACK(*results, str);
         }
         }
         closedir(dir);
         closedir(dir);
@@ -834,7 +859,7 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir)
     static RefCount search_lock;
     static RefCount search_lock;
     vector_al_string results = VECTOR_INIT_STATIC();
     vector_al_string results = VECTOR_INIT_STATIC();
 
 
-    while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
+    while(ATOMIC_EXCHANGE_SEQ(&search_lock, 1) == 1)
         althrd_yield();
         althrd_yield();
 
 
     if(subdir[0] == '/')
     if(subdir[0] == '/')
@@ -843,36 +868,53 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir)
     {
     {
         al_string path = AL_STRING_INIT_STATIC();
         al_string path = AL_STRING_INIT_STATIC();
         const char *str, *next;
         const char *str, *next;
-        char cwdbuf[PATH_MAX];
 
 
         /* Search the app-local directory. */
         /* Search the app-local directory. */
         if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0')
         if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0')
             DirectorySearch(str, ext, &results);
             DirectorySearch(str, ext, &results);
-        else if(getcwd(cwdbuf, sizeof(cwdbuf)))
-            DirectorySearch(cwdbuf, ext, &results);
         else
         else
-            DirectorySearch(".", ext, &results);
+        {
+            size_t cwdlen = 256;
+            char *cwdbuf = malloc(cwdlen);
+            while(!getcwd(cwdbuf, cwdlen))
+            {
+                free(cwdbuf);
+                cwdbuf = NULL;
+                if(errno != ERANGE)
+                    break;
+                cwdlen <<= 1;
+                cwdbuf = malloc(cwdlen);
+            }
+            if(!cwdbuf)
+                DirectorySearch(".", ext, &results);
+            else
+            {
+                DirectorySearch(cwdbuf, ext, &results);
+                free(cwdbuf);
+                cwdbuf = NULL;
+            }
+        }
 
 
         // Search local data dir
         // Search local data dir
         if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
         if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
         {
         {
-            al_string_copy_cstr(&path, str);
+            alstr_copy_cstr(&path, str);
             if(VECTOR_BACK(path) != '/')
             if(VECTOR_BACK(path) != '/')
-                al_string_append_char(&path, '/');
-            al_string_append_cstr(&path, subdir);
-            DirectorySearch(al_string_get_cstr(path), ext, &results);
+                alstr_append_char(&path, '/');
+            alstr_append_cstr(&path, subdir);
+            DirectorySearch(alstr_get_cstr(path), ext, &results);
         }
         }
         else if((str=getenv("HOME")) != NULL && str[0] != '\0')
         else if((str=getenv("HOME")) != NULL && str[0] != '\0')
         {
         {
-            al_string_copy_cstr(&path, str);
+            alstr_copy_cstr(&path, str);
             if(VECTOR_BACK(path) == '/')
             if(VECTOR_BACK(path) == '/')
             {
             {
                 VECTOR_POP_BACK(path);
                 VECTOR_POP_BACK(path);
                 *VECTOR_END(path) = 0;
                 *VECTOR_END(path) = 0;
             }
             }
-            al_string_append_cstr(&path, "/.local/share/");
-            al_string_append_cstr(&path, subdir);
-            DirectorySearch(al_string_get_cstr(path), ext, &results);
+            alstr_append_cstr(&path, "/.local/share/");
+            alstr_append_cstr(&path, subdir);
+            DirectorySearch(alstr_get_cstr(path), ext, &results);
         }
         }
 
 
         // Search global data dirs
         // Search global data dirs
@@ -884,26 +926,26 @@ vector_al_string SearchDataFiles(const char *ext, const char *subdir)
         {
         {
             next = strchr(str, ':');
             next = strchr(str, ':');
             if(!next)
             if(!next)
-                al_string_copy_cstr(&path, str);
+                alstr_copy_cstr(&path, str);
             else
             else
             {
             {
-                al_string_copy_range(&path, str, next);
+                alstr_copy_range(&path, str, next);
                 ++next;
                 ++next;
             }
             }
-            if(!al_string_empty(path))
+            if(!alstr_empty(path))
             {
             {
                 if(VECTOR_BACK(path) != '/')
                 if(VECTOR_BACK(path) != '/')
-                    al_string_append_char(&path, '/');
-                al_string_append_cstr(&path, subdir);
+                    alstr_append_char(&path, '/');
+                alstr_append_cstr(&path, subdir);
 
 
-                DirectorySearch(al_string_get_cstr(path), ext, &results);
+                DirectorySearch(alstr_get_cstr(path), ext, &results);
             }
             }
         }
         }
 
 
-        al_string_deinit(&path);
+        alstr_reset(&path);
     }
     }
 
 
-    ATOMIC_STORE(&search_lock, 0);
+    ATOMIC_STORE_SEQ(&search_lock, 0);
 
 
     return results;
     return results;
 }
 }
@@ -977,14 +1019,14 @@ void SetRTPriority(void)
 }
 }
 
 
 
 
-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);
+extern inline void alstr_reset(al_string *str);
+extern inline size_t alstr_length(const_al_string str);
+extern inline ALboolean alstr_empty(const_al_string str);
+extern inline const al_string_char_type *alstr_get_cstr(const_al_string str);
 
 
-void al_string_clear(al_string *str)
+void alstr_clear(al_string *str)
 {
 {
-    if(!al_string_empty(*str))
+    if(!alstr_empty(*str))
     {
     {
         /* Reserve one more character than the total size of the string. This
         /* Reserve one more character than the total size of the string. This
          * is to ensure we have space to add a null terminator in the string
          * is to ensure we have space to add a null terminator in the string
@@ -995,8 +1037,8 @@ void al_string_clear(al_string *str)
     }
     }
 }
 }
 
 
-static inline int al_string_compare(const al_string_char_type *str1, size_t str1len,
-                                    const al_string_char_type *str2, size_t str2len)
+static inline int alstr_compare(const al_string_char_type *str1, size_t str1len,
+                                const al_string_char_type *str2, size_t str2len)
 {
 {
     size_t complen = (str1len < str2len) ? str1len : str2len;
     size_t complen = (str1len < str2len) ? str1len : str2len;
     int ret = memcmp(str1, str2, complen);
     int ret = memcmp(str1, str2, complen);
@@ -1007,20 +1049,20 @@ static inline int al_string_compare(const al_string_char_type *str1, size_t str1
     }
     }
     return ret;
     return ret;
 }
 }
-int al_string_cmp(const_al_string str1, const_al_string str2)
+int alstr_cmp(const_al_string str1, const_al_string str2)
 {
 {
-    return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
-                             &VECTOR_FRONT(str2), al_string_length(str2));
+    return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1),
+                         &VECTOR_FRONT(str2), alstr_length(str2));
 }
 }
-int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2)
+int alstr_cmp_cstr(const_al_string str1, const al_string_char_type *str2)
 {
 {
-    return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
-                             str2, strlen(str2));
+    return alstr_compare(&VECTOR_FRONT(str1), alstr_length(str1),
+                         str2, strlen(str2));
 }
 }
 
 
-void al_string_copy(al_string *str, const_al_string from)
+void alstr_copy(al_string *str, const_al_string from)
 {
 {
-    size_t len = al_string_length(from);
+    size_t len = alstr_length(from);
     size_t i;
     size_t i;
 
 
     VECTOR_RESIZE(*str, len, len+1);
     VECTOR_RESIZE(*str, len, len+1);
@@ -1029,7 +1071,7 @@ void al_string_copy(al_string *str, const_al_string from)
     VECTOR_ELEM(*str, i) = 0;
     VECTOR_ELEM(*str, i) = 0;
 }
 }
 
 
-void al_string_copy_cstr(al_string *str, const al_string_char_type *from)
+void alstr_copy_cstr(al_string *str, const al_string_char_type *from)
 {
 {
     size_t len = strlen(from);
     size_t len = strlen(from);
     size_t i;
     size_t i;
@@ -1040,7 +1082,7 @@ void al_string_copy_cstr(al_string *str, const al_string_char_type *from)
     VECTOR_ELEM(*str, i) = 0;
     VECTOR_ELEM(*str, i) = 0;
 }
 }
 
 
-void al_string_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to)
+void alstr_copy_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to)
 {
 {
     size_t len = to - from;
     size_t len = to - from;
     size_t i;
     size_t i;
@@ -1051,20 +1093,20 @@ void al_string_copy_range(al_string *str, const al_string_char_type *from, const
     VECTOR_ELEM(*str, i) = 0;
     VECTOR_ELEM(*str, i) = 0;
 }
 }
 
 
-void al_string_append_char(al_string *str, const al_string_char_type c)
+void alstr_append_char(al_string *str, const al_string_char_type c)
 {
 {
-    size_t len = al_string_length(*str);
+    size_t len = alstr_length(*str);
     VECTOR_RESIZE(*str, len, len+2);
     VECTOR_RESIZE(*str, len, len+2);
     VECTOR_PUSH_BACK(*str, c);
     VECTOR_PUSH_BACK(*str, c);
     VECTOR_ELEM(*str, len+1) = 0;
     VECTOR_ELEM(*str, len+1) = 0;
 }
 }
 
 
-void al_string_append_cstr(al_string *str, const al_string_char_type *from)
+void alstr_append_cstr(al_string *str, const al_string_char_type *from)
 {
 {
     size_t len = strlen(from);
     size_t len = strlen(from);
     if(len != 0)
     if(len != 0)
     {
     {
-        size_t base = al_string_length(*str);
+        size_t base = alstr_length(*str);
         size_t i;
         size_t i;
 
 
         VECTOR_RESIZE(*str, base+len, base+len+1);
         VECTOR_RESIZE(*str, base+len, base+len+1);
@@ -1074,12 +1116,12 @@ void al_string_append_cstr(al_string *str, const al_string_char_type *from)
     }
     }
 }
 }
 
 
-void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to)
+void alstr_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to)
 {
 {
     size_t len = to - from;
     size_t len = to - from;
     if(len != 0)
     if(len != 0)
     {
     {
-        size_t base = al_string_length(*str);
+        size_t base = alstr_length(*str);
         size_t i;
         size_t i;
 
 
         VECTOR_RESIZE(*str, base+len, base+len+1);
         VECTOR_RESIZE(*str, base+len, base+len+1);
@@ -1090,7 +1132,7 @@ void al_string_append_range(al_string *str, const al_string_char_type *from, con
 }
 }
 
 
 #ifdef _WIN32
 #ifdef _WIN32
-void al_string_copy_wcstr(al_string *str, const wchar_t *from)
+void alstr_copy_wcstr(al_string *str, const wchar_t *from)
 {
 {
     int len;
     int len;
     if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
     if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
@@ -1101,24 +1143,35 @@ 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 alstr_append_wcstr(al_string *str, const wchar_t *from)
 {
 {
     int len;
     int len;
     if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
     if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
     {
     {
-        size_t base = al_string_length(*str);
+        size_t base = alstr_length(*str);
         VECTOR_RESIZE(*str, base+len-1, base+len);
         VECTOR_RESIZE(*str, base+len-1, base+len);
         WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, NULL, NULL);
         WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_ELEM(*str, base), len, NULL, NULL);
         VECTOR_ELEM(*str, base+len-1) = 0;
         VECTOR_ELEM(*str, base+len-1) = 0;
     }
     }
 }
 }
 
 
-void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to)
+void alstr_copy_wrange(al_string *str, const wchar_t *from, const wchar_t *to)
+{
+    int len;
+    if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0)
+    {
+        VECTOR_RESIZE(*str, len, len+1);
+        WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str), len+1, NULL, NULL);
+        VECTOR_ELEM(*str, len) = 0;
+    }
+}
+
+void alstr_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to)
 {
 {
     int len;
     int len;
     if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0)
     if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0)
     {
     {
-        size_t base = al_string_length(*str);
+        size_t base = alstr_length(*str);
         VECTOR_RESIZE(*str, base+len, base+len+1);
         VECTOR_RESIZE(*str, base+len, base+len+1);
         WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, NULL, NULL);
         WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_ELEM(*str, base), len+1, NULL, NULL);
         VECTOR_ELEM(*str, base+len) = 0;
         VECTOR_ELEM(*str, base+len) = 0;

Файловите разлики са ограничени, защото са твърде много
+ 661 - 343
Engine/lib/openal-soft/Alc/hrtf.c


+ 62 - 25
Engine/lib/openal-soft/Alc/hrtf.h

@@ -4,49 +4,86 @@
 #include "AL/al.h"
 #include "AL/al.h"
 #include "AL/alc.h"
 #include "AL/alc.h"
 
 
+#include "alMain.h"
 #include "alstring.h"
 #include "alstring.h"
+#include "atomic.h"
 
 
 
 
+/* The maximum number of virtual speakers used to generate HRTF coefficients
+ * for decoding B-Format.
+ */
+#define HRTF_AMBI_MAX_CHANNELS 18
+
+
+#define HRTF_HISTORY_BITS   (6)
+#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
+#define HRTF_HISTORY_MASK   (HRTF_HISTORY_LENGTH-1)
+
+#define HRIR_BITS        (7)
+#define HRIR_LENGTH      (1<<HRIR_BITS)
+#define HRIR_MASK        (HRIR_LENGTH-1)
+
+
+struct HrtfEntry;
+
 struct Hrtf {
 struct Hrtf {
+    RefCount ref;
+
     ALuint sampleRate;
     ALuint sampleRate;
-    ALuint irSize;
+    ALsizei irSize;
+
+    ALfloat distance;
     ALubyte evCount;
     ALubyte evCount;
 
 
     const ALubyte *azCount;
     const ALubyte *azCount;
     const ALushort *evOffset;
     const ALushort *evOffset;
-    const ALshort *coeffs;
-    const ALubyte *delays;
-
-    const char *filename;
-    struct Hrtf *next;
+    const ALfloat (*coeffs)[2];
+    const ALubyte (*delays)[2];
 };
 };
 
 
-typedef struct HrtfEntry {
-    al_string name;
 
 
-    const struct Hrtf *hrtf;
-} HrtfEntry;
-TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry)
+typedef struct HrtfState {
+    alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
+    alignas(16) ALfloat Values[HRIR_LENGTH][2];
+} HrtfState;
+
+typedef struct HrtfParams {
+    alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
+    ALsizei Delay[2];
+    ALfloat Gain;
+} HrtfParams;
+
+typedef struct DirectHrtfState {
+    /* HRTF filter state for dry buffer content */
+    ALsizei Offset;
+    ALsizei IrSize;
+    struct {
+        alignas(16) ALfloat Values[HRIR_LENGTH][2];
+        alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
+    } Chan[];
+} DirectHrtfState;
+
+struct AngularPoint {
+    ALfloat Elev;
+    ALfloat Azim;
+};
 
 
-#define HRIR_BITS        (7)
-#define HRIR_LENGTH      (1<<HRIR_BITS)
-#define HRIR_MASK        (HRIR_LENGTH-1)
-#define HRTFDELAY_BITS    (20)
-#define HRTFDELAY_FRACONE (1<<HRTFDELAY_BITS)
-#define HRTFDELAY_MASK    (HRTFDELAY_FRACONE-1)
 
 
 void FreeHrtfs(void);
 void FreeHrtfs(void);
 
 
-vector_HrtfEntry EnumerateHrtf(const_al_string devname);
-void FreeHrtfList(vector_HrtfEntry *list);
+vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname);
+void FreeHrtfList(vector_EnumeratedHrtf *list);
+struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry);
+void Hrtf_IncRef(struct Hrtf *hrtf);
+void Hrtf_DecRef(struct Hrtf *hrtf);
 
 
-void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
+void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays);
 
 
-/* Produces HRTF filter coefficients for decoding B-Format. The result will
- * have ACN ordering with N3D normalization. NumChannels must currently be 4,
- * for first-order. Returns the maximum impulse-response length of the
- * generated coefficients.
+/**
+ * Produces HRTF filter coefficients for decoding B-Format, given a set of
+ * virtual speaker positions and HF/LF matrices for decoding to them. The
+ * returned coefficients are ordered and scaled according to the matrices.
  */
  */
-ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels);
+void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const struct AngularPoint *AmbiPoints, const ALfloat (*restrict AmbiMatrix)[MAX_AMBI_COEFFS], ALsizei AmbiCount, const ALfloat *restrict AmbiOrderHFGain);
 
 
 #endif /* ALC_HRTF_H */
 #endif /* ALC_HRTF_H */

+ 0 - 5
Engine/lib/openal-soft/Alc/hrtf_res.h

@@ -1,5 +0,0 @@
-
-#define MHRTYPE 256
-
-#define IDR_DEFAULT_44100_MHR 0
-#define IDR_DEFAULT_48000_MHR 1

+ 0 - 4
Engine/lib/openal-soft/Alc/hrtf_res.rc

@@ -1,4 +0,0 @@
-#include "hrtf_res.h"
-
-IDR_DEFAULT_44100_MHR MHRTYPE "../hrtf/default-44100.mhr"
-IDR_DEFAULT_48000_MHR MHRTYPE "../hrtf/default-48000.mhr"

+ 79 - 0
Engine/lib/openal-soft/Alc/inprogext.h

@@ -0,0 +1,79 @@
+#ifndef INPROGEXT_H
+#define INPROGEXT_H
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef ALC_SOFT_loopback2
+#define ALC_SOFT_loopback2 1
+#define ALC_AMBISONIC_LAYOUT_SOFT                0xfff0
+#define ALC_AMBISONIC_SCALING_SOFT               0xfff1
+#define ALC_AMBISONIC_ORDER_SOFT                 0xfff2
+#define ALC_MAX_AMBISONIC_ORDER_SOFT             0xfff3
+
+#define ALC_BFORMAT3D_SOFT                       0x1508
+
+/* Ambisonic layouts */
+#define ALC_ACN_SOFT                             0xfff4
+#define ALC_FUMA_SOFT                            0xfff5
+
+/* Ambisonic scalings (normalization) */
+/*#define ALC_FUMA_SOFT*/
+#define ALC_SN3D_SOFT                            0xfff6
+#define ALC_N3D_SOFT                             0xfff7
+#endif
+
+#ifndef AL_SOFT_map_buffer
+#define AL_SOFT_map_buffer 1
+typedef unsigned int ALbitfieldSOFT;
+#define AL_MAP_READ_BIT_SOFT                     0x00000001
+#define AL_MAP_WRITE_BIT_SOFT                    0x00000002
+#define AL_MAP_PERSISTENT_BIT_SOFT               0x00000004
+#define AL_PRESERVE_DATA_BIT_SOFT                0x00000008
+typedef void (AL_APIENTRY*LPALBUFFERSTORAGESOFT)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags);
+typedef void* (AL_APIENTRY*LPALMAPBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access);
+typedef void (AL_APIENTRY*LPALUNMAPBUFFERSOFT)(ALuint buffer);
+typedef void (AL_APIENTRY*LPALFLUSHMAPPEDBUFFERSOFT)(ALuint buffer, ALsizei offset, ALsizei length);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API void AL_APIENTRY alBufferStorageSOFT(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq, ALbitfieldSOFT flags);
+AL_API void* AL_APIENTRY alMapBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length, ALbitfieldSOFT access);
+AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer);
+AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, ALsizei length);
+#endif
+#endif
+
+#ifndef AL_SOFT_events
+#define AL_SOFT_events 1
+#define AL_EVENT_CALLBACK_FUNCTION_SOFT          0x1220
+#define AL_EVENT_CALLBACK_USER_PARAM_SOFT        0x1221
+#define AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT      0x1222
+#define AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT  0x1223
+#define AL_EVENT_TYPE_ERROR_SOFT                 0x1224
+#define AL_EVENT_TYPE_PERFORMANCE_SOFT           0x1225
+#define AL_EVENT_TYPE_DEPRECATED_SOFT            0x1226
+#define AL_EVENT_TYPE_DISCONNECTED_SOFT          0x1227
+typedef void (AL_APIENTRY*ALEVENTPROCSOFT)(ALenum eventType, ALuint object, ALuint param,
+                                           ALsizei length, const ALchar *message,
+                                           void *userParam);
+typedef void (AL_APIENTRY*LPALEVENTCONTROLSOFT)(ALsizei count, const ALenum *types, ALboolean enable);
+typedef void (AL_APIENTRY*LPALEVENTCALLBACKSOFT)(ALEVENTPROCSOFT callback, void *userParam);
+typedef void* (AL_APIENTRY*LPALGETPOINTERSOFT)(ALenum pname);
+typedef void (AL_APIENTRY*LPALGETPOINTERVSOFT)(ALenum pname, void **values);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable);
+AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam);
+AL_API void* AL_APIENTRY alGetPointerSOFT(ALenum pname);
+AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, void **values);
+#endif
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* INPROGEXT_H */

+ 69 - 0
Engine/lib/openal-soft/Alc/logging.h

@@ -0,0 +1,69 @@
+#ifndef LOGGING_H
+#define LOGGING_H
+
+#include <stdio.h>
+
+
+#ifdef __GNUC__
+#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z))))
+#else
+#define DECL_FORMAT(x, y, z)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern FILE *LogFile;
+
+#if defined(__GNUC__) && !defined(_WIN32)
+#define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__)
+#else
+void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4);
+#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__)
+#endif
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#define LOG_ANDROID(T, MSG, ...) __android_log_print(T, "openal", "AL lib: %s: "MSG, __FUNCTION__ , ## __VA_ARGS__)
+#else
+#define LOG_ANDROID(T, MSG, ...) ((void)0)
+#endif
+
+enum LogLevel {
+    NoLog,
+    LogError,
+    LogWarning,
+    LogTrace,
+    LogRef
+};
+extern enum LogLevel LogLevel;
+
+#define TRACEREF(...) do {                                                    \
+    if(LogLevel >= LogRef)                                                    \
+        AL_PRINT("(--)", __VA_ARGS__);                                        \
+} while(0)
+
+#define TRACE(...) do {                                                       \
+    if(LogLevel >= LogTrace)                                                  \
+        AL_PRINT("(II)", __VA_ARGS__);                                        \
+    LOG_ANDROID(ANDROID_LOG_DEBUG, __VA_ARGS__);                              \
+} while(0)
+
+#define WARN(...) do {                                                        \
+    if(LogLevel >= LogWarning)                                                \
+        AL_PRINT("(WW)", __VA_ARGS__);                                        \
+    LOG_ANDROID(ANDROID_LOG_WARN, __VA_ARGS__);                               \
+} while(0)
+
+#define ERR(...) do {                                                         \
+    if(LogLevel >= LogError)                                                  \
+        AL_PRINT("(EE)", __VA_ARGS__);                                        \
+    LOG_ANDROID(ANDROID_LOG_ERROR, __VA_ARGS__);                              \
+} while(0)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LOGGING_H */

+ 232 - 0
Engine/lib/openal-soft/Alc/mastering.c

@@ -0,0 +1,232 @@
+#include "config.h"
+
+#include <math.h>
+
+#include "mastering.h"
+#include "alu.h"
+#include "almalloc.h"
+
+
+extern inline ALuint GetCompressorSampleRate(const Compressor *Comp);
+
+#define RMS_WINDOW_SIZE (1<<7)
+#define RMS_WINDOW_MASK (RMS_WINDOW_SIZE-1)
+#define RMS_VALUE_MAX  (1<<24)
+
+static_assert(RMS_VALUE_MAX < (UINT_MAX / RMS_WINDOW_SIZE), "RMS_VALUE_MAX is too big");
+
+
+/* Multichannel compression is linked via one of two modes:
+ *
+ *   Summed - Absolute sum of all channels.
+ *   Maxed  - Absolute maximum of any channel.
+ */
+static void SumChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
+                        ALfloat (*restrict OutBuffer)[BUFFERSIZE])
+{
+    ALsizei c, i;
+
+    for(i = 0;i < SamplesToDo;i++)
+        Comp->Envelope[i] = 0.0f;
+
+    for(c = 0;c < NumChans;c++)
+    {
+        for(i = 0;i < SamplesToDo;i++)
+            Comp->Envelope[i] += OutBuffer[c][i];
+    }
+
+    for(i = 0;i < SamplesToDo;i++)
+        Comp->Envelope[i] = fabsf(Comp->Envelope[i]);
+}
+
+static void MaxChannels(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
+                        ALfloat (*restrict OutBuffer)[BUFFERSIZE])
+{
+    ALsizei c, i;
+
+    for(i = 0;i < SamplesToDo;i++)
+        Comp->Envelope[i] = 0.0f;
+
+    for(c = 0;c < NumChans;c++)
+    {
+        for(i = 0;i < SamplesToDo;i++)
+            Comp->Envelope[i] = maxf(Comp->Envelope[i], fabsf(OutBuffer[c][i]));
+    }
+}
+
+/* Envelope detection/sensing can be done via:
+ *
+ *   RMS  - Rectangular windowed root mean square of linking stage.
+ *   Peak - Implicit output from linking stage.
+ */
+static void RmsDetection(Compressor *Comp, const ALsizei SamplesToDo)
+{
+    ALuint sum = Comp->RmsSum;
+    ALuint *window = Comp->RmsWindow;
+    ALsizei index = Comp->RmsIndex;
+    ALsizei i;
+
+    for(i = 0;i < SamplesToDo;i++)
+    {
+        ALfloat sig = Comp->Envelope[i];
+
+        sum -= window[index];
+        window[index] = fastf2i(minf(sig * sig * 65536.0f, RMS_VALUE_MAX));
+        sum += window[index];
+        index = (index + 1) & RMS_WINDOW_MASK;
+
+        Comp->Envelope[i] = sqrtf(sum / 65536.0f / RMS_WINDOW_SIZE);
+    }
+
+    Comp->RmsSum = sum;
+    Comp->RmsIndex = index;
+}
+
+/* This isn't a very sophisticated envelope follower, but it gets the job
+ * done.  First, it operates at logarithmic scales to keep transitions
+ * appropriate for human hearing.  Second, it can apply adaptive (automated)
+ * attack/release adjustments based on the signal.
+ */
+static void FollowEnvelope(Compressor *Comp, const ALsizei SamplesToDo)
+{
+    ALfloat attackMin = Comp->AttackMin;
+    ALfloat attackMax = Comp->AttackMax;
+    ALfloat releaseMin = Comp->ReleaseMin;
+    ALfloat releaseMax = Comp->ReleaseMax;
+    ALfloat last = Comp->EnvLast;
+    ALsizei i;
+
+    for(i = 0;i < SamplesToDo;i++)
+    {
+        ALfloat env = log10f(maxf(Comp->Envelope[i], 0.000001f));
+        ALfloat slope = minf(1.0f, fabsf(env - last) / 4.5f);
+
+        if(env > last)
+            last = minf(env, last + lerp(attackMin, attackMax, 1.0f - (slope * slope)));
+        else
+            last = maxf(env, last + lerp(releaseMin, releaseMax, 1.0f - (slope * slope)));
+
+        Comp->Envelope[i] = last;
+    }
+
+    Comp->EnvLast = last;
+}
+
+/* The envelope is converted to control gain with an optional soft knee. */
+static void EnvelopeGain(Compressor *Comp, const ALsizei SamplesToDo, const ALfloat Slope)
+{
+    const ALfloat threshold = Comp->Threshold;
+    const ALfloat knee = Comp->Knee;
+    ALsizei i;
+
+    if(!(knee > 0.0f))
+    {
+        for(i = 0;i < SamplesToDo;i++)
+        {
+            ALfloat gain = Slope * (threshold - Comp->Envelope[i]);
+            Comp->Envelope[i] = powf(10.0f, minf(0.0f, gain));
+        }
+    }
+    else
+    {
+        const ALfloat lower = threshold - (0.5f * knee);
+        const ALfloat upper = threshold + (0.5f * knee);
+        const ALfloat m = 0.5f * Slope / knee;
+
+        for(i = 0;i < SamplesToDo;i++)
+        {
+            ALfloat env = Comp->Envelope[i];
+            ALfloat gain;
+
+            if(env > lower && env < upper)
+                gain = m * (env - lower) * (lower - env);
+            else
+                gain = Slope * (threshold - env);
+
+            Comp->Envelope[i] = powf(10.0f, minf(0.0f, gain));
+        }
+    }
+}
+
+
+Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb,
+                           const ALboolean SummedLink, const ALboolean RmsSensing,
+                           const ALfloat AttackTimeMin, const ALfloat AttackTimeMax,
+                           const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax,
+                           const ALfloat Ratio, const ALfloat ThresholdDb,
+                           const ALfloat KneeDb, const ALuint SampleRate)
+{
+    Compressor *Comp;
+    size_t size;
+    ALsizei i;
+
+    size = sizeof(*Comp);
+    if(RmsSensing)
+        size += sizeof(Comp->RmsWindow[0]) * RMS_WINDOW_SIZE;
+    Comp = al_calloc(16, size);
+
+    Comp->PreGain = powf(10.0f, PreGainDb / 20.0f);
+    Comp->PostGain = powf(10.0f, PostGainDb / 20.0f);
+    Comp->SummedLink = SummedLink;
+    Comp->AttackMin = 1.0f / maxf(0.000001f, AttackTimeMin * SampleRate * logf(10.0f));
+    Comp->AttackMax = 1.0f / maxf(0.000001f, AttackTimeMax * SampleRate * logf(10.0f));
+    Comp->ReleaseMin = -1.0f / maxf(0.000001f, ReleaseTimeMin * SampleRate * logf(10.0f));
+    Comp->ReleaseMax = -1.0f / maxf(0.000001f, ReleaseTimeMax * SampleRate * logf(10.0f));
+    Comp->Ratio = Ratio;
+    Comp->Threshold = ThresholdDb / 20.0f;
+    Comp->Knee = maxf(0.0f, KneeDb / 20.0f);
+    Comp->SampleRate = SampleRate;
+
+    Comp->RmsSum = 0;
+    if(RmsSensing)
+        Comp->RmsWindow = (ALuint*)(Comp+1);
+    else
+        Comp->RmsWindow = NULL;
+    Comp->RmsIndex = 0;
+
+    for(i = 0;i < BUFFERSIZE;i++)
+        Comp->Envelope[i] = 0.0f;
+    Comp->EnvLast = -6.0f;
+
+    return Comp;
+}
+
+void ApplyCompression(Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
+                      ALfloat (*restrict OutBuffer)[BUFFERSIZE])
+{
+    ALsizei c, i;
+
+    if(Comp->PreGain != 1.0f)
+    {
+        for(c = 0;c < NumChans;c++)
+        {
+            for(i = 0;i < SamplesToDo;i++)
+                OutBuffer[c][i] *= Comp->PreGain;
+        }
+    }
+
+    if(Comp->SummedLink)
+        SumChannels(Comp, NumChans, SamplesToDo, OutBuffer);
+    else
+        MaxChannels(Comp, NumChans, SamplesToDo, OutBuffer);
+
+    if(Comp->RmsWindow)
+        RmsDetection(Comp, SamplesToDo);
+    FollowEnvelope(Comp, SamplesToDo);
+
+    if(Comp->Ratio > 0.0f)
+        EnvelopeGain(Comp, SamplesToDo, 1.0f - (1.0f / Comp->Ratio));
+    else
+        EnvelopeGain(Comp, SamplesToDo, 1.0f);
+
+    if(Comp->PostGain != 1.0f)
+    {
+        for(i = 0;i < SamplesToDo;i++)
+            Comp->Envelope[i] *= Comp->PostGain;
+    }
+    for(c = 0;c < NumChans;c++)
+    {
+        for(i = 0;i < SamplesToDo;i++)
+            OutBuffer[c][i] *= Comp->Envelope[i];
+    }
+}

+ 57 - 0
Engine/lib/openal-soft/Alc/mastering.h

@@ -0,0 +1,57 @@
+#ifndef MASTERING_H
+#define MASTERING_H
+
+#include "AL/al.h"
+
+/* For BUFFERSIZE. */
+#include "alMain.h"
+
+typedef struct Compressor {
+    ALfloat PreGain;
+    ALfloat PostGain;
+    ALboolean SummedLink;
+    ALfloat AttackMin;
+    ALfloat AttackMax;
+    ALfloat ReleaseMin;
+    ALfloat ReleaseMax;
+    ALfloat Ratio;
+    ALfloat Threshold;
+    ALfloat Knee;
+    ALuint SampleRate;
+
+    ALuint RmsSum;
+    ALuint *RmsWindow;
+    ALsizei RmsIndex;
+    ALfloat Envelope[BUFFERSIZE];
+    ALfloat EnvLast;
+} Compressor;
+
+/* The compressor requires the following information for proper
+ * initialization:
+ *
+ *   PreGainDb      - Gain applied before detection (in dB).
+ *   PostGainDb     - Gain applied after compression (in dB).
+ *   SummedLink     - Whether to use summed (true) or maxed (false) linking.
+ *   RmsSensing     - Whether to use RMS (true) or Peak (false) sensing.
+ *   AttackTimeMin  - Minimum attack time (in seconds).
+ *   AttackTimeMax  - Maximum attack time.  Automates when min != max.
+ *   ReleaseTimeMin - Minimum release time (in seconds).
+ *   ReleaseTimeMax - Maximum release time.  Automates when min != max.
+ *   Ratio          - Compression ratio (x:1).  Set to 0 for true limiter.
+ *   ThresholdDb    - Triggering threshold (in dB).
+ *   KneeDb         - Knee width (below threshold; in dB).
+ *   SampleRate     - Sample rate to process.
+ */
+Compressor *CompressorInit(const ALfloat PreGainDb, const ALfloat PostGainDb,
+    const ALboolean SummedLink, const ALboolean RmsSensing, const ALfloat AttackTimeMin,
+    const ALfloat AttackTimeMax, const ALfloat ReleaseTimeMin, const ALfloat ReleaseTimeMax,
+    const ALfloat Ratio, const ALfloat ThresholdDb, const ALfloat KneeDb,
+    const ALuint SampleRate);
+
+void ApplyCompression(struct Compressor *Comp, const ALsizei NumChans, const ALsizei SamplesToDo,
+                      ALfloat (*restrict OutBuffer)[BUFFERSIZE]);
+
+inline ALuint GetCompressorSampleRate(const Compressor *Comp)
+{ return Comp->SampleRate; }
+
+#endif /* MASTERING_H */

+ 0 - 702
Engine/lib/openal-soft/Alc/mixer.c

@@ -1,702 +0,0 @@
-/**
- * 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 <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include "alMain.h"
-#include "AL/al.h"
-#include "AL/alc.h"
-#include "alSource.h"
-#include "alBuffer.h"
-#include "alListener.h"
-#include "alAuxEffectSlot.h"
-#include "alu.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 *restrict frac_arr, ALuint *restrict 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 MixerFunc MixSamples = Mix_C;
-static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
-static ResamplerFunc ResampleSamples = Resample_point32_C;
-
-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;
-}
-
-RowMixerFunc SelectRowMixer(void)
-{
-#ifdef HAVE_SSE
-    if((CPUCapFlags&CPU_CAP_SSE))
-        return MixRow_SSE;
-#endif
-#ifdef HAVE_NEON
-    if((CPUCapFlags&CPU_CAP_NEON))
-        return MixRow_Neon;
-#endif
-    return MixRow_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 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); }
-
-static inline ALfloat Sample_ALshort(ALshort val)
-{ return val * (1.0f/32767.0f); }
-
-static inline ALfloat Sample_ALfloat(ALfloat val)
-{ return val; }
-
-#define DECL_TEMPLATE(T)                                                      \
-static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
-{                                                                             \
-    ALuint i;                                                                 \
-    for(i = 0;i < samples;i++)                                                \
-        dst[i] = Sample_##T(src[i*srcstep]);                                  \
-}
-
-DECL_TEMPLATE(ALbyte)
-DECL_TEMPLATE(ALshort)
-DECL_TEMPLATE(ALfloat)
-
-#undef DECL_TEMPLATE
-
-static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples)
-{
-    switch(srctype)
-    {
-        case FmtByte:
-            Load_ALbyte(dst, src, srcstep, samples);
-            break;
-        case FmtShort:
-            Load_ALshort(dst, src, srcstep, samples);
-            break;
-        case FmtFloat:
-            Load_ALfloat(dst, src, srcstep, samples);
-            break;
-    }
-}
-
-static inline void SilenceSamples(ALfloat *dst, ALuint samples)
-{
-    ALuint i;
-    for(i = 0;i < samples;i++)
-        dst[i] = 0.0f;
-}
-
-
-static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter,
-                                ALfloat *restrict dst, const ALfloat *restrict src,
-                                ALuint numsamples, enum ActiveFilters type)
-{
-    ALuint i;
-    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[256];
-                ALuint todo = minu(256, numsamples-i);
-
-                ALfilterState_process(lpfilter, temp, src+i, todo);
-                ALfilterState_process(hpfilter, dst+i, temp, todo);
-                i += todo;
-            }
-            return dst;
-    }
-    return src;
-}
-
-
-ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
-{
-    ResamplerFunc Resample;
-    ALbufferlistitem *BufferListItem;
-    ALuint DataPosInt, DataPosFrac;
-    ALboolean Looping;
-    ALuint increment;
-    ALenum State;
-    ALuint OutPos;
-    ALuint NumChannels;
-    ALuint SampleSize;
-    ALint64 DataSize64;
-    ALuint Counter;
-    ALuint IrSize;
-    ALuint chan, send, j;
-
-    /* Get source info */
-    State          = AL_PLAYING; /* Only called while playing. */
-    BufferListItem = ATOMIC_LOAD(&Source->current_buffer);
-    DataPosInt     = ATOMIC_LOAD(&Source->position, almemory_order_relaxed);
-    DataPosFrac    = ATOMIC_LOAD(&Source->position_fraction, almemory_order_relaxed);
-    Looping        = ATOMIC_LOAD(&Source->looping, almemory_order_relaxed);
-    NumChannels    = Source->NumChannels;
-    SampleSize     = Source->SampleSize;
-    increment      = voice->Step;
-
-    IrSize = (Device->Hrtf.Handle ? Device->Hrtf.Handle->irSize : 0);
-
-    Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
-                Resample_copy32_C : ResampleSamples);
-
-    Counter = voice->Moving ? SamplesToDo : 0;
-    OutPos = 0;
-    do {
-        ALuint SrcBufferSize, DstBufferSize;
-
-        /* Figure out how many buffer samples will be needed */
-        DataSize64  = SamplesToDo-OutPos;
-        DataSize64 *= increment;
-        DataSize64 += DataPosFrac+FRACTIONMASK;
-        DataSize64 >>= FRACTIONBITS;
-        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 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
-        DataSize64 <<= FRACTIONBITS;
-        DataSize64 -= DataPosFrac;
-
-        DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
-        DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos));
-
-        /* Some mixers like having a multiple of 4, so try to give that unless
-         * this is the last update. */
-        if(OutPos+DstBufferSize < SamplesToDo)
-            DstBufferSize &= ~3;
-
-        for(chan = 0;chan < NumChannels;chan++)
-        {
-            const ALfloat *ResampledData;
-            ALfloat *SrcData = Device->SourceData;
-            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)
-            {
-                const ALbuffer *ALBuffer = BufferListItem->buffer;
-                const ALubyte *Data = ALBuffer->data;
-                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;
-
-                    /* Load what's left to play from the source buffer, and
-                     * clear the rest of the temp buffer */
-                    pos = DataPosInt;
-                    DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
-
-                    LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
-                                NumChannels, ALBuffer->FmtType, DataSize);
-                    SrcDataSize += DataSize;
-
-                    SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
-                    SrcDataSize += SrcBufferSize - SrcDataSize;
-                }
-                else
-                {
-                    ALuint LoopStart = ALBuffer->LoopStart;
-                    ALuint LoopEnd   = ALBuffer->LoopEnd;
-
-                    /* Load what's left of this loop iteration, then load
-                     * repeats of the loop section */
-                    pos = DataPosInt;
-                    DataSize = LoopEnd - pos;
-                    DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
-
-                    LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
-                                NumChannels, ALBuffer->FmtType, DataSize);
-                    SrcDataSize += DataSize;
-
-                    DataSize = LoopEnd-LoopStart;
-                    while(SrcBufferSize > SrcDataSize)
-                    {
-                        DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
-
-                        LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
-                                    NumChannels, ALBuffer->FmtType, DataSize);
-                        SrcDataSize += DataSize;
-                    }
-                }
-            }
-            else
-            {
-                /* Crawl the buffer queue to fill in the temp buffer */
-                ALbufferlistitem *tmpiter = BufferListItem;
-                ALuint pos = DataPosInt;
-
-                while(tmpiter && SrcBufferSize > SrcDataSize)
-                {
-                    const ALbuffer *ALBuffer;
-                    if((ALBuffer=tmpiter->buffer) != NULL)
-                    {
-                        const ALubyte *Data = ALBuffer->data;
-                        ALuint DataSize = ALBuffer->SampleLen;
-
-                        /* Skip the data already played */
-                        if(DataSize <= pos)
-                            pos -= DataSize;
-                        else
-                        {
-                            Data += (pos*NumChannels + chan)*SampleSize;
-                            DataSize -= pos;
-                            pos -= pos;
-
-                            DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
-                            LoadSamples(&SrcData[SrcDataSize], Data, NumChannels,
-                                        ALBuffer->FmtType, DataSize);
-                            SrcDataSize += DataSize;
-                        }
-                    }
-                    tmpiter = tmpiter->next;
-                    if(!tmpiter && Looping)
-                        tmpiter = ATOMIC_LOAD(&Source->queue);
-                    else if(!tmpiter)
-                    {
-                        SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize);
-                        SrcDataSize += SrcBufferSize - SrcDataSize;
-                    }
-                }
-            }
-
-            /* Store the last source samples used for next time. */
-            memcpy(voice->PrevSamples[chan],
-                &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
-                MAX_PRE_SAMPLES*sizeof(ALfloat)
-            );
-
-            /* Now resample, then filter and mix to the appropriate outputs. */
-            ResampledData = Resample(&voice->SincState,
-                &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
-                Device->ResampledData, DstBufferSize
-            );
-            {
-                DirectParams *parms = &voice->Chan[chan].Direct;
-                const ALfloat *samples;
-
-                samples = DoFilters(
-                    &parms->LowPass, &parms->HighPass, Device->FilteredData,
-                    ResampledData, DstBufferSize, parms->FilterType
-                );
-                if(!voice->IsHrtf)
-                {
-                    if(!Counter)
-                        memcpy(parms->Gains.Current, parms->Gains.Target,
-                               sizeof(parms->Gains.Current));
-                    MixSamples(samples, voice->DirectOut.Channels, voice->DirectOut.Buffer,
-                        parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize
-                    );
-                }
-                else
-                {
-                    MixHrtfParams hrtfparams;
-                    int lidx, ridx;
-
-                    if(!Counter)
-                    {
-                        parms->Hrtf.Current = parms->Hrtf.Target;
-                        for(j = 0;j < HRIR_LENGTH;j++)
-                        {
-                            hrtfparams.Steps.Coeffs[j][0] = 0.0f;
-                            hrtfparams.Steps.Coeffs[j][1] = 0.0f;
-                        }
-                        hrtfparams.Steps.Delay[0] = 0;
-                        hrtfparams.Steps.Delay[1] = 0;
-                    }
-                    else
-                    {
-                        ALfloat delta = 1.0f / (ALfloat)Counter;
-                        ALfloat coeffdiff;
-                        ALint delaydiff;
-                        for(j = 0;j < IrSize;j++)
-                        {
-                            coeffdiff = parms->Hrtf.Target.Coeffs[j][0] - parms->Hrtf.Current.Coeffs[j][0];
-                            hrtfparams.Steps.Coeffs[j][0] = coeffdiff * delta;
-                            coeffdiff = parms->Hrtf.Target.Coeffs[j][1] - parms->Hrtf.Current.Coeffs[j][1];
-                            hrtfparams.Steps.Coeffs[j][1] = coeffdiff * delta;
-                        }
-                        delaydiff = (ALint)(parms->Hrtf.Target.Delay[0] - parms->Hrtf.Current.Delay[0]);
-                        hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * delta);
-                        delaydiff = (ALint)(parms->Hrtf.Target.Delay[1] - parms->Hrtf.Current.Delay[1]);
-                        hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * delta);
-                    }
-                    hrtfparams.Target = &parms->Hrtf.Target;
-                    hrtfparams.Current = &parms->Hrtf.Current;
-
-                    lidx = GetChannelIdxByName(Device->RealOut, FrontLeft);
-                    ridx = GetChannelIdxByName(Device->RealOut, FrontRight);
-                    assert(lidx != -1 && ridx != -1);
-
-                    MixHrtfSamples(voice->DirectOut.Buffer, lidx, ridx, samples, Counter,
-                                   voice->Offset, OutPos, IrSize, &hrtfparams,
-                                   &parms->Hrtf.State, DstBufferSize);
-                }
-            }
-
-            for(send = 0;send < Device->NumAuxSends;send++)
-            {
-                SendParams *parms = &voice->Chan[chan].Send[send];
-                const ALfloat *samples;
-
-                if(!voice->SendOut[send].Buffer)
-                    continue;
-
-                samples = DoFilters(
-                    &parms->LowPass, &parms->HighPass, Device->FilteredData,
-                    ResampledData, DstBufferSize, parms->FilterType
-                );
-
-                if(!Counter)
-                    memcpy(parms->Gains.Current, parms->Gains.Target,
-                           sizeof(parms->Gains.Current));
-                MixSamples(samples, voice->SendOut[send].Channels, voice->SendOut[send].Buffer,
-                    parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize
-                );
-            }
-        }
-        /* Update positions */
-        DataPosFrac += increment*DstBufferSize;
-        DataPosInt  += DataPosFrac>>FRACTIONBITS;
-        DataPosFrac &= FRACTIONMASK;
-
-        OutPos += DstBufferSize;
-        voice->Offset += DstBufferSize;
-        Counter = maxu(DstBufferSize, Counter) - DstBufferSize;
-
-        /* Handle looping sources */
-        while(1)
-        {
-            const ALbuffer *ALBuffer;
-            ALuint DataSize = 0;
-            ALuint LoopStart = 0;
-            ALuint LoopEnd = 0;
-
-            if((ALBuffer=BufferListItem->buffer) != NULL)
-            {
-                DataSize = ALBuffer->SampleLen;
-                LoopStart = ALBuffer->LoopStart;
-                LoopEnd = ALBuffer->LoopEnd;
-                if(LoopEnd > DataPosInt)
-                    break;
-            }
-
-            if(Looping && Source->SourceType == AL_STATIC)
-            {
-                assert(LoopEnd > LoopStart);
-                DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
-                break;
-            }
-
-            if(DataSize > DataPosInt)
-                break;
-
-            if(!(BufferListItem=BufferListItem->next))
-            {
-                if(Looping)
-                    BufferListItem = ATOMIC_LOAD(&Source->queue);
-                else
-                {
-                    State = AL_STOPPED;
-                    BufferListItem = NULL;
-                    DataPosInt = 0;
-                    DataPosFrac = 0;
-                    break;
-                }
-            }
-
-            DataPosInt -= DataSize;
-        }
-    } while(State == AL_PLAYING && OutPos < SamplesToDo);
-
-    voice->Moving = AL_TRUE;
-
-    /* Update source info */
-    Source->state = State;
-    ATOMIC_STORE(&Source->current_buffer,    BufferListItem, almemory_order_relaxed);
-    ATOMIC_STORE(&Source->position,          DataPosInt, almemory_order_relaxed);
-    ATOMIC_STORE(&Source->position_fraction, DataPosFrac);
-}

+ 119 - 0
Engine/lib/openal-soft/Alc/mixer/defs.h

@@ -0,0 +1,119 @@
+#ifndef MIXER_DEFS_H
+#define MIXER_DEFS_H
+
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "alMain.h"
+#include "alu.h"
+
+struct MixGains;
+
+struct MixHrtfParams;
+struct HrtfState;
+
+/* C resamplers */
+const ALfloat *Resample_copy_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
+const ALfloat *Resample_point_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
+const ALfloat *Resample_lerp_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
+const ALfloat *Resample_cubic_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
+const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restrict src, ALsizei frac, ALint increment, ALfloat *restrict dst, ALsizei dstlen);
+
+
+/* C mixers */
+void MixHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+               const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+               const ALsizei IrSize, struct MixHrtfParams *hrtfparams,
+               struct HrtfState *hrtfstate, ALsizei BufferSize);
+void MixHrtfBlend_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                    const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+                    const ALsizei IrSize, const HrtfParams *oldparams,
+                    MixHrtfParams *newparams, HrtfState *hrtfstate,
+                    ALsizei BufferSize);
+void MixDirectHrtf_C(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                     const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
+                     const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
+                     ALsizei BufferSize);
+void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+           ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
+           ALsizei BufferSize);
+void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains,
+              const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
+              ALsizei InPos, ALsizei BufferSize);
+
+/* SSE mixers */
+void MixHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                 const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+                 const ALsizei IrSize, struct MixHrtfParams *hrtfparams,
+                 struct HrtfState *hrtfstate, ALsizei BufferSize);
+void MixHrtfBlend_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                      const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+                      const ALsizei IrSize, const HrtfParams *oldparams,
+                      MixHrtfParams *newparams, HrtfState *hrtfstate,
+                      ALsizei BufferSize);
+void MixDirectHrtf_SSE(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                       const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
+                       const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
+                       ALsizei BufferSize);
+void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+             ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
+             ALsizei BufferSize);
+void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains,
+                const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
+                ALsizei InPos, ALsizei BufferSize);
+
+/* SSE resamplers */
+inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size)
+{
+    ALsizei i;
+
+    pos_arr[0] = 0;
+    frac_arr[0] = frac;
+    for(i = 1;i < size;i++)
+    {
+        ALint frac_tmp = frac_arr[i-1] + increment;
+        pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS);
+        frac_arr[i] = frac_tmp&FRACTIONMASK;
+    }
+}
+
+const ALfloat *Resample_lerp_SSE2(const InterpState *state, const ALfloat *restrict src,
+                                  ALsizei frac, ALint increment, ALfloat *restrict dst,
+                                  ALsizei numsamples);
+const ALfloat *Resample_lerp_SSE41(const InterpState *state, const ALfloat *restrict src,
+                                   ALsizei frac, ALint increment, ALfloat *restrict dst,
+                                   ALsizei numsamples);
+
+const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restrict src,
+                                  ALsizei frac, ALint increment, ALfloat *restrict dst,
+                                  ALsizei dstlen);
+
+/* Neon mixers */
+void MixHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                  const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+                  const ALsizei IrSize, struct MixHrtfParams *hrtfparams,
+                  struct HrtfState *hrtfstate, ALsizei BufferSize);
+void MixHrtfBlend_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                       const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+                       const ALsizei IrSize, const HrtfParams *oldparams,
+                       MixHrtfParams *newparams, HrtfState *hrtfstate,
+                       ALsizei BufferSize);
+void MixDirectHrtf_Neon(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                        const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
+                        const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
+                        ALsizei BufferSize);
+void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+              ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
+              ALsizei BufferSize);
+void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains,
+                 const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
+                 ALsizei InPos, ALsizei BufferSize);
+
+/* Neon resamplers */
+const ALfloat *Resample_lerp_Neon(const InterpState *state, const ALfloat *restrict src,
+                                  ALsizei frac, ALint increment, ALfloat *restrict dst,
+                                  ALsizei numsamples);
+const ALfloat *Resample_bsinc_Neon(const InterpState *state, const ALfloat *restrict src,
+                                   ALsizei frac, ALint increment, ALfloat *restrict dst,
+                                   ALsizei dstlen);
+
+#endif /* MIXER_DEFS_H */

+ 123 - 0
Engine/lib/openal-soft/Alc/mixer/hrtf_inc.c

@@ -0,0 +1,123 @@
+#include "config.h"
+
+#include "alMain.h"
+#include "alSource.h"
+
+#include "hrtf.h"
+#include "align.h"
+#include "alu.h"
+#include "defs.h"
+
+
+static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
+                               const ALsizei irSize,
+                               const ALfloat (*restrict Coeffs)[2],
+                               ALfloat left, ALfloat right);
+
+
+void MixHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+             const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+             const ALsizei IrSize, MixHrtfParams *hrtfparams, HrtfState *hrtfstate,
+             ALsizei BufferSize)
+{
+    const ALfloat (*Coeffs)[2] = ASSUME_ALIGNED(hrtfparams->Coeffs, 16);
+    const ALsizei Delay[2] = { hrtfparams->Delay[0], hrtfparams->Delay[1] };
+    ALfloat gainstep = hrtfparams->GainStep;
+    ALfloat gain = hrtfparams->Gain;
+    ALfloat left, right;
+    ALsizei i;
+
+    ASSUME(IrSize >= 4);
+    ASSUME(BufferSize > 0);
+
+    LeftOut  += OutPos;
+    RightOut += OutPos;
+    for(i = 0;i < BufferSize;i++)
+    {
+        hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++);
+        left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]*gain;
+        right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]*gain;
+
+        hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f;
+        hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f;
+
+        ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
+        *(LeftOut++)  += hrtfstate->Values[Offset&HRIR_MASK][0];
+        *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1];
+
+        gain += gainstep;
+        Offset++;
+    }
+    hrtfparams->Gain = gain;
+}
+
+void MixHrtfBlend(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                  const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+                  const ALsizei IrSize, const HrtfParams *oldparams,
+                  MixHrtfParams *newparams, HrtfState *hrtfstate,
+                  ALsizei BufferSize)
+{
+    const ALfloat (*OldCoeffs)[2] = ASSUME_ALIGNED(oldparams->Coeffs, 16);
+    const ALsizei OldDelay[2] = { oldparams->Delay[0], oldparams->Delay[1] };
+    ALfloat oldGain = oldparams->Gain;
+    ALfloat oldGainStep = -oldGain / (ALfloat)BufferSize;
+    const ALfloat (*NewCoeffs)[2] = ASSUME_ALIGNED(newparams->Coeffs, 16);
+    const ALsizei NewDelay[2] = { newparams->Delay[0], newparams->Delay[1] };
+    ALfloat newGain = newparams->Gain;
+    ALfloat newGainStep = newparams->GainStep;
+    ALfloat left, right;
+    ALsizei i;
+
+    ASSUME(IrSize >= 4);
+    ASSUME(BufferSize > 0);
+
+    LeftOut  += OutPos;
+    RightOut += OutPos;
+    for(i = 0;i < BufferSize;i++)
+    {
+        hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][0] = 0.0f;
+        hrtfstate->Values[(Offset+IrSize-1)&HRIR_MASK][1] = 0.0f;
+
+        hrtfstate->History[Offset&HRTF_HISTORY_MASK] = *(data++);
+
+        left = hrtfstate->History[(Offset-OldDelay[0])&HRTF_HISTORY_MASK]*oldGain;
+        right = hrtfstate->History[(Offset-OldDelay[1])&HRTF_HISTORY_MASK]*oldGain;
+        ApplyCoeffs(Offset, hrtfstate->Values, IrSize, OldCoeffs, left, right);
+
+        left = hrtfstate->History[(Offset-NewDelay[0])&HRTF_HISTORY_MASK]*newGain;
+        right = hrtfstate->History[(Offset-NewDelay[1])&HRTF_HISTORY_MASK]*newGain;
+        ApplyCoeffs(Offset, hrtfstate->Values, IrSize, NewCoeffs, left, right);
+
+        *(LeftOut++)  += hrtfstate->Values[Offset&HRIR_MASK][0];
+        *(RightOut++) += hrtfstate->Values[Offset&HRIR_MASK][1];
+
+        oldGain += oldGainStep;
+        newGain += newGainStep;
+        Offset++;
+    }
+    newparams->Gain = newGain;
+}
+
+void MixDirectHrtf(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                   const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
+                   const ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
+                   ALsizei BufferSize)
+{
+    ALfloat insample;
+    ALsizei i;
+
+    ASSUME(IrSize >= 4);
+    ASSUME(BufferSize > 0);
+
+    for(i = 0;i < BufferSize;i++)
+    {
+        Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
+        Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
+        Offset++;
+
+        insample = *(data++);
+        ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample);
+        *(LeftOut++)  += Values[Offset&HRIR_MASK][0];
+        *(RightOut++) += Values[Offset&HRIR_MASK][1];
+    }
+}

+ 176 - 0
Engine/lib/openal-soft/Alc/mixer/mixer_c.c

@@ -0,0 +1,176 @@
+#include "config.h"
+
+#include <assert.h>
+
+#include "alMain.h"
+#include "alu.h"
+#include "alSource.h"
+#include "alAuxEffectSlot.h"
+#include "defs.h"
+
+
+static inline ALfloat do_point(const ALfloat *restrict vals, ALsizei UNUSED(frac))
+{ return vals[0]; }
+static inline ALfloat do_lerp(const ALfloat *restrict vals, ALsizei frac)
+{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
+static inline ALfloat do_cubic(const ALfloat *restrict vals, ALsizei frac)
+{ return cubic(vals[0], vals[1], vals[2], vals[3], frac * (1.0f/FRACTIONONE)); }
+
+const ALfloat *Resample_copy_C(const InterpState* UNUSED(state),
+  const ALfloat *restrict src, ALsizei UNUSED(frac), ALint UNUSED(increment),
+  ALfloat *restrict dst, ALsizei numsamples)
+{
+#if defined(HAVE_SSE) || defined(HAVE_NEON)
+    /* Avoid copying the source data if it's aligned like the destination. */
+    if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
+        return src;
+#endif
+    memcpy(dst, src, numsamples*sizeof(ALfloat));
+    return dst;
+}
+
+#define DECL_TEMPLATE(Tag, Sampler, O)                                        \
+const ALfloat *Resample_##Tag##_C(const InterpState* UNUSED(state),           \
+  const ALfloat *restrict src, ALsizei frac, ALint increment,                 \
+  ALfloat *restrict dst, ALsizei numsamples)                                  \
+{                                                                             \
+    ALsizei i;                                                                \
+                                                                              \
+    src -= O;                                                                 \
+    for(i = 0;i < numsamples;i++)                                             \
+    {                                                                         \
+        dst[i] = Sampler(src, frac);                                          \
+                                                                              \
+        frac += increment;                                                    \
+        src  += frac>>FRACTIONBITS;                                           \
+        frac &= FRACTIONMASK;                                                 \
+    }                                                                         \
+    return dst;                                                               \
+}
+
+DECL_TEMPLATE(point, do_point, 0)
+DECL_TEMPLATE(lerp, do_lerp, 0)
+DECL_TEMPLATE(cubic, do_cubic, 1)
+
+#undef DECL_TEMPLATE
+
+const ALfloat *Resample_bsinc_C(const InterpState *state, const ALfloat *restrict src,
+                                ALsizei frac, ALint increment, ALfloat *restrict dst,
+                                ALsizei dstlen)
+{
+    const ALfloat *fil, *scd, *phd, *spd;
+    const ALfloat *const filter = state->bsinc.filter;
+    const ALfloat sf = state->bsinc.sf;
+    const ALsizei m = state->bsinc.m;
+    ALsizei j_f, pi, i;
+    ALfloat pf, r;
+
+    ASSUME(m > 0);
+
+    src += state->bsinc.l;
+    for(i = 0;i < dstlen;i++)
+    {
+        // Calculate the phase index and factor.
+#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
+        pi = frac >> FRAC_PHASE_BITDIFF;
+        pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
+#undef FRAC_PHASE_BITDIFF
+
+        fil = ASSUME_ALIGNED(filter + m*pi*4, 16);
+        scd = ASSUME_ALIGNED(fil + m, 16);
+        phd = ASSUME_ALIGNED(scd + m, 16);
+        spd = ASSUME_ALIGNED(phd + m, 16);
+
+        // Apply the scale and phase interpolated filter.
+        r = 0.0f;
+        for(j_f = 0;j_f < m;j_f++)
+            r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) * src[j_f];
+        dst[i] = r;
+
+        frac += increment;
+        src  += frac>>FRACTIONBITS;
+        frac &= FRACTIONMASK;
+    }
+    return dst;
+}
+
+
+static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
+                               const ALsizei IrSize,
+                               const ALfloat (*restrict Coeffs)[2],
+                               ALfloat left, ALfloat right)
+{
+    ALsizei c;
+    for(c = 0;c < IrSize;c++)
+    {
+        const ALsizei off = (Offset+c)&HRIR_MASK;
+        Values[off][0] += Coeffs[c][0] * left;
+        Values[off][1] += Coeffs[c][1] * right;
+    }
+}
+
+#define MixHrtf MixHrtf_C
+#define MixHrtfBlend MixHrtfBlend_C
+#define MixDirectHrtf MixDirectHrtf_C
+#include "hrtf_inc.c"
+
+
+void Mix_C(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+           ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
+           ALsizei BufferSize)
+{
+    ALfloat gain, delta, step;
+    ALsizei c;
+
+    ASSUME(OutChans > 0);
+    ASSUME(BufferSize > 0);
+    delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
+
+    for(c = 0;c < OutChans;c++)
+    {
+        ALsizei pos = 0;
+        gain = CurrentGains[c];
+        step = (TargetGains[c] - gain) * delta;
+        if(fabsf(step) > FLT_EPSILON)
+        {
+            ALsizei minsize = mini(BufferSize, Counter);
+            for(;pos < minsize;pos++)
+            {
+                OutBuffer[c][OutPos+pos] += data[pos]*gain;
+                gain += step;
+            }
+            if(pos == Counter)
+                gain = TargetGains[c];
+            CurrentGains[c] = gain;
+        }
+
+        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
+            continue;
+        for(;pos < BufferSize;pos++)
+            OutBuffer[c][OutPos+pos] += data[pos]*gain;
+    }
+}
+
+/* Basically the inverse of the above. Rather than one input going to multiple
+ * outputs (each with its own gain), it's multiple inputs (each with its own
+ * gain) going to one output. This applies one row (vs one column) of a matrix
+ * transform. And as the matrices are more or less static once set up, no
+ * stepping is necessary.
+ */
+void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize)
+{
+    ALsizei c, i;
+
+    ASSUME(InChans > 0);
+    ASSUME(BufferSize > 0);
+
+    for(c = 0;c < InChans;c++)
+    {
+        ALfloat gain = Gains[c];
+        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
+            continue;
+
+        for(i = 0;i < BufferSize;i++)
+            OutBuffer[i] += data[c][InPos+i] * gain;
+    }
+}

+ 269 - 0
Engine/lib/openal-soft/Alc/mixer/mixer_neon.c

@@ -0,0 +1,269 @@
+#include "config.h"
+
+#include <arm_neon.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alu.h"
+#include "hrtf.h"
+#include "defs.h"
+
+
+const ALfloat *Resample_lerp_Neon(const InterpState* UNUSED(state),
+  const ALfloat *restrict src, ALsizei frac, ALint increment,
+  ALfloat *restrict dst, ALsizei numsamples)
+{
+    const int32x4_t increment4 = vdupq_n_s32(increment*4);
+    const float32x4_t fracOne4 = vdupq_n_f32(1.0f/FRACTIONONE);
+    const int32x4_t fracMask4 = vdupq_n_s32(FRACTIONMASK);
+    alignas(16) ALint pos_[4];
+    alignas(16) ALsizei frac_[4];
+    int32x4_t pos4;
+    int32x4_t frac4;
+    ALsizei i;
+
+    ASSUME(numsamples > 0);
+
+    InitiatePositionArrays(frac, increment, frac_, pos_, 4);
+
+    frac4 = vld1q_s32(frac_);
+    pos4 = vld1q_s32(pos_);
+
+    for(i = 0;numsamples-i > 3;i += 4)
+    {
+        const float32x4_t val1 = (float32x4_t){src[pos_[0]], src[pos_[1]], src[pos_[2]], src[pos_[3]]};
+        const float32x4_t val2 = (float32x4_t){src[pos_[0]+1], src[pos_[1]+1], src[pos_[2]+1], src[pos_[3]+1]};
+
+        /* val1 + (val2-val1)*mu */
+        const float32x4_t r0 = vsubq_f32(val2, val1);
+        const float32x4_t mu = vmulq_f32(vcvtq_f32_s32(frac4), fracOne4);
+        const float32x4_t out = vmlaq_f32(val1, mu, r0);
+
+        vst1q_f32(&dst[i], out);
+
+        frac4 = vaddq_s32(frac4, increment4);
+        pos4 = vaddq_s32(pos4, vshrq_n_s32(frac4, FRACTIONBITS));
+        frac4 = vandq_s32(frac4, fracMask4);
+
+        vst1q_s32(pos_, pos4);
+    }
+
+    if(i < numsamples)
+    {
+        /* NOTE: These four elements represent the position *after* the last
+         * four samples, so the lowest element is the next position to
+         * resample.
+         */
+        ALint pos = pos_[0];
+        frac = vgetq_lane_s32(frac4, 0);
+        do {
+            dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
+
+            frac += increment;
+            pos  += frac>>FRACTIONBITS;
+            frac &= FRACTIONMASK;
+        } while(++i < numsamples);
+    }
+    return dst;
+}
+
+const ALfloat *Resample_bsinc_Neon(const InterpState *state,
+  const ALfloat *restrict src, ALsizei frac, ALint increment,
+  ALfloat *restrict dst, ALsizei dstlen)
+{
+    const ALfloat *const filter = state->bsinc.filter;
+    const float32x4_t sf4 = vdupq_n_f32(state->bsinc.sf);
+    const ALsizei m = state->bsinc.m;
+    const float32x4_t *fil, *scd, *phd, *spd;
+    ALsizei pi, i, j, offset;
+    float32x4_t r4;
+    ALfloat pf;
+
+    ASSUME(m > 0);
+    ASSUME(dstlen > 0);
+
+    src += state->bsinc.l;
+    for(i = 0;i < dstlen;i++)
+    {
+        // Calculate the phase index and factor.
+#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
+        pi = frac >> FRAC_PHASE_BITDIFF;
+        pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
+#undef FRAC_PHASE_BITDIFF
+
+        offset = m*pi*4;
+        fil = ASSUME_ALIGNED(filter + offset, 16); offset += m;
+        scd = ASSUME_ALIGNED(filter + offset, 16); offset += m;
+        phd = ASSUME_ALIGNED(filter + offset, 16); offset += m;
+        spd = ASSUME_ALIGNED(filter + offset, 16);
+
+        // Apply the scale and phase interpolated filter.
+        r4 = vdupq_n_f32(0.0f);
+        {
+            const float32x4_t pf4 = vdupq_n_f32(pf);
+            for(j = 0;j < m;j+=4,fil++,scd++,phd++,spd++)
+            {
+                /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */
+                const float32x4_t f4 = vmlaq_f32(
+                    vmlaq_f32(*fil, sf4, *scd),
+                    pf4, vmlaq_f32(*phd, sf4, *spd)
+                );
+                /* r += f*src */
+                r4 = vmlaq_f32(r4, f4, vld1q_f32(&src[j]));
+            }
+        }
+        r4 = vaddq_f32(r4, vcombine_f32(vrev64_f32(vget_high_f32(r4)),
+                                        vrev64_f32(vget_low_f32(r4))));
+        dst[i] = vget_lane_f32(vadd_f32(vget_low_f32(r4), vget_high_f32(r4)), 0);
+
+        frac += increment;
+        src  += frac>>FRACTIONBITS;
+        frac &= FRACTIONMASK;
+    }
+    return dst;
+}
+
+
+static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
+                               const ALsizei IrSize,
+                               const ALfloat (*restrict Coeffs)[2],
+                               ALfloat left, ALfloat right)
+{
+    ALsizei c;
+    float32x4_t leftright4;
+    {
+        float32x2_t leftright2 = vdup_n_f32(0.0);
+        leftright2 = vset_lane_f32(left, leftright2, 0);
+        leftright2 = vset_lane_f32(right, leftright2, 1);
+        leftright4 = vcombine_f32(leftright2, leftright2);
+    }
+    Values = ASSUME_ALIGNED(Values, 16);
+    Coeffs = ASSUME_ALIGNED(Coeffs, 16);
+    for(c = 0;c < IrSize;c += 2)
+    {
+        const ALsizei o0 = (Offset+c)&HRIR_MASK;
+        const ALsizei o1 = (o0+1)&HRIR_MASK;
+        float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
+                                        vld1_f32((float32_t*)&Values[o1][0]));
+        float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
+
+        vals = vmlaq_f32(vals, coefs, leftright4);
+
+        vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
+        vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
+    }
+}
+
+#define MixHrtf MixHrtf_Neon
+#define MixHrtfBlend MixHrtfBlend_Neon
+#define MixDirectHrtf MixDirectHrtf_Neon
+#include "hrtf_inc.c"
+
+
+void Mix_Neon(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+              ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
+              ALsizei BufferSize)
+{
+    ALfloat gain, delta, step;
+    float32x4_t gain4;
+    ALsizei c;
+
+    ASSUME(OutChans > 0);
+    ASSUME(BufferSize > 0);
+    data = ASSUME_ALIGNED(data, 16);
+    OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
+
+    delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
+
+    for(c = 0;c < OutChans;c++)
+    {
+        ALsizei pos = 0;
+        gain = CurrentGains[c];
+        step = (TargetGains[c] - gain) * delta;
+        if(fabsf(step) > FLT_EPSILON)
+        {
+            ALsizei minsize = mini(BufferSize, Counter);
+            /* Mix with applying gain steps in aligned multiples of 4. */
+            if(minsize-pos > 3)
+            {
+                float32x4_t step4;
+                gain4 = vsetq_lane_f32(gain, gain4, 0);
+                gain4 = vsetq_lane_f32(gain + step, gain4, 1);
+                gain4 = vsetq_lane_f32(gain + step + step, gain4, 2);
+                gain4 = vsetq_lane_f32(gain + step + step + step, gain4, 3);
+                step4 = vdupq_n_f32(step + step + step + step);
+                do {
+                    const float32x4_t val4 = vld1q_f32(&data[pos]);
+                    float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
+                    dry4 = vmlaq_f32(dry4, val4, gain4);
+                    gain4 = vaddq_f32(gain4, step4);
+                    vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
+                    pos += 4;
+                } while(minsize-pos > 3);
+                /* NOTE: gain4 now represents the next four gains after the
+                 * last four mixed samples, so the lowest element represents
+                 * the next gain to apply.
+                 */
+                gain = vgetq_lane_f32(gain4, 0);
+            }
+            /* Mix with applying left over gain steps that aren't aligned multiples of 4. */
+            for(;pos < minsize;pos++)
+            {
+                OutBuffer[c][OutPos+pos] += data[pos]*gain;
+                gain += step;
+            }
+            if(pos == Counter)
+                gain = TargetGains[c];
+            CurrentGains[c] = gain;
+
+            /* Mix until pos is aligned with 4 or the mix is done. */
+            minsize = mini(BufferSize, (pos+3)&~3);
+            for(;pos < minsize;pos++)
+                OutBuffer[c][OutPos+pos] += data[pos]*gain;
+        }
+
+        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
+            continue;
+        gain4 = vdupq_n_f32(gain);
+        for(;BufferSize-pos > 3;pos += 4)
+        {
+            const float32x4_t val4 = vld1q_f32(&data[pos]);
+            float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
+            dry4 = vmlaq_f32(dry4, val4, gain4);
+            vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
+        }
+        for(;pos < BufferSize;pos++)
+            OutBuffer[c][OutPos+pos] += data[pos]*gain;
+    }
+}
+
+void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize)
+{
+    float32x4_t gain4;
+    ALsizei c;
+
+    ASSUME(InChans > 0);
+    ASSUME(BufferSize > 0);
+    data = ASSUME_ALIGNED(data, 16);
+    OutBuffer = ASSUME_ALIGNED(OutBuffer, 16);
+
+    for(c = 0;c < InChans;c++)
+    {
+        ALsizei pos = 0;
+        ALfloat gain = Gains[c];
+        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
+            continue;
+
+        gain4 = vdupq_n_f32(gain);
+        for(;BufferSize-pos > 3;pos += 4)
+        {
+            const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]);
+            float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]);
+            dry4 = vmlaq_f32(dry4, val4, gain4);
+            vst1q_f32(&OutBuffer[pos], dry4);
+        }
+        for(;pos < BufferSize;pos++)
+            OutBuffer[pos] += data[c][InPos+pos]*gain;
+    }
+}

+ 54 - 110
Engine/lib/openal-soft/Alc/mixer_sse.c → Engine/lib/openal-soft/Alc/mixer/mixer_sse.c

@@ -9,22 +9,25 @@
 
 
 #include "alSource.h"
 #include "alSource.h"
 #include "alAuxEffectSlot.h"
 #include "alAuxEffectSlot.h"
-#include "mixer_defs.h"
+#include "defs.h"
 
 
 
 
-const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src,
-                                    ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                    ALuint dstlen)
+const ALfloat *Resample_bsinc_SSE(const InterpState *state, const ALfloat *restrict src,
+                                  ALsizei frac, ALint increment, ALfloat *restrict dst,
+                                  ALsizei 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;
+    const ALfloat *const filter = state->bsinc.filter;
+    const __m128 sf4 = _mm_set1_ps(state->bsinc.sf);
+    const ALsizei m = state->bsinc.m;
+    const __m128 *fil, *scd, *phd, *spd;
+    ALsizei pi, i, j, offset;
     ALfloat pf;
     ALfloat pf;
-    ALint j_s;
     __m128 r4;
     __m128 r4;
 
 
+    ASSUME(m > 0);
+    ASSUME(dstlen > 0);
+
+    src += state->bsinc.l;
     for(i = 0;i < dstlen;i++)
     for(i = 0;i < dstlen;i++)
     {
     {
         // Calculate the phase index and factor.
         // Calculate the phase index and factor.
@@ -33,32 +36,28 @@ const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *rest
         pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
         pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
 #undef 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;
+        offset = m*pi*4;
+        fil = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m;
+        scd = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m;
+        phd = (const __m128*)ASSUME_ALIGNED(filter + offset, 16); offset += m;
+        spd = (const __m128*)ASSUME_ALIGNED(filter + offset, 16);
 
 
         // Apply the scale and phase interpolated filter.
         // Apply the scale and phase interpolated filter.
         r4 = _mm_setzero_ps();
         r4 = _mm_setzero_ps();
         {
         {
             const __m128 pf4 = _mm_set1_ps(pf);
             const __m128 pf4 = _mm_set1_ps(pf);
-            for(j_f = 0,j_s = l;j_f < m;j_f+=4,j_s+=4)
+#define MLA4(x, y, z) _mm_add_ps(x, _mm_mul_ps(y, z))
+            for(j = 0;j < m;j+=4,fil++,scd++,phd++,spd++)
             {
             {
-                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]))
-                        )
-                    )
+                /* f = ((fil + sf*scd) + pf*(phd + sf*spd)) */
+                const __m128 f4 = MLA4(
+                    MLA4(*fil, sf4, *scd),
+                    pf4, MLA4(*phd, sf4, *spd)
                 );
                 );
-                r4 = _mm_add_ps(r4, _mm_mul_ps(f4, _mm_loadu_ps(&src[j_s])));
+                /* r += f*src */
+                r4 = MLA4(r4, f4, _mm_loadu_ps(&src[j]));
             }
             }
+#undef MLA4
         }
         }
         r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3)));
         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));
         r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4));
@@ -72,82 +71,22 @@ const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *rest
 }
 }
 
 
 
 
-static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
-                                   const ALuint IrSize,
-                                   ALfloat (*restrict Coeffs)[2],
-                                   const ALfloat (*restrict CoeffStep)[2],
-                                   ALfloat left, ALfloat right)
-{
-    const __m128 lrlr = _mm_setr_ps(left, right, left, right);
-    __m128 coeffs, deltas, imp0, imp1;
-    __m128 vals = _mm_setzero_ps();
-    ALuint i;
-
-    if((Offset&1))
-    {
-        const ALuint o0 = Offset&HRIR_MASK;
-        const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK;
-
-        coeffs = _mm_load_ps(&Coeffs[0][0]);
-        deltas = _mm_load_ps(&CoeffStep[0][0]);
-        vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]);
-        imp0 = _mm_mul_ps(lrlr, coeffs);
-        coeffs = _mm_add_ps(coeffs, deltas);
-        vals = _mm_add_ps(imp0, vals);
-        _mm_store_ps(&Coeffs[0][0], coeffs);
-        _mm_storel_pi((__m64*)&Values[o0][0], vals);
-        for(i = 1;i < IrSize-1;i += 2)
-        {
-            const ALuint o2 = (Offset+i)&HRIR_MASK;
-
-            coeffs = _mm_load_ps(&Coeffs[i+1][0]);
-            deltas = _mm_load_ps(&CoeffStep[i+1][0]);
-            vals = _mm_load_ps(&Values[o2][0]);
-            imp1 = _mm_mul_ps(lrlr, coeffs);
-            coeffs = _mm_add_ps(coeffs, deltas);
-            imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2));
-            vals = _mm_add_ps(imp0, vals);
-            _mm_store_ps(&Coeffs[i+1][0], coeffs);
-            _mm_store_ps(&Values[o2][0], vals);
-            imp0 = imp1;
-        }
-        vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]);
-        imp0 = _mm_movehl_ps(imp0, imp0);
-        vals = _mm_add_ps(imp0, vals);
-        _mm_storel_pi((__m64*)&Values[o1][0], vals);
-    }
-    else
-    {
-        for(i = 0;i < IrSize;i += 2)
-        {
-            const ALuint o = (Offset + i)&HRIR_MASK;
-
-            coeffs = _mm_load_ps(&Coeffs[i][0]);
-            deltas = _mm_load_ps(&CoeffStep[i][0]);
-            vals = _mm_load_ps(&Values[o][0]);
-            imp0 = _mm_mul_ps(lrlr, coeffs);
-            coeffs = _mm_add_ps(coeffs, deltas);
-            vals = _mm_add_ps(imp0, vals);
-            _mm_store_ps(&Coeffs[i][0], coeffs);
-            _mm_store_ps(&Values[o][0], vals);
-        }
-    }
-}
-
-static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
-                               const ALuint IrSize,
-                               ALfloat (*restrict Coeffs)[2],
+static inline void ApplyCoeffs(ALsizei Offset, ALfloat (*restrict Values)[2],
+                               const ALsizei IrSize,
+                               const ALfloat (*restrict Coeffs)[2],
                                ALfloat left, ALfloat right)
                                ALfloat left, ALfloat right)
 {
 {
     const __m128 lrlr = _mm_setr_ps(left, right, left, right);
     const __m128 lrlr = _mm_setr_ps(left, right, left, right);
     __m128 vals = _mm_setzero_ps();
     __m128 vals = _mm_setzero_ps();
     __m128 coeffs;
     __m128 coeffs;
-    ALuint i;
+    ALsizei i;
 
 
+    Values = ASSUME_ALIGNED(Values, 16);
+    Coeffs = ASSUME_ALIGNED(Coeffs, 16);
     if((Offset&1))
     if((Offset&1))
     {
     {
-        const ALuint o0 = Offset&HRIR_MASK;
-        const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK;
+        const ALsizei o0 = Offset&HRIR_MASK;
+        const ALsizei o1 = (Offset+IrSize-1)&HRIR_MASK;
         __m128 imp0, imp1;
         __m128 imp0, imp1;
 
 
         coeffs = _mm_load_ps(&Coeffs[0][0]);
         coeffs = _mm_load_ps(&Coeffs[0][0]);
@@ -157,7 +96,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
         _mm_storel_pi((__m64*)&Values[o0][0], vals);
         _mm_storel_pi((__m64*)&Values[o0][0], vals);
         for(i = 1;i < IrSize-1;i += 2)
         for(i = 1;i < IrSize-1;i += 2)
         {
         {
-            const ALuint o2 = (Offset+i)&HRIR_MASK;
+            const ALsizei o2 = (Offset+i)&HRIR_MASK;
 
 
             coeffs = _mm_load_ps(&Coeffs[i+1][0]);
             coeffs = _mm_load_ps(&Coeffs[i+1][0]);
             vals = _mm_load_ps(&Values[o2][0]);
             vals = _mm_load_ps(&Values[o2][0]);
@@ -176,7 +115,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
     {
     {
         for(i = 0;i < IrSize;i += 2)
         for(i = 0;i < IrSize;i += 2)
         {
         {
-            const ALuint o = (Offset + i)&HRIR_MASK;
+            const ALsizei o = (Offset + i)&HRIR_MASK;
 
 
             coeffs = _mm_load_ps(&Coeffs[i][0]);
             coeffs = _mm_load_ps(&Coeffs[i][0]);
             vals = _mm_load_ps(&Values[o][0]);
             vals = _mm_load_ps(&Values[o][0]);
@@ -187,29 +126,31 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
 }
 }
 
 
 #define MixHrtf MixHrtf_SSE
 #define MixHrtf MixHrtf_SSE
+#define MixHrtfBlend MixHrtfBlend_SSE
 #define MixDirectHrtf MixDirectHrtf_SSE
 #define MixDirectHrtf MixDirectHrtf_SSE
-#include "mixer_inc.c"
-#undef MixHrtf
+#include "hrtf_inc.c"
 
 
 
 
-void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-             ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos,
-             ALuint BufferSize)
+void Mix_SSE(const ALfloat *data, ALsizei OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+             ALfloat *CurrentGains, const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
+             ALsizei BufferSize)
 {
 {
     ALfloat gain, delta, step;
     ALfloat gain, delta, step;
     __m128 gain4;
     __m128 gain4;
-    ALuint c;
+    ALsizei c;
 
 
+    ASSUME(OutChans > 0);
+    ASSUME(BufferSize > 0);
     delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
     delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
 
 
     for(c = 0;c < OutChans;c++)
     for(c = 0;c < OutChans;c++)
     {
     {
-        ALuint pos = 0;
+        ALsizei pos = 0;
         gain = CurrentGains[c];
         gain = CurrentGains[c];
         step = (TargetGains[c] - gain) * delta;
         step = (TargetGains[c] - gain) * delta;
         if(fabsf(step) > FLT_EPSILON)
         if(fabsf(step) > FLT_EPSILON)
         {
         {
-            ALuint minsize = minu(BufferSize, Counter);
+            ALsizei minsize = mini(BufferSize, Counter);
             /* Mix with applying gain steps in aligned multiples of 4. */
             /* Mix with applying gain steps in aligned multiples of 4. */
             if(minsize-pos > 3)
             if(minsize-pos > 3)
             {
             {
@@ -246,7 +187,7 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)
             CurrentGains[c] = gain;
             CurrentGains[c] = gain;
 
 
             /* Mix until pos is aligned with 4 or the mix is done. */
             /* Mix until pos is aligned with 4 or the mix is done. */
-            minsize = minu(BufferSize, (pos+3)&~3);
+            minsize = mini(BufferSize, (pos+3)&~3);
             for(;pos < minsize;pos++)
             for(;pos < minsize;pos++)
                 OutBuffer[c][OutPos+pos] += data[pos]*gain;
                 OutBuffer[c][OutPos+pos] += data[pos]*gain;
         }
         }
@@ -266,14 +207,17 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)
     }
     }
 }
 }
 
 
-void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize)
+void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans, ALsizei InPos, ALsizei BufferSize)
 {
 {
     __m128 gain4;
     __m128 gain4;
-    ALuint c;
+    ALsizei c;
+
+    ASSUME(InChans > 0);
+    ASSUME(BufferSize > 0);
 
 
     for(c = 0;c < InChans;c++)
     for(c = 0;c < InChans;c++)
     {
     {
-        ALuint pos = 0;
+        ALsizei pos = 0;
         ALfloat gain = Gains[c];
         ALfloat gain = Gains[c];
         if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
         if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
             continue;
             continue;

+ 10 - 8
Engine/lib/openal-soft/Alc/mixer_sse2.c → Engine/lib/openal-soft/Alc/mixer/mixer_sse2.c

@@ -24,21 +24,23 @@
 #include <emmintrin.h>
 #include <emmintrin.h>
 
 
 #include "alu.h"
 #include "alu.h"
-#include "mixer_defs.h"
+#include "defs.h"
 
 
 
 
-const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *restrict src,
-                                    ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                    ALuint numsamples)
+const ALfloat *Resample_lerp_SSE2(const InterpState* UNUSED(state),
+  const ALfloat *restrict src, ALsizei frac, ALint increment,
+  ALfloat *restrict dst, ALsizei numsamples)
 {
 {
     const __m128i increment4 = _mm_set1_epi32(increment*4);
     const __m128i increment4 = _mm_set1_epi32(increment*4);
     const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
     const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
     const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
     const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
-    union { alignas(16) ALuint i[4]; float f[4]; } pos_;
-    union { alignas(16) ALuint i[4]; float f[4]; } frac_;
+    union { alignas(16) ALint i[4]; float f[4]; } pos_;
+    union { alignas(16) ALsizei i[4]; float f[4]; } frac_;
     __m128i frac4, pos4;
     __m128i frac4, pos4;
-    ALuint pos;
-    ALuint i;
+    ALint pos;
+    ALsizei i;
+
+    ASSUME(numsamples > 0);
 
 
     InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
     InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
 
 

+ 0 - 0
Engine/lib/openal-soft/Alc/mixer/mixer_sse3.c


+ 88 - 0
Engine/lib/openal-soft/Alc/mixer/mixer_sse41.c

@@ -0,0 +1,88 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2014 by Timothy Arceri <[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 <smmintrin.h>
+
+#include "alu.h"
+#include "defs.h"
+
+
+const ALfloat *Resample_lerp_SSE41(const InterpState* UNUSED(state),
+  const ALfloat *restrict src, ALsizei frac, ALint increment,
+  ALfloat *restrict dst, ALsizei numsamples)
+{
+    const __m128i increment4 = _mm_set1_epi32(increment*4);
+    const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
+    const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+    union { alignas(16) ALint i[4]; float f[4]; } pos_;
+    union { alignas(16) ALsizei i[4]; float f[4]; } frac_;
+    __m128i frac4, pos4;
+    ALint pos;
+    ALsizei i;
+
+    ASSUME(numsamples > 0);
+
+    InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+    frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+    pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+    for(i = 0;numsamples-i > 3;i += 4)
+    {
+        const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]);
+        const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]);
+
+        /* val1 + (val2-val1)*mu */
+        const __m128 r0 = _mm_sub_ps(val2, val1);
+        const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
+        const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0));
+
+        _mm_store_ps(&dst[i], out);
+
+        frac4 = _mm_add_epi32(frac4, increment4);
+        pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+        frac4 = _mm_and_si128(frac4, fracMask4);
+
+        pos_.i[0] = _mm_extract_epi32(pos4, 0);
+        pos_.i[1] = _mm_extract_epi32(pos4, 1);
+        pos_.i[2] = _mm_extract_epi32(pos4, 2);
+        pos_.i[3] = _mm_extract_epi32(pos4, 3);
+    }
+
+    /* NOTE: These four elements represent the position *after* the last four
+     * samples, so the lowest element is the next position to resample.
+     */
+    pos = pos_.i[0];
+    frac = _mm_cvtsi128_si32(frac4);
+
+    for(;i < numsamples;i++)
+    {
+        dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
+
+        frac += increment;
+        pos  += frac>>FRACTIONBITS;
+        frac &= FRACTIONMASK;
+    }
+    return dst;
+}

+ 0 - 228
Engine/lib/openal-soft/Alc/mixer_c.c

@@ -1,228 +0,0 @@
-#include "config.h"
-
-#include <assert.h>
-
-#include "alMain.h"
-#include "alu.h"
-#include "alSource.h"
-#include "alAuxEffectSlot.h"
-
-
-static inline ALfloat point32(const ALfloat *restrict vals, ALuint UNUSED(frac))
-{ return vals[0]; }
-static inline ALfloat lerp32(const ALfloat *restrict vals, ALuint frac)
-{ return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
-static inline ALfloat fir4_32(const ALfloat *restrict vals, ALuint frac)
-{ return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); }
-static inline ALfloat fir8_32(const ALfloat *restrict 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 BsincState* UNUSED(state), const ALfloat *restrict src, ALuint UNUSED(frac),
-  ALuint UNUSED(increment), ALfloat *restrict dst, ALuint numsamples)
-{
-#if defined(HAVE_SSE) || defined(HAVE_NEON)
-    /* Avoid copying the source data if it's aligned like the destination. */
-    if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
-        return src;
-#endif
-    memcpy(dst, src, numsamples*sizeof(ALfloat));
-    return dst;
-}
-
-#define DECL_TEMPLATE(Sampler)                                                \
-const ALfloat *Resample_##Sampler##_C(const BsincState* UNUSED(state),        \
-  const ALfloat *restrict src, ALuint frac, ALuint increment,                 \
-  ALfloat *restrict dst, ALuint numsamples)                                   \
-{                                                                             \
-    ALuint i;                                                                 \
-    for(i = 0;i < numsamples;i++)                                             \
-    {                                                                         \
-        dst[i] = Sampler(src, frac);                                          \
-                                                                              \
-        frac += increment;                                                    \
-        src  += frac>>FRACTIONBITS;                                           \
-        frac &= FRACTIONMASK;                                                 \
-    }                                                                         \
-    return dst;                                                               \
-}
-
-DECL_TEMPLATE(point32)
-DECL_TEMPLATE(lerp32)
-DECL_TEMPLATE(fir4_32)
-DECL_TEMPLATE(fir8_32)
-
-#undef DECL_TEMPLATE
-
-const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict 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 *restrict src, ALuint numsamples)
-{
-    ALuint i;
-    if(numsamples > 1)
-    {
-        dst[0] = filter->b0 * src[0] +
-                 filter->b1 * filter->x[0] +
-                 filter->b2 * filter->x[1] -
-                 filter->a1 * filter->y[0] -
-                 filter->a2 * filter->y[1];
-        dst[1] = filter->b0 * src[1] +
-                 filter->b1 * src[0] +
-                 filter->b2 * filter->x[0] -
-                 filter->a1 * dst[0] -
-                 filter->a2 * filter->y[0];
-        for(i = 2;i < numsamples;i++)
-            dst[i] = filter->b0 * src[i] +
-                     filter->b1 * src[i-1] +
-                     filter->b2 * src[i-2] -
-                     filter->a1 * dst[i-1] -
-                     filter->a2 * dst[i-2];
-        filter->x[0] = src[i-1];
-        filter->x[1] = src[i-2];
-        filter->y[0] = dst[i-1];
-        filter->y[1] = dst[i-2];
-    }
-    else if(numsamples == 1)
-    {
-        dst[0] = filter->b0 * src[0] +
-                 filter->b1 * filter->x[0] +
-                 filter->b2 * filter->x[1] -
-                 filter->a1 * filter->y[0] -
-                 filter->a2 * filter->y[1];
-        filter->x[1] = filter->x[0];
-        filter->x[0] = src[0];
-        filter->y[1] = filter->y[0];
-        filter->y[0] = dst[0];
-    }
-}
-
-
-static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
-                                   const ALuint IrSize,
-                                   ALfloat (*restrict Coeffs)[2],
-                                   const ALfloat (*restrict CoeffStep)[2],
-                                   ALfloat left, ALfloat right)
-{
-    ALuint c;
-    for(c = 0;c < IrSize;c++)
-    {
-        const ALuint off = (Offset+c)&HRIR_MASK;
-        Values[off][0] += Coeffs[c][0] * left;
-        Values[off][1] += Coeffs[c][1] * right;
-        Coeffs[c][0] += CoeffStep[c][0];
-        Coeffs[c][1] += CoeffStep[c][1];
-    }
-}
-
-static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
-                               const ALuint IrSize,
-                               ALfloat (*restrict Coeffs)[2],
-                               ALfloat left, ALfloat right)
-{
-    ALuint c;
-    for(c = 0;c < IrSize;c++)
-    {
-        const ALuint off = (Offset+c)&HRIR_MASK;
-        Values[off][0] += Coeffs[c][0] * left;
-        Values[off][1] += Coeffs[c][1] * right;
-    }
-}
-
-#define MixHrtf MixHrtf_C
-#define MixDirectHrtf MixDirectHrtf_C
-#include "mixer_inc.c"
-#undef MixHrtf
-
-
-void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-           ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos,
-           ALuint BufferSize)
-{
-    ALfloat gain, delta, step;
-    ALuint c;
-
-    delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
-
-    for(c = 0;c < OutChans;c++)
-    {
-        ALuint pos = 0;
-        gain = CurrentGains[c];
-        step = (TargetGains[c] - gain) * delta;
-        if(fabsf(step) > FLT_EPSILON)
-        {
-            ALuint minsize = minu(BufferSize, Counter);
-            for(;pos < minsize;pos++)
-            {
-                OutBuffer[c][OutPos+pos] += data[pos]*gain;
-                gain += step;
-            }
-            if(pos == Counter)
-                gain = TargetGains[c];
-            CurrentGains[c] = gain;
-        }
-
-        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
-            continue;
-        for(;pos < BufferSize;pos++)
-            OutBuffer[c][OutPos+pos] += data[pos]*gain;
-    }
-}
-
-/* Basically the inverse of the above. Rather than one input going to multiple
- * outputs (each with its own gain), it's multiple inputs (each with its own
- * gain) going to one output. This applies one row (vs one column) of a matrix
- * transform. And as the matrices are more or less static once set up, no
- * stepping is necessary.
- */
-void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize)
-{
-    ALuint c, i;
-
-    for(c = 0;c < InChans;c++)
-    {
-        ALfloat gain = Gains[c];
-        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
-            continue;
-
-        for(i = 0;i < BufferSize;i++)
-            OutBuffer[i] += data[c][InPos+i] * gain;
-    }
-}

+ 0 - 110
Engine/lib/openal-soft/Alc/mixer_defs.h

@@ -1,110 +0,0 @@
-#ifndef MIXER_DEFS_H
-#define MIXER_DEFS_H
-
-#include "AL/alc.h"
-#include "AL/al.h"
-#include "alMain.h"
-#include "alu.h"
-
-struct MixGains;
-
-struct MixHrtfParams;
-struct HrtfState;
-
-/* C resamplers */
-const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-
-
-/* C mixers */
-void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-               const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos,
-               const ALuint IrSize, const struct MixHrtfParams *hrtfparams,
-               struct HrtfState *hrtfstate, ALuint BufferSize);
-void MixDirectHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-                     const ALfloat *data, ALuint Offset, const ALuint IrSize,
-                     ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
-                     ALuint BufferSize);
-void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-           ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos,
-           ALuint BufferSize);
-void MixRow_C(ALfloat *OutBuffer, const ALfloat *Gains,
-              const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans,
-              ALuint InPos, ALuint BufferSize);
-
-/* SSE mixers */
-void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-                 const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos,
-                 const ALuint IrSize, const struct MixHrtfParams *hrtfparams,
-                 struct HrtfState *hrtfstate, ALuint BufferSize);
-void MixDirectHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-                       const ALfloat *data, ALuint Offset, const ALuint IrSize,
-                       ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
-                       ALuint BufferSize);
-void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-             ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos,
-             ALuint BufferSize);
-void MixRow_SSE(ALfloat *OutBuffer, const ALfloat *Gains,
-                const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans,
-                ALuint InPos, ALuint BufferSize);
-
-/* SSE resamplers */
-inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *restrict frac_arr, ALuint *restrict pos_arr, ALuint size)
-{
-    ALuint i;
-
-    pos_arr[0] = 0;
-    frac_arr[0] = frac;
-    for(i = 1;i < size;i++)
-    {
-        ALuint frac_tmp = frac_arr[i-1] + increment;
-        pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS);
-        frac_arr[i] = frac_tmp&FRACTIONMASK;
-    }
-}
-
-const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *restrict src, ALuint frac,
-                                    ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-
-const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *restrict src,
-                                    ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                    ALuint numsamples);
-const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *restrict src,
-                                     ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                     ALuint numsamples);
-
-const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *restrict src,
-                                     ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                     ALuint numsamples);
-const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *restrict src,
-                                      ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                      ALuint numsamples);
-
-const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *restrict src,
-                                     ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                     ALuint numsamples);
-const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *restrict src,
-                                      ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                      ALuint numsamples);
-
-/* Neon mixers */
-void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-                  const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos,
-                  const ALuint IrSize, const struct MixHrtfParams *hrtfparams,
-                  struct HrtfState *hrtfstate, ALuint BufferSize);
-void MixDirectHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-                        const ALfloat *data, ALuint Offset, const ALuint IrSize,
-                        ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
-                        ALuint BufferSize);
-void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-              ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos,
-              ALuint BufferSize);
-void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains,
-                 const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans,
-                 ALuint InPos, ALuint BufferSize);
-
-#endif /* MIXER_DEFS_H */

+ 0 - 149
Engine/lib/openal-soft/Alc/mixer_inc.c

@@ -1,149 +0,0 @@
-#include "config.h"
-
-#include "alMain.h"
-#include "alSource.h"
-
-#include "hrtf.h"
-#include "mixer_defs.h"
-#include "align.h"
-#include "alu.h"
-
-
-#define MAX_UPDATE_SAMPLES 128
-
-
-static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
-                                   const ALuint irSize,
-                                   ALfloat (*restrict Coeffs)[2],
-                                   const ALfloat (*restrict CoeffStep)[2],
-                                   ALfloat left, ALfloat right);
-static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
-                               const ALuint irSize,
-                               ALfloat (*restrict Coeffs)[2],
-                               ALfloat left, ALfloat right);
-
-
-void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-             const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos,
-             const ALuint IrSize, const MixHrtfParams *hrtfparams, HrtfState *hrtfstate,
-             ALuint BufferSize)
-{
-    ALfloat (*Coeffs)[2] = hrtfparams->Current->Coeffs;
-    ALuint Delay[2] = { hrtfparams->Current->Delay[0], hrtfparams->Current->Delay[1] };
-    ALfloat out[MAX_UPDATE_SAMPLES][2];
-    ALfloat left, right;
-    ALuint minsize;
-    ALuint pos, i;
-
-    pos = 0;
-    if(Counter == 0)
-        goto skip_stepping;
-
-    minsize = minu(BufferSize, Counter);
-    while(pos < minsize)
-    {
-        ALuint todo = minu(minsize-pos, MAX_UPDATE_SAMPLES);
-
-        for(i = 0;i < todo;i++)
-        {
-            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))&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->Steps.Delay[0];
-            Delay[1] += hrtfparams->Steps.Delay[1];
-
-            hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
-            hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
-            Offset++;
-
-            ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->Steps.Coeffs, left, right);
-            out[i][0] = hrtfstate->Values[Offset&HRIR_MASK][0];
-            out[i][1] = hrtfstate->Values[Offset&HRIR_MASK][1];
-        }
-
-        for(i = 0;i < todo;i++)
-            OutBuffer[lidx][OutPos+i] += out[i][0];
-        for(i = 0;i < todo;i++)
-            OutBuffer[ridx][OutPos+i] += out[i][1];
-        OutPos += todo;
-    }
-
-    if(pos == Counter)
-    {
-        *hrtfparams->Current = *hrtfparams->Target;
-        Delay[0] = hrtfparams->Target->Delay[0];
-        Delay[1] = hrtfparams->Target->Delay[1];
-    }
-    else
-    {
-        hrtfparams->Current->Delay[0] = Delay[0];
-        hrtfparams->Current->Delay[1] = Delay[1];
-    }
-
-skip_stepping:
-    Delay[0] >>= HRTFDELAY_BITS;
-    Delay[1] >>= HRTFDELAY_BITS;
-    while(pos < BufferSize)
-    {
-        ALuint todo = minu(BufferSize-pos, MAX_UPDATE_SAMPLES);
-
-        for(i = 0;i < todo;i++)
-        {
-            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);
-            out[i][0] = hrtfstate->Values[Offset&HRIR_MASK][0];
-            out[i][1] = hrtfstate->Values[Offset&HRIR_MASK][1];
-        }
-
-        for(i = 0;i < todo;i++)
-            OutBuffer[lidx][OutPos+i] += out[i][0];
-        for(i = 0;i < todo;i++)
-            OutBuffer[ridx][OutPos+i] += out[i][1];
-        OutPos += todo;
-    }
-}
-
-void MixDirectHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-                   const ALfloat *data, ALuint Offset, const ALuint IrSize,
-                   ALfloat (*restrict Coeffs)[2], ALfloat (*restrict Values)[2],
-                   ALuint BufferSize)
-{
-    ALfloat out[MAX_UPDATE_SAMPLES][2];
-    ALfloat insample;
-    ALuint pos, i;
-
-    for(pos = 0;pos < BufferSize;)
-    {
-        ALuint todo = minu(BufferSize-pos, MAX_UPDATE_SAMPLES);
-
-        for(i = 0;i < todo;i++)
-        {
-            Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
-            Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
-            Offset++;
-
-            insample = *(data++);
-            ApplyCoeffs(Offset, Values, IrSize, Coeffs, insample, insample);
-            out[i][0] = Values[Offset&HRIR_MASK][0];
-            out[i][1] = Values[Offset&HRIR_MASK][1];
-        }
-
-        for(i = 0;i < todo;i++)
-            OutBuffer[lidx][pos+i] += out[i][0];
-        for(i = 0;i < todo;i++)
-            OutBuffer[ridx][pos+i] += out[i][1];
-        pos += todo;
-    }
-}

+ 0 - 173
Engine/lib/openal-soft/Alc/mixer_neon.c

@@ -1,173 +0,0 @@
-#include "config.h"
-
-#include <arm_neon.h>
-
-#include "AL/al.h"
-#include "AL/alc.h"
-#include "alMain.h"
-#include "alu.h"
-#include "hrtf.h"
-
-
-static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
-                                   const ALuint IrSize,
-                                   ALfloat (*restrict Coeffs)[2],
-                                   const ALfloat (*restrict CoeffStep)[2],
-                                   ALfloat left, ALfloat right)
-{
-    ALuint c;
-    float32x4_t leftright4;
-    {
-        float32x2_t leftright2 = vdup_n_f32(0.0);
-        leftright2 = vset_lane_f32(left, leftright2, 0);
-        leftright2 = vset_lane_f32(right, leftright2, 1);
-        leftright4 = vcombine_f32(leftright2, leftright2);
-    }
-    for(c = 0;c < IrSize;c += 2)
-    {
-        const ALuint o0 = (Offset+c)&HRIR_MASK;
-        const ALuint o1 = (o0+1)&HRIR_MASK;
-        float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
-                                        vld1_f32((float32_t*)&Values[o1][0]));
-        float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
-        float32x4_t deltas = vld1q_f32(&CoeffStep[c][0]);
-
-        vals = vmlaq_f32(vals, coefs, leftright4);
-        coefs = vaddq_f32(coefs, deltas);
-
-        vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
-        vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
-        vst1q_f32(&Coeffs[c][0], coefs);
-    }
-}
-
-static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
-                               const ALuint IrSize,
-                               ALfloat (*restrict Coeffs)[2],
-                               ALfloat left, ALfloat right)
-{
-    ALuint c;
-    float32x4_t leftright4;
-    {
-        float32x2_t leftright2 = vdup_n_f32(0.0);
-        leftright2 = vset_lane_f32(left, leftright2, 0);
-        leftright2 = vset_lane_f32(right, leftright2, 1);
-        leftright4 = vcombine_f32(leftright2, leftright2);
-    }
-    for(c = 0;c < IrSize;c += 2)
-    {
-        const ALuint o0 = (Offset+c)&HRIR_MASK;
-        const ALuint o1 = (o0+1)&HRIR_MASK;
-        float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]),
-                                        vld1_f32((float32_t*)&Values[o1][0]));
-        float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]);
-
-        vals = vmlaq_f32(vals, coefs, leftright4);
-
-        vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals));
-        vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals));
-    }
-}
-
-#define MixHrtf MixHrtf_Neon
-#define MixDirectHrtf MixDirectHrtf_Neon
-#include "mixer_inc.c"
-#undef MixHrtf
-
-
-void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-              ALfloat *CurrentGains, const ALfloat *TargetGains, ALuint Counter, ALuint OutPos,
-              ALuint BufferSize)
-{
-    ALfloat gain, delta, step;
-    float32x4_t gain4;
-    ALuint c;
-
-    delta = (Counter > 0) ? 1.0f/(ALfloat)Counter : 0.0f;
-
-    for(c = 0;c < OutChans;c++)
-    {
-        ALuint pos = 0;
-        gain = CurrentGains[c];
-        step = (TargetGains[c] - gain) * delta;
-        if(fabsf(step) > FLT_EPSILON)
-        {
-            ALuint minsize = minu(BufferSize, Counter);
-            /* Mix with applying gain steps in aligned multiples of 4. */
-            if(minsize-pos > 3)
-            {
-                float32x4_t step4;
-                gain4 = vsetq_lane_f32(gain, gain4, 0);
-                gain4 = vsetq_lane_f32(gain + step, gain4, 1);
-                gain4 = vsetq_lane_f32(gain + step + step, gain4, 2);
-                gain4 = vsetq_lane_f32(gain + step + step + step, gain4, 3);
-                step4 = vdupq_n_f32(step + step + step + step);
-                do {
-                    const float32x4_t val4 = vld1q_f32(&data[pos]);
-                    float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
-                    dry4 = vmlaq_f32(dry4, val4, gain4);
-                    gain4 = vaddq_f32(gain4, step4);
-                    vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
-                    pos += 4;
-                } while(minsize-pos > 3);
-                /* NOTE: gain4 now represents the next four gains after the
-                 * last four mixed samples, so the lowest element represents
-                 * the next gain to apply.
-                 */
-                gain = vgetq_lane_f32(gain4, 0);
-            }
-            /* Mix with applying left over gain steps that aren't aligned multiples of 4. */
-            for(;pos < minsize;pos++)
-            {
-                OutBuffer[c][OutPos+pos] += data[pos]*gain;
-                gain += step;
-            }
-            if(pos == Counter)
-                gain = TargetGains[c];
-            CurrentGains[c] = gain;
-
-            /* Mix until pos is aligned with 4 or the mix is done. */
-            minsize = minu(BufferSize, (pos+3)&~3);
-            for(;pos < minsize;pos++)
-                OutBuffer[c][OutPos+pos] += data[pos]*gain;
-        }
-
-        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
-            continue;
-        gain4 = vdupq_n_f32(gain);
-        for(;BufferSize-pos > 3;pos += 4)
-        {
-            const float32x4_t val4 = vld1q_f32(&data[pos]);
-            float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
-            dry4 = vmlaq_f32(dry4, val4, gain4);
-            vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
-        }
-        for(;pos < BufferSize;pos++)
-            OutBuffer[c][OutPos+pos] += data[pos]*gain;
-    }
-}
-
-void MixRow_Neon(ALfloat *OutBuffer, const ALfloat *Gains, const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans, ALuint InPos, ALuint BufferSize)
-{
-    float32x4_t gain4;
-    ALuint c;
-
-    for(c = 0;c < InChans;c++)
-    {
-        ALuint pos = 0;
-        ALfloat gain = Gains[c];
-        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
-            continue;
-
-        gain4 = vdupq_n_f32(gain);
-        for(;BufferSize-pos > 3;pos += 4)
-        {
-            const float32x4_t val4 = vld1q_f32(&data[c][InPos+pos]);
-            float32x4_t dry4 = vld1q_f32(&OutBuffer[pos]);
-            dry4 = vmlaq_f32(dry4, val4, gain4);
-            vst1q_f32(&OutBuffer[pos], dry4);
-        }
-        for(;pos < BufferSize;pos++)
-            OutBuffer[pos] += data[c][InPos+pos]*gain;
-    }
-}

+ 0 - 164
Engine/lib/openal-soft/Alc/mixer_sse3.c

@@ -1,164 +0,0 @@
-/**
- * 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 *restrict 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);
-    union { alignas(16) ALuint i[4]; float f[4]; } pos_;
-    union { alignas(16) 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 *restrict 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);
-    union { alignas(16) ALuint i[4]; float f[4]; } pos_;
-    union { alignas(16) 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;
-}

+ 0 - 227
Engine/lib/openal-soft/Alc/mixer_sse41.c

@@ -1,227 +0,0 @@
-/**
- * OpenAL cross platform audio library
- * Copyright (C) 2014 by Timothy Arceri <[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 <smmintrin.h>
-
-#include "alu.h"
-#include "mixer_defs.h"
-
-
-const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict src,
-                                     ALuint frac, ALuint increment, ALfloat *restrict dst,
-                                     ALuint numsamples)
-{
-    const __m128i increment4 = _mm_set1_epi32(increment*4);
-    const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE);
-    const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
-    union { alignas(16) ALuint i[4]; float f[4]; } pos_;
-    union { alignas(16) ALuint i[4]; float f[4]; } frac_;
-    __m128i frac4, pos4;
-    ALuint pos;
-    ALuint i;
-
-    InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
-
-    frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
-    pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
-
-    for(i = 0;numsamples-i > 3;i += 4)
-    {
-        const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]);
-        const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]);
-
-        /* val1 + (val2-val1)*mu */
-        const __m128 r0 = _mm_sub_ps(val2, val1);
-        const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4);
-        const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0));
-
-        _mm_store_ps(&dst[i], out);
-
-        frac4 = _mm_add_epi32(frac4, increment4);
-        pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
-        frac4 = _mm_and_si128(frac4, fracMask4);
-
-        pos_.i[0] = _mm_extract_epi32(pos4, 0);
-        pos_.i[1] = _mm_extract_epi32(pos4, 1);
-        pos_.i[2] = _mm_extract_epi32(pos4, 2);
-        pos_.i[3] = _mm_extract_epi32(pos4, 3);
-    }
-
-    /* NOTE: These four elements represent the position *after* the last four
-     * samples, so the lowest element is the next position to resample.
-     */
-    pos = pos_.i[0];
-    frac = _mm_cvtsi128_si32(frac4);
-
-    for(;i < numsamples;i++)
-    {
-        dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE));
-
-        frac += increment;
-        pos  += frac>>FRACTIONBITS;
-        frac &= FRACTIONMASK;
-    }
-    return dst;
-}
-
-const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *restrict 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);
-    union { alignas(16) ALuint i[4]; float f[4]; } pos_;
-    union { alignas(16) 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 *restrict 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);
-    union { alignas(16) ALuint i[4]; float f[4]; } pos_;
-    union { alignas(16) 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;
-}

+ 761 - 0
Engine/lib/openal-soft/Alc/mixvoice.c

@@ -0,0 +1,761 @@
+/**
+ * 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 <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alListener.h"
+#include "alAuxEffectSlot.h"
+#include "sample_cvt.h"
+#include "alu.h"
+#include "alconfig.h"
+#include "ringbuffer.h"
+
+#include "cpu_caps.h"
+#include "mixer/defs.h"
+
+
+static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
+              "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
+
+extern inline void InitiatePositionArrays(ALsizei frac, ALint increment, ALsizei *restrict frac_arr, ALint *restrict pos_arr, ALsizei size);
+
+
+/* BSinc24 requires up to 23 extra samples before the current position, and 24 after. */
+static_assert(MAX_RESAMPLE_PADDING >= 24, "MAX_RESAMPLE_PADDING must be at least 24!");
+
+
+enum Resampler ResamplerDefault = LinearResampler;
+
+MixerFunc MixSamples = Mix_C;
+RowMixerFunc MixRowSamples = MixRow_C;
+static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
+static HrtfMixerBlendFunc MixHrtfBlendSamples = MixHrtfBlend_C;
+
+static MixerFunc SelectMixer(void)
+{
+#ifdef HAVE_NEON
+    if((CPUCapFlags&CPU_CAP_NEON))
+        return Mix_Neon;
+#endif
+#ifdef HAVE_SSE
+    if((CPUCapFlags&CPU_CAP_SSE))
+        return Mix_SSE;
+#endif
+    return Mix_C;
+}
+
+static RowMixerFunc SelectRowMixer(void)
+{
+#ifdef HAVE_NEON
+    if((CPUCapFlags&CPU_CAP_NEON))
+        return MixRow_Neon;
+#endif
+#ifdef HAVE_SSE
+    if((CPUCapFlags&CPU_CAP_SSE))
+        return MixRow_SSE;
+#endif
+    return MixRow_C;
+}
+
+static inline HrtfMixerFunc SelectHrtfMixer(void)
+{
+#ifdef HAVE_NEON
+    if((CPUCapFlags&CPU_CAP_NEON))
+        return MixHrtf_Neon;
+#endif
+#ifdef HAVE_SSE
+    if((CPUCapFlags&CPU_CAP_SSE))
+        return MixHrtf_SSE;
+#endif
+    return MixHrtf_C;
+}
+
+static inline HrtfMixerBlendFunc SelectHrtfBlendMixer(void)
+{
+#ifdef HAVE_NEON
+    if((CPUCapFlags&CPU_CAP_NEON))
+        return MixHrtfBlend_Neon;
+#endif
+#ifdef HAVE_SSE
+    if((CPUCapFlags&CPU_CAP_SSE))
+        return MixHrtfBlend_SSE;
+#endif
+    return MixHrtfBlend_C;
+}
+
+ResamplerFunc SelectResampler(enum Resampler resampler)
+{
+    switch(resampler)
+    {
+        case PointResampler:
+            return Resample_point_C;
+        case LinearResampler:
+#ifdef HAVE_NEON
+            if((CPUCapFlags&CPU_CAP_NEON))
+                return Resample_lerp_Neon;
+#endif
+#ifdef HAVE_SSE4_1
+            if((CPUCapFlags&CPU_CAP_SSE4_1))
+                return Resample_lerp_SSE41;
+#endif
+#ifdef HAVE_SSE2
+            if((CPUCapFlags&CPU_CAP_SSE2))
+                return Resample_lerp_SSE2;
+#endif
+            return Resample_lerp_C;
+        case FIR4Resampler:
+            return Resample_cubic_C;
+        case BSinc12Resampler:
+        case BSinc24Resampler:
+#ifdef HAVE_NEON
+            if((CPUCapFlags&CPU_CAP_NEON))
+                return Resample_bsinc_Neon;
+#endif
+#ifdef HAVE_SSE
+            if((CPUCapFlags&CPU_CAP_SSE))
+                return Resample_bsinc_SSE;
+#endif
+            return Resample_bsinc_C;
+    }
+
+    return Resample_point_C;
+}
+
+
+void aluInitMixer(void)
+{
+    const char *str;
+
+    if(ConfigValueStr(NULL, NULL, "resampler", &str))
+    {
+        if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
+            ResamplerDefault = PointResampler;
+        else if(strcasecmp(str, "linear") == 0)
+            ResamplerDefault = LinearResampler;
+        else if(strcasecmp(str, "cubic") == 0)
+            ResamplerDefault = FIR4Resampler;
+        else if(strcasecmp(str, "bsinc12") == 0)
+            ResamplerDefault = BSinc12Resampler;
+        else if(strcasecmp(str, "bsinc24") == 0)
+            ResamplerDefault = BSinc24Resampler;
+        else if(strcasecmp(str, "bsinc") == 0)
+        {
+            WARN("Resampler option \"%s\" is deprecated, using bsinc12\n", str);
+            ResamplerDefault = BSinc12Resampler;
+        }
+        else if(strcasecmp(str, "sinc4") == 0 || strcasecmp(str, "sinc8") == 0)
+        {
+            WARN("Resampler option \"%s\" is deprecated, using cubic\n", str);
+            ResamplerDefault = FIR4Resampler;
+        }
+        else
+        {
+            char *end;
+            long n = strtol(str, &end, 0);
+            if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
+                ResamplerDefault = n;
+            else
+                WARN("Invalid resampler: %s\n", str);
+        }
+    }
+
+    MixHrtfBlendSamples = SelectHrtfBlendMixer();
+    MixHrtfSamples = SelectHrtfMixer();
+    MixSamples = SelectMixer();
+    MixRowSamples = SelectRowMixer();
+}
+
+
+static void SendAsyncEvent(ALCcontext *context, ALuint enumtype, ALenum type,
+                           ALuint objid, ALuint param, const char *msg)
+{
+    AsyncEvent evt;
+    evt.EnumType = enumtype;
+    evt.Type = type;
+    evt.ObjectId = objid;
+    evt.Param = param;
+    strcpy(evt.Message, msg);
+    if(ll_ringbuffer_write(context->AsyncEvents, (const char*)&evt, 1) == 1)
+        alsem_post(&context->EventSem);
+}
+
+
+static inline ALfloat Sample_ALubyte(ALubyte val)
+{ return (val-128) * (1.0f/128.0f); }
+
+static inline ALfloat Sample_ALshort(ALshort val)
+{ return val * (1.0f/32768.0f); }
+
+static inline ALfloat Sample_ALfloat(ALfloat val)
+{ return val; }
+
+static inline ALfloat Sample_ALdouble(ALdouble val)
+{ return (ALfloat)val; }
+
+typedef ALubyte ALmulaw;
+static inline ALfloat Sample_ALmulaw(ALmulaw val)
+{ return muLawDecompressionTable[val] * (1.0f/32768.0f); }
+
+typedef ALubyte ALalaw;
+static inline ALfloat Sample_ALalaw(ALalaw val)
+{ return aLawDecompressionTable[val] * (1.0f/32768.0f); }
+
+#define DECL_TEMPLATE(T)                                                      \
+static inline void Load_##T(ALfloat *restrict dst, const T *restrict src,     \
+                            ALint srcstep, ALsizei samples)                   \
+{                                                                             \
+    ALsizei i;                                                                \
+    for(i = 0;i < samples;i++)                                                \
+        dst[i] += Sample_##T(src[i*srcstep]);                                 \
+}
+
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+DECL_TEMPLATE(ALmulaw)
+DECL_TEMPLATE(ALalaw)
+
+#undef DECL_TEMPLATE
+
+static void LoadSamples(ALfloat *restrict dst, const ALvoid *restrict src, ALint srcstep,
+                        enum FmtType srctype, ALsizei samples)
+{
+#define HANDLE_FMT(ET, ST) case ET: Load_##ST(dst, src, srcstep, samples); break
+    switch(srctype)
+    {
+        HANDLE_FMT(FmtUByte, ALubyte);
+        HANDLE_FMT(FmtShort, ALshort);
+        HANDLE_FMT(FmtFloat, ALfloat);
+        HANDLE_FMT(FmtDouble, ALdouble);
+        HANDLE_FMT(FmtMulaw, ALmulaw);
+        HANDLE_FMT(FmtAlaw, ALalaw);
+    }
+#undef HANDLE_FMT
+}
+
+
+static const ALfloat *DoFilters(BiquadFilter *lpfilter, BiquadFilter *hpfilter,
+                                ALfloat *restrict dst, const ALfloat *restrict src,
+                                ALsizei numsamples, enum ActiveFilters type)
+{
+    ALsizei i;
+    switch(type)
+    {
+        case AF_None:
+            BiquadFilter_passthru(lpfilter, numsamples);
+            BiquadFilter_passthru(hpfilter, numsamples);
+            break;
+
+        case AF_LowPass:
+            BiquadFilter_process(lpfilter, dst, src, numsamples);
+            BiquadFilter_passthru(hpfilter, numsamples);
+            return dst;
+        case AF_HighPass:
+            BiquadFilter_passthru(lpfilter, numsamples);
+            BiquadFilter_process(hpfilter, dst, src, numsamples);
+            return dst;
+
+        case AF_BandPass:
+            for(i = 0;i < numsamples;)
+            {
+                ALfloat temp[256];
+                ALsizei todo = mini(256, numsamples-i);
+
+                BiquadFilter_process(lpfilter, temp, src+i, todo);
+                BiquadFilter_process(hpfilter, dst+i, temp, todo);
+                i += todo;
+            }
+            return dst;
+    }
+    return src;
+}
+
+
+/* This function uses these device temp buffers. */
+#define SOURCE_DATA_BUF 0
+#define RESAMPLED_BUF 1
+#define FILTERED_BUF 2
+#define NFC_DATA_BUF 3
+ALboolean MixSource(ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo)
+{
+    ALCdevice *Device = Context->Device;
+    ALbufferlistitem *BufferListItem;
+    ALbufferlistitem *BufferLoopItem;
+    ALsizei NumChannels, SampleSize;
+    ALbitfieldSOFT enabledevt;
+    ALsizei buffers_done = 0;
+    ResamplerFunc Resample;
+    ALsizei DataPosInt;
+    ALsizei DataPosFrac;
+    ALint64 DataSize64;
+    ALint increment;
+    ALsizei Counter;
+    ALsizei OutPos;
+    ALsizei IrSize;
+    bool isplaying;
+    bool firstpass;
+    bool isstatic;
+    ALsizei chan;
+    ALsizei send;
+
+    /* Get source info */
+    isplaying      = true; /* Will only be called while playing. */
+    isstatic       = !!(voice->Flags&VOICE_IS_STATIC);
+    DataPosInt     = ATOMIC_LOAD(&voice->position, almemory_order_acquire);
+    DataPosFrac    = ATOMIC_LOAD(&voice->position_fraction, almemory_order_relaxed);
+    BufferListItem = ATOMIC_LOAD(&voice->current_buffer, almemory_order_relaxed);
+    BufferLoopItem = ATOMIC_LOAD(&voice->loop_buffer, almemory_order_relaxed);
+    NumChannels    = voice->NumChannels;
+    SampleSize     = voice->SampleSize;
+    increment      = voice->Step;
+
+    IrSize = (Device->HrtfHandle ? Device->HrtfHandle->irSize : 0);
+
+    Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
+                Resample_copy_C : voice->Resampler);
+
+    Counter = (voice->Flags&VOICE_IS_FADING) ? SamplesToDo : 0;
+    firstpass = true;
+    OutPos = 0;
+
+    do {
+        ALsizei SrcBufferSize, DstBufferSize;
+
+        /* Figure out how many buffer samples will be needed */
+        DataSize64  = SamplesToDo-OutPos;
+        DataSize64 *= increment;
+        DataSize64 += DataPosFrac+FRACTIONMASK;
+        DataSize64 >>= FRACTIONBITS;
+        DataSize64 += MAX_RESAMPLE_PADDING*2;
+        SrcBufferSize = (ALsizei)mini64(DataSize64, BUFFERSIZE);
+
+        /* Figure out how many samples we can actually mix from this. */
+        DataSize64  = SrcBufferSize;
+        DataSize64 -= MAX_RESAMPLE_PADDING*2;
+        DataSize64 <<= FRACTIONBITS;
+        DataSize64 -= DataPosFrac;
+        DstBufferSize = (ALsizei)mini64((DataSize64+(increment-1)) / increment,
+                                        SamplesToDo - OutPos);
+
+        /* Some mixers like having a multiple of 4, so try to give that unless
+         * this is the last update. */
+        if(DstBufferSize < SamplesToDo-OutPos)
+            DstBufferSize &= ~3;
+
+        /* It's impossible to have a buffer list item with no entries. */
+        assert(BufferListItem->num_buffers > 0);
+
+        for(chan = 0;chan < NumChannels;chan++)
+        {
+            const ALfloat *ResampledData;
+            ALfloat *SrcData = Device->TempBuffer[SOURCE_DATA_BUF];
+            ALsizei FilledAmt;
+
+            /* Load the previous samples into the source data first, and clear the rest. */
+            memcpy(SrcData, voice->PrevSamples[chan], MAX_RESAMPLE_PADDING*sizeof(ALfloat));
+            memset(SrcData+MAX_RESAMPLE_PADDING, 0, (BUFFERSIZE-MAX_RESAMPLE_PADDING)*
+                                                    sizeof(ALfloat));
+            FilledAmt = MAX_RESAMPLE_PADDING;
+
+            if(isstatic)
+            {
+                /* TODO: For static sources, loop points are taken from the
+                 * first buffer (should be adjusted by any buffer offset, to
+                 * possibly be added later).
+                 */
+                const ALbuffer *Buffer0 = BufferListItem->buffers[0];
+                const ALsizei LoopStart = Buffer0->LoopStart;
+                const ALsizei LoopEnd   = Buffer0->LoopEnd;
+                const ALsizei LoopSize  = LoopEnd - LoopStart;
+
+                /* If current pos is beyond the loop range, do not loop */
+                if(!BufferLoopItem || DataPosInt >= LoopEnd)
+                {
+                    ALsizei SizeToDo = SrcBufferSize - FilledAmt;
+                    ALsizei CompLen = 0;
+                    ALsizei i;
+
+                    BufferLoopItem = NULL;
+
+                    for(i = 0;i < BufferListItem->num_buffers;i++)
+                    {
+                        const ALbuffer *buffer = BufferListItem->buffers[i];
+                        const ALubyte *Data = buffer->data;
+                        ALsizei DataSize;
+
+                        if(DataPosInt >= buffer->SampleLen)
+                            continue;
+
+                        /* Load what's left to play from the buffer */
+                        DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt);
+                        CompLen = maxi(CompLen, DataSize);
+
+                        LoadSamples(&SrcData[FilledAmt],
+                            &Data[(DataPosInt*NumChannels + chan)*SampleSize],
+                            NumChannels, buffer->FmtType, DataSize
+                        );
+                    }
+                    FilledAmt += CompLen;
+                }
+                else
+                {
+                    ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopEnd - DataPosInt);
+                    ALsizei CompLen = 0;
+                    ALsizei i;
+
+                    for(i = 0;i < BufferListItem->num_buffers;i++)
+                    {
+                        const ALbuffer *buffer = BufferListItem->buffers[i];
+                        const ALubyte *Data = buffer->data;
+                        ALsizei DataSize;
+
+                        if(DataPosInt >= buffer->SampleLen)
+                            continue;
+
+                        /* Load what's left of this loop iteration */
+                        DataSize = mini(SizeToDo, buffer->SampleLen - DataPosInt);
+                        CompLen = maxi(CompLen, DataSize);
+
+                        LoadSamples(&SrcData[FilledAmt],
+                            &Data[(DataPosInt*NumChannels + chan)*SampleSize],
+                            NumChannels, buffer->FmtType, DataSize
+                        );
+                    }
+                    FilledAmt += CompLen;
+
+                    while(SrcBufferSize > FilledAmt)
+                    {
+                        const ALsizei SizeToDo = mini(SrcBufferSize - FilledAmt, LoopSize);
+
+                        CompLen = 0;
+                        for(i = 0;i < BufferListItem->num_buffers;i++)
+                        {
+                            const ALbuffer *buffer = BufferListItem->buffers[i];
+                            const ALubyte *Data = buffer->data;
+                            ALsizei DataSize;
+
+                            if(LoopStart >= buffer->SampleLen)
+                                continue;
+
+                            DataSize = mini(SizeToDo, buffer->SampleLen - LoopStart);
+                            CompLen = maxi(CompLen, DataSize);
+
+                            LoadSamples(&SrcData[FilledAmt],
+                                &Data[(LoopStart*NumChannels + chan)*SampleSize],
+                                NumChannels, buffer->FmtType, DataSize
+                            );
+                        }
+                        FilledAmt += CompLen;
+                    }
+                }
+            }
+            else
+            {
+                /* Crawl the buffer queue to fill in the temp buffer */
+                ALbufferlistitem *tmpiter = BufferListItem;
+                ALsizei pos = DataPosInt;
+
+                while(tmpiter && SrcBufferSize > FilledAmt)
+                {
+                    ALsizei SizeToDo = SrcBufferSize - FilledAmt;
+                    ALsizei i;
+
+                    for(i = 0;i < tmpiter->num_buffers;i++)
+                    {
+                        const ALbuffer *ALBuffer = tmpiter->buffers[i];
+                        ALsizei DataSize = ALBuffer ? ALBuffer->SampleLen : 0;
+
+                        if(DataSize > pos)
+                        {
+                            const ALubyte *Data = ALBuffer->data;
+                            Data += (pos*NumChannels + chan)*SampleSize;
+
+                            DataSize = minu(SizeToDo, DataSize - pos);
+                            LoadSamples(&SrcData[FilledAmt], Data, NumChannels,
+                                        ALBuffer->FmtType, DataSize);
+                        }
+                    }
+                    if(pos > tmpiter->max_samples)
+                        pos -= tmpiter->max_samples;
+                    else
+                    {
+                        FilledAmt += tmpiter->max_samples - pos;
+                        pos = 0;
+                    }
+                    if(SrcBufferSize > FilledAmt)
+                    {
+                        tmpiter = ATOMIC_LOAD(&tmpiter->next, almemory_order_acquire);
+                        if(!tmpiter) tmpiter = BufferLoopItem;
+                    }
+                }
+            }
+
+            /* Store the last source samples used for next time. */
+            memcpy(voice->PrevSamples[chan],
+                &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
+                MAX_RESAMPLE_PADDING*sizeof(ALfloat)
+            );
+
+            /* Now resample, then filter and mix to the appropriate outputs. */
+            ResampledData = Resample(&voice->ResampleState,
+                &SrcData[MAX_RESAMPLE_PADDING], DataPosFrac, increment,
+                Device->TempBuffer[RESAMPLED_BUF], DstBufferSize
+            );
+            {
+                DirectParams *parms = &voice->Direct.Params[chan];
+                const ALfloat *samples;
+
+                samples = DoFilters(
+                    &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF],
+                    ResampledData, DstBufferSize, voice->Direct.FilterType
+                );
+                if(!(voice->Flags&VOICE_HAS_HRTF))
+                {
+                    if(!Counter)
+                        memcpy(parms->Gains.Current, parms->Gains.Target,
+                               sizeof(parms->Gains.Current));
+                    if(!(voice->Flags&VOICE_HAS_NFC))
+                        MixSamples(samples, voice->Direct.Channels, voice->Direct.Buffer,
+                            parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
+                            DstBufferSize
+                        );
+                    else
+                    {
+                        ALfloat *nfcsamples = Device->TempBuffer[NFC_DATA_BUF];
+                        ALsizei chanoffset = 0;
+
+                        MixSamples(samples,
+                            voice->Direct.ChannelsPerOrder[0], voice->Direct.Buffer,
+                            parms->Gains.Current, parms->Gains.Target, Counter, OutPos,
+                            DstBufferSize
+                        );
+                        chanoffset += voice->Direct.ChannelsPerOrder[0];
+#define APPLY_NFC_MIX(order)                                                  \
+    if(voice->Direct.ChannelsPerOrder[order] > 0)                             \
+    {                                                                         \
+        NfcFilterProcess##order(&parms->NFCtrlFilter, nfcsamples, samples,    \
+                               DstBufferSize);                                \
+        MixSamples(nfcsamples, voice->Direct.ChannelsPerOrder[order],         \
+            voice->Direct.Buffer+chanoffset, parms->Gains.Current+chanoffset, \
+            parms->Gains.Target+chanoffset, Counter, OutPos, DstBufferSize    \
+        );                                                                    \
+        chanoffset += voice->Direct.ChannelsPerOrder[order];                  \
+    }
+                        APPLY_NFC_MIX(1)
+                        APPLY_NFC_MIX(2)
+                        APPLY_NFC_MIX(3)
+#undef APPLY_NFC_MIX
+                    }
+                }
+                else
+                {
+                    MixHrtfParams hrtfparams;
+                    ALsizei fademix = 0;
+                    int lidx, ridx;
+
+                    lidx = GetChannelIdxByName(&Device->RealOut, FrontLeft);
+                    ridx = GetChannelIdxByName(&Device->RealOut, FrontRight);
+                    assert(lidx != -1 && ridx != -1);
+
+                    if(!Counter)
+                    {
+                        /* No fading, just overwrite the old HRTF params. */
+                        parms->Hrtf.Old = parms->Hrtf.Target;
+                    }
+                    else if(!(parms->Hrtf.Old.Gain > GAIN_SILENCE_THRESHOLD))
+                    {
+                        /* The old HRTF params are silent, so overwrite the old
+                         * coefficients with the new, and reset the old gain to
+                         * 0. The future mix will then fade from silence.
+                         */
+                        parms->Hrtf.Old = parms->Hrtf.Target;
+                        parms->Hrtf.Old.Gain = 0.0f;
+                    }
+                    else if(firstpass)
+                    {
+                        ALfloat gain;
+
+                        /* Fade between the coefficients over 128 samples. */
+                        fademix = mini(DstBufferSize, 128);
+
+                        /* The new coefficients need to fade in completely
+                         * since they're replacing the old ones. To keep the
+                         * gain fading consistent, interpolate between the old
+                         * and new target gains given how much of the fade time
+                         * this mix handles.
+                         */
+                        gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain,
+                                    minf(1.0f, (ALfloat)fademix/Counter));
+                        hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs;
+                        hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0];
+                        hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1];
+                        hrtfparams.Gain = 0.0f;
+                        hrtfparams.GainStep = gain / (ALfloat)fademix;
+
+                        MixHrtfBlendSamples(
+                            voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
+                            samples, voice->Offset, OutPos, IrSize, &parms->Hrtf.Old,
+                            &hrtfparams, &parms->Hrtf.State, fademix
+                        );
+                        /* Update the old parameters with the result. */
+                        parms->Hrtf.Old = parms->Hrtf.Target;
+                        if(fademix < Counter)
+                            parms->Hrtf.Old.Gain = hrtfparams.Gain;
+                    }
+
+                    if(fademix < DstBufferSize)
+                    {
+                        ALsizei todo = DstBufferSize - fademix;
+                        ALfloat gain = parms->Hrtf.Target.Gain;
+
+                        /* Interpolate the target gain if the gain fading lasts
+                         * longer than this mix.
+                         */
+                        if(Counter > DstBufferSize)
+                            gain = lerp(parms->Hrtf.Old.Gain, gain,
+                                        (ALfloat)todo/(Counter-fademix));
+
+                        hrtfparams.Coeffs = parms->Hrtf.Target.Coeffs;
+                        hrtfparams.Delay[0] = parms->Hrtf.Target.Delay[0];
+                        hrtfparams.Delay[1] = parms->Hrtf.Target.Delay[1];
+                        hrtfparams.Gain = parms->Hrtf.Old.Gain;
+                        hrtfparams.GainStep = (gain - parms->Hrtf.Old.Gain) / (ALfloat)todo;
+                        MixHrtfSamples(
+                            voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx],
+                            samples+fademix, voice->Offset+fademix, OutPos+fademix, IrSize,
+                            &hrtfparams, &parms->Hrtf.State, todo
+                        );
+                        /* Store the interpolated gain or the final target gain
+                         * depending if the fade is done.
+                         */
+                        if(DstBufferSize < Counter)
+                            parms->Hrtf.Old.Gain = gain;
+                        else
+                            parms->Hrtf.Old.Gain = parms->Hrtf.Target.Gain;
+                    }
+                }
+            }
+
+            for(send = 0;send < Device->NumAuxSends;send++)
+            {
+                SendParams *parms = &voice->Send[send].Params[chan];
+                const ALfloat *samples;
+
+                if(!voice->Send[send].Buffer)
+                    continue;
+
+                samples = DoFilters(
+                    &parms->LowPass, &parms->HighPass, Device->TempBuffer[FILTERED_BUF],
+                    ResampledData, DstBufferSize, voice->Send[send].FilterType
+                );
+
+                if(!Counter)
+                    memcpy(parms->Gains.Current, parms->Gains.Target,
+                           sizeof(parms->Gains.Current));
+                MixSamples(samples, voice->Send[send].Channels, voice->Send[send].Buffer,
+                    parms->Gains.Current, parms->Gains.Target, Counter, OutPos, DstBufferSize
+                );
+            }
+        }
+        /* Update positions */
+        DataPosFrac += increment*DstBufferSize;
+        DataPosInt  += DataPosFrac>>FRACTIONBITS;
+        DataPosFrac &= FRACTIONMASK;
+
+        OutPos += DstBufferSize;
+        voice->Offset += DstBufferSize;
+        Counter = maxi(DstBufferSize, Counter) - DstBufferSize;
+        firstpass = false;
+
+        if(isstatic)
+        {
+            if(BufferLoopItem)
+            {
+                /* Handle looping static source */
+                const ALbuffer *Buffer = BufferListItem->buffers[0];
+                ALsizei LoopStart = Buffer->LoopStart;
+                ALsizei LoopEnd = Buffer->LoopEnd;
+                if(DataPosInt >= LoopEnd)
+                {
+                    assert(LoopEnd > LoopStart);
+                    DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
+                }
+            }
+            else
+            {
+                /* Handle non-looping static source */
+                if(DataPosInt >= BufferListItem->max_samples)
+                {
+                    isplaying = false;
+                    BufferListItem = NULL;
+                    DataPosInt = 0;
+                    DataPosFrac = 0;
+                    break;
+                }
+            }
+        }
+        else while(1)
+        {
+            /* Handle streaming source */
+            if(BufferListItem->max_samples > DataPosInt)
+                break;
+
+            buffers_done += BufferListItem->num_buffers;
+            BufferListItem = ATOMIC_LOAD(&BufferListItem->next, almemory_order_acquire);
+            if(!BufferListItem && !(BufferListItem=BufferLoopItem))
+            {
+                isplaying = false;
+                DataPosInt = 0;
+                DataPosFrac = 0;
+                break;
+            }
+
+            DataPosInt -= BufferListItem->max_samples;
+        }
+    } while(isplaying && OutPos < SamplesToDo);
+
+    voice->Flags |= VOICE_IS_FADING;
+
+    /* Update source info */
+    ATOMIC_STORE(&voice->position,          DataPosInt, almemory_order_relaxed);
+    ATOMIC_STORE(&voice->position_fraction, DataPosFrac, almemory_order_relaxed);
+    ATOMIC_STORE(&voice->current_buffer,    BufferListItem, almemory_order_release);
+
+    /* Send any events now, after the position/buffer info was updated. */
+    enabledevt = ATOMIC_LOAD(&Context->EnabledEvts, almemory_order_acquire);
+    if(buffers_done > 0 && (enabledevt&EventType_BufferCompleted))
+        SendAsyncEvent(Context, EventType_BufferCompleted,
+            AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, SourceID, buffers_done, "Buffer completed"
+        );
+
+    return isplaying;
+}

Файловите разлики са ограничени, защото са твърде много
+ 432 - 275
Engine/lib/openal-soft/Alc/panning.c


+ 105 - 0
Engine/lib/openal-soft/Alc/polymorphism.h

@@ -0,0 +1,105 @@
+#ifndef POLYMORPHISM_H
+#define POLYMORPHISM_H
+
+/* Macros to declare inheriting types, and to (down-)cast and up-cast. */
+#define DERIVE_FROM_TYPE(t)          t t##_parent
+#define STATIC_CAST(to, obj)         (&(obj)->to##_parent)
+#ifdef __GNUC__
+#define STATIC_UPCAST(to, from, obj) __extension__({                          \
+    static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))),       \
+                  "Invalid upcast object from type");                         \
+    (to*)((char*)(obj) - offsetof(to, from##_parent));                        \
+})
+#else
+#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent)))
+#endif
+
+/* Defines method forwards, which call the given parent's (T2's) implementation. */
+#define DECLARE_FORWARD(T1, T2, rettype, func)                                \
+rettype T1##_##func(T1 *obj)                                                  \
+{ return T2##_##func(STATIC_CAST(T2, obj)); }
+
+#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1)                     \
+rettype T1##_##func(T1 *obj, argtype1 a)                                      \
+{ return T2##_##func(STATIC_CAST(T2, obj), a); }
+
+#define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2)           \
+rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b)                          \
+{ return T2##_##func(STATIC_CAST(T2, obj), a, b); }
+
+#define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
+rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c)              \
+{ return T2##_##func(STATIC_CAST(T2, obj), a, b, c); }
+
+/* Defines method thunks, functions that call to the child's method. */
+#define DECLARE_THUNK(T1, T2, rettype, func)                                  \
+static rettype T1##_##T2##_##func(T2 *obj)                                    \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); }
+
+#define DECLARE_THUNK1(T1, T2, rettype, func, argtype1)                       \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a)                        \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a); }
+
+#define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2)             \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b)            \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b); }
+
+#define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3)   \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
+
+#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); }
+
+/* Defines the default functions used to (de)allocate a polymorphic object. */
+#define DECLARE_DEFAULT_ALLOCATORS(T)                                         \
+static void* T##_New(size_t size) { return al_malloc(16, size); }             \
+static void T##_Delete(void *ptr) { al_free(ptr); }
+
+
+/* Helper to extract an argument list for virtual method calls. */
+#define EXTRACT_VCALL_ARGS(...)  __VA_ARGS__))
+
+/* Call a "virtual" method on an object, with arguments. */
+#define V(obj, func)  ((obj)->vtbl->func((obj), EXTRACT_VCALL_ARGS
+/* Call a "virtual" method on an object, with no arguments. */
+#define V0(obj, func) ((obj)->vtbl->func((obj) EXTRACT_VCALL_ARGS
+
+
+/* Helper to extract an argument list for NEW_OBJ calls. */
+#define EXTRACT_NEW_ARGS(...)  __VA_ARGS__);                                  \
+    }                                                                         \
+} while(0)
+
+/* Allocate and construct an object, with arguments. */
+#define NEW_OBJ(_res, T) do {                                                 \
+    _res = T##_New(sizeof(T));                                                \
+    if(_res)                                                                  \
+    {                                                                         \
+        memset(_res, 0, sizeof(T));                                           \
+        T##_Construct(_res, EXTRACT_NEW_ARGS
+/* Allocate and construct an object, with no arguments. */
+#define NEW_OBJ0(_res, T) do {                                                \
+    _res = T##_New(sizeof(T));                                                \
+    if(_res)                                                                  \
+    {                                                                         \
+        memset(_res, 0, sizeof(T));                                           \
+        T##_Construct(_res EXTRACT_NEW_ARGS
+
+/* Destructs and deallocate an object. */
+#define DELETE_OBJ(obj) do {                                                  \
+    if((obj) != NULL)                                                         \
+    {                                                                         \
+        V0((obj),Destruct)();                                                 \
+        V0((obj),Delete)();                                                   \
+    }                                                                         \
+} while(0)
+
+
+/* Helper to get a type's vtable thunk for a child type. */
+#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable))
+/* Helper to set an object's vtable thunk for a child type. Used when constructing an object. */
+#define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2))
+
+#endif /* POLYMORPHISM_H */

+ 295 - 0
Engine/lib/openal-soft/Alc/ringbuffer.c

@@ -0,0 +1,295 @@
+/**
+ * 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 <string.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "ringbuffer.h"
+#include "align.h"
+#include "atomic.h"
+#include "threads.h"
+#include "almalloc.h"
+#include "compat.h"
+
+
+/* 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 {
+    ATOMIC(size_t) write_ptr;
+    ATOMIC(size_t) read_ptr;
+    size_t size;
+    size_t size_mask;
+    size_t elem_size;
+
+    alignas(16) char buf[];
+};
+
+ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes)
+{
+    ll_ringbuffer_t *rb;
+    size_t power_of_two = 0;
+
+    if(sz > 0)
+    {
+        power_of_two = sz;
+        power_of_two |= power_of_two>>1;
+        power_of_two |= power_of_two>>2;
+        power_of_two |= power_of_two>>4;
+        power_of_two |= power_of_two>>8;
+        power_of_two |= power_of_two>>16;
+#if SIZE_MAX > UINT_MAX
+        power_of_two |= power_of_two>>32;
+#endif
+    }
+    power_of_two++;
+    if(power_of_two < sz) return NULL;
+
+    rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz);
+    if(!rb) return NULL;
+
+    ATOMIC_INIT(&rb->write_ptr, 0);
+    ATOMIC_INIT(&rb->read_ptr, 0);
+    rb->size = limit_writes ? sz : power_of_two;
+    rb->size_mask = power_of_two - 1;
+    rb->elem_size = elem_sz;
+    return rb;
+}
+
+void ll_ringbuffer_free(ll_ringbuffer_t *rb)
+{
+    al_free(rb);
+}
+
+void ll_ringbuffer_reset(ll_ringbuffer_t *rb)
+{
+    ATOMIC_STORE(&rb->write_ptr, 0, almemory_order_release);
+    ATOMIC_STORE(&rb->read_ptr, 0, almemory_order_release);
+    memset(rb->buf, 0, (rb->size_mask+1)*rb->elem_size);
+}
+
+
+size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb)
+{
+    size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire);
+    size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire);
+    return (w-r) & rb->size_mask;
+}
+
+size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb)
+{
+    size_t w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire);
+    size_t r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire);
+    w = (r-w-1) & rb->size_mask;
+    return (w > rb->size) ? rb->size : w;
+}
+
+
+size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt)
+{
+    size_t read_ptr;
+    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;
+    read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask;
+
+    cnt2 = read_ptr + to_read;
+    if(cnt2 > rb->size_mask+1)
+    {
+        n1 = rb->size_mask+1 - read_ptr;
+        n2 = cnt2 & rb->size_mask;
+    }
+    else
+    {
+        n1 = to_read;
+        n2 = 0;
+    }
+
+    memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size);
+    read_ptr += n1;
+    if(n2)
+    {
+        memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size],
+               n2*rb->elem_size);
+        read_ptr += n2;
+    }
+    ATOMIC_STORE(&rb->read_ptr, read_ptr, almemory_order_release);
+    return to_read;
+}
+
+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 read_ptr;
+
+    free_cnt = ll_ringbuffer_read_space(rb);
+    if(free_cnt == 0) return 0;
+
+    to_read = (cnt > free_cnt) ? free_cnt : cnt;
+    read_ptr = ATOMIC_LOAD(&rb->read_ptr, almemory_order_relaxed) & rb->size_mask;
+
+    cnt2 = read_ptr + to_read;
+    if(cnt2 > rb->size_mask+1)
+    {
+        n1 = rb->size_mask+1 - read_ptr;
+        n2 = cnt2 & rb->size_mask;
+    }
+    else
+    {
+        n1 = to_read;
+        n2 = 0;
+    }
+
+    memcpy(dest, &rb->buf[read_ptr*rb->elem_size], n1*rb->elem_size);
+    if(n2)
+    {
+        read_ptr += n1;
+        memcpy(dest + n1*rb->elem_size, &rb->buf[(read_ptr&rb->size_mask)*rb->elem_size],
+               n2*rb->elem_size);
+    }
+    return to_read;
+}
+
+size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt)
+{
+    size_t write_ptr;
+    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;
+    write_ptr = ATOMIC_LOAD(&rb->write_ptr, almemory_order_relaxed) & rb->size_mask;
+
+    cnt2 = write_ptr + to_write;
+    if(cnt2 > rb->size_mask+1)
+    {
+        n1 = rb->size_mask+1 - write_ptr;
+        n2 = cnt2 & rb->size_mask;
+    }
+    else
+    {
+        n1 = to_write;
+        n2 = 0;
+    }
+
+    memcpy(&rb->buf[write_ptr*rb->elem_size], src, n1*rb->elem_size);
+    write_ptr += n1;
+    if(n2)
+    {
+        memcpy(&rb->buf[(write_ptr&rb->size_mask)*rb->elem_size], src + n1*rb->elem_size,
+               n2*rb->elem_size);
+        write_ptr += n2;
+    }
+    ATOMIC_STORE(&rb->write_ptr, write_ptr, almemory_order_release);
+    return to_write;
+}
+
+
+void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt)
+{
+    ATOMIC_ADD(&rb->read_ptr, cnt, almemory_order_acq_rel);
+}
+
+void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt)
+{
+    ATOMIC_ADD(&rb->write_ptr, cnt, almemory_order_acq_rel);
+}
+
+
+void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2])
+{
+    size_t free_cnt;
+    size_t cnt2;
+    size_t w, r;
+
+    w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire);
+    r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire);
+    w &= rb->size_mask;
+    r &= rb->size_mask;
+    free_cnt = (w-r) & rb->size_mask;
+
+    cnt2 = r + free_cnt;
+    if(cnt2 > rb->size_mask+1)
+    {
+        /* Two part vector: the rest of the buffer after the current write ptr,
+         * plus some from the start of the buffer. */
+        vec[0].buf = (char*)&rb->buf[r*rb->elem_size];
+        vec[0].len = rb->size_mask+1 - r;
+        vec[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;
+    }
+}
+
+void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2])
+{
+    size_t free_cnt;
+    size_t cnt2;
+    size_t w, r;
+
+    w = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->write_ptr, almemory_order_acquire);
+    r = ATOMIC_LOAD(&CONST_CAST(ll_ringbuffer_t*,rb)->read_ptr, almemory_order_acquire);
+    w &= rb->size_mask;
+    r &= rb->size_mask;
+    free_cnt = (r-w-1) & rb->size_mask;
+    if(free_cnt > rb->size) free_cnt = rb->size;
+
+    cnt2 = w + free_cnt;
+    if(cnt2 > rb->size_mask+1)
+    {
+        /* Two part vector: the rest of the buffer after the current write ptr,
+         * plus some from the start of the buffer. */
+        vec[0].buf = (char*)&rb->buf[w*rb->elem_size];
+        vec[0].len = rb->size_mask+1 - w;
+        vec[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;
+    }
+}

+ 77 - 0
Engine/lib/openal-soft/Alc/ringbuffer.h

@@ -0,0 +1,77 @@
+#ifndef RINGBUFFER_H
+#define RINGBUFFER_H
+
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ll_ringbuffer ll_ringbuffer_t;
+typedef struct ll_ringbuffer_data {
+    char *buf;
+    size_t len;
+} ll_ringbuffer_data_t;
+
+
+/**
+ * Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes.
+ * The number of elements is rounded up to the next power of two (even if it is
+ * already a power of two, to ensure the requested amount can be written).
+ */
+ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz, int limit_writes);
+/** Free all data associated with the ringbuffer `rb'. */
+void ll_ringbuffer_free(ll_ringbuffer_t *rb);
+/** Reset the read and write pointers to zero. This is not thread safe. */
+void ll_ringbuffer_reset(ll_ringbuffer_t *rb);
+
+/**
+ * The non-copying data reader. `vec' is an array of two places. Set the values
+ * at `vec' to hold the current readable data at `rb'. If the readable data is
+ * in one segment the second segment has zero length.
+ */
+void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]);
+/**
+ * The non-copying data writer. `vec' is an array of two places. Set the values
+ * at `vec' to hold the current writeable data at `rb'. If the writeable data
+ * is in one segment the second segment has zero length.
+ */
+void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t vec[2]);
+
+/**
+ * Return the number of elements available for reading. This is the number of
+ * elements in front of the read pointer and behind the write pointer.
+ */
+size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb);
+/**
+ * The copying data reader. Copy at most `cnt' elements from `rb' to `dest'.
+ * Returns the actual number of elements copied.
+ */
+size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt);
+/**
+ * The copying data reader w/o read pointer advance. Copy at most `cnt'
+ * elements from `rb' to `dest'. Returns the actual number of elements copied.
+ */
+size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt);
+/** Advance the read pointer `cnt' places. */
+void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt);
+
+/**
+ * Return the number of elements available for writing. This is the number of
+ * elements in front of the write pointer and behind the read pointer.
+ */
+size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb);
+/**
+ * The copying data writer. Copy at most `cnt' elements to `rb' from `src'.
+ * Returns the actual number of elements copied.
+ */
+size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt);
+/** Advance the write pointer `cnt' places. */
+void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* RINGBUFFER_H */

+ 38 - 52
Engine/lib/openal-soft/Alc/uhjfilter.c

@@ -9,36 +9,29 @@
 #define MAX_UPDATE_SAMPLES  128
 #define MAX_UPDATE_SAMPLES  128
 
 
 
 
-static const ALfloat Filter1Coeff[4] = {
-    0.6923878f, 0.9360654322959f, 0.9882295226860f, 0.9987488452737f
+static const ALfloat Filter1CoeffSqr[4] = {
+    0.479400865589f, 0.876218493539f, 0.976597589508f, 0.997499255936f
 };
 };
-static const ALfloat Filter2Coeff[4] = {
-    0.4021921162426f, 0.8561710882420f, 0.9722909545651f, 0.9952884791278f
+static const ALfloat Filter2CoeffSqr[4] = {
+    0.161758498368f, 0.733028932341f, 0.945349700329f, 0.990599156685f
 };
 };
 
 
-static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALuint todo)
+static void allpass_process(AllPassState *state, ALfloat *restrict dst, const ALfloat *restrict src, const ALfloat aa, ALsizei todo)
 {
 {
-    ALuint i;
+    ALfloat z1 = state->z[0];
+    ALfloat z2 = state->z[1];
+    ALsizei i;
 
 
-    if(todo > 1)
+    for(i = 0;i < todo;i++)
     {
     {
-        dst[0] = aa*(src[0] + state->y[1]) - state->x[1];
-        dst[1] = aa*(src[1] + state->y[0]) - state->x[0];
-        for(i = 2;i < todo;i++)
-            dst[i] = aa*(src[i] + dst[i-2]) - src[i-2];
-        state->x[1] = src[i-2];
-        state->x[0] = src[i-1];
-        state->y[1] = dst[i-2];
-        state->y[0] = dst[i-1];
-    }
-    else if(todo == 1)
-    {
-        dst[0] = aa*(src[0] + state->y[1]) - state->x[1];
-        state->x[1] = state->x[0];
-        state->x[0] = src[0];
-        state->y[1] = state->y[0];
-        state->y[0] = dst[0];
+        ALfloat input = src[i];
+        ALfloat output = input*aa + z1;
+        z1 = z2; z2 = output*aa - input;
+        dst[i] = output;
     }
     }
+
+    state->z[0] = z1;
+    state->z[1] = z2;
 }
 }
 
 
 
 
@@ -62,47 +55,43 @@ static void allpass_process(AllPassState *state, ALfloat *restrict dst, const AL
  * know which is the intended result.
  * know which is the intended result.
  */
  */
 
 
-void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo)
+void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo)
 {
 {
     ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES];
     ALfloat D[MAX_UPDATE_SAMPLES], S[MAX_UPDATE_SAMPLES];
     ALfloat temp[2][MAX_UPDATE_SAMPLES];
     ALfloat temp[2][MAX_UPDATE_SAMPLES];
-    ALuint base, i;
+    ALsizei base, i;
+
+    ASSUME(SamplesToDo > 0);
 
 
     for(base = 0;base < SamplesToDo;)
     for(base = 0;base < SamplesToDo;)
     {
     {
-        ALuint todo = minu(SamplesToDo - base, MAX_UPDATE_SAMPLES);
+        ALsizei todo = mini(SamplesToDo - base, MAX_UPDATE_SAMPLES);
+        ASSUME(todo > 0);
 
 
         /* D = 0.6554516*Y */
         /* D = 0.6554516*Y */
         for(i = 0;i < todo;i++)
         for(i = 0;i < todo;i++)
             temp[0][i] = 0.6554516f*InSamples[2][base+i];
             temp[0][i] = 0.6554516f*InSamples[2][base+i];
-        allpass_process(&enc->Filter1_Y[0], temp[1], temp[0],
-                        Filter1Coeff[0]*Filter1Coeff[0], todo);
-        allpass_process(&enc->Filter1_Y[1], temp[0], temp[1],
-                        Filter1Coeff[1]*Filter1Coeff[1], todo);
-        allpass_process(&enc->Filter1_Y[2], temp[1], temp[0],
-                        Filter1Coeff[2]*Filter1Coeff[2], todo);
+        allpass_process(&enc->Filter1_Y[0], temp[1], temp[0], Filter1CoeffSqr[0], todo);
+        allpass_process(&enc->Filter1_Y[1], temp[0], temp[1], Filter1CoeffSqr[1], todo);
+        allpass_process(&enc->Filter1_Y[2], temp[1], temp[0], Filter1CoeffSqr[2], todo);
+        allpass_process(&enc->Filter1_Y[3], temp[0], temp[1], Filter1CoeffSqr[3], todo);
         /* NOTE: Filter1 requires a 1 sample delay for the final output, so
         /* NOTE: Filter1 requires a 1 sample delay for the final output, so
          * take the last processed sample from the previous run as the first
          * take the last processed sample from the previous run as the first
          * output sample.
          * output sample.
          */
          */
-        D[0] = enc->Filter1_Y[3].y[0];
-        allpass_process(&enc->Filter1_Y[3], temp[0], temp[1],
-                        Filter1Coeff[3]*Filter1Coeff[3], todo);
+        D[0] = enc->LastY;
         for(i = 1;i < todo;i++)
         for(i = 1;i < todo;i++)
             D[i] = temp[0][i-1];
             D[i] = temp[0][i-1];
+        enc->LastY = temp[0][i-1];
 
 
         /* D += j(-0.3420201*W + 0.5098604*X) */
         /* D += j(-0.3420201*W + 0.5098604*X) */
         for(i = 0;i < todo;i++)
         for(i = 0;i < todo;i++)
             temp[0][i] = -0.3420201f*InSamples[0][base+i] +
             temp[0][i] = -0.3420201f*InSamples[0][base+i] +
                           0.5098604f*InSamples[1][base+i];
                           0.5098604f*InSamples[1][base+i];
-        allpass_process(&enc->Filter2_WX[0], temp[1], temp[0],
-                        Filter2Coeff[0]*Filter2Coeff[0], todo);
-        allpass_process(&enc->Filter2_WX[1], temp[0], temp[1],
-                        Filter2Coeff[1]*Filter2Coeff[1], todo);
-        allpass_process(&enc->Filter2_WX[2], temp[1], temp[0],
-                        Filter2Coeff[2]*Filter2Coeff[2], todo);
-        allpass_process(&enc->Filter2_WX[3], temp[0], temp[1],
-                        Filter2Coeff[3]*Filter2Coeff[3], todo);
+        allpass_process(&enc->Filter2_WX[0], temp[1], temp[0], Filter2CoeffSqr[0], todo);
+        allpass_process(&enc->Filter2_WX[1], temp[0], temp[1], Filter2CoeffSqr[1], todo);
+        allpass_process(&enc->Filter2_WX[2], temp[1], temp[0], Filter2CoeffSqr[2], todo);
+        allpass_process(&enc->Filter2_WX[3], temp[0], temp[1], Filter2CoeffSqr[3], todo);
         for(i = 0;i < todo;i++)
         for(i = 0;i < todo;i++)
             D[i] += temp[0][i];
             D[i] += temp[0][i];
 
 
@@ -110,17 +99,14 @@ void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict R
         for(i = 0;i < todo;i++)
         for(i = 0;i < todo;i++)
             temp[0][i] = 0.9396926f*InSamples[0][base+i] +
             temp[0][i] = 0.9396926f*InSamples[0][base+i] +
                          0.1855740f*InSamples[1][base+i];
                          0.1855740f*InSamples[1][base+i];
-        allpass_process(&enc->Filter1_WX[0], temp[1], temp[0],
-                        Filter1Coeff[0]*Filter1Coeff[0], todo);
-        allpass_process(&enc->Filter1_WX[1], temp[0], temp[1],
-                        Filter1Coeff[1]*Filter1Coeff[1], todo);
-        allpass_process(&enc->Filter1_WX[2], temp[1], temp[0],
-                        Filter1Coeff[2]*Filter1Coeff[2], todo);
-        S[0] = enc->Filter1_WX[3].y[0];
-        allpass_process(&enc->Filter1_WX[3], temp[0], temp[1],
-                        Filter1Coeff[3]*Filter1Coeff[3], todo);
+        allpass_process(&enc->Filter1_WX[0], temp[1], temp[0], Filter1CoeffSqr[0], todo);
+        allpass_process(&enc->Filter1_WX[1], temp[0], temp[1], Filter1CoeffSqr[1], todo);
+        allpass_process(&enc->Filter1_WX[2], temp[1], temp[0], Filter1CoeffSqr[2], todo);
+        allpass_process(&enc->Filter1_WX[3], temp[0], temp[1], Filter1CoeffSqr[3], todo);
+        S[0] = enc->LastWX;
         for(i = 1;i < todo;i++)
         for(i = 1;i < todo;i++)
             S[i] = temp[0][i-1];
             S[i] = temp[0][i-1];
+        enc->LastWX = temp[0][i-1];
 
 
         /* Left = (S + D)/2.0 */
         /* Left = (S + D)/2.0 */
         for(i = 0;i < todo;i++)
         for(i = 0;i < todo;i++)

+ 6 - 5
Engine/lib/openal-soft/Alc/uhjfilter.h

@@ -6,8 +6,7 @@
 #include "alMain.h"
 #include "alMain.h"
 
 
 typedef struct AllPassState {
 typedef struct AllPassState {
-    ALfloat x[2]; /* Last two input samples */
-    ALfloat y[2]; /* Last two output samples */
+    ALfloat z[2];
 } AllPassState;
 } AllPassState;
 
 
 /* Encoding 2-channel UHJ from B-Format is done as:
 /* Encoding 2-channel UHJ from B-Format is done as:
@@ -36,13 +35,15 @@ typedef struct AllPassState {
  */
  */
 
 
 typedef struct Uhj2Encoder {
 typedef struct Uhj2Encoder {
-    AllPassState Filter1_WX[4];
     AllPassState Filter1_Y[4];
     AllPassState Filter1_Y[4];
     AllPassState Filter2_WX[4];
     AllPassState Filter2_WX[4];
+    AllPassState Filter1_WX[4];
+    ALfloat LastY, LastWX;
 } Uhj2Encoder;
 } Uhj2Encoder;
 
 
 /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input
 /* Encodes a 2-channel UHJ (stereo-compatible) signal from a B-Format input
- * signal. */
-void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALuint SamplesToDo);
+ * signal. The input must use FuMa channel ordering and scaling.
+ */
+void EncodeUhj2(Uhj2Encoder *enc, ALfloat *restrict LeftOut, ALfloat *restrict RightOut, ALfloat (*restrict InSamples)[BUFFERSIZE], ALsizei SamplesToDo);
 
 
 #endif /* UHJFILTER_H */
 #endif /* UHJFILTER_H */

+ 4 - 20
Engine/lib/openal-soft/Alc/vector.h

@@ -37,13 +37,15 @@ typedef const _##N* const_##N;
                                                                               \
                                                                               \
     if(((_x) ? (_x)->Capacity : 0) < _cap)                                    \
     if(((_x) ? (_x)->Capacity : 0) < _cap)                                    \
     {                                                                         \
     {                                                                         \
+        ptrdiff_t data_offset = (_x) ? (char*)((_x)->Data) - (char*)(_x) :    \
+                                sizeof(*(_x));                                \
         size_t old_size = ((_x) ? (_x)->Size : 0);                            \
         size_t old_size = ((_x) ? (_x)->Size : 0);                            \
         void *temp;                                                           \
         void *temp;                                                           \
                                                                               \
                                                                               \
-        temp = al_calloc(16, sizeof(*(_x)) + sizeof((_x)->Data[0])*_cap);     \
+        temp = al_calloc(16, data_offset + sizeof((_x)->Data[0])*_cap);       \
         assert(temp != NULL);                                                 \
         assert(temp != NULL);                                                 \
         if((_x))                                                              \
         if((_x))                                                              \
-            memcpy(((ALubyte*)temp)+sizeof(*(_x)), (_x)->Data,                \
+            memcpy(((char*)temp)+data_offset, (_x)->Data,                     \
                    sizeof((_x)->Data[0])*old_size);                           \
                    sizeof((_x)->Data[0])*old_size);                           \
                                                                               \
                                                                               \
         al_free((_x));                                                        \
         al_free((_x));                                                        \
@@ -78,13 +80,6 @@ typedef const _##N* const_##N;
         _f(_iter);                                                            \
         _f(_iter);                                                            \
 } while(0)
 } while(0)
 
 
-#define VECTOR_FOR_EACH_PARAMS(_t, _x, _f, ...)  do {                         \
-    _t *_iter = VECTOR_BEGIN((_x));                                           \
-    _t *_end = VECTOR_END((_x));                                              \
-    for(;_iter != _end;++_iter)                                               \
-        _f(__VA_ARGS__, _iter);                                               \
-} while(0)
-
 #define VECTOR_FIND_IF(_i, _t, _x, _f)  do {                                  \
 #define VECTOR_FIND_IF(_i, _t, _x, _f)  do {                                  \
     _t *_iter = VECTOR_BEGIN((_x));                                           \
     _t *_iter = VECTOR_BEGIN((_x));                                           \
     _t *_end = VECTOR_END((_x));                                              \
     _t *_end = VECTOR_END((_x));                                              \
@@ -96,15 +91,4 @@ typedef const _##N* const_##N;
     (_i) = _iter;                                                             \
     (_i) = _iter;                                                             \
 } while(0)
 } while(0)
 
 
-#define VECTOR_FIND_IF_PARMS(_i, _t, _x, _f, ...)  do {                       \
-    _t *_iter = VECTOR_BEGIN((_x));                                           \
-    _t *_end = VECTOR_END((_x));                                              \
-    for(;_iter != _end;++_iter)                                               \
-    {                                                                         \
-        if(_f(__VA_ARGS__, _iter))                                            \
-            break;                                                            \
-    }                                                                         \
-    (_i) = _iter;                                                             \
-} while(0)
-
 #endif /* AL_VECTOR_H */
 #endif /* AL_VECTOR_H */

Файловите разлики са ограничени, защото са твърде много
+ 366 - 217
Engine/lib/openal-soft/CMakeLists.txt


+ 165 - 0
Engine/lib/openal-soft/ChangeLog

@@ -1,3 +1,168 @@
+openal-soft-1.19.0:
+
+    Implemented the ALC_SOFT_device_clock extension.
+
+    Implemented the Pitch Shifter effect.
+
+    Fixed compiling on FreeBSD systems that use freebsd-lib 9.1.
+
+    Fixed compiling on NetBSD.
+
+    Fixed the reverb effect's density scale and panning parameters.
+
+    Fixed use of the WASAPI backend with certain games, which caused odd COM
+    initialization errors.
+
+    Increased the number of virtual channels for decoding Ambisonics to HRTF
+    output.
+
+    Replaced the 4-point Sinc resampler with a more efficient cubic resampler.
+
+    Renamed the MMDevAPI backend to WASAPI.
+
+    Added support fot 24-bit, dual-ear HRTF data sets. The built-in data set
+    has been updated to 24-bit.
+
+    Added a 24- to 48-point band-limited Sinc resampler.
+
+    Added an SDL2 playback backend. Disabled by default to avoid a dependency
+    on SDL2.
+
+    Improved the performance and quality of the Chorus and Flanger effects.
+
+    Improved the efficiency of the band-limited Sinc resampler.
+
+    Improved the Sinc resampler's transition band to avoid over-attenuating
+    higher frequencies.
+
+    Improved the performance of some filter operations.
+
+    Improved the efficiency of object ID lookups.
+
+    Improved the efficienty of internal voice/source synchronization.
+
+    Improved AL call error logging with contextualized messages.
+
+    Removed the reverb effect's modulation stage. Due to the lack of reference
+    for its intended behavior and strength.
+
+openal-soft-1.18.2:
+
+    Fixed resetting the FPU rounding mode after certain function calls on
+    Windows.
+
+    Fixed use of SSE intrinsics when building with Clang on Windows.
+
+    Fixed a crash with the JACK backend when using JACK1.
+
+    Fixed use of pthread_setnane_np on NetBSD.
+
+    Fixed building on FreeBSD with an older freebsd-lib.
+
+    OSS now links with libossaudio if found at build time (for NetBSD).
+
+openal-soft-1.18.1:
+
+    Fixed an issue where resuming a source might not restart playing it.
+
+    Fixed PulseAudio playback when the configured stream length is much less
+    than the requested length.
+
+    Fixed MMDevAPI capture with sample rates not matching the backing device.
+
+    Fixed int32 output for the Wave Writer.
+
+    Fixed enumeration of OSS devices that are missing device files.
+
+    Added correct retrieval of the executable's path on FreeBSD.
+
+    Added a config option to specify the dithering depth.
+
+    Added a 5.1 decoder preset that excludes front-center output.
+
+openal-soft-1.18.0:
+
+    Implemented the AL_EXT_STEREO_ANGLES and AL_EXT_SOURCE_RADIUS extensions.
+
+    Implemented the AL_SOFT_gain_clamp_ex, AL_SOFT_source_resampler,
+    AL_SOFT_source_spatialize, and ALC_SOFT_output_limiter extensions.
+
+    Implemented 3D processing for some effects. Currently implemented for
+    Reverb, Compressor, Equalizer, and Ring Modulator.
+
+    Implemented 2-channel UHJ output encoding. This needs to be enabled with a
+    config option to be used.
+
+    Implemented dual-band processing for high-quality ambisonic decoding.
+
+    Implemented distance-compensation for surround sound output.
+
+    Implemented near-field emulation and compensation with ambisonic rendering.
+    Currently only applies when using the high-quality ambisonic decoder or
+    ambisonic output, with appropriate config options.
+
+    Implemented an output limiter to reduce the amount of distortion from
+    clipping.
+
+    Implemented dithering for 8-bit and 16-bit output.
+
+    Implemented a config option to select a preferred HRTF.
+
+    Implemented a run-time check for NEON extensions using /proc/cpuinfo.
+
+    Implemented experimental capture support for the OpenSL backend.
+
+    Fixed building on compilers with NEON support but don't default to having
+    NEON enabled.
+
+    Fixed support for JACK on Windows.
+
+    Fixed starting a source while alcSuspendContext is in effect.
+
+    Fixed detection of headsets as headphones, with MMDevAPI.
+
+    Added support for AmbDec config files, for custom ambisonic decoder
+    configurations. Version 3 files only.
+
+    Added backend-specific options to alsoft-config.
+
+    Added first-, second-, and third-order ambisonic output formats. Currently
+    only works with backends that don't rely on channel labels, like JACK,
+    ALSA, and OSS.
+
+    Added a build option to embed the default HRTFs into the lib.
+
+    Added AmbDec presets to enable high-quality ambisonic decoding.
+
+    Added an AmbDec preset for 3D7.1 speaker setups.
+
+    Added documentation regarding Ambisonics, 3D7.1, AmbDec config files, and
+    the provided ambdec presets.
+
+    Added the ability for MMDevAPI to open devices given a Device ID or GUID
+    string.
+
+    Added an option to the example apps to open a specific device.
+
+    Increased the maximum auxiliary send limit to 16 (up from 4). Requires
+    requesting them with the ALC_MAX_AUXILIARY_SENDS context creation
+    attribute.
+
+    Increased the default auxiliary effect slot count to 64 (up from 4).
+
+    Reduced the default period count to 3 (down from 4).
+
+    Slightly improved automatic naming for enumerated HRTFs.
+
+    Improved B-Format decoding with HRTF output.
+
+    Improved internal property handling for better batching behavior.
+
+    Improved performance of certain filter uses.
+
+    Removed support for the AL_SOFT_buffer_samples and AL_SOFT_buffer_sub_data
+    extensions. Due to conflicts with AL_EXT_SOURCE_RADIUS.
+
 openal-soft-1.17.2:
 openal-soft-1.17.2:
 
 
     Implemented device enumeration for OSSv4.
     Implemented device enumeration for OSSv4.

+ 56 - 56
Engine/lib/openal-soft/OpenAL32/Include/alAuxEffectSlot.h

@@ -4,6 +4,7 @@
 #include "alMain.h"
 #include "alMain.h"
 #include "alEffect.h"
 #include "alEffect.h"
 
 
+#include "atomic.h"
 #include "align.h"
 #include "align.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -18,7 +19,7 @@ typedef struct ALeffectState {
     const struct ALeffectStateVtable *vtbl;
     const struct ALeffectStateVtable *vtbl;
 
 
     ALfloat (*OutBuffer)[BUFFERSIZE];
     ALfloat (*OutBuffer)[BUFFERSIZE];
-    ALuint OutChannels;
+    ALsizei OutChannels;
 } ALeffectState;
 } ALeffectState;
 
 
 void ALeffectState_Construct(ALeffectState *state);
 void ALeffectState_Construct(ALeffectState *state);
@@ -28,17 +29,22 @@ struct ALeffectStateVtable {
     void (*const Destruct)(ALeffectState *state);
     void (*const Destruct)(ALeffectState *state);
 
 
     ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
     ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
-    void (*const update)(ALeffectState *state, const ALCdevice *device, const struct ALeffectslot *slot, const union ALeffectProps *props);
-    void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels);
+    void (*const update)(ALeffectState *state, const ALCcontext *context, const struct ALeffectslot *slot, const union ALeffectProps *props);
+    void (*const process)(ALeffectState *state, ALsizei samplesToDo, const ALfloat (*restrict samplesIn)[BUFFERSIZE], ALfloat (*restrict samplesOut)[BUFFERSIZE], ALsizei numChannels);
 
 
     void (*const Delete)(void *ptr);
     void (*const Delete)(void *ptr);
 };
 };
 
 
+/* Small hack to use a pointer-to-array types as a normal argument type.
+ * Shouldn't be used directly.
+ */
+typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];
+
 #define DEFINE_ALEFFECTSTATE_VTABLE(T)                                        \
 #define DEFINE_ALEFFECTSTATE_VTABLE(T)                                        \
 DECLARE_THUNK(T, ALeffectState, void, Destruct)                               \
 DECLARE_THUNK(T, ALeffectState, void, Destruct)                               \
 DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*)         \
 DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*)         \
-DECLARE_THUNK3(T, ALeffectState, void, update, const ALCdevice*, const ALeffectslot*, const ALeffectProps*) \
-DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \
+DECLARE_THUNK3(T, ALeffectState, void, update, const ALCcontext*, const ALeffectslot*, const ALeffectProps*) \
+DECLARE_THUNK4(T, ALeffectState, void, process, ALsizei, const ALfloatBUFFERSIZE*restrict, ALfloatBUFFERSIZE*restrict, ALsizei) \
 static void T##_ALeffectState_Delete(void *ptr)                               \
 static void T##_ALeffectState_Delete(void *ptr)                               \
 { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); }  \
 { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); }  \
                                                                               \
                                                                               \
@@ -53,43 +59,48 @@ static const struct ALeffectStateVtable T##_ALeffectState_vtable = {          \
 }
 }
 
 
 
 
-struct ALeffectStateFactoryVtable;
+struct EffectStateFactoryVtable;
 
 
-typedef struct ALeffectStateFactory {
-    const struct ALeffectStateFactoryVtable *vtbl;
-} ALeffectStateFactory;
+typedef struct EffectStateFactory {
+    const struct EffectStateFactoryVtable *vtab;
+} EffectStateFactory;
 
 
-struct ALeffectStateFactoryVtable {
-    ALeffectState *(*const create)(ALeffectStateFactory *factory);
+struct EffectStateFactoryVtable {
+    ALeffectState *(*const create)(EffectStateFactory *factory);
 };
 };
+#define EffectStateFactory_create(x) ((x)->vtab->create((x)))
 
 
-#define DEFINE_ALEFFECTSTATEFACTORY_VTABLE(T)                                 \
-DECLARE_THUNK(T, ALeffectStateFactory, ALeffectState*, create)                \
+#define DEFINE_EFFECTSTATEFACTORY_VTABLE(T)                                   \
+DECLARE_THUNK(T, EffectStateFactory, ALeffectState*, create)                  \
                                                                               \
                                                                               \
-static const struct ALeffectStateFactoryVtable T##_ALeffectStateFactory_vtable = { \
-    T##_ALeffectStateFactory_create,                                          \
+static const struct EffectStateFactoryVtable T##_EffectStateFactory_vtable = { \
+    T##_EffectStateFactory_create,                                            \
 }
 }
 
 
 
 
 #define MAX_EFFECT_CHANNELS (4)
 #define MAX_EFFECT_CHANNELS (4)
 
 
 
 
+struct ALeffectslotArray {
+    ALsizei count;
+    struct ALeffectslot *slot[];
+};
+
+
 struct ALeffectslotProps {
 struct ALeffectslotProps {
-    ATOMIC(ALfloat)   Gain;
-    ATOMIC(ALboolean) AuxSendAuto;
+    ALfloat   Gain;
+    ALboolean AuxSendAuto;
 
 
-    ATOMIC(ALenum) Type;
+    ALenum Type;
     ALeffectProps Props;
     ALeffectProps Props;
 
 
-    ATOMIC(ALeffectState*) State;
+    ALeffectState *State;
 
 
     ATOMIC(struct ALeffectslotProps*) next;
     ATOMIC(struct ALeffectslotProps*) next;
 };
 };
 
 
 
 
 typedef struct ALeffectslot {
 typedef struct ALeffectslot {
-    ALboolean NeedsUpdate;
-
     ALfloat   Gain;
     ALfloat   Gain;
     ALboolean AuxSendAuto;
     ALboolean AuxSendAuto;
 
 
@@ -100,81 +111,70 @@ typedef struct ALeffectslot {
         ALeffectState *State;
         ALeffectState *State;
     } Effect;
     } Effect;
 
 
+    ATOMIC_FLAG PropsClean;
+
     RefCount ref;
     RefCount ref;
 
 
     ATOMIC(struct ALeffectslotProps*) Update;
     ATOMIC(struct ALeffectslotProps*) Update;
-    ATOMIC(struct ALeffectslotProps*) FreeList;
 
 
     struct {
     struct {
         ALfloat   Gain;
         ALfloat   Gain;
         ALboolean AuxSendAuto;
         ALboolean AuxSendAuto;
 
 
         ALenum EffectType;
         ALenum EffectType;
+        ALeffectProps EffectProps;
         ALeffectState *EffectState;
         ALeffectState *EffectState;
 
 
         ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */
         ALfloat RoomRolloff; /* Added to the source's room rolloff, not multiplied. */
         ALfloat DecayTime;
         ALfloat DecayTime;
+        ALfloat DecayLFRatio;
+        ALfloat DecayHFRatio;
+        ALboolean DecayHFLimit;
         ALfloat AirAbsorptionGainHF;
         ALfloat AirAbsorptionGainHF;
     } Params;
     } Params;
 
 
     /* Self ID */
     /* Self ID */
     ALuint id;
     ALuint id;
 
 
-    ALuint NumChannels;
+    ALsizei NumChannels;
     BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS];
     BFChannelConfig ChanMap[MAX_EFFECT_CHANNELS];
     /* Wet buffer configuration is ACN channel order with N3D scaling:
     /* Wet buffer configuration is ACN channel order with N3D scaling:
      * * Channel 0 is the unattenuated mono signal.
      * * Channel 0 is the unattenuated mono signal.
-     * * Channel 1 is OpenAL -X
-     * * Channel 2 is OpenAL Y
-     * * Channel 3 is OpenAL -Z
+     * * Channel 1 is OpenAL -X * sqrt(3)
+     * * Channel 2 is OpenAL Y * sqrt(3)
+     * * Channel 3 is OpenAL -Z * sqrt(3)
      * Consequently, effects that only want to work with mono input can use
      * Consequently, effects that only want to work with mono input can use
      * channel 0 by itself. Effects that want multichannel can process the
      * channel 0 by itself. Effects that want multichannel can process the
      * ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for
      * ambisonics signal and make a B-Format pan (ComputeFirstOrderGains) for
      * first-order device output (FOAOut).
      * first-order device output (FOAOut).
      */
      */
     alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
     alignas(16) ALfloat WetBuffer[MAX_EFFECT_CHANNELS][BUFFERSIZE];
-
-    ATOMIC(struct ALeffectslot*) next;
 } ALeffectslot;
 } ALeffectslot;
 
 
-inline void LockEffectSlotsRead(ALCcontext *context)
-{ LockUIntMapRead(&context->EffectSlotMap); }
-inline void UnlockEffectSlotsRead(ALCcontext *context)
-{ UnlockUIntMapRead(&context->EffectSlotMap); }
-inline void LockEffectSlotsWrite(ALCcontext *context)
-{ LockUIntMapWrite(&context->EffectSlotMap); }
-inline void UnlockEffectSlotsWrite(ALCcontext *context)
-{ UnlockUIntMapWrite(&context->EffectSlotMap); }
-
-inline struct ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id)
-{ return (struct ALeffectslot*)LookupUIntMapKeyNoLock(&context->EffectSlotMap, id); }
-inline struct ALeffectslot *RemoveEffectSlot(ALCcontext *context, ALuint id)
-{ return (struct ALeffectslot*)RemoveUIntMapKeyNoLock(&context->EffectSlotMap, id); }
-
 ALenum InitEffectSlot(ALeffectslot *slot);
 ALenum InitEffectSlot(ALeffectslot *slot);
 void DeinitEffectSlot(ALeffectslot *slot);
 void DeinitEffectSlot(ALeffectslot *slot);
-void UpdateEffectSlotProps(ALeffectslot *slot);
+void UpdateEffectSlotProps(ALeffectslot *slot, ALCcontext *context);
 void UpdateAllEffectSlotProps(ALCcontext *context);
 void UpdateAllEffectSlotProps(ALCcontext *context);
 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
 ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
 
 
 
 
-ALeffectStateFactory *ALnullStateFactory_getFactory(void);
-ALeffectStateFactory *ALreverbStateFactory_getFactory(void);
-ALeffectStateFactory *ALchorusStateFactory_getFactory(void);
-ALeffectStateFactory *ALcompressorStateFactory_getFactory(void);
-ALeffectStateFactory *ALdistortionStateFactory_getFactory(void);
-ALeffectStateFactory *ALechoStateFactory_getFactory(void);
-ALeffectStateFactory *ALequalizerStateFactory_getFactory(void);
-ALeffectStateFactory *ALflangerStateFactory_getFactory(void);
-ALeffectStateFactory *ALmodulatorStateFactory_getFactory(void);
+EffectStateFactory *NullStateFactory_getFactory(void);
+EffectStateFactory *ReverbStateFactory_getFactory(void);
+EffectStateFactory *ChorusStateFactory_getFactory(void);
+EffectStateFactory *CompressorStateFactory_getFactory(void);
+EffectStateFactory *DistortionStateFactory_getFactory(void);
+EffectStateFactory *EchoStateFactory_getFactory(void);
+EffectStateFactory *EqualizerStateFactory_getFactory(void);
+EffectStateFactory *FlangerStateFactory_getFactory(void);
+EffectStateFactory *ModulatorStateFactory_getFactory(void);
+EffectStateFactory *PshifterStateFactory_getFactory(void);
 
 
-ALeffectStateFactory *ALdedicatedStateFactory_getFactory(void);
+EffectStateFactory *DedicatedStateFactory_getFactory(void);
 
 
 
 
-ALenum InitializeEffect(ALCdevice *Device, ALeffectslot *EffectSlot, ALeffect *effect);
+ALenum InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
 
 
-void InitEffectFactoryMap(void);
-void DeinitEffectFactoryMap(void);
+void ALeffectState_DecRef(ALeffectState *state);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 47 - 62
Engine/lib/openal-soft/OpenAL32/Include/alBuffer.h

@@ -1,7 +1,13 @@
 #ifndef _AL_BUFFER_H_
 #ifndef _AL_BUFFER_H_
 #define _AL_BUFFER_H_
 #define _AL_BUFFER_H_
 
 
-#include "alMain.h"
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "AL/alext.h"
+
+#include "inprogext.h"
+#include "atomic.h"
+#include "rwlock.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -9,36 +15,30 @@ extern "C" {
 
 
 /* User formats */
 /* User formats */
 enum UserFmtType {
 enum UserFmtType {
-    UserFmtByte   = AL_BYTE_SOFT,
-    UserFmtUByte  = AL_UNSIGNED_BYTE_SOFT,
-    UserFmtShort  = AL_SHORT_SOFT,
-    UserFmtUShort = AL_UNSIGNED_SHORT_SOFT,
-    UserFmtInt    = AL_INT_SOFT,
-    UserFmtUInt   = AL_UNSIGNED_INT_SOFT,
-    UserFmtFloat  = AL_FLOAT_SOFT,
-    UserFmtDouble = AL_DOUBLE_SOFT,
-    UserFmtByte3  = AL_BYTE3_SOFT,
-    UserFmtUByte3 = AL_UNSIGNED_BYTE3_SOFT,
-    UserFmtMulaw  = AL_MULAW_SOFT,
-    UserFmtAlaw   = 0x10000000,
+    UserFmtUByte,
+    UserFmtShort,
+    UserFmtFloat,
+    UserFmtDouble,
+    UserFmtMulaw,
+    UserFmtAlaw,
     UserFmtIMA4,
     UserFmtIMA4,
     UserFmtMSADPCM,
     UserFmtMSADPCM,
 };
 };
 enum UserFmtChannels {
 enum UserFmtChannels {
-    UserFmtMono      = AL_MONO_SOFT,
-    UserFmtStereo    = AL_STEREO_SOFT,
-    UserFmtRear      = AL_REAR_SOFT,
-    UserFmtQuad      = AL_QUAD_SOFT,
-    UserFmtX51       = AL_5POINT1_SOFT, /* (WFX order) */
-    UserFmtX61       = AL_6POINT1_SOFT, /* (WFX order) */
-    UserFmtX71       = AL_7POINT1_SOFT, /* (WFX order) */
-    UserFmtBFormat2D = AL_BFORMAT2D_SOFT, /* WXY */
-    UserFmtBFormat3D = AL_BFORMAT3D_SOFT, /* WXYZ */
+    UserFmtMono,
+    UserFmtStereo,
+    UserFmtRear,
+    UserFmtQuad,
+    UserFmtX51, /* (WFX order) */
+    UserFmtX61, /* (WFX order) */
+    UserFmtX71, /* (WFX order) */
+    UserFmtBFormat2D, /* WXY */
+    UserFmtBFormat3D, /* WXYZ */
 };
 };
 
 
-ALuint BytesFromUserFmt(enum UserFmtType type);
-ALuint ChannelsFromUserFmt(enum UserFmtChannels chans);
-inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
+ALsizei BytesFromUserFmt(enum UserFmtType type);
+ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans);
+inline ALsizei FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType type)
 {
 {
     return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
     return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
 }
 }
@@ -46,9 +46,12 @@ inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans, enum UserFmtType
 
 
 /* Storable formats */
 /* Storable formats */
 enum FmtType {
 enum FmtType {
-    FmtByte  = UserFmtByte,
-    FmtShort = UserFmtShort,
-    FmtFloat = UserFmtFloat,
+    FmtUByte  = UserFmtUByte,
+    FmtShort  = UserFmtShort,
+    FmtFloat  = UserFmtFloat,
+    FmtDouble = UserFmtDouble,
+    FmtMulaw  = UserFmtMulaw,
+    FmtAlaw   = UserFmtAlaw,
 };
 };
 enum FmtChannels {
 enum FmtChannels {
     FmtMono   = UserFmtMono,
     FmtMono   = UserFmtMono,
@@ -63,9 +66,9 @@ enum FmtChannels {
 };
 };
 #define MAX_INPUT_CHANNELS  (8)
 #define MAX_INPUT_CHANNELS  (8)
 
 
-ALuint BytesFromFmt(enum FmtType type);
-ALuint ChannelsFromFmt(enum FmtChannels chans);
-inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
+ALsizei BytesFromFmt(enum FmtType type);
+ALsizei ChannelsFromFmt(enum FmtChannels chans);
+inline ALsizei FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
 {
 {
     return ChannelsFromFmt(chans) * BytesFromFmt(type);
     return ChannelsFromFmt(chans) * BytesFromFmt(type);
 }
 }
@@ -74,53 +77,35 @@ inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
 typedef struct ALbuffer {
 typedef struct ALbuffer {
     ALvoid  *data;
     ALvoid  *data;
 
 
-    ALsizei  Frequency;
-    ALenum   Format;
-    ALsizei  SampleLen;
+    ALsizei Frequency;
+    ALbitfieldSOFT Access;
+    ALsizei SampleLen;
 
 
     enum FmtChannels FmtChannels;
     enum FmtChannels FmtChannels;
     enum FmtType     FmtType;
     enum FmtType     FmtType;
-    ALuint BytesAlloc;
+    ALsizei BytesAlloc;
 
 
-    enum UserFmtChannels OriginalChannels;
-    enum UserFmtType     OriginalType;
-    ALsizei              OriginalSize;
-    ALsizei              OriginalAlign;
+    enum UserFmtType OriginalType;
+    ALsizei OriginalSize;
+    ALsizei OriginalAlign;
 
 
-    ALsizei  LoopStart;
-    ALsizei  LoopEnd;
+    ALsizei LoopStart;
+    ALsizei LoopEnd;
 
 
     ATOMIC(ALsizei) UnpackAlign;
     ATOMIC(ALsizei) UnpackAlign;
     ATOMIC(ALsizei) PackAlign;
     ATOMIC(ALsizei) PackAlign;
 
 
+    ALbitfieldSOFT MappedAccess;
+    ALsizei MappedOffset;
+    ALsizei MappedSize;
+
     /* Number of times buffer was attached to a source (deletion can only occur when 0) */
     /* Number of times buffer was attached to a source (deletion can only occur when 0) */
     RefCount ref;
     RefCount ref;
 
 
-    RWLock lock;
-
     /* Self ID */
     /* Self ID */
     ALuint id;
     ALuint id;
 } ALbuffer;
 } ALbuffer;
 
 
-ALbuffer *NewBuffer(ALCcontext *context);
-void DeleteBuffer(ALCdevice *device, ALbuffer *buffer);
-
-ALenum LoadData(ALbuffer *buffer, ALuint freq, ALenum NewFormat, ALsizei frames, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data, ALsizei align, ALboolean storesrc);
-
-inline void LockBuffersRead(ALCdevice *device)
-{ LockUIntMapRead(&device->BufferMap); }
-inline void UnlockBuffersRead(ALCdevice *device)
-{ UnlockUIntMapRead(&device->BufferMap); }
-inline void LockBuffersWrite(ALCdevice *device)
-{ LockUIntMapWrite(&device->BufferMap); }
-inline void UnlockBuffersWrite(ALCdevice *device)
-{ UnlockUIntMapWrite(&device->BufferMap); }
-
-inline struct ALbuffer *LookupBuffer(ALCdevice *device, ALuint id)
-{ return (struct ALbuffer*)LookupUIntMapKeyNoLock(&device->BufferMap, id); }
-inline struct ALbuffer *RemoveBuffer(ALCdevice *device, ALuint id)
-{ return (struct ALbuffer*)RemoveUIntMapKeyNoLock(&device->BufferMap, id); }
-
 ALvoid ReleaseALBuffers(ALCdevice *device);
 ALvoid ReleaseALBuffers(ALCdevice *device);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 39 - 39
Engine/lib/openal-soft/OpenAL32/Include/alEffect.h

@@ -10,23 +10,32 @@ extern "C" {
 struct ALeffect;
 struct ALeffect;
 
 
 enum {
 enum {
-    EAXREVERB = 0,
-    REVERB,
-    CHORUS,
-    COMPRESSOR,
-    DISTORTION,
-    ECHO,
-    EQUALIZER,
-    FLANGER,
-    MODULATOR,
-    DEDICATED,
+    EAXREVERB_EFFECT = 0,
+    REVERB_EFFECT,
+    CHORUS_EFFECT,
+    COMPRESSOR_EFFECT,
+    DISTORTION_EFFECT,
+    ECHO_EFFECT,
+    EQUALIZER_EFFECT,
+    FLANGER_EFFECT,
+    MODULATOR_EFFECT,
+    PSHIFTER_EFFECT,
+    DEDICATED_EFFECT,
 
 
     MAX_EFFECTS
     MAX_EFFECTS
 };
 };
 extern ALboolean DisabledEffects[MAX_EFFECTS];
 extern ALboolean DisabledEffects[MAX_EFFECTS];
 
 
 extern ALfloat ReverbBoost;
 extern ALfloat ReverbBoost;
-extern ALboolean EmulateEAXReverb;
+
+struct EffectList {
+    const char name[16];
+    int type;
+    ALenum val;
+};
+#define EFFECTLIST_SIZE 12
+extern const struct EffectList EffectList[EFFECTLIST_SIZE];
+
 
 
 struct ALeffectVtable {
 struct ALeffectVtable {
     void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
     void (*const setParami)(struct ALeffect *effect, ALCcontext *context, ALenum param, ALint val);
@@ -58,6 +67,7 @@ extern const struct ALeffectVtable ALequalizer_vtable;
 extern const struct ALeffectVtable ALflanger_vtable;
 extern const struct ALeffectVtable ALflanger_vtable;
 extern const struct ALeffectVtable ALmodulator_vtable;
 extern const struct ALeffectVtable ALmodulator_vtable;
 extern const struct ALeffectVtable ALnull_vtable;
 extern const struct ALeffectVtable ALnull_vtable;
+extern const struct ALeffectVtable ALpshifter_vtable;
 extern const struct ALeffectVtable ALdedicated_vtable;
 extern const struct ALeffectVtable ALdedicated_vtable;
 
 
 
 
@@ -98,7 +108,7 @@ typedef union ALeffectProps {
         ALfloat Depth;
         ALfloat Depth;
         ALfloat Feedback;
         ALfloat Feedback;
         ALfloat Delay;
         ALfloat Delay;
-    } Chorus;
+    } Chorus; /* Also Flanger */
 
 
     struct {
     struct {
         ALboolean OnOff;
         ALboolean OnOff;
@@ -135,21 +145,17 @@ typedef union ALeffectProps {
         ALfloat HighGain;
         ALfloat HighGain;
     } Equalizer;
     } Equalizer;
 
 
-    struct {
-        ALint Waveform;
-        ALint Phase;
-        ALfloat Rate;
-        ALfloat Depth;
-        ALfloat Feedback;
-        ALfloat Delay;
-    } Flanger;
-
     struct {
     struct {
         ALfloat Frequency;
         ALfloat Frequency;
         ALfloat HighPassCutoff;
         ALfloat HighPassCutoff;
         ALint Waveform;
         ALint Waveform;
     } Modulator;
     } Modulator;
 
 
+    struct {
+        ALint CoarseTune;
+        ALint FineTune;
+    } Pshifter;
+
     struct {
     struct {
         ALfloat Gain;
         ALfloat Gain;
     } Dedicated;
     } Dedicated;
@@ -161,33 +167,27 @@ typedef struct ALeffect {
 
 
     ALeffectProps Props;
     ALeffectProps Props;
 
 
-    const struct ALeffectVtable *vtbl;
+    const struct ALeffectVtable *vtab;
 
 
     /* Self ID */
     /* Self ID */
     ALuint id;
     ALuint id;
 } ALeffect;
 } ALeffect;
-
-inline void LockEffectsRead(ALCdevice *device)
-{ LockUIntMapRead(&device->EffectMap); }
-inline void UnlockEffectsRead(ALCdevice *device)
-{ UnlockUIntMapRead(&device->EffectMap); }
-inline void LockEffectsWrite(ALCdevice *device)
-{ LockUIntMapWrite(&device->EffectMap); }
-inline void UnlockEffectsWrite(ALCdevice *device)
-{ UnlockUIntMapWrite(&device->EffectMap); }
-
-inline struct ALeffect *LookupEffect(ALCdevice *device, ALuint id)
-{ return (struct ALeffect*)LookupUIntMapKeyNoLock(&device->EffectMap, id); }
-inline struct ALeffect *RemoveEffect(ALCdevice *device, ALuint id)
-{ return (struct ALeffect*)RemoveUIntMapKeyNoLock(&device->EffectMap, id); }
+#define ALeffect_setParami(o, c, p, v)   ((o)->vtab->setParami(o, c, p, v))
+#define ALeffect_setParamf(o, c, p, v)   ((o)->vtab->setParamf(o, c, p, v))
+#define ALeffect_setParamiv(o, c, p, v)  ((o)->vtab->setParamiv(o, c, p, v))
+#define ALeffect_setParamfv(o, c, p, v)  ((o)->vtab->setParamfv(o, c, p, v))
+#define ALeffect_getParami(o, c, p, v)   ((o)->vtab->getParami(o, c, p, v))
+#define ALeffect_getParamf(o, c, p, v)   ((o)->vtab->getParamf(o, c, p, v))
+#define ALeffect_getParamiv(o, c, p, v)  ((o)->vtab->getParamiv(o, c, p, v))
+#define ALeffect_getParamfv(o, c, p, v)  ((o)->vtab->getParamfv(o, c, p, v))
 
 
 inline ALboolean IsReverbEffect(ALenum type)
 inline ALboolean IsReverbEffect(ALenum type)
 { return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; }
 { return type == AL_EFFECT_REVERB || type == AL_EFFECT_EAXREVERB; }
 
 
-ALenum InitEffect(ALeffect *effect);
-ALvoid ReleaseALEffects(ALCdevice *device);
+void InitEffect(ALeffect *effect);
+void ReleaseALEffects(ALCdevice *device);
 
 
-ALvoid LoadReverbPreset(const char *name, ALeffect *effect);
+void LoadReverbPreset(const char *name, ALeffect *effect);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 8 - 12
Engine/lib/openal-soft/OpenAL32/Include/alError.h

@@ -2,6 +2,7 @@
 #define _AL_ERROR_H_
 #define _AL_ERROR_H_
 
 
 #include "alMain.h"
 #include "alMain.h"
+#include "logging.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -9,21 +10,16 @@ extern "C" {
 
 
 extern ALboolean TrapALError;
 extern ALboolean TrapALError;
 
 
-ALvoid alSetError(ALCcontext *Context, ALenum errorCode);
+void alSetError(ALCcontext *context, ALenum errorCode, const char *msg, ...) DECL_FORMAT(printf, 3, 4);
 
 
-#define SET_ERROR_AND_RETURN(ctx, err) do {                                    \
-    alSetError((ctx), (err));                                                  \
-    return;                                                                    \
-} while(0)
-
-#define SET_ERROR_AND_RETURN_VALUE(ctx, err, val) do {                         \
-    alSetError((ctx), (err));                                                  \
-    return (val);                                                              \
+#define SETERR_GOTO(ctx, err, lbl, ...) do {                                   \
+    alSetError((ctx), (err), __VA_ARGS__);                                     \
+    goto lbl;                                                                  \
 } while(0)
 } while(0)
 
 
-#define SET_ERROR_AND_GOTO(ctx, err, lbl) do {                                 \
-    alSetError((ctx), (err));                                                  \
-    goto lbl;                                                                  \
+#define SETERR_RETURN(ctx, err, retval, ...) do {                              \
+    alSetError((ctx), (err), __VA_ARGS__);                                     \
+    return retval;                                                             \
 } while(0)
 } while(0)
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 30 - 118
Engine/lib/openal-soft/OpenAL32/Include/alFilter.h

@@ -1,9 +1,8 @@
 #ifndef _AL_FILTER_H_
 #ifndef _AL_FILTER_H_
 #define _AL_FILTER_H_
 #define _AL_FILTER_H_
 
 
-#include "alMain.h"
-
-#include "math_defs.h"
+#include "AL/alc.h"
+#include "AL/al.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -13,91 +12,28 @@ extern "C" {
 #define HIGHPASSFREQREF  (250.0f)
 #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
- */
-/* 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 and reference frequency. */
-    ALfilterType_Peaking,
-
-    /** Low-pass cut-off filter, specifying a cut-off frequency. */
-    ALfilterType_LowPass,
-    /** High-pass cut-off filter, specifying a cut-off frequency. */
-    ALfilterType_HighPass,
-    /** Band-pass filter, specifying a center frequency. */
-    ALfilterType_BandPass,
-} ALfilterType;
-
-typedef struct ALfilterState {
-    ALfloat x[2]; /* History of two last input samples  */
-    ALfloat y[2]; /* History of two last output samples */
-    ALfloat a1, a2; /* Transfer function coefficients "a" (a0 is pre-applied) */
-    ALfloat b0, b1, b2; /* Transfer function coefficients "b" */
-} ALfilterState;
-/* Currently only a C-based filter process method is implemented. */
-#define ALfilterState_process ALfilterState_processC
-
-/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the
- * reference gain and shelf slope parameter.
- * 0 < gain
- * 0 < slope <= 1
- */
-inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope)
-{
-    return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f);
-}
-/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency
- * multiple (i.e. ref_freq / sampling_freq) and bandwidth.
- * 0 < freq_mult < 0.5.
- */
-inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth)
-{
-    ALfloat w0 = F_TAU * freq_mult;
-    return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0));
-}
-
-inline void ALfilterState_clear(ALfilterState *filter)
-{
-    filter->x[0] = 0.0f;
-    filter->x[1] = 0.0f;
-    filter->y[0] = 0.0f;
-    filter->y[1] = 0.0f;
-}
+struct ALfilter;
 
 
-void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
+typedef struct ALfilterVtable {
+    void (*const setParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val);
+    void (*const setParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals);
+    void (*const setParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val);
+    void (*const setParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals);
 
 
-void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *restrict src, ALuint numsamples);
+    void (*const getParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val);
+    void (*const getParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals);
+    void (*const getParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val);
+    void (*const getParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals);
+} ALfilterVtable;
 
 
-inline void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *restrict 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];
-    }
+#define DEFINE_ALFILTER_VTABLE(T)           \
+const struct ALfilterVtable T##_vtable = {  \
+    T##_setParami, T##_setParamiv,          \
+    T##_setParamf, T##_setParamfv,          \
+    T##_getParami, T##_getParamiv,          \
+    T##_getParamf, T##_getParamfv,          \
 }
 }
 
 
-
 typedef struct ALfilter {
 typedef struct ALfilter {
     // Filter type (AL_FILTER_NULL, ...)
     // Filter type (AL_FILTER_NULL, ...)
     ALenum type;
     ALenum type;
@@ -108,45 +44,21 @@ typedef struct ALfilter {
     ALfloat GainLF;
     ALfloat GainLF;
     ALfloat LFReference;
     ALfloat LFReference;
 
 
-    void (*SetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val);
-    void (*SetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals);
-    void (*SetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val);
-    void (*SetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals);
-
-    void (*GetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val);
-    void (*GetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals);
-    void (*GetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val);
-    void (*GetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals);
+    const struct ALfilterVtable *vtab;
 
 
     /* Self ID */
     /* Self ID */
     ALuint id;
     ALuint id;
 } ALfilter;
 } ALfilter;
-
-#define ALfilter_SetParami(x, c, p, v)  ((x)->SetParami((x),(c),(p),(v)))
-#define ALfilter_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v)))
-#define ALfilter_SetParamf(x, c, p, v)  ((x)->SetParamf((x),(c),(p),(v)))
-#define ALfilter_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v)))
-
-#define ALfilter_GetParami(x, c, p, v)  ((x)->GetParami((x),(c),(p),(v)))
-#define ALfilter_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v)))
-#define ALfilter_GetParamf(x, c, p, v)  ((x)->GetParamf((x),(c),(p),(v)))
-#define ALfilter_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v)))
-
-inline void LockFiltersRead(ALCdevice *device)
-{ LockUIntMapRead(&device->FilterMap); }
-inline void UnlockFiltersRead(ALCdevice *device)
-{ UnlockUIntMapRead(&device->FilterMap); }
-inline void LockFiltersWrite(ALCdevice *device)
-{ LockUIntMapWrite(&device->FilterMap); }
-inline void UnlockFiltersWrite(ALCdevice *device)
-{ UnlockUIntMapWrite(&device->FilterMap); }
-
-inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id)
-{ return (struct ALfilter*)LookupUIntMapKeyNoLock(&device->FilterMap, id); }
-inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id)
-{ return (struct ALfilter*)RemoveUIntMapKeyNoLock(&device->FilterMap, id); }
-
-ALvoid ReleaseALFilters(ALCdevice *device);
+#define ALfilter_setParami(o, c, p, v)   ((o)->vtab->setParami(o, c, p, v))
+#define ALfilter_setParamf(o, c, p, v)   ((o)->vtab->setParamf(o, c, p, v))
+#define ALfilter_setParamiv(o, c, p, v)  ((o)->vtab->setParamiv(o, c, p, v))
+#define ALfilter_setParamfv(o, c, p, v)  ((o)->vtab->setParamfv(o, c, p, v))
+#define ALfilter_getParami(o, c, p, v)   ((o)->vtab->getParami(o, c, p, v))
+#define ALfilter_getParamf(o, c, p, v)   ((o)->vtab->getParamf(o, c, p, v))
+#define ALfilter_getParamiv(o, c, p, v)  ((o)->vtab->getParamiv(o, c, p, v))
+#define ALfilter_getParamfv(o, c, p, v)  ((o)->vtab->getParamfv(o, c, p, v))
+
+void ReleaseALFilters(ALCdevice *device);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 25 - 24
Engine/lib/openal-soft/OpenAL32/Include/alListener.h

@@ -8,40 +8,40 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+struct ALcontextProps {
+    ALfloat DopplerFactor;
+    ALfloat DopplerVelocity;
+    ALfloat SpeedOfSound;
+    ALboolean SourceDistanceModel;
+    enum DistanceModel DistanceModel;
+    ALfloat MetersPerUnit;
+
+    ATOMIC(struct ALcontextProps*) next;
+};
+
 struct ALlistenerProps {
 struct ALlistenerProps {
-    ATOMIC(ALfloat) Position[3];
-    ATOMIC(ALfloat) Velocity[3];
-    ATOMIC(ALfloat) Forward[3];
-    ATOMIC(ALfloat) Up[3];
-    ATOMIC(ALfloat) Gain;
-    ATOMIC(ALfloat) MetersPerUnit;
-
-    ATOMIC(ALfloat) DopplerFactor;
-    ATOMIC(ALfloat) DopplerVelocity;
-    ATOMIC(ALfloat) SpeedOfSound;
-    ATOMIC(ALboolean) SourceDistanceModel;
-    ATOMIC(enum DistanceModel) DistanceModel;
+    ALfloat Position[3];
+    ALfloat Velocity[3];
+    ALfloat Forward[3];
+    ALfloat Up[3];
+    ALfloat Gain;
 
 
     ATOMIC(struct ALlistenerProps*) next;
     ATOMIC(struct ALlistenerProps*) next;
 };
 };
 
 
 typedef struct ALlistener {
 typedef struct ALlistener {
-    volatile ALfloat Position[3];
-    volatile ALfloat Velocity[3];
-    volatile ALfloat Forward[3];
-    volatile ALfloat Up[3];
-    volatile ALfloat Gain;
-    volatile ALfloat MetersPerUnit;
+    alignas(16) ALfloat Position[3];
+    ALfloat Velocity[3];
+    ALfloat Forward[3];
+    ALfloat Up[3];
+    ALfloat Gain;
+
+    ATOMIC_FLAG PropsClean;
 
 
     /* Pointer to the most recent property values that are awaiting an update.
     /* Pointer to the most recent property values that are awaiting an update.
      */
      */
     ATOMIC(struct ALlistenerProps*) Update;
     ATOMIC(struct ALlistenerProps*) Update;
 
 
-    /* A linked list of unused property containers, free to use for future
-     * updates.
-     */
-    ATOMIC(struct ALlistenerProps*) FreeList;
-
     struct {
     struct {
         aluMatrixf Matrix;
         aluMatrixf Matrix;
         aluVector  Velocity;
         aluVector  Velocity;
@@ -50,7 +50,8 @@ typedef struct ALlistener {
         ALfloat MetersPerUnit;
         ALfloat MetersPerUnit;
 
 
         ALfloat DopplerFactor;
         ALfloat DopplerFactor;
-        ALfloat SpeedOfSound;
+        ALfloat SpeedOfSound; /* in units per sec! */
+        ALfloat ReverbSpeedOfSound; /* in meters per sec! */
 
 
         ALboolean SourceDistanceModel;
         ALboolean SourceDistanceModel;
         enum DistanceModel DistanceModel;
         enum DistanceModel DistanceModel;

Файловите разлики са ограничени, защото са твърде много
+ 358 - 462
Engine/lib/openal-soft/OpenAL32/Include/alMain.h


+ 21 - 132
Engine/lib/openal-soft/OpenAL32/Include/alSource.h

@@ -1,11 +1,14 @@
 #ifndef _AL_SOURCE_H_
 #ifndef _AL_SOURCE_H_
 #define _AL_SOURCE_H_
 #define _AL_SOURCE_H_
 
 
-#define MAX_SENDS                 4
-
+#include "bool.h"
 #include "alMain.h"
 #include "alMain.h"
 #include "alu.h"
 #include "alu.h"
 #include "hrtf.h"
 #include "hrtf.h"
+#include "atomic.h"
+
+#define MAX_SENDS      16
+#define DEFAULT_SENDS  2
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -13,104 +16,16 @@ extern "C" {
 
 
 struct ALbuffer;
 struct ALbuffer;
 struct ALsource;
 struct ALsource;
-struct ALsourceProps;
 
 
 
 
 typedef struct ALbufferlistitem {
 typedef struct ALbufferlistitem {
-    struct ALbuffer *buffer;
-    struct ALbufferlistitem *volatile next;
+    ATOMIC(struct ALbufferlistitem*) next;
+    ALsizei max_samples;
+    ALsizei num_buffers;
+    struct ALbuffer *buffers[];
 } ALbufferlistitem;
 } ALbufferlistitem;
 
 
 
 
-struct ALsourceProps {
-    ATOMIC(ALfloat)   Pitch;
-    ATOMIC(ALfloat)   Gain;
-    ATOMIC(ALfloat)   OuterGain;
-    ATOMIC(ALfloat)   MinGain;
-    ATOMIC(ALfloat)   MaxGain;
-    ATOMIC(ALfloat)   InnerAngle;
-    ATOMIC(ALfloat)   OuterAngle;
-    ATOMIC(ALfloat)   RefDistance;
-    ATOMIC(ALfloat)   MaxDistance;
-    ATOMIC(ALfloat)   RollOffFactor;
-    ATOMIC(ALfloat)   Position[3];
-    ATOMIC(ALfloat)   Velocity[3];
-    ATOMIC(ALfloat)   Direction[3];
-    ATOMIC(ALfloat)   Orientation[2][3];
-    ATOMIC(ALboolean) HeadRelative;
-    ATOMIC(enum DistanceModel) DistanceModel;
-    ATOMIC(ALboolean) DirectChannels;
-
-    ATOMIC(ALboolean) DryGainHFAuto;
-    ATOMIC(ALboolean) WetGainAuto;
-    ATOMIC(ALboolean) WetGainHFAuto;
-    ATOMIC(ALfloat)   OuterGainHF;
-
-    ATOMIC(ALfloat) AirAbsorptionFactor;
-    ATOMIC(ALfloat) RoomRolloffFactor;
-    ATOMIC(ALfloat) DopplerFactor;
-
-    ATOMIC(ALfloat) StereoPan[2];
-
-    ATOMIC(ALfloat) Radius;
-
-    /** Direct filter and auxiliary send info. */
-    struct {
-        ATOMIC(ALfloat) Gain;
-        ATOMIC(ALfloat) GainHF;
-        ATOMIC(ALfloat) HFReference;
-        ATOMIC(ALfloat) GainLF;
-        ATOMIC(ALfloat) LFReference;
-    } Direct;
-    struct {
-        ATOMIC(struct ALeffectslot*) Slot;
-        ATOMIC(ALfloat) Gain;
-        ATOMIC(ALfloat) GainHF;
-        ATOMIC(ALfloat) HFReference;
-        ATOMIC(ALfloat) GainLF;
-        ATOMIC(ALfloat) LFReference;
-    } Send[MAX_SENDS];
-
-    ATOMIC(struct ALsourceProps*) next;
-};
-
-
-typedef struct ALvoice {
-    struct ALsourceProps Props;
-
-    struct ALsource *volatile Source;
-
-    /** Current target parameters used for mixing. */
-    ALint Step;
-
-    /* If not 'moving', gain/coefficients are set directly without fading. */
-    ALboolean Moving;
-
-    ALboolean IsHrtf;
-
-    ALuint Offset; /* Number of output samples mixed since starting. */
-
-    alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
-
-    BsincState SincState;
-
-    struct {
-        ALfloat (*Buffer)[BUFFERSIZE];
-        ALuint Channels;
-    } DirectOut;
-
-    struct {
-        ALfloat (*Buffer)[BUFFERSIZE];
-        ALuint Channels;
-    } SendOut[MAX_SENDS];
-
-    struct {
-        DirectParams Direct;
-        SendParams Send[MAX_SENDS];
-    } Chan[MAX_INPUT_CHANNELS];
-} ALvoice;
-
-
 typedef struct ALsource {
 typedef struct ALsource {
     /** Source properties. */
     /** Source properties. */
     ALfloat   Pitch;
     ALfloat   Pitch;
@@ -122,14 +37,17 @@ typedef struct ALsource {
     ALfloat   OuterAngle;
     ALfloat   OuterAngle;
     ALfloat   RefDistance;
     ALfloat   RefDistance;
     ALfloat   MaxDistance;
     ALfloat   MaxDistance;
-    ALfloat   RollOffFactor;
+    ALfloat   RolloffFactor;
     ALfloat   Position[3];
     ALfloat   Position[3];
     ALfloat   Velocity[3];
     ALfloat   Velocity[3];
     ALfloat   Direction[3];
     ALfloat   Direction[3];
     ALfloat   Orientation[2][3];
     ALfloat   Orientation[2][3];
     ALboolean HeadRelative;
     ALboolean HeadRelative;
+    ALboolean Looping;
     enum DistanceModel DistanceModel;
     enum DistanceModel DistanceModel;
+    enum Resampler Resampler;
     ALboolean DirectChannels;
     ALboolean DirectChannels;
+    enum SpatializeMode Spatialize;
 
 
     ALboolean DryGainHFAuto;
     ALboolean DryGainHFAuto;
     ALboolean WetGainAuto;
     ALboolean WetGainAuto;
@@ -162,7 +80,7 @@ typedef struct ALsource {
         ALfloat HFReference;
         ALfloat HFReference;
         ALfloat GainLF;
         ALfloat GainLF;
         ALfloat LFReference;
         ALfloat LFReference;
-    } Send[MAX_SENDS];
+    } *Send;
 
 
     /**
     /**
      * Last user-specified offset, and the offset type (bytes, samples, or
      * Last user-specified offset, and the offset type (bytes, samples, or
@@ -176,51 +94,22 @@ typedef struct ALsource {
 
 
     /** Source state (initial, playing, paused, or stopped) */
     /** Source state (initial, playing, paused, or stopped) */
     ALenum state;
     ALenum state;
-    ALenum new_state;
-
-    /** Source Buffer Queue info. */
-    RWLock queue_lock;
-    ATOMIC(ALbufferlistitem*) queue;
-    ATOMIC(ALbufferlistitem*) current_buffer;
-
-    /**
-     * Source offset in samples, relative to the currently playing buffer, NOT
-     * the whole queue, and the fractional (fixed-point) offset to the next
-     * sample.
-     */
-    ATOMIC(ALuint) position;
-    ATOMIC(ALuint) position_fraction;
 
 
-    ATOMIC(ALboolean) looping;
+    /** Source Buffer Queue head. */
+    ALbufferlistitem *queue;
 
 
-    /** Current buffer sample info. */
-    ALuint NumChannels;
-    ALuint SampleSize;
+    ATOMIC_FLAG PropsClean;
 
 
-    ATOMIC(struct ALsourceProps*) Update;
-    ATOMIC(struct ALsourceProps*) FreeList;
+    /* Index into the context's Voices array. Lazily updated, only checked and
+     * reset when looking up the voice.
+     */
+    ALint VoiceIdx;
 
 
     /** Self ID */
     /** Self ID */
     ALuint id;
     ALuint id;
 } ALsource;
 } ALsource;
 
 
-inline void LockSourcesRead(ALCcontext *context)
-{ LockUIntMapRead(&context->SourceMap); }
-inline void UnlockSourcesRead(ALCcontext *context)
-{ UnlockUIntMapRead(&context->SourceMap); }
-inline void LockSourcesWrite(ALCcontext *context)
-{ LockUIntMapWrite(&context->SourceMap); }
-inline void UnlockSourcesWrite(ALCcontext *context)
-{ UnlockUIntMapWrite(&context->SourceMap); }
-
-inline struct ALsource *LookupSource(ALCcontext *context, ALuint id)
-{ return (struct ALsource*)LookupUIntMapKeyNoLock(&context->SourceMap, id); }
-inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id)
-{ return (struct ALsource*)RemoveUIntMapKeyNoLock(&context->SourceMap, id); }
-
 void UpdateAllSourceProps(ALCcontext *context);
 void UpdateAllSourceProps(ALCcontext *context);
-ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state);
-ALboolean ApplyOffset(ALsource *Source);
 
 
 ALvoid ReleaseALSources(ALCcontext *Context);
 ALvoid ReleaseALSources(ALCcontext *Context);
 
 

+ 0 - 20
Engine/lib/openal-soft/OpenAL32/Include/alThunk.h

@@ -1,20 +0,0 @@
-#ifndef ALTHUNK_H
-#define ALTHUNK_H
-
-#include "alMain.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void ThunkInit(void);
-void ThunkExit(void);
-ALenum NewThunkEntry(ALuint *index);
-void FreeThunkEntry(ALuint index);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //ALTHUNK_H
-

+ 268 - 107
Engine/lib/openal-soft/OpenAL32/Include/alu.h

@@ -12,35 +12,56 @@
 
 
 #include "alMain.h"
 #include "alMain.h"
 #include "alBuffer.h"
 #include "alBuffer.h"
-#include "alFilter.h"
-#include "alAuxEffectSlot.h"
 
 
 #include "hrtf.h"
 #include "hrtf.h"
 #include "align.h"
 #include "align.h"
 #include "math_defs.h"
 #include "math_defs.h"
+#include "filters/defs.h"
+#include "filters/nfc.h"
 
 
 
 
 #define MAX_PITCH  (255)
 #define MAX_PITCH  (255)
 
 
-/* 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
+/* Maximum number of samples to pad on either end of a buffer for resampling.
+ * Note that both the beginning and end need padding!
+ */
+#define MAX_RESAMPLE_PADDING 24
 
 
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+struct BSincTable;
 struct ALsource;
 struct ALsource;
-struct ALsourceProps;
+struct ALbufferlistitem;
 struct ALvoice;
 struct ALvoice;
 struct ALeffectslot;
 struct ALeffectslot;
-struct ALbuffer;
 
 
 
 
-/* The number of distinct scale and phase intervals within the filter table. */
+#define DITHER_RNG_SEED 22222
+
+
+enum SpatializeMode {
+    SpatializeOff = AL_FALSE,
+    SpatializeOn = AL_TRUE,
+    SpatializeAuto = AL_AUTO_SOFT
+};
+
+enum Resampler {
+    PointResampler,
+    LinearResampler,
+    FIR4Resampler,
+    BSinc12Resampler,
+    BSinc24Resampler,
+
+    ResamplerMax = BSinc24Resampler
+};
+extern enum Resampler ResamplerDefault;
+
+/* The number of distinct scale and phase intervals within the bsinc filter
+ * table.
+ */
 #define BSINC_SCALE_BITS  4
 #define BSINC_SCALE_BITS  4
 #define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
 #define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
 #define BSINC_PHASE_BITS  4
 #define BSINC_PHASE_BITS  4
@@ -52,16 +73,29 @@ struct ALbuffer;
  */
  */
 typedef struct BsincState {
 typedef struct BsincState {
     ALfloat sf; /* Scale interpolation factor. */
     ALfloat sf; /* Scale interpolation factor. */
-    ALuint m;   /* Coefficient count. */
+    ALsizei m;  /* Coefficient count. */
     ALint l;    /* Left coefficient offset. */
     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];
+    /* Filter coefficients, followed by the scale, phase, and scale-phase
+     * delta coefficients. Starting at phase index 0, each subsequent phase
+     * index follows contiguously.
+     */
+    const ALfloat *filter;
 } BsincState;
 } BsincState;
 
 
+typedef union InterpState {
+    BsincState bsinc;
+} InterpState;
+
+typedef const ALfloat* (*ResamplerFunc)(const InterpState *state,
+    const ALfloat *restrict src, ALsizei frac, ALint increment,
+    ALfloat *restrict dst, ALsizei dstlen
+);
+
+void BsincPrepare(const ALuint increment, BsincState *state, const struct BSincTable *table);
+
+extern const struct BSincTable bsinc12;
+extern const struct BSincTable bsinc24;
+
 
 
 typedef union aluVector {
 typedef union aluVector {
     alignas(16) ALfloat v[4];
     alignas(16) ALfloat v[4];
@@ -111,21 +145,21 @@ enum ActiveFilters {
 
 
 
 
 typedef struct MixHrtfParams {
 typedef struct MixHrtfParams {
-    const HrtfParams *Target;
-    HrtfParams *Current;
-    struct {
-        alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
-        ALint Delay[2];
-    } Steps;
+    const ALfloat (*Coeffs)[2];
+    ALsizei Delay[2];
+    ALfloat Gain;
+    ALfloat GainStep;
 } MixHrtfParams;
 } MixHrtfParams;
 
 
+
 typedef struct DirectParams {
 typedef struct DirectParams {
-    enum ActiveFilters FilterType;
-    ALfilterState LowPass;
-    ALfilterState HighPass;
+    BiquadFilter LowPass;
+    BiquadFilter HighPass;
+
+    NfcFilter NFCtrlFilter;
 
 
     struct {
     struct {
-        HrtfParams Current;
+        HrtfParams Old;
         HrtfParams Target;
         HrtfParams Target;
         HrtfState State;
         HrtfState State;
     } Hrtf;
     } Hrtf;
@@ -137,9 +171,8 @@ typedef struct DirectParams {
 } DirectParams;
 } DirectParams;
 
 
 typedef struct SendParams {
 typedef struct SendParams {
-    enum ActiveFilters FilterType;
-    ALfilterState LowPass;
-    ALfilterState HighPass;
+    BiquadFilter LowPass;
+    BiquadFilter HighPass;
 
 
     struct {
     struct {
         ALfloat Current[MAX_OUTPUT_CHANNELS];
         ALfloat Current[MAX_OUTPUT_CHANNELS];
@@ -148,25 +181,150 @@ typedef struct SendParams {
 } SendParams;
 } SendParams;
 
 
 
 
-typedef const ALfloat* (*ResamplerFunc)(const BsincState *state,
-    const ALfloat *restrict src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen
-);
+struct ALvoiceProps {
+    ATOMIC(struct ALvoiceProps*) next;
+
+    ALfloat Pitch;
+    ALfloat Gain;
+    ALfloat OuterGain;
+    ALfloat MinGain;
+    ALfloat MaxGain;
+    ALfloat InnerAngle;
+    ALfloat OuterAngle;
+    ALfloat RefDistance;
+    ALfloat MaxDistance;
+    ALfloat RolloffFactor;
+    ALfloat Position[3];
+    ALfloat Velocity[3];
+    ALfloat Direction[3];
+    ALfloat Orientation[2][3];
+    ALboolean HeadRelative;
+    enum DistanceModel DistanceModel;
+    enum Resampler Resampler;
+    ALboolean DirectChannels;
+    enum SpatializeMode SpatializeMode;
+
+    ALboolean DryGainHFAuto;
+    ALboolean WetGainAuto;
+    ALboolean WetGainHFAuto;
+    ALfloat   OuterGainHF;
+
+    ALfloat AirAbsorptionFactor;
+    ALfloat RoomRolloffFactor;
+    ALfloat DopplerFactor;
+
+    ALfloat StereoPan[2];
+
+    ALfloat Radius;
+
+    /** Direct filter and auxiliary send info. */
+    struct {
+        ALfloat Gain;
+        ALfloat GainHF;
+        ALfloat HFReference;
+        ALfloat GainLF;
+        ALfloat LFReference;
+    } Direct;
+    struct {
+        struct ALeffectslot *Slot;
+        ALfloat Gain;
+        ALfloat GainHF;
+        ALfloat HFReference;
+        ALfloat GainLF;
+        ALfloat LFReference;
+    } Send[];
+};
+
+#define VOICE_IS_STATIC (1<<0)
+#define VOICE_IS_FADING (1<<1) /* Fading sources use gain stepping for smooth transitions. */
+#define VOICE_HAS_HRTF  (1<<2)
+#define VOICE_HAS_NFC   (1<<3)
+
+typedef struct ALvoice {
+    struct ALvoiceProps *Props;
+
+    ATOMIC(struct ALvoiceProps*) Update;
+
+    ATOMIC(struct ALsource*) Source;
+    ATOMIC(bool) Playing;
+
+    /**
+     * Source offset in samples, relative to the currently playing buffer, NOT
+     * the whole queue, and the fractional (fixed-point) offset to the next
+     * sample.
+     */
+    ATOMIC(ALuint) position;
+    ATOMIC(ALsizei) position_fraction;
+
+    /* Current buffer queue item being played. */
+    ATOMIC(struct ALbufferlistitem*) current_buffer;
+
+    /* Buffer queue item to loop to at end of queue (will be NULL for non-
+     * looping voices).
+     */
+    ATOMIC(struct ALbufferlistitem*) loop_buffer;
+
+    /**
+     * Number of channels and bytes-per-sample for the attached source's
+     * buffer(s).
+     */
+    ALsizei NumChannels;
+    ALsizei SampleSize;
+
+    /** Current target parameters used for mixing. */
+    ALint Step;
+
+    ResamplerFunc Resampler;
+
+    ALuint Flags;
+
+    ALuint Offset; /* Number of output samples mixed since starting. */
 
 
-typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans,
+    alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_RESAMPLE_PADDING];
+
+    InterpState ResampleState;
+
+    struct {
+        enum ActiveFilters FilterType;
+        DirectParams Params[MAX_INPUT_CHANNELS];
+
+        ALfloat (*Buffer)[BUFFERSIZE];
+        ALsizei Channels;
+        ALsizei ChannelsPerOrder[MAX_AMBI_ORDER+1];
+    } Direct;
+
+    struct {
+        enum ActiveFilters FilterType;
+        SendParams Params[MAX_INPUT_CHANNELS];
+
+        ALfloat (*Buffer)[BUFFERSIZE];
+        ALsizei Channels;
+    } Send[];
+} ALvoice;
+
+void DeinitVoice(ALvoice *voice);
+
+
+typedef void (*MixerFunc)(const ALfloat *data, ALsizei OutChans,
                           ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains,
                           ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALfloat *CurrentGains,
-                          const ALfloat *TargetGains, ALuint Counter, ALuint OutPos,
-                          ALuint BufferSize);
+                          const ALfloat *TargetGains, ALsizei Counter, ALsizei OutPos,
+                          ALsizei BufferSize);
 typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains,
 typedef void (*RowMixerFunc)(ALfloat *OutBuffer, const ALfloat *gains,
-                             const ALfloat (*restrict data)[BUFFERSIZE], ALuint InChans,
-                             ALuint InPos, ALuint BufferSize);
-typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], ALuint lidx, ALuint ridx,
-                              const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos,
-                              const ALuint IrSize, const MixHrtfParams *hrtfparams,
-                              HrtfState *hrtfstate, ALuint BufferSize);
-typedef void (*HrtfDirectMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-                                    ALuint lidx, ALuint ridx, const ALfloat *data, ALuint Offset,
-                                    const ALuint IrSize, ALfloat (*restrict Coeffs)[2],
-                                    ALfloat (*restrict Values)[2], ALuint BufferSize);
+                             const ALfloat (*restrict data)[BUFFERSIZE], ALsizei InChans,
+                             ALsizei InPos, ALsizei BufferSize);
+typedef void (*HrtfMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                              const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+                              const ALsizei IrSize, MixHrtfParams *hrtfparams,
+                              HrtfState *hrtfstate, ALsizei BufferSize);
+typedef void (*HrtfMixerBlendFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                                   const ALfloat *data, ALsizei Offset, ALsizei OutPos,
+                                   const ALsizei IrSize, const HrtfParams *oldparams,
+                                   MixHrtfParams *newparams, HrtfState *hrtfstate,
+                                   ALsizei BufferSize);
+typedef void (*HrtfDirectMixerFunc)(ALfloat *restrict LeftOut, ALfloat *restrict RightOut,
+                                    const ALfloat *data, ALsizei Offset, const ALsizei IrSize,
+                                    const ALfloat (*restrict Coeffs)[2],
+                                    ALfloat (*restrict Values)[2], ALsizei BufferSize);
 
 
 
 
 #define GAIN_MIX_MAX  (16.0f) /* +24dB */
 #define GAIN_MIX_MAX  (16.0f) /* +24dB */
@@ -176,6 +334,9 @@ typedef void (*HrtfDirectMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE],
 #define SPEEDOFSOUNDMETRESPERSEC  (343.3f)
 #define SPEEDOFSOUNDMETRESPERSEC  (343.3f)
 #define AIRABSORBGAINHF           (0.99426f) /* -0.05dB */
 #define AIRABSORBGAINHF           (0.99426f) /* -0.05dB */
 
 
+/* Target gain for the reverb decay feedback reaching the decay time. */
+#define REVERB_DECAY_GAIN  (0.001f) /* -60 dB */
+
 #define FRACTIONBITS (12)
 #define FRACTIONBITS (12)
 #define FRACTIONONE  (1<<FRACTIONBITS)
 #define FRACTIONONE  (1<<FRACTIONBITS)
 #define FRACTIONMASK (FRACTIONONE-1)
 #define FRACTIONMASK (FRACTIONONE-1)
@@ -223,30 +384,26 @@ inline ALuint64 maxu64(ALuint64 a, ALuint64 b)
 inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
 inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
 { return minu64(max, maxu64(min, val)); }
 { 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 size_t minz(size_t a, size_t b)
+{ return ((a > b) ? b : a); }
+inline size_t maxz(size_t a, size_t b)
+{ return ((a > b) ? a : b); }
+inline size_t clampz(size_t val, size_t min, size_t max)
+{ return minz(max, maxz(min, val)); }
 
 
 
 
 inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
 inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
 {
 {
     return val1 + (val2-val1)*mu;
     return val1 + (val2-val1)*mu;
 }
 }
-inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac)
-{
-    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)
+inline ALfloat cubic(ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat mu)
 {
 {
-    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;
+    ALfloat mu2 = mu*mu, mu3 = mu2*mu;
+    ALfloat a0 = -0.5f*mu3 +       mu2 + -0.5f*mu;
+    ALfloat a1 =  1.5f*mu3 + -2.5f*mu2            + 1.0f;
+    ALfloat a2 = -1.5f*mu3 +  2.0f*mu2 +  0.5f*mu;
+    ALfloat a3 =  0.5f*mu3 + -0.5f*mu2;
+    return val1*a0 + val2*a1 + val3*a2 + val4*a3;
 }
 }
 
 
 
 
@@ -256,11 +413,11 @@ enum HrtfRequestMode {
     Hrtf_Disable = 2,
     Hrtf_Disable = 2,
 };
 };
 
 
+void aluInit(void);
 
 
 void aluInitMixer(void);
 void aluInitMixer(void);
 
 
-MixerFunc SelectMixer(void);
-RowMixerFunc SelectRowMixer(void);
+ResamplerFunc SelectResampler(enum Resampler resampler);
 
 
 /* aluInitRenderer
 /* aluInitRenderer
  *
  *
@@ -271,6 +428,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
 
 
 void aluInitEffectPanning(struct ALeffectslot *slot);
 void aluInitEffectPanning(struct ALeffectslot *slot);
 
 
+void aluSelectPostProcess(ALCdevice *device);
+
 /**
 /**
  * CalcDirectionCoeffs
  * CalcDirectionCoeffs
  *
  *
@@ -281,55 +440,52 @@ void aluInitEffectPanning(struct ALeffectslot *slot);
 void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
 void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
 
 
 /**
 /**
- * CalcXYZCoeffs
+ * CalcAngleCoeffs
  *
  *
- * Same as CalcDirectionCoeffs except the direction is specified as separate x,
- * y, and z parameters instead of an array.
+ * Calculates ambisonic coefficients based on azimuth and elevation. The
+ * azimuth and elevation parameters are in radians, going right and up
+ * respectively.
  */
  */
-inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
+inline void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
 {
 {
-    ALfloat dir[3] = { x, y, z };
+    ALfloat dir[3] = {
+        sinf(azimuth) * cosf(elevation),
+        sinf(elevation),
+        -cosf(azimuth) * cosf(elevation)
+    };
     CalcDirectionCoeffs(dir, spread, coeffs);
     CalcDirectionCoeffs(dir, spread, coeffs);
 }
 }
 
 
 /**
 /**
- * CalcAngleCoeffs
+ * CalcAnglePairwiseCoeffs
  *
  *
  * Calculates ambisonic coefficients based on azimuth and elevation. The
  * Calculates ambisonic coefficients based on azimuth and elevation. The
  * azimuth and elevation parameters are in radians, going right and up
  * azimuth and elevation parameters are in radians, going right and up
- * respectively.
+ * respectively. This pairwise variant warps the result such that +30 azimuth
+ * is full right, and -30 azimuth is full left.
  */
  */
-void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
+void CalcAnglePairwiseCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
 
 
-/**
- * ComputeAmbientGains
- *
- * Computes channel gains for ambient, omni-directional sounds.
- */
-#define ComputeAmbientGains(b, g, o) do {                                     \
-    if((b).CoeffCount > 0)                                                    \
-        ComputeAmbientGainsMC((b).Ambi.Coeffs, (b).NumChannels, g, o);        \
-    else                                                                      \
-        ComputeAmbientGainsBF((b).Ambi.Map, (b).NumChannels, g, o);           \
-} while (0)
-void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
-void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
 
 
+void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
 /**
 /**
- * ComputePanningGains
+ * ComputeDryPanGains
  *
  *
  * Computes panning gains using the given channel decoder coefficients and the
  * Computes panning gains using the given channel decoder coefficients and the
  * pre-calculated direction or angle coefficients.
  * pre-calculated direction or angle coefficients.
  */
  */
-#define ComputePanningGains(b, c, g, o) do {                                  \
-    if((b).CoeffCount > 0)                                                    \
-        ComputePanningGainsMC((b).Ambi.Coeffs, (b).NumChannels, (b).CoeffCount, c, g, o);\
-    else                                                                      \
-        ComputePanningGainsBF((b).Ambi.Map, (b).NumChannels, c, g, o);        \
-} while (0)
-void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
-void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+inline void ComputeDryPanGains(const DryMixParams *dry, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
+{
+    if(dry->CoeffCount > 0)
+        ComputePanningGainsMC(dry->Ambi.Coeffs, dry->NumChannels, dry->CoeffCount,
+                              coeffs, ingain, gains);
+    else
+        ComputePanningGainsBF(dry->Ambi.Map, dry->NumChannels, coeffs, ingain, gains);
+}
 
 
+void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
 /**
 /**
  * ComputeFirstOrderGains
  * ComputeFirstOrderGains
  *
  *
@@ -337,24 +493,29 @@ void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, cons
  * a 1x4 'slice' of a transform matrix for the input channel, used to scale and
  * a 1x4 'slice' of a transform matrix for the input channel, used to scale and
  * orient the sound samples.
  * orient the sound samples.
  */
  */
-#define ComputeFirstOrderGains(b, m, g, o) do {                               \
-    if((b).CoeffCount > 0)                                                    \
-        ComputeFirstOrderGainsMC((b).Ambi.Coeffs, (b).NumChannels, m, g, o);  \
-    else                                                                      \
-        ComputeFirstOrderGainsBF((b).Ambi.Map, (b).NumChannels, m, g, o);     \
-} while (0)
-void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
-void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+inline void ComputeFirstOrderGains(const BFMixParams *foa, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
+{
+    if(foa->CoeffCount > 0)
+        ComputeFirstOrderGainsMC(foa->Ambi.Coeffs, foa->NumChannels, mtx, ingain, gains);
+    else
+        ComputeFirstOrderGainsBF(foa->Ambi.Map, foa->NumChannels, mtx, ingain, gains);
+}
+
+
+ALboolean MixSource(struct ALvoice *voice, ALuint SourceID, ALCcontext *Context, ALsizei SamplesToDo);
 
 
+void aluMixData(ALCdevice *device, ALvoid *OutBuffer, ALsizei NumSamples);
+/* Caller must lock the device, and the mixer must not be running. */
+void aluHandleDisconnect(ALCdevice *device, const char *msg, ...) DECL_FORMAT(printf, 2, 3);
 
 
-ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo);
+void UpdateContextProps(ALCcontext *context);
 
 
-ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
-/* Caller must lock the device. */
-ALvoid aluHandleDisconnect(ALCdevice *device);
+extern MixerFunc MixSamples;
+extern RowMixerFunc MixRowSamples;
 
 
 extern ALfloat ConeScale;
 extern ALfloat ConeScale;
 extern ALfloat ZScale;
 extern ALfloat ZScale;
+extern ALboolean OverrideReverbSpeedOfSound;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 1 - 1
Engine/lib/openal-soft/OpenAL32/Include/bs2b.h

@@ -85,7 +85,7 @@ int bs2b_get_srate(struct bs2b *bs2b);
 /* Clear buffer */
 /* Clear buffer */
 void bs2b_clear(struct bs2b *bs2b);
 void bs2b_clear(struct bs2b *bs2b);
 
 
-void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, unsigned int SamplesToDo);
+void bs2b_cross_feed(struct bs2b *bs2b, float *restrict Left, float *restrict Right, int SamplesToDo);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }    /* extern "C" */
 }    /* extern "C" */

Някои файлове не бяха показани, защото твърде много файлове са промени