Browse Source

Added missing changes to the OpenAL-Soft update.

Alex Szpakowski 10 years ago
parent
commit
e9d77ef766
94 changed files with 8302 additions and 5351 deletions
  1. 1 1
      CMakeLists.txt
  2. 491 262
      libs/openal-soft/Alc/ALc.c
  3. 546 286
      libs/openal-soft/Alc/ALu.c
  4. 86 35
      libs/openal-soft/Alc/alcConfig.c
  5. 274 2
      libs/openal-soft/Alc/alcRing.c
  6. 4 1
      libs/openal-soft/Alc/alstring.h
  7. 16 23
      libs/openal-soft/Alc/backends/alsa.c
  8. 4 21
      libs/openal-soft/Alc/backends/base.c
  9. 5 0
      libs/openal-soft/Alc/backends/base.h
  10. 10 5
      libs/openal-soft/Alc/backends/coreaudio.c
  11. 45 40
      libs/openal-soft/Alc/backends/dsound.c
  12. 3 8
      libs/openal-soft/Alc/backends/loopback.c
  13. 733 70
      libs/openal-soft/Alc/backends/mmdevapi.c
  14. 4 9
      libs/openal-soft/Alc/backends/null.c
  15. 16 7
      libs/openal-soft/Alc/backends/opensl.c
  16. 9 19
      libs/openal-soft/Alc/backends/oss.c
  17. 259 155
      libs/openal-soft/Alc/backends/portaudio.c
  18. 165 140
      libs/openal-soft/Alc/backends/pulseaudio.c
  19. 108 352
      libs/openal-soft/Alc/backends/qsa.c
  20. 3 4
      libs/openal-soft/Alc/backends/sndio.c
  21. 132 82
      libs/openal-soft/Alc/backends/solaris.c
  22. 195 130
      libs/openal-soft/Alc/backends/wave.c
  23. 365 311
      libs/openal-soft/Alc/backends/winmm.c
  24. 6 17
      libs/openal-soft/Alc/bs2b.c
  25. 12 14
      libs/openal-soft/Alc/effects/autowah.c
  26. 14 12
      libs/openal-soft/Alc/effects/chorus.c
  27. 11 14
      libs/openal-soft/Alc/effects/compressor.c
  28. 28 14
      libs/openal-soft/Alc/effects/dedicated.c
  29. 18 20
      libs/openal-soft/Alc/effects/distortion.c
  30. 18 16
      libs/openal-soft/Alc/effects/echo.c
  31. 30 23
      libs/openal-soft/Alc/effects/equalizer.c
  32. 14 12
      libs/openal-soft/Alc/effects/flanger.c
  33. 16 17
      libs/openal-soft/Alc/effects/modulator.c
  34. 1 4
      libs/openal-soft/Alc/effects/null.c
  35. 417 395
      libs/openal-soft/Alc/effects/reverb.c
  36. 655 93
      libs/openal-soft/Alc/helpers.c
  37. 255 175
      libs/openal-soft/Alc/hrtf.c
  38. 16 4
      libs/openal-soft/Alc/hrtf.h
  39. 253 125
      libs/openal-soft/Alc/mixer.c
  40. 69 14
      libs/openal-soft/Alc/mixer_c.c
  41. 22 7
      libs/openal-soft/Alc/mixer_defs.h
  42. 18 32
      libs/openal-soft/Alc/mixer_inc.c
  43. 32 11
      libs/openal-soft/Alc/mixer_neon.c
  44. 99 22
      libs/openal-soft/Alc/mixer_sse.c
  45. 6 3
      libs/openal-soft/Alc/mixer_sse2.c
  46. 145 3
      libs/openal-soft/Alc/mixer_sse41.c
  47. 452 345
      libs/openal-soft/Alc/panning.c
  48. 26 8
      libs/openal-soft/Alc/vector.h
  49. 167 117
      libs/openal-soft/CMakeLists.txt
  50. 10 13
      libs/openal-soft/COPYING
  51. 58 0
      libs/openal-soft/ChangeLog
  52. 2 2
      libs/openal-soft/OpenAL32/Include/alAuxEffectSlot.h
  53. 6 2
      libs/openal-soft/OpenAL32/Include/alBuffer.h
  54. 0 1
      libs/openal-soft/OpenAL32/Include/alEffect.h
  55. 37 8
      libs/openal-soft/OpenAL32/Include/alFilter.h
  56. 5 4
      libs/openal-soft/OpenAL32/Include/alListener.h
  57. 135 289
      libs/openal-soft/OpenAL32/Include/alMain.h
  58. 14 13
      libs/openal-soft/OpenAL32/Include/alSource.h
  59. 158 64
      libs/openal-soft/OpenAL32/Include/alu.h
  60. 4 7
      libs/openal-soft/OpenAL32/Include/bs2b.h
  61. 2 2
      libs/openal-soft/OpenAL32/alAuxEffectSlot.c
  62. 41 11
      libs/openal-soft/OpenAL32/alBuffer.c
  63. 16 2
      libs/openal-soft/OpenAL32/alEffect.c
  64. 2 2
      libs/openal-soft/OpenAL32/alError.c
  65. 2 2
      libs/openal-soft/OpenAL32/alExtension.c
  66. 57 37
      libs/openal-soft/OpenAL32/alFilter.c
  67. 16 20
      libs/openal-soft/OpenAL32/alListener.c
  68. 410 345
      libs/openal-soft/OpenAL32/alSource.c
  69. 5 172
      libs/openal-soft/OpenAL32/alState.c
  70. 28 14
      libs/openal-soft/OpenAL32/alThunk.c
  71. 6 4
      libs/openal-soft/README
  72. 12 5
      libs/openal-soft/XCompile.txt
  73. 123 125
      libs/openal-soft/alsoftrc.sample
  74. 2 2
      libs/openal-soft/cmake/CheckFileOffsetBits.cmake
  75. 7 7
      libs/openal-soft/cmake/CheckSharedFunctionExists.cmake
  76. 4 2
      libs/openal-soft/cmake/FindDSound.cmake
  77. 218 169
      libs/openal-soft/cmake/FindSDL_sound.cmake
  78. 5 5
      libs/openal-soft/common/threads.c
  79. 10 12
      libs/openal-soft/config.h.in
  80. 10 0
      libs/openal-soft/env-vars.txt
  81. 64 10
      libs/openal-soft/examples/alffplay.c
  82. 3 3
      libs/openal-soft/examples/alloopback.c
  83. 1 1
      libs/openal-soft/hrtf.txt
  84. 40 2
      libs/openal-soft/include/AL/alext.h
  85. 1 1
      libs/openal-soft/include/AL/efx-presets.h
  86. 4 4
      libs/openal-soft/include/align.h
  87. 99 78
      libs/openal-soft/include/atomic.h
  88. 4 0
      libs/openal-soft/include/static_assert.h
  89. 1 1
      libs/openal-soft/include/threads.h
  90. 237 70
      libs/openal-soft/utils/alsoft-config/mainwindow.cpp
  91. 0 4
      libs/openal-soft/utils/alsoft-config/mainwindow.h
  92. 138 263
      libs/openal-soft/utils/alsoft-config/mainwindow.ui
  93. 1 93
      libs/openal-soft/utils/makehrtf.c
  94. 30 0
      libs/openal-soft/utils/openal-info.c

+ 1 - 1
CMakeLists.txt

@@ -138,7 +138,7 @@ set(MEGA_LIBTHEORA_VER "1.1")
 set(MEGA_MPG123_VER "1.15.3")
 set(MEGA_FREETYPE_VER "2.5.0.1")
 set(MEGA_SDL2_VER "2.0.3-dba168c67bea")
-set(MEGA_OPENAL_VER "1.16.0")
+set(MEGA_OPENAL_VER "1.17.0")
 set(MEGA_MODPLUG_VER "0.8.8.4")
 
 set(SKIP_INSTALL_ALL TRUE)

File diff suppressed because it is too large
+ 491 - 262
libs/openal-soft/Alc/ALc.c


File diff suppressed because it is too large
+ 546 - 286
libs/openal-soft/Alc/ALu.c


+ 86 - 35
libs/openal-soft/Alc/alcConfig.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -33,11 +33,13 @@
 #include <ctype.h>
 #include <string.h>
 #ifdef _WIN32_IE
+#include <windows.h>
 #include <shlobj.h>
 #endif
 
 #include "alMain.h"
 #include "compat.h"
+#include "bool.h"
 
 
 typedef struct ConfigEntry {
@@ -137,13 +139,21 @@ static char *expdup(const char *str)
             }
             else
             {
+                bool hasbraces;
                 char envname[1024];
                 size_t k = 0;
 
+                hasbraces = (*str == '{');
+                if(hasbraces) str++;
+
                 while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1)
                     envname[k++] = *(str++);
                 envname[k++] = '\0';
 
+                if(hasbraces && *str != '}')
+                    continue;
+
+                if(hasbraces) str++;
                 if((addstr=getenv(envname)) == NULL)
                     continue;
                 addstrlen = strlen(addstr);
@@ -192,12 +202,8 @@ static void LoadConfigFromFile(FILE *f)
         char key[256] = "";
         char value[256] = "";
 
-        comment = strchr(buffer, '#');
-        if(comment) *(comment++) = 0;
-
         line = rstrip(lstrip(buffer));
-        if(!line[0])
-            continue;
+        if(!line[0]) continue;
 
         if(line[0] == '[')
         {
@@ -205,10 +211,21 @@ static void LoadConfigFromFile(FILE *f)
             char *endsection;
 
             endsection = strchr(section, ']');
-            if(!endsection || section == endsection || endsection[1] != 0)
+            if(!endsection || section == endsection)
             {
-                 ERR("config parse error: bad line \"%s\"\n", line);
-                 continue;
+                ERR("config parse error: bad line \"%s\"\n", line);
+                continue;
+            }
+            if(endsection[1] != 0)
+            {
+                char *end = endsection+1;
+                while(isspace(*end))
+                    ++end;
+                if(*end != 0 && *end != '#')
+                {
+                    ERR("config parse error: bad line \"%s\"\n", line);
+                    continue;
+                }
             }
             *endsection = 0;
 
@@ -223,6 +240,10 @@ static void LoadConfigFromFile(FILE *f)
             continue;
         }
 
+        comment = strchr(line, '#');
+        if(comment) *(comment++) = 0;
+        if(!line[0]) continue;
+
         if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 ||
            sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 ||
            sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2)
@@ -296,27 +317,33 @@ void ReadALConfig(void)
 
     if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
     {
-        size_t p = lstrlenW(buffer);
-        _snwprintf(buffer+p, PATH_MAX-p, L"\\alsoft.ini");
+        al_string filepath = AL_STRING_INIT_STATIC();
+        al_string_copy_wcstr(&filepath, buffer);
+        al_string_append_cstr(&filepath, "\\alsoft.ini");
 
-        TRACE("Loading config %ls...\n", buffer);
-        f = _wfopen(buffer, L"rt");
+        TRACE("Loading config %s...\n", al_string_get_cstr(filepath));
+        f = al_fopen(al_string_get_cstr(filepath), "rt");
         if(f)
         {
             LoadConfigFromFile(f);
             fclose(f);
         }
+        al_string_deinit(&filepath);
     }
 
     if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str)
     {
-        TRACE("Loading config %ls...\n", str);
-        f = _wfopen(str, L"rt");
+        al_string filepath = AL_STRING_INIT_STATIC();
+        al_string_copy_wcstr(&filepath, str);
+
+        TRACE("Loading config %s...\n", al_string_get_cstr(filepath));
+        f = al_fopen(al_string_get_cstr(filepath), "rt");
         if(f)
         {
             LoadConfigFromFile(f);
             fclose(f);
         }
+        al_string_deinit(&filepath);
     }
 }
 #else
@@ -428,7 +455,7 @@ void FreeALConfig(void)
     free(cfgBlock.entries);
 }
 
-const char *GetConfigValue(const char *blockName, const char *keyName, const char *def)
+const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def)
 {
     unsigned int i;
     char key[256];
@@ -437,16 +464,26 @@ const char *GetConfigValue(const char *blockName, const char *keyName, const cha
         return def;
 
     if(blockName && strcasecmp(blockName, "general") != 0)
-        snprintf(key, sizeof(key), "%s/%s", blockName, keyName);
+    {
+        if(devName)
+            snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName);
+        else
+            snprintf(key, sizeof(key), "%s/%s", blockName, keyName);
+    }
     else
     {
-        strncpy(key, keyName, sizeof(key)-1);
-        key[sizeof(key)-1] = 0;
+        if(devName)
+            snprintf(key, sizeof(key), "%s/%s", devName, keyName);
+        else
+        {
+            strncpy(key, keyName, sizeof(key)-1);
+            key[sizeof(key)-1] = 0;
+        }
     }
 
     for(i = 0;i < cfgBlock.entryCount;i++)
     {
-        if(strcasecmp(cfgBlock.entries[i].key, key) == 0)
+        if(strcmp(cfgBlock.entries[i].key, key) == 0)
         {
             TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value);
             if(cfgBlock.entries[i].value[0])
@@ -455,46 +492,50 @@ const char *GetConfigValue(const char *blockName, const char *keyName, const cha
         }
     }
 
-    TRACE("Key %s not found\n", key);
-    return def;
+    if(!devName)
+    {
+        TRACE("Key %s not found\n", key);
+        return def;
+    }
+    return GetConfigValue(NULL, blockName, keyName, def);
 }
 
-int ConfigValueExists(const char *blockName, const char *keyName)
+int ConfigValueExists(const char *devName, const char *blockName, const char *keyName)
 {
-    const char *val = GetConfigValue(blockName, keyName, "");
+    const char *val = GetConfigValue(devName, blockName, keyName, "");
     return !!val[0];
 }
 
-int ConfigValueStr(const char *blockName, const char *keyName, const char **ret)
+int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret)
 {
-    const char *val = GetConfigValue(blockName, keyName, "");
+    const char *val = GetConfigValue(devName, blockName, keyName, "");
     if(!val[0]) return 0;
 
     *ret = val;
     return 1;
 }
 
-int ConfigValueInt(const char *blockName, const char *keyName, int *ret)
+int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret)
 {
-    const char *val = GetConfigValue(blockName, keyName, "");
+    const char *val = GetConfigValue(devName, blockName, keyName, "");
     if(!val[0]) return 0;
 
     *ret = strtol(val, NULL, 0);
     return 1;
 }
 
-int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret)
+int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret)
 {
-    const char *val = GetConfigValue(blockName, keyName, "");
+    const char *val = GetConfigValue(devName, blockName, keyName, "");
     if(!val[0]) return 0;
 
     *ret = strtoul(val, NULL, 0);
     return 1;
 }
 
-int ConfigValueFloat(const char *blockName, const char *keyName, float *ret)
+int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret)
 {
-    const char *val = GetConfigValue(blockName, keyName, "");
+    const char *val = GetConfigValue(devName, blockName, keyName, "");
     if(!val[0]) return 0;
 
 #ifdef HAVE_STRTOF
@@ -505,9 +546,19 @@ int ConfigValueFloat(const char *blockName, const char *keyName, float *ret)
     return 1;
 }
 
-int GetConfigValueBool(const char *blockName, const char *keyName, int def)
+int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret)
+{
+    const char *val = GetConfigValue(devName, blockName, keyName, "");
+    if(!val[0]) return 0;
+
+    *ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
+            strcasecmp(val, "on") == 0 || atoi(val) != 0);
+    return 1;
+}
+
+int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def)
 {
-    const char *val = GetConfigValue(blockName, keyName, "");
+    const char *val = GetConfigValue(devName, blockName, keyName, "");
 
     if(!val[0]) return !!def;
     return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||

+ 274 - 2
libs/openal-soft/Alc/alcRing.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -127,3 +127,275 @@ void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
 
     almtx_unlock(&ring->mtx);
 }
+
+
+/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended
+ * to include an element size. Consequently, parameters and return values for a
+ * size or count is in 'elements', not bytes. Additionally, it only supports
+ * single-consumer/single-provider operation. */
+struct ll_ringbuffer {
+    volatile size_t write_ptr;
+    volatile size_t read_ptr;
+    size_t size;
+    size_t size_mask;
+    size_t elem_size;
+    int mlocked;
+
+    alignas(16) char buf[];
+};
+
+/* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes.
+ * The number of elements is rounded up to the next power of two. */
+ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz)
+{
+    ll_ringbuffer_t *rb;
+    ALuint power_of_two;
+
+    power_of_two = NextPowerOf2(sz);
+    if(power_of_two < sz)
+        return NULL;
+
+    rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz);
+    if(!rb) return NULL;
+
+    rb->size = power_of_two;
+    rb->size_mask = rb->size - 1;
+    rb->elem_size = elem_sz;
+    rb->write_ptr = 0;
+    rb->read_ptr = 0;
+    rb->mlocked = 0;
+    return rb;
+}
+
+/* Free all data associated with the ringbuffer `rb'. */
+void ll_ringbuffer_free(ll_ringbuffer_t *rb)
+{
+    if(rb)
+    {
+#ifdef USE_MLOCK
+        if(rb->mlocked)
+            munlock(rb, sizeof(*rb) + rb->size*rb->elem_size);
+#endif /* USE_MLOCK */
+        al_free(rb);
+    }
+}
+
+/* Lock the data block of `rb' using the system call 'mlock'. */
+int ll_ringbuffer_mlock(ll_ringbuffer_t *rb)
+{
+#ifdef USE_MLOCK
+    if(!rb->locked && mlock(rb, sizeof(*rb) + rb->size*rb->elem_size))
+        return -1;
+#endif /* USE_MLOCK */
+    rb->mlocked = 1;
+    return 0;
+}
+
+/* Reset the read and write pointers to zero. This is not thread safe. */
+void ll_ringbuffer_reset(ll_ringbuffer_t *rb)
+{
+    rb->read_ptr = 0;
+    rb->write_ptr = 0;
+    memset(rb->buf, 0, rb->size*rb->elem_size);
+}
+
+/* Return the number of elements available for reading. This is the number of
+ * elements in front of the read pointer and behind the write pointer. */
+size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb)
+{
+    size_t w = rb->write_ptr;
+    size_t r = rb->read_ptr;
+    return (rb->size+w-r) & rb->size_mask;
+}
+/* Return the number of elements available for writing. This is the number of
+ * elements in front of the write pointer and behind the read pointer. */
+size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb)
+{
+    size_t w = rb->write_ptr;
+    size_t r = rb->read_ptr;
+    return (rb->size+r-w-1) & rb->size_mask;
+}
+
+/* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'.
+ * Returns the actual number of elements copied. */
+size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt)
+{
+    size_t free_cnt;
+    size_t cnt2;
+    size_t to_read;
+    size_t n1, n2;
+
+    free_cnt = ll_ringbuffer_read_space(rb);
+    if(free_cnt == 0) return 0;
+
+    to_read = (cnt > free_cnt) ? free_cnt : cnt;
+    cnt2 = rb->read_ptr + to_read;
+    if(cnt2 > rb->size)
+    {
+        n1 = rb->size - rb->read_ptr;
+        n2 = cnt2 & rb->size_mask;
+    }
+    else
+    {
+        n1 = to_read;
+        n2 = 0;
+    }
+
+    memcpy(dest, &(rb->buf[rb->read_ptr*rb->elem_size]), n1*rb->elem_size);
+    rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
+    if(n2)
+    {
+        memcpy(dest + n1*rb->elem_size, &(rb->buf[rb->read_ptr*rb->elem_size]), n2*rb->elem_size);
+        rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
+    }
+    return to_read;
+}
+
+/* The copying data reader w/o read pointer advance. Copy at most `cnt'
+ * elements from `rb' to `dest'. Returns the actual number of elements copied.
+ */
+size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt)
+{
+    size_t free_cnt;
+    size_t cnt2;
+    size_t to_read;
+    size_t n1, n2;
+    size_t tmp_read_ptr;
+
+    tmp_read_ptr = rb->read_ptr;
+    free_cnt = ll_ringbuffer_read_space(rb);
+    if(free_cnt == 0) return 0;
+
+    to_read = (cnt > free_cnt) ? free_cnt : cnt;
+    cnt2 = tmp_read_ptr + to_read;
+    if(cnt2 > rb->size)
+    {
+        n1 = rb->size - tmp_read_ptr;
+        n2 = cnt2 & rb->size_mask;
+    }
+    else
+    {
+        n1 = to_read;
+        n2 = 0;
+    }
+
+    memcpy(dest, &(rb->buf[tmp_read_ptr*rb->elem_size]), n1*rb->elem_size);
+    tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
+    if(n2)
+        memcpy(dest + n1*rb->elem_size, &(rb->buf[tmp_read_ptr*rb->elem_size]), n2*rb->elem_size);
+    return to_read;
+}
+
+/* The copying data writer. Copy at most `cnt' elements to `rb' from `src'.
+ * Returns the actual number of elements copied. */
+size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt)
+{
+    size_t free_cnt;
+    size_t cnt2;
+    size_t to_write;
+    size_t n1, n2;
+
+    free_cnt = ll_ringbuffer_write_space(rb);
+    if(free_cnt == 0) return 0;
+
+    to_write = (cnt > free_cnt) ? free_cnt : cnt;
+    cnt2 = rb->write_ptr + to_write;
+    if(cnt2 > rb->size)
+    {
+        n1 = rb->size - rb->write_ptr;
+        n2 = cnt2 & rb->size_mask;
+    }
+    else
+    {
+        n1 = to_write;
+        n2 = 0;
+    }
+
+    memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src, n1*rb->elem_size);
+    rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
+    if(n2)
+    {
+        memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src + n1*rb->elem_size, n2*rb->elem_size);
+        rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
+    }
+    return to_write;
+}
+
+/* Advance the read pointer `cnt' places. */
+void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt)
+{
+    size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
+    rb->read_ptr = tmp;
+}
+
+/* Advance the write pointer `cnt' places. */
+void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt)
+{
+    size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
+    rb->write_ptr = tmp;
+}
+
+/* The non-copying data reader. `vec' is an array of two places. Set the values
+ * at `vec' to hold the current readable data at `rb'. If the readable data is
+ * in one segment the second segment has zero length. */
+void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t * vec)
+{
+    size_t free_cnt;
+    size_t cnt2;
+    size_t w, r;
+
+    w = rb->write_ptr;
+    r = rb->read_ptr;
+    free_cnt = (rb->size+w-r) & rb->size_mask;
+
+    cnt2 = r + free_cnt;
+    if(cnt2 > rb->size)
+    {
+        /* Two part vector: the rest of the buffer after the current write ptr,
+         * plus some from the start of the buffer. */
+        vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]);
+        vec[0].len = rb->size - r;
+        vec[1].buf = (char*)rb->buf;
+        vec[1].len = cnt2 & rb->size_mask;
+    }
+    else
+    {
+        /* Single part vector: just the rest of the buffer */
+        vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]);
+        vec[0].len = free_cnt;
+        vec[1].buf = NULL;
+        vec[1].len = 0;
+    }
+}
+
+/* The non-copying data writer. `vec' is an array of two places. Set the values
+ * at `vec' to hold the current writeable data at `rb'. If the writeable data
+ * is in one segment the second segment has zero length. */
+void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec)
+{
+    size_t free_cnt;
+    size_t cnt2;
+    size_t w, r;
+
+    w = rb->write_ptr;
+    r = rb->read_ptr;
+    free_cnt = (rb->size+r-w-1) & rb->size_mask;
+
+    cnt2 = w + free_cnt;
+    if(cnt2 > rb->size)
+    {
+        /* Two part vector: the rest of the buffer after the current write ptr,
+         * plus some from the start of the buffer. */
+        vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]);
+        vec[0].len = rb->size - w;
+        vec[1].buf = (char*)rb->buf;
+        vec[1].len = cnt2 & rb->size_mask;
+    }
+    else
+    {
+        vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]);
+        vec[0].len = free_cnt;
+        vec[1].buf = NULL;
+        vec[1].len = 0;
+    }
+}

+ 4 - 1
libs/openal-soft/Alc/alstring.h

@@ -8,6 +8,7 @@
 
 typedef char al_string_char_type;
 TYPEDEF_VECTOR(al_string_char_type, al_string)
+TYPEDEF_VECTOR(al_string, vector_al_string)
 
 inline void al_string_deinit(al_string *str)
 { VECTOR_DEINIT(*str); }
@@ -15,7 +16,7 @@ inline void al_string_deinit(al_string *str)
 #define AL_STRING_INIT_STATIC()  ((al_string)NULL)
 #define AL_STRING_DEINIT(_x)     al_string_deinit(&(_x))
 
-inline ALsizei al_string_length(const_al_string str)
+inline size_t al_string_length(const_al_string str)
 { return VECTOR_SIZE(str); }
 
 inline ALboolean al_string_empty(const_al_string str)
@@ -40,6 +41,8 @@ void al_string_append_range(al_string *str, const al_string_char_type *from, con
 #include <wchar.h>
 /* Windows-only methods to deal with WideChar strings. */
 void al_string_copy_wcstr(al_string *str, const wchar_t *from);
+void al_string_append_wcstr(al_string *str, const wchar_t *from);
+void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to);
 #endif
 
 #endif /* ALSTRING_H */

+ 16 - 23
libs/openal-soft/Alc/backends/alsa.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -273,14 +273,14 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.device_name);
     al_string_copy_cstr(&entry.name, alsaDevice);
-    al_string_copy_cstr(&entry.device_name, GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
+    al_string_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ?
                                                            "device" : "capture", "default"));
     VECTOR_PUSH_BACK(*DeviceList, entry);
 
     card = -1;
     if((err=snd_card_next(&card)) < 0)
         ERR("Failed to find a card: %s\n", snd_strerror(err));
-    ConfigValueStr("alsa", prefix_name(stream), &main_prefix);
+    ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix);
     while(card >= 0)
     {
         const char *card_prefix = main_prefix;
@@ -304,7 +304,7 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
         cardid = snd_ctl_card_info_get_id(info);
 
         snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid);
-        ConfigValueStr("alsa", name, &card_prefix);
+        ConfigValueStr(NULL, "alsa", name, &card_prefix);
 
         dev = -1;
         while(1)
@@ -330,7 +330,7 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList)
             devname = snd_pcm_info_get_name(pcminfo);
 
             snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev);
-            ConfigValueStr("alsa", name, &device_prefix);
+            ConfigValueStr(NULL, "alsa", name, &device_prefix);
 
             snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)",
                         cardname, devname, cardid, dev);
@@ -640,7 +640,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name)
     else
     {
         name = alsaDevice;
-        driver = GetConfigValue("alsa", "device", "default");
+        driver = GetConfigValue(NULL, "alsa", "device", "default");
     }
 
     TRACE("Opening device \"%s\"\n", driver);
@@ -704,7 +704,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
             break;
     }
 
-    allowmmap = GetConfigValueBool("alsa", "mmap", 1);
+    allowmmap = GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "mmap", 1);
     periods = device->NumUpdates;
     periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
     bufferLen = periodLen * periods;
@@ -770,8 +770,11 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self)
     }
     CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans)));
     /* set rate (implicitly constrains period/buffer parameters) */
-    if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
-        ERR("Failed to disable ALSA resampler\n");
+    if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0))
+    {
+        if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0)
+            ERR("Failed to disable ALSA resampler\n");
+    }
     CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL));
     /* set buffer time (implicitly constrains period/buffer parameters) */
     if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0)
@@ -965,7 +968,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name)
     else
     {
         name = alsaDevice;
-        driver = GetConfigValue("alsa", "capture", "default");
+        driver = GetConfigValue(NULL, "alsa", "capture", "default");
     }
 
     TRACE("Opening device \"%s\"\n", driver);
@@ -1352,25 +1355,15 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN
     if(type == ALCbackend_Playback)
     {
         ALCplaybackAlsa *backend;
-
-        backend = ALCplaybackAlsa_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCplaybackAlsa)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCplaybackAlsa_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
     if(type == ALCbackend_Capture)
     {
         ALCcaptureAlsa *backend;
-
-        backend = ALCcaptureAlsa_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCcaptureAlsa)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCcaptureAlsa_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 

+ 4 - 21
libs/openal-soft/Alc/backends/base.c

@@ -77,7 +77,7 @@ static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self);
 static void PlaybackWrapper_stop(PlaybackWrapper *self);
 static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
 static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples)
-static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self);
+static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALint64, getLatency)
 static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock)
 static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock)
 DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper)
@@ -121,12 +121,6 @@ static void PlaybackWrapper_stop(PlaybackWrapper *self)
     self->Funcs->StopPlayback(device);
 }
 
-static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    return self->Funcs->GetLatency(device);
-}
-
 
 typedef struct CaptureWrapper {
     DERIVE_FROM_TYPE(ALCbackend);
@@ -143,13 +137,12 @@ static ALCboolean CaptureWrapper_start(CaptureWrapper *self);
 static void CaptureWrapper_stop(CaptureWrapper *self);
 static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples);
 static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self);
-static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self);
+static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALint64, getLatency)
 static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock)
 static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock)
 DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper)
 DEFINE_ALCBACKEND_VTABLE(CaptureWrapper);
 
-
 static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs)
 {
     ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
@@ -195,12 +188,6 @@ static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self)
     return self->Funcs->AvailableSamples(device);
 }
 
-static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self)
-{
-    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
-    return self->Funcs->GetLatency(device);
-}
-
 
 ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type)
 {
@@ -208,11 +195,9 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs,
     {
         PlaybackWrapper *backend;
 
-        backend = PlaybackWrapper_New(sizeof(*backend));
+        NEW_OBJ(backend, PlaybackWrapper)(device, funcs);
         if(!backend) return NULL;
 
-        PlaybackWrapper_Construct(backend, device, funcs);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 
@@ -220,11 +205,9 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs,
     {
         CaptureWrapper *backend;
 
-        backend = CaptureWrapper_New(sizeof(*backend));
+        NEW_OBJ(backend, CaptureWrapper)(device, funcs);
         if(!backend) return NULL;
 
-        CaptureWrapper_Construct(backend, device, funcs);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 

+ 5 - 0
libs/openal-soft/Alc/backends/base.h

@@ -123,9 +123,14 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = {  \
 ALCbackendFactory *ALCpulseBackendFactory_getFactory(void);
 ALCbackendFactory *ALCalsaBackendFactory_getFactory(void);
 ALCbackendFactory *ALCossBackendFactory_getFactory(void);
+ALCbackendFactory *ALCjackBackendFactory_getFactory(void);
+ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
 ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void);
 ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
+ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void);
+ALCbackendFactory *ALCportBackendFactory_getFactory(void);
 ALCbackendFactory *ALCnullBackendFactory_getFactory(void);
+ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
 ALCbackendFactory *ALCloopbackFactory_getFactory(void);
 
 ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type);

+ 10 - 5
libs/openal-soft/Alc/backends/coreaudio.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -383,6 +383,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
     ca_data *data;
     OSStatus err;
 
+    if(!deviceName)
+        deviceName = ca_device;
+    else if(strcmp(deviceName, ca_device) != 0)
+        return ALC_INVALID_VALUE;
+
     desc.componentType = kAudioUnitType_Output;
     desc.componentSubType = kAudioUnitSubType_HALOutput;
     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
@@ -514,9 +519,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
 
         case DevFmtQuad:
         case DevFmtX51:
-        case DevFmtX51Side:
+        case DevFmtX51Rear:
         case DevFmtX61:
         case DevFmtX71:
+        case DevFmtBFormat3D:
             ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
             goto error;
     }
@@ -679,8 +685,7 @@ static const BackendFuncs ca_funcs = {
     ca_start_capture,
     ca_stop_capture,
     ca_capture_samples,
-    ca_available_samples,
-    ALCdevice_GetLatencyDefault
+    ca_available_samples
 };
 
 ALCboolean alc_ca_init(BackendFuncs *func_list)

+ 45 - 40
libs/openal-soft/Alc/backends/dsound.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -43,6 +43,9 @@
 #ifndef DSSPEAKER_5POINT1
 #   define DSSPEAKER_5POINT1          0x00000006
 #endif
+#ifndef DSSPEAKER_5POINT1_BACK
+#   define DSSPEAKER_5POINT1_BACK     0x00000006
+#endif
 #ifndef DSSPEAKER_7POINT1
 #   define DSSPEAKER_7POINT1          0x00000007
 #endif
@@ -57,6 +60,8 @@
 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
 
+#define DEVNAME_TAIL " on OpenAL Soft"
+
 
 #ifdef HAVE_DYNLOAD
 static void *ds_handle;
@@ -118,15 +123,14 @@ static void clear_devlist(vector_DevMap *list)
 {
 #define DEINIT_STR(i) AL_STRING_DEINIT((i)->name)
     VECTOR_FOR_EACH(DevMap, *list, DEINIT_STR);
-#undef DEINIT_STR
     VECTOR_RESIZE(*list, 0);
+#undef DEINIT_STR
 }
 
 static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data)
 {
     vector_DevMap *devices = data;
     OLECHAR *guidstr = NULL;
-    DevMap *iter, *end;
     DevMap entry;
     HRESULT hr;
     int count;
@@ -137,24 +141,26 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA
     AL_STRING_INIT(entry.name);
 
     count = 0;
-    do {
+    while(1)
+    {
+        const DevMap *iter;
+
         al_string_copy_wcstr(&entry.name, desc);
-        if(count != 0)
+        if(count == 0)
+            al_string_append_cstr(&entry.name, DEVNAME_TAIL);
+        else
         {
             char str[64];
-            snprintf(str, sizeof(str), " #%d", count+1);
+            snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1);
             al_string_append_cstr(&entry.name, str);
         }
-        count++;
 
-        iter = VECTOR_ITER_BEGIN(*devices);
-        end = VECTOR_ITER_END(*devices);
-        for(;iter != end;++iter)
-        {
-            if(al_string_cmp(entry.name, iter->name) == 0)
-                break;
-        }
-    } while(iter != end);
+#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+        VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY);
+        if(iter == VECTOR_ITER_END(*devices)) break;
+#undef MATCH_ENTRY
+        count++;
+    }
     entry.guid = *guid;
 
     hr = StringFromCLSID(guid, &guidstr);
@@ -441,28 +447,35 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
     hr = IDirectSound_GetSpeakerConfig(self->DS, &speakers);
     if(SUCCEEDED(hr))
     {
+        speakers = DSSPEAKER_CONFIG(speakers);
         if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
         {
-            speakers = DSSPEAKER_CONFIG(speakers);
             if(speakers == DSSPEAKER_MONO)
                 device->FmtChans = DevFmtMono;
             else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
                 device->FmtChans = DevFmtStereo;
             else if(speakers == DSSPEAKER_QUAD)
                 device->FmtChans = DevFmtQuad;
-            else if(speakers == DSSPEAKER_5POINT1 || speakers == DSSPEAKER_5POINT1_SURROUND)
+            else if(speakers == DSSPEAKER_5POINT1_SURROUND)
                 device->FmtChans = DevFmtX51;
+            else if(speakers == DSSPEAKER_5POINT1_BACK)
+                device->FmtChans = DevFmtX51Rear;
             else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND)
                 device->FmtChans = DevFmtX71;
             else
                 ERR("Unknown system speaker config: 0x%lx\n", speakers);
         }
+        device->IsHeadphones = (device->FmtChans == DevFmtStereo &&
+                                speakers == DSSPEAKER_HEADPHONE);
 
         switch(device->FmtChans)
         {
             case DevFmtMono:
                 OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
                 break;
+            case DevFmtBFormat3D:
+                device->FmtChans = DevFmtStereo;
+                /*fall-through*/
             case DevFmtStereo:
                 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                            SPEAKER_FRONT_RIGHT;
@@ -478,16 +491,16 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
                                            SPEAKER_FRONT_RIGHT |
                                            SPEAKER_FRONT_CENTER |
                                            SPEAKER_LOW_FREQUENCY |
-                                           SPEAKER_BACK_LEFT |
-                                           SPEAKER_BACK_RIGHT;
+                                           SPEAKER_SIDE_LEFT |
+                                           SPEAKER_SIDE_RIGHT;
                 break;
-            case DevFmtX51Side:
+            case DevFmtX51Rear:
                 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                            SPEAKER_FRONT_RIGHT |
                                            SPEAKER_FRONT_CENTER |
                                            SPEAKER_LOW_FREQUENCY |
-                                           SPEAKER_SIDE_LEFT |
-                                           SPEAKER_SIDE_RIGHT;
+                                           SPEAKER_BACK_LEFT |
+                                           SPEAKER_BACK_RIGHT;
                 break;
             case DevFmtX61:
                 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
@@ -745,16 +758,16 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
                                           SPEAKER_FRONT_RIGHT |
                                           SPEAKER_FRONT_CENTER |
                                           SPEAKER_LOW_FREQUENCY |
-                                          SPEAKER_BACK_LEFT |
-                                          SPEAKER_BACK_RIGHT;
+                                          SPEAKER_SIDE_LEFT |
+                                          SPEAKER_SIDE_RIGHT;
                 break;
-            case DevFmtX51Side:
+            case DevFmtX51Rear:
                 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
                                           SPEAKER_FRONT_RIGHT |
                                           SPEAKER_FRONT_CENTER |
                                           SPEAKER_LOW_FREQUENCY |
-                                          SPEAKER_SIDE_LEFT |
-                                          SPEAKER_SIDE_RIGHT;
+                                          SPEAKER_BACK_LEFT |
+                                          SPEAKER_BACK_RIGHT;
                 break;
             case DevFmtX61:
                 InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
@@ -775,6 +788,8 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi
                                           SPEAKER_SIDE_LEFT |
                                           SPEAKER_SIDE_RIGHT;
                 break;
+            case DevFmtBFormat3D:
+                break;
         }
 
         InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
@@ -1027,26 +1042,16 @@ static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory
     if(type == ALCbackend_Playback)
     {
         ALCdsoundPlayback *backend;
-
-        backend = ALCdsoundPlayback_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCdsoundPlayback)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCdsoundPlayback_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 
     if(type == ALCbackend_Capture)
     {
         ALCdsoundCapture *backend;
-
-        backend = ALCdsoundCapture_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCdsoundCapture)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCdsoundCapture_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 

+ 3 - 8
libs/openal-soft/Alc/backends/loopback.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -124,13 +124,8 @@ static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(s
     if(type == ALCbackend_Loopback)
     {
         ALCloopback *backend;
-
-        backend = ALCloopback_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCloopback)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCloopback_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 

+ 733 - 70
libs/openal-soft/Alc/backends/mmdevapi.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -51,14 +51,18 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x
 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
 
 DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
+DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
 
 #define MONO SPEAKER_FRONT_CENTER
 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
-#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
-#define X5DOT1SIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
+#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
+#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
 #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
+#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER)
+
+#define DEVNAME_TAIL " on OpenAL Soft"
 
 
 typedef struct {
@@ -69,16 +73,14 @@ TYPEDEF_VECTOR(DevMap, vector_DevMap)
 
 static void clear_devlist(vector_DevMap *list)
 {
-    DevMap *iter, *end;
-
-    iter = VECTOR_ITER_BEGIN(*list);
-    end = VECTOR_ITER_END(*list);
-    for(;iter != end;iter++)
-    {
-        AL_STRING_DEINIT(iter->name);
-        free(iter->devid);
-    }
+#define CLEAR_DEVMAP(i) do {     \
+    AL_STRING_DEINIT((i)->name); \
+    free((i)->devid);            \
+    (i)->devid = NULL;           \
+} while(0)
+    VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP);
     VECTOR_RESIZE(*list, 0);
+#undef CLEAR_DEVMAP
 }
 
 static vector_DevMap PlaybackDevices;
@@ -134,39 +136,105 @@ static void get_device_name(IMMDevice *device, al_string *name)
 
     hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname);
     if(FAILED(hr))
-        WARN("GetValue failed: 0x%08lx\n", hr);
-    else
+        WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr);
+    else if(pvname.vt == VT_LPWSTR)
         al_string_copy_wcstr(name, pvname.pwszVal);
+    else
+        WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt);
 
     PropVariantClear(&pvname);
     IPropertyStore_Release(ps);
 }
 
-static void add_device(IMMDevice *device, vector_DevMap *list)
+static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor)
 {
-    LPWSTR devid;
+    IPropertyStore *ps;
+    PROPVARIANT pvform;
     HRESULT hr;
 
-    hr = IMMDevice_GetId(device, &devid);
-    if(SUCCEEDED(hr))
+    hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
+    if(FAILED(hr))
     {
-        DevMap entry;
-        AL_STRING_INIT(entry.name);
+        WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
+        return;
+    }
+
+    PropVariantInit(&pvform);
+
+    hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_FormFactor, &pvform);
+    if(FAILED(hr))
+        WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr);
+    else if(pvform.vt == VT_UI4)
+        *formfactor = pvform.ulVal;
+    else if(pvform.vt == VT_EMPTY)
+        *formfactor = UnknownFormFactor;
+    else
+        WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt);
+
+    PropVariantClear(&pvform);
+    IPropertyStore_Release(ps);
+}
+
+
+static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list)
+{
+    int count = 0;
+    al_string tmpname;
+    DevMap entry;
+
+    AL_STRING_INIT(tmpname);
+    AL_STRING_INIT(entry.name);
+
+    entry.devid = strdupW(devid);
+    get_device_name(device, &tmpname);
+
+    while(1)
+    {
+        const DevMap *iter;
+
+        al_string_copy(&entry.name, tmpname);
+        if(count == 0)
+            al_string_append_cstr(&entry.name, DEVNAME_TAIL);
+        else
+        {
+            char str[64];
+            snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1);
+            al_string_append_cstr(&entry.name, str);
+        }
+
+#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+        VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY);
+        if(iter == VECTOR_ITER_END(*list)) break;
+#undef MATCH_ENTRY
+        count++;
+    }
 
-        entry.devid = strdupW(devid);
-        get_device_name(device, &entry.name);
+    TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
+    VECTOR_PUSH_BACK(*list, entry);
 
-        CoTaskMemFree(devid);
+    AL_STRING_DEINIT(tmpname);
+}
+
+static LPWSTR get_device_id(IMMDevice *device)
+{
+    LPWSTR devid;
+    HRESULT hr;
 
-        TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
-        VECTOR_PUSH_BACK(*list, entry);
+    hr = IMMDevice_GetId(device, &devid);
+    if(FAILED(hr))
+    {
+        ERR("Failed to get device id: %lx\n", hr);
+        return NULL;
     }
+
+    return devid;
 }
 
 static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list)
 {
     IMMDeviceCollection *coll;
     IMMDevice *defdev = NULL;
+    LPWSTR defdevid = NULL;
     HRESULT hr;
     UINT count;
     UINT i;
@@ -183,7 +251,7 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve
     if(SUCCEEDED(hr) && count > 0)
     {
         clear_devlist(list);
-        if(!VECTOR_RESERVE(*list, count+1))
+        if(!VECTOR_RESERVE(*list, count))
         {
             IMMDeviceCollection_Release(coll);
             return E_OUTOFMEMORY;
@@ -193,22 +261,32 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve
                                                          eMultimedia, &defdev);
     }
     if(SUCCEEDED(hr) && defdev != NULL)
-        add_device(defdev, list);
+    {
+        defdevid = get_device_id(defdev);
+        if(defdevid)
+            add_device(defdev, defdevid, list);
+    }
 
     for(i = 0;i < count;++i)
     {
         IMMDevice *device;
+        LPWSTR devid;
 
-        if(FAILED(IMMDeviceCollection_Item(coll, i, &device)))
-            continue;
-
-        if(device != defdev)
-            add_device(device, list);
+        hr = IMMDeviceCollection_Item(coll, i, &device);
+        if(FAILED(hr)) continue;
 
+        devid = get_device_id(device);
+        if(devid)
+        {
+            if(wcscmp(devid, defdevid) != 0)
+                add_device(device, devid, list);
+            CoTaskMemFree(devid);
+        }
         IMMDevice_Release(device);
     }
 
     if(defdev) IMMDevice_Release(defdev);
+    if(defdevid) CoTaskMemFree(defdevid);
     IMMDeviceCollection_Release(coll);
 
     return S_OK;
@@ -294,7 +372,7 @@ static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr)
     TRACE("Starting message loop\n");
     while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last))
     {
-        TRACE("Got message %u\n", msg.message);
+        TRACE("Got message %u (lparam=%p, wparam=%p)\n", msg.message, (void*)msg.lParam, (void*)msg.wParam);
         switch(msg.message)
         {
         case WM_USER_OpenDevice:
@@ -483,9 +561,9 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
     if(FAILED(hr))
     {
         ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
-        ALCdevice_Lock(device);
+        V0(device->Backend,lock)();
         aluHandleDisconnect(device);
-        ALCdevice_Unlock(device);
+        V0(device->Backend,unlock)();
         return 1;
     }
 
@@ -500,9 +578,9 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
         if(FAILED(hr))
         {
             ERR("Failed to get padding: 0x%08lx\n", hr);
-            ALCdevice_Lock(device);
+            V0(device->Backend,lock)();
             aluHandleDisconnect(device);
-            ALCdevice_Unlock(device);
+            V0(device->Backend,unlock)();
             break;
         }
         self->Padding = written;
@@ -521,18 +599,18 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
         hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer);
         if(SUCCEEDED(hr))
         {
-            ALCdevice_Lock(device);
+            V0(device->Backend,lock)();
             aluMixData(device, buffer, len);
             self->Padding = written + len;
-            ALCdevice_Unlock(device);
+            V0(device->Backend,unlock)();
             hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0);
         }
         if(FAILED(hr))
         {
             ERR("Failed to buffer data: 0x%08lx\n", hr);
-            ALCdevice_Lock(device);
+            V0(device->Backend,lock)();
             aluHandleDisconnect(device);
-            ALCdevice_Unlock(device);
+            V0(device->Backend,unlock)();
             break;
         }
     }
@@ -599,7 +677,7 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi
     {
         if(deviceName)
         {
-            const DevMap *iter, *end;
+            const DevMap *iter;
 
             if(VECTOR_SIZE(PlaybackDevices) == 0)
             {
@@ -609,19 +687,18 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi
             }
 
             hr = E_FAIL;
-            iter = VECTOR_ITER_BEGIN(PlaybackDevices);
-            end = VECTOR_ITER_END(PlaybackDevices);
-            for(;iter != end;iter++)
+#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
+            VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
+            if(iter == VECTOR_ITER_END(PlaybackDevices))
+                WARN("Failed to find device name matching \"%s\"\n", deviceName);
+            else
             {
-                if(al_string_cmp_cstr(iter->name, deviceName) == 0)
-                {
-                    self->devid = strdupW(iter->devid);
-                    hr = S_OK;
-                    break;
-                }
+                ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+                self->devid = strdupW(iter->devid);
+                al_string_copy(&device->DeviceName, iter->name);
+                hr = S_OK;
             }
-            if(FAILED(hr))
-                WARN("Failed to find device name matching \"%s\"\n", deviceName);
+#undef MATCH_NAME
         }
     }
 
@@ -677,7 +754,11 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self)
     if(SUCCEEDED(hr))
     {
         self->client = ptr;
-        get_device_name(self->mmdev, &device->DeviceName);
+        if(al_string_empty(device->DeviceName))
+        {
+            get_device_name(self->mmdev, &device->DeviceName);
+            al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL);
+        }
     }
 
     if(FAILED(hr))
@@ -734,6 +815,7 @@ static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self)
 static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
 {
     ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    EndpointFormFactor formfactor = UnknownFormFactor;
     WAVEFORMATEXTENSIBLE OutputType;
     WAVEFORMATEX *wfx = NULL;
     REFERENCE_TIME min_per, buf_time;
@@ -783,11 +865,11 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
             device->FmtChans = DevFmtQuad;
         else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
             device->FmtChans = DevFmtX51;
-        else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
-            device->FmtChans = DevFmtX51Side;
+        else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR)
+            device->FmtChans = DevFmtX51Rear;
         else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
             device->FmtChans = DevFmtX61;
-        else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
+        else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE))
             device->FmtChans = DevFmtX71;
         else
             ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
@@ -799,6 +881,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
             OutputType.Format.nChannels = 1;
             OutputType.dwChannelMask = MONO;
             break;
+        case DevFmtBFormat3D:
+            device->FmtChans = DevFmtStereo;
+            /*fall-through*/
         case DevFmtStereo:
             OutputType.Format.nChannels = 2;
             OutputType.dwChannelMask = STEREO;
@@ -811,9 +896,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
             OutputType.Format.nChannels = 6;
             OutputType.dwChannelMask = X5DOT1;
             break;
-        case DevFmtX51Side:
+        case DevFmtX51Rear:
             OutputType.Format.nChannels = 6;
-            OutputType.dwChannelMask = X5DOT1SIDE;
+            OutputType.dwChannelMask = X5DOT1REAR;
             break;
         case DevFmtX61:
             OutputType.Format.nChannels = 7;
@@ -894,11 +979,11 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
             device->FmtChans = DevFmtQuad;
         else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
             device->FmtChans = DevFmtX51;
-        else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
-            device->FmtChans = DevFmtX51Side;
+        else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR)
+            device->FmtChans = DevFmtX51Rear;
         else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
             device->FmtChans = DevFmtX61;
-        else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
+        else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE))
             device->FmtChans = DevFmtX71;
         else
         {
@@ -936,6 +1021,8 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
         }
         OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
     }
+    get_device_formfactor(self->mmdev, &formfactor);
+    device->IsHeadphones = (device->FmtChans == DevFmtStereo && formfactor == Headphones);
 
     SetDefaultWFXChannelOrder(device);
 
@@ -1055,6 +1142,575 @@ static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self)
 }
 
 
+typedef struct ALCmmdevCapture {
+    DERIVE_FROM_TYPE(ALCbackend);
+    DERIVE_FROM_TYPE(ALCmmdevProxy);
+
+    WCHAR *devid;
+
+    IMMDevice *mmdev;
+    IAudioClient *client;
+    IAudioCaptureClient *capture;
+    HANDLE NotifyEvent;
+
+    HANDLE MsgEvent;
+
+    ll_ringbuffer_t *Ring;
+
+    volatile int killNow;
+    althrd_t thread;
+} ALCmmdevCapture;
+
+static int ALCmmdevCapture_recordProc(void *arg);
+
+static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device);
+static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self);
+static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *name);
+static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self);
+static void ALCmmdevCapture_close(ALCmmdevCapture *self);
+static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self);
+static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALCboolean, reset)
+static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self);
+static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self);
+static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self);
+static void ALCmmdevCapture_stop(ALCmmdevCapture *self);
+static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self);
+static ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self);
+static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCmmdevCapture)
+
+DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevCapture);
+DEFINE_ALCBACKEND_VTABLE(ALCmmdevCapture);
+
+
+static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device)
+{
+    SET_VTABLE2(ALCmmdevCapture, ALCbackend, self);
+    SET_VTABLE2(ALCmmdevCapture, ALCmmdevProxy, self);
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self));
+
+    self->devid = NULL;
+
+    self->mmdev = NULL;
+    self->client = NULL;
+    self->capture = NULL;
+    self->NotifyEvent = NULL;
+
+    self->MsgEvent = NULL;
+
+    self->Ring = NULL;
+
+    self->killNow = 0;
+}
+
+static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self)
+{
+    ll_ringbuffer_free(self->Ring);
+    self->Ring = NULL;
+
+    if(self->NotifyEvent != NULL)
+        CloseHandle(self->NotifyEvent);
+    self->NotifyEvent = NULL;
+    if(self->MsgEvent != NULL)
+        CloseHandle(self->MsgEvent);
+    self->MsgEvent = NULL;
+
+    free(self->devid);
+    self->devid = NULL;
+
+    ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self));
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg)
+{
+    ALCmmdevCapture *self = arg;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    HRESULT hr;
+
+    hr = CoInitialize(NULL);
+    if(FAILED(hr))
+    {
+        ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
+        V0(device->Backend,lock)();
+        aluHandleDisconnect(device);
+        V0(device->Backend,unlock)();
+        return 1;
+    }
+
+    althrd_setname(althrd_current(), RECORD_THREAD_NAME);
+
+    while(!self->killNow)
+    {
+        UINT32 avail;
+        DWORD res;
+
+        hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail);
+        if(FAILED(hr))
+            ERR("Failed to get next packet size: 0x%08lx\n", hr);
+        else while(avail > 0 && SUCCEEDED(hr))
+        {
+            UINT32 numsamples;
+            DWORD flags;
+            BYTE *data;
+
+            hr = IAudioCaptureClient_GetBuffer(self->capture,
+                &data, &numsamples, &flags, NULL, NULL
+            );
+            if(FAILED(hr))
+            {
+                ERR("Failed to get capture buffer: 0x%08lx\n", hr);
+                break;
+            }
+
+            ll_ringbuffer_write(self->Ring, (char*)data, numsamples);
+
+            hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples);
+            if(FAILED(hr))
+            {
+                ERR("Failed to release capture buffer: 0x%08lx\n", hr);
+                break;
+            }
+
+            hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail);
+            if(FAILED(hr))
+                ERR("Failed to get next packet size: 0x%08lx\n", hr);
+        }
+
+        if(FAILED(hr))
+        {
+            V0(device->Backend,lock)();
+            aluHandleDisconnect(device);
+            V0(device->Backend,unlock)();
+            break;
+        }
+
+        res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE);
+        if(res != WAIT_OBJECT_0)
+            ERR("WaitForSingleObjectEx error: 0x%lx\n", res);
+    }
+
+    CoUninitialize();
+    return 0;
+}
+
+
+static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *deviceName)
+{
+    HRESULT hr = S_OK;
+
+    self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    self->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if(self->NotifyEvent == NULL || self->MsgEvent == NULL)
+    {
+        ERR("Failed to create message events: %lu\n", GetLastError());
+        hr = E_FAIL;
+    }
+
+    if(SUCCEEDED(hr))
+    {
+        if(deviceName)
+        {
+            const DevMap *iter;
+
+            if(VECTOR_SIZE(CaptureDevices) == 0)
+            {
+                ThreadRequest req = { self->MsgEvent, 0 };
+                if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE))
+                    (void)WaitForResponse(&req);
+            }
+
+            hr = E_FAIL;
+#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0)
+            VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
+            if(iter == VECTOR_ITER_END(CaptureDevices))
+                WARN("Failed to find device name matching \"%s\"\n", deviceName);
+            else
+            {
+                ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+                self->devid = strdupW(iter->devid);
+                al_string_copy(&device->DeviceName, iter->name);
+                hr = S_OK;
+            }
+#undef MATCH_NAME
+        }
+    }
+
+    if(SUCCEEDED(hr))
+    {
+        ThreadRequest req = { self->MsgEvent, 0 };
+
+        hr = E_FAIL;
+        if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+            hr = WaitForResponse(&req);
+        else
+            ERR("Failed to post thread message: %lu\n", GetLastError());
+    }
+
+    if(FAILED(hr))
+    {
+        if(self->NotifyEvent != NULL)
+            CloseHandle(self->NotifyEvent);
+        self->NotifyEvent = NULL;
+        if(self->MsgEvent != NULL)
+            CloseHandle(self->MsgEvent);
+        self->MsgEvent = NULL;
+
+        free(self->devid);
+        self->devid = NULL;
+
+        ERR("Device init failed: 0x%08lx\n", hr);
+        return ALC_INVALID_VALUE;
+    }
+    else
+    {
+        ThreadRequest req = { self->MsgEvent, 0 };
+
+        hr = E_FAIL;
+        if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+            hr = WaitForResponse(&req);
+        else
+            ERR("Failed to post thread message: %lu\n", GetLastError());
+
+        if(FAILED(hr))
+        {
+            ALCmmdevCapture_close(self);
+            if(hr == E_OUTOFMEMORY)
+               return ALC_OUT_OF_MEMORY;
+            return ALC_INVALID_VALUE;
+        }
+    }
+
+    return ALC_NO_ERROR;
+}
+
+static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    void *ptr;
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
+    if(SUCCEEDED(hr))
+    {
+        IMMDeviceEnumerator *Enumerator = ptr;
+        if(!self->devid)
+            hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eCapture, eMultimedia, &self->mmdev);
+        else
+            hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev);
+        IMMDeviceEnumerator_Release(Enumerator);
+        Enumerator = NULL;
+    }
+    if(SUCCEEDED(hr))
+        hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
+    if(SUCCEEDED(hr))
+    {
+        self->client = ptr;
+        if(al_string_empty(device->DeviceName))
+        {
+            get_device_name(self->mmdev, &device->DeviceName);
+            al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL);
+        }
+    }
+
+    if(FAILED(hr))
+    {
+        if(self->mmdev)
+            IMMDevice_Release(self->mmdev);
+        self->mmdev = NULL;
+    }
+
+    return hr;
+}
+
+
+static void ALCmmdevCapture_close(ALCmmdevCapture *self)
+{
+    ThreadRequest req = { self->MsgEvent, 0 };
+
+    if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+        (void)WaitForResponse(&req);
+
+    ll_ringbuffer_free(self->Ring);
+    self->Ring = NULL;
+
+    CloseHandle(self->MsgEvent);
+    self->MsgEvent = NULL;
+
+    CloseHandle(self->NotifyEvent);
+    self->NotifyEvent = NULL;
+
+    free(self->devid);
+    self->devid = NULL;
+}
+
+static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self)
+{
+    if(self->client)
+        IAudioClient_Release(self->client);
+    self->client = NULL;
+
+    if(self->mmdev)
+        IMMDevice_Release(self->mmdev);
+    self->mmdev = NULL;
+}
+
+
+static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self)
+{
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    WAVEFORMATEXTENSIBLE OutputType;
+    WAVEFORMATEX *wfx = NULL;
+    REFERENCE_TIME buf_time;
+    UINT32 buffer_len;
+    void *ptr = NULL;
+    HRESULT hr;
+
+    if(self->client)
+        IAudioClient_Release(self->client);
+    self->client = NULL;
+
+    hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
+    if(FAILED(hr))
+    {
+        ERR("Failed to reactivate audio client: 0x%08lx\n", hr);
+        return hr;
+    }
+    self->client = ptr;
+
+    buf_time = ((REFERENCE_TIME)device->UpdateSize*device->NumUpdates*10000000 +
+                                device->Frequency-1) / device->Frequency;
+
+    OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+    switch(device->FmtChans)
+    {
+        case DevFmtMono:
+            OutputType.Format.nChannels = 1;
+            OutputType.dwChannelMask = MONO;
+            break;
+        case DevFmtStereo:
+            OutputType.Format.nChannels = 2;
+            OutputType.dwChannelMask = STEREO;
+            break;
+        case DevFmtQuad:
+            OutputType.Format.nChannels = 4;
+            OutputType.dwChannelMask = QUAD;
+            break;
+        case DevFmtX51:
+            OutputType.Format.nChannels = 6;
+            OutputType.dwChannelMask = X5DOT1;
+            break;
+        case DevFmtX51Rear:
+            OutputType.Format.nChannels = 6;
+            OutputType.dwChannelMask = X5DOT1REAR;
+            break;
+        case DevFmtX61:
+            OutputType.Format.nChannels = 7;
+            OutputType.dwChannelMask = X6DOT1;
+            break;
+        case DevFmtX71:
+            OutputType.Format.nChannels = 8;
+            OutputType.dwChannelMask = X7DOT1;
+            break;
+
+        case DevFmtBFormat3D:
+            return E_FAIL;
+    }
+    switch(device->FmtType)
+    {
+        case DevFmtUByte:
+            OutputType.Format.wBitsPerSample = 8;
+            OutputType.Samples.wValidBitsPerSample = 8;
+            OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+            break;
+        case DevFmtShort:
+            OutputType.Format.wBitsPerSample = 16;
+            OutputType.Samples.wValidBitsPerSample = 16;
+            OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+            break;
+        case DevFmtInt:
+            OutputType.Format.wBitsPerSample = 32;
+            OutputType.Samples.wValidBitsPerSample = 32;
+            OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+            break;
+        case DevFmtFloat:
+            OutputType.Format.wBitsPerSample = 32;
+            OutputType.Samples.wValidBitsPerSample = 32;
+            OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+            break;
+
+        case DevFmtByte:
+        case DevFmtUShort:
+        case DevFmtUInt:
+            WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
+            return E_FAIL;
+    }
+    OutputType.Format.nSamplesPerSec = device->Frequency;
+
+    OutputType.Format.nBlockAlign = OutputType.Format.nChannels *
+                                    OutputType.Format.wBitsPerSample / 8;
+    OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
+                                        OutputType.Format.nBlockAlign;
+    OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format);
+
+    hr = IAudioClient_IsFormatSupported(self->client,
+        AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx
+    );
+    if(FAILED(hr))
+    {
+        ERR("Failed to check format support: 0x%08lx\n", hr);
+        return hr;
+    }
+
+    /* FIXME: We should do conversion/resampling if we didn't get a matching format. */
+    if(wfx->nSamplesPerSec != OutputType.Format.nSamplesPerSec ||
+       wfx->wBitsPerSample != OutputType.Format.wBitsPerSample ||
+       wfx->nChannels != OutputType.Format.nChannels ||
+       wfx->nBlockAlign != OutputType.Format.nBlockAlign)
+    {
+        ERR("Did not get matching format, wanted: %s %s %uhz, got: %d channel(s) %d-bit %luhz\n",
+            DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency,
+            wfx->nChannels, wfx->wBitsPerSample, wfx->nSamplesPerSec);
+        CoTaskMemFree(wfx);
+        return E_FAIL;
+    }
+
+    if(!MakeExtensible(&OutputType, wfx))
+    {
+        CoTaskMemFree(wfx);
+        return E_FAIL;
+    }
+    CoTaskMemFree(wfx);
+    wfx = NULL;
+
+    hr = IAudioClient_Initialize(self->client,
+        AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+        buf_time, 0, &OutputType.Format, NULL
+    );
+    if(FAILED(hr))
+    {
+        ERR("Failed to initialize audio client: 0x%08lx\n", hr);
+        return hr;
+    }
+
+    hr = IAudioClient_GetBufferSize(self->client, &buffer_len);
+    if(FAILED(hr))
+    {
+        ERR("Failed to get buffer size: 0x%08lx\n", hr);
+        return hr;
+    }
+
+    buffer_len = maxu(device->UpdateSize*device->NumUpdates + 1, buffer_len);
+    ll_ringbuffer_free(self->Ring);
+    self->Ring = ll_ringbuffer_create(buffer_len, OutputType.Format.nBlockAlign);
+    if(!self->Ring)
+    {
+        ERR("Failed to allocate capture ring buffer\n");
+        return E_OUTOFMEMORY;
+    }
+
+    hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent);
+    if(FAILED(hr))
+    {
+        ERR("Failed to set event handle: 0x%08lx\n", hr);
+        return hr;
+    }
+
+    return hr;
+}
+
+
+static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self)
+{
+    ThreadRequest req = { self->MsgEvent, 0 };
+    HRESULT hr = E_FAIL;
+
+    if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+        hr = WaitForResponse(&req);
+
+    return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
+}
+
+static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self)
+{
+    HRESULT hr;
+    void *ptr;
+
+    ResetEvent(self->NotifyEvent);
+    hr = IAudioClient_Start(self->client);
+    if(FAILED(hr))
+    {
+        ERR("Failed to start audio client: 0x%08lx\n", hr);
+        return hr;
+    }
+
+    hr = IAudioClient_GetService(self->client, &IID_IAudioCaptureClient, &ptr);
+    if(SUCCEEDED(hr))
+    {
+        self->capture = ptr;
+        self->killNow = 0;
+        if(althrd_create(&self->thread, ALCmmdevCapture_recordProc, self) != althrd_success)
+        {
+            ERR("Failed to start thread\n");
+            IAudioCaptureClient_Release(self->capture);
+            self->capture = NULL;
+            hr = E_FAIL;
+        }
+    }
+
+    if(FAILED(hr))
+    {
+        IAudioClient_Stop(self->client);
+        IAudioClient_Reset(self->client);
+    }
+
+    return hr;
+}
+
+
+static void ALCmmdevCapture_stop(ALCmmdevCapture *self)
+{
+    ThreadRequest req = { self->MsgEvent, 0 };
+    if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+        (void)WaitForResponse(&req);
+}
+
+static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self)
+{
+    int res;
+
+    if(!self->capture)
+        return;
+
+    self->killNow = 1;
+    althrd_join(self->thread, &res);
+
+    IAudioCaptureClient_Release(self->capture);
+    self->capture = NULL;
+    IAudioClient_Stop(self->client);
+    IAudioClient_Reset(self->client);
+}
+
+
+ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self)
+{
+    return (ALuint)ll_ringbuffer_read_space(self->Ring);
+}
+
+ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples)
+{
+    if(ALCmmdevCapture_availableSamples(self) < samples)
+        return ALC_INVALID_VALUE;
+    ll_ringbuffer_read(self->Ring, buffer, samples);
+    return ALC_NO_ERROR;
+}
+
+
 static inline void AppendAllDevicesList2(const DevMap *entry)
 { AppendAllDevicesList(al_string_get_cstr(entry->name)); }
 static inline void AppendCaptureDeviceList2(const DevMap *entry)
@@ -1125,7 +1781,12 @@ static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory* UNUSED(self))
 
 static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory* UNUSED(self), ALCbackend_Type type)
 {
-    if(type == ALCbackend_Playback)
+    /* TODO: Disable capture with mmdevapi for now, since it doesn't do any
+     * rechanneling or resampling; if the device is configured for 48000hz
+     * stereo input, for example, and the app asks for 22050hz mono,
+     * initialization will fail.
+     */
+    if(type == ALCbackend_Playback /*|| type == ALCbackend_Capture*/)
         return ALC_TRUE;
     return ALC_FALSE;
 }
@@ -1162,13 +1823,15 @@ static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory*
     if(type == ALCbackend_Playback)
     {
         ALCmmdevPlayback *backend;
-
-        backend = ALCmmdevPlayback_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCmmdevPlayback)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+    if(type == ALCbackend_Capture)
+    {
+        ALCmmdevCapture *backend;
+        NEW_OBJ(backend, ALCmmdevCapture)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCmmdevPlayback_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 

+ 4 - 9
libs/openal-soft/Alc/backends/null.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -106,7 +106,7 @@ static int ALCnullBackend_mixerProc(void *ptr)
         }
 
         if(avail-done < device->UpdateSize)
-            al_nssleep(0, restTime);
+            al_nssleep(restTime);
         else while(avail-done >= device->UpdateSize)
         {
             aluMixData(device, NULL, device->UpdateSize);
@@ -214,13 +214,8 @@ static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UN
     if(type == ALCbackend_Playback)
     {
         ALCnullBackend *backend;
-
-        backend = ALCnullBackend_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCnullBackend)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCnullBackend_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 

+ 16 - 7
libs/openal-soft/Alc/backends/opensl.c

@@ -25,7 +25,7 @@
 
 #include "alMain.h"
 #include "alu.h"
-
+#include "threads.h"
 
 #include <SLES/OpenSLES.h>
 #include <SLES/OpenSLES_Android.h>
@@ -67,7 +67,10 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans)
                                 SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
         case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
                                SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
-                               SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
+                               SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
+        case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
+                                   SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
+                                   SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT;
         case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
                                SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
                                SL_SPEAKER_BACK_CENTER|
@@ -76,9 +79,7 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans)
                                SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
                                SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT|
                                SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
-        case DevFmtX51Side: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT|
-                                   SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY|
-                                   SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
+        case DevFmtBFormat3D: break;
     }
     return 0;
 }
@@ -378,6 +379,15 @@ static void opensl_stop_playback(ALCdevice *Device)
         result = VCALL0(bufferQueue,Clear)();
         PRINTERR(result, "bufferQueue->Clear");
     }
+    if(SL_RESULT_SUCCESS == result)
+    {
+        SLAndroidSimpleBufferQueueState state;
+        do {
+            althrd_yield();
+            result = VCALL(bufferQueue,GetState)(&state);
+        } while(SL_RESULT_SUCCESS == result && state.count > 0);
+        PRINTERR(result, "bufferQueue->GetState");
+    }
 
     free(data->buffer);
     data->buffer = NULL;
@@ -396,8 +406,7 @@ static const BackendFuncs opensl_funcs = {
     NULL,
     NULL,
     NULL,
-    NULL,
-    ALCdevice_GetLatencyDefault
+    NULL
 };
 
 

+ 9 - 19
libs/openal-soft/Alc/backends/oss.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -131,7 +131,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr)
                     break;
                 }
 
-                al_nssleep(0, 1000000);
+                al_nssleep(1000000);
                 continue;
             }
 
@@ -345,7 +345,7 @@ static int ALCcaptureOSS_recordProc(void *ptr)
     int amt;
 
     SetRTPriority();
-    althrd_setname(althrd_current(), "alsoft-record");
+    althrd_setname(althrd_current(), RECORD_THREAD_NAME);
 
     frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
 
@@ -362,7 +362,7 @@ static int ALCcaptureOSS_recordProc(void *ptr)
         }
         if(amt == 0)
         {
-            al_nssleep(0, 1000000);
+            al_nssleep(1000000);
             continue;
         }
         if(self->doCapture)
@@ -562,8 +562,8 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void)
 
 ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self))
 {
-    ConfigValueStr("oss", "device", &oss_driver);
-    ConfigValueStr("oss", "capture", &oss_capture);
+    ConfigValueStr(NULL, "oss", "device", &oss_driver);
+    ConfigValueStr(NULL, "oss", "capture", &oss_capture);
 
     return ALC_TRUE;
 }
@@ -606,25 +606,15 @@ ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self
     if(type == ALCbackend_Playback)
     {
         ALCplaybackOSS *backend;
-
-        backend = ALCplaybackOSS_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCplaybackOSS)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCplaybackOSS_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
     if(type == ALCbackend_Capture)
     {
         ALCcaptureOSS *backend;
-
-        backend = ALCcaptureOSS_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCcaptureOSS)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCcaptureOSS_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 

+ 259 - 155
libs/openal-soft/Alc/backends/portaudio.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -28,6 +28,8 @@
 #include "alu.h"
 #include "compat.h"
 
+#include "backends/base.h"
+
 #include <portaudio.h>
 
 
@@ -122,149 +124,171 @@ static ALCboolean pa_load(void)
 }
 
 
-typedef struct {
+typedef struct ALCportPlayback {
+    DERIVE_FROM_TYPE(ALCbackend);
+
     PaStream *stream;
     PaStreamParameters params;
     ALuint update_size;
+} ALCportPlayback;
+
+static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer,
+    unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+    const PaStreamCallbackFlags statusFlags, void *userData);
+
+static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device);
+static void ALCportPlayback_Destruct(ALCportPlayback *self);
+static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name);
+static void ALCportPlayback_close(ALCportPlayback *self);
+static ALCboolean ALCportPlayback_reset(ALCportPlayback *self);
+static ALCboolean ALCportPlayback_start(ALCportPlayback *self);
+static void ALCportPlayback_stop(ALCportPlayback *self);
+static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
+static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback)
+
+DEFINE_ALCBACKEND_VTABLE(ALCportPlayback);
+
+
+static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCportPlayback, ALCbackend, self);
 
-    RingBuffer *ring;
-} pa_data;
-
+    self->stream = NULL;
+}
 
-static int pa_callback(const void *UNUSED(inputBuffer), void *outputBuffer,
-                       unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
-                       const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
+static void ALCportPlayback_Destruct(ALCportPlayback *self)
 {
-    ALCdevice *device = (ALCdevice*)userData;
+    if(self->stream)
+        Pa_CloseStream(self->stream);
+    self->stream = NULL;
 
-    aluMixData(device, outputBuffer, framesPerBuffer);
-    return 0;
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
 }
 
-static int pa_capture_cb(const void *inputBuffer, void *UNUSED(outputBuffer),
-                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
-                         const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
+
+static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer,
+    unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
+    const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
 {
-    ALCdevice *device = (ALCdevice*)userData;
-    pa_data *data = (pa_data*)device->ExtraData;
+    ALCportPlayback *self = userData;
 
-    WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer);
+    aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer);
     return 0;
 }
 
 
-static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
+static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name)
 {
-    pa_data *data;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     PaError err;
 
-    if(!deviceName)
-        deviceName = pa_device;
-    else if(strcmp(deviceName, pa_device) != 0)
+    if(!name)
+        name = pa_device;
+    else if(strcmp(name, pa_device) != 0)
         return ALC_INVALID_VALUE;
 
-    data = (pa_data*)calloc(1, sizeof(pa_data));
-    data->update_size = device->UpdateSize;
+    self->update_size = device->UpdateSize;
 
-    data->params.device = -1;
-    if(!ConfigValueInt("port", "device", &data->params.device) ||
-       data->params.device < 0)
-        data->params.device = Pa_GetDefaultOutputDevice();
-    data->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
+    self->params.device = -1;
+    if(!ConfigValueInt(NULL, "port", "device", &self->params.device) ||
+       self->params.device < 0)
+        self->params.device = Pa_GetDefaultOutputDevice();
+    self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
                                     (float)device->Frequency;
-    data->params.hostApiSpecificStreamInfo = NULL;
+    self->params.hostApiSpecificStreamInfo = NULL;
 
-    data->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
+    self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
 
     switch(device->FmtType)
     {
         case DevFmtByte:
-            data->params.sampleFormat = paInt8;
+            self->params.sampleFormat = paInt8;
             break;
         case DevFmtUByte:
-            data->params.sampleFormat = paUInt8;
+            self->params.sampleFormat = paUInt8;
             break;
         case DevFmtUShort:
             /* fall-through */
         case DevFmtShort:
-            data->params.sampleFormat = paInt16;
+            self->params.sampleFormat = paInt16;
             break;
         case DevFmtUInt:
             /* fall-through */
         case DevFmtInt:
-            data->params.sampleFormat = paInt32;
+            self->params.sampleFormat = paInt32;
             break;
         case DevFmtFloat:
-            data->params.sampleFormat = paFloat32;
+            self->params.sampleFormat = paFloat32;
             break;
     }
 
 retry_open:
-    err = Pa_OpenStream(&data->stream, NULL, &data->params, device->Frequency,
-                        device->UpdateSize, paNoFlag, pa_callback, device);
+    err = Pa_OpenStream(&self->stream, NULL, &self->params,
+        device->Frequency, device->UpdateSize, paNoFlag,
+        ALCportPlayback_WriteCallback, self
+    );
     if(err != paNoError)
     {
-        if(data->params.sampleFormat == paFloat32)
+        if(self->params.sampleFormat == paFloat32)
         {
-            data->params.sampleFormat = paInt16;
+            self->params.sampleFormat = paInt16;
             goto retry_open;
         }
         ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
-        free(data);
         return ALC_INVALID_VALUE;
     }
 
-    device->ExtraData = data;
-    al_string_copy_cstr(&device->DeviceName, deviceName);
+    al_string_copy_cstr(&device->DeviceName, name);
 
     return ALC_NO_ERROR;
+
 }
 
-static void pa_close_playback(ALCdevice *device)
+static void ALCportPlayback_close(ALCportPlayback *self)
 {
-    pa_data *data = (pa_data*)device->ExtraData;
-    PaError err;
-
-    err = Pa_CloseStream(data->stream);
+    PaError err = Pa_CloseStream(self->stream);
     if(err != paNoError)
         ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
-
-    free(data);
-    device->ExtraData = NULL;
+    self->stream = NULL;
 }
 
-static ALCboolean pa_reset_playback(ALCdevice *device)
+static ALCboolean ALCportPlayback_reset(ALCportPlayback *self)
 {
-    pa_data *data = (pa_data*)device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     const PaStreamInfo *streamInfo;
 
-    streamInfo = Pa_GetStreamInfo(data->stream);
+    streamInfo = Pa_GetStreamInfo(self->stream);
     device->Frequency = streamInfo->sampleRate;
-    device->UpdateSize = data->update_size;
+    device->UpdateSize = self->update_size;
 
-    if(data->params.sampleFormat == paInt8)
+    if(self->params.sampleFormat == paInt8)
         device->FmtType = DevFmtByte;
-    else if(data->params.sampleFormat == paUInt8)
+    else if(self->params.sampleFormat == paUInt8)
         device->FmtType = DevFmtUByte;
-    else if(data->params.sampleFormat == paInt16)
+    else if(self->params.sampleFormat == paInt16)
         device->FmtType = DevFmtShort;
-    else if(data->params.sampleFormat == paInt32)
+    else if(self->params.sampleFormat == paInt32)
         device->FmtType = DevFmtInt;
-    else if(data->params.sampleFormat == paFloat32)
+    else if(self->params.sampleFormat == paFloat32)
         device->FmtType = DevFmtFloat;
     else
     {
-        ERR("Unexpected sample format: 0x%lx\n", data->params.sampleFormat);
+        ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat);
         return ALC_FALSE;
     }
 
-    if(data->params.channelCount == 2)
+    if(self->params.channelCount == 2)
         device->FmtChans = DevFmtStereo;
-    else if(data->params.channelCount == 1)
+    else if(self->params.channelCount == 1)
         device->FmtChans = DevFmtMono;
     else
     {
-        ERR("Unexpected channel count: %u\n", data->params.channelCount);
+        ERR("Unexpected channel count: %u\n", self->params.channelCount);
         return ALC_FALSE;
     }
     SetDefaultChannelOrder(device);
@@ -272,12 +296,11 @@ static ALCboolean pa_reset_playback(ALCdevice *device)
     return ALC_TRUE;
 }
 
-static ALCboolean pa_start_playback(ALCdevice *device)
+static ALCboolean ALCportPlayback_start(ALCportPlayback *self)
 {
-    pa_data *data = (pa_data*)device->ExtraData;
     PaError err;
 
-    err = Pa_StartStream(data->stream);
+    err = Pa_StartStream(self->stream);
     if(err != paNoError)
     {
         ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err));
@@ -287,161 +310,209 @@ static ALCboolean pa_start_playback(ALCdevice *device)
     return ALC_TRUE;
 }
 
-static void pa_stop_playback(ALCdevice *device)
+static void ALCportPlayback_stop(ALCportPlayback *self)
 {
-    pa_data *data = (pa_data*)device->ExtraData;
-    PaError err;
-
-    err = Pa_StopStream(data->stream);
+    PaError err = Pa_StopStream(self->stream);
     if(err != paNoError)
         ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
 }
 
 
-static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
+typedef struct ALCportCapture {
+    DERIVE_FROM_TYPE(ALCbackend);
+
+    PaStream *stream;
+    PaStreamParameters params;
+
+    ll_ringbuffer_t *ring;
+} ALCportCapture;
+
+static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer,
+    unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+    const PaStreamCallbackFlags statusFlags, void *userData);
+
+static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device);
+static void ALCportCapture_Destruct(ALCportCapture *self);
+static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name);
+static void ALCportCapture_close(ALCportCapture *self);
+static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset)
+static ALCboolean ALCportCapture_start(ALCportCapture *self);
+static void ALCportCapture_stop(ALCportCapture *self);
+static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples);
+static ALCuint ALCportCapture_availableSamples(ALCportCapture *self);
+static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCportCapture)
+
+DEFINE_ALCBACKEND_VTABLE(ALCportCapture);
+
+
+static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCportCapture, ALCbackend, self);
+
+    self->stream = NULL;
+}
+
+static void ALCportCapture_Destruct(ALCportCapture *self)
+{
+    if(self->stream)
+        Pa_CloseStream(self->stream);
+    self->stream = NULL;
+
+    if(self->ring)
+        ll_ringbuffer_free(self->ring);
+    self->ring = NULL;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer),
+    unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
+    const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
+{
+    ALCportCapture *self = userData;
+    size_t writable = ll_ringbuffer_write_space(self->ring);
+
+    if(framesPerBuffer > writable)
+        framesPerBuffer = writable;
+    ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer);
+    return 0;
+}
+
+
+static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
 {
-    ALuint frame_size;
-    pa_data *data;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    ALuint samples, frame_size;
     PaError err;
 
-    if(!deviceName)
-        deviceName = pa_device;
-    else if(strcmp(deviceName, pa_device) != 0)
+    if(!name)
+        name = pa_device;
+    else if(strcmp(name, pa_device) != 0)
         return ALC_INVALID_VALUE;
 
-    data = (pa_data*)calloc(1, sizeof(pa_data));
-    if(data == NULL)
-        return ALC_OUT_OF_MEMORY;
-
+    samples = device->UpdateSize * device->NumUpdates;
+    samples = maxu(samples, 100 * device->Frequency / 1000);
     frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
-    data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates);
-    if(data->ring == NULL)
-        goto error;
 
-    data->params.device = -1;
-    if(!ConfigValueInt("port", "capture", &data->params.device) ||
-       data->params.device < 0)
-        data->params.device = Pa_GetDefaultInputDevice();
-    data->params.suggestedLatency = 0.0f;
-    data->params.hostApiSpecificStreamInfo = NULL;
+    self->ring = ll_ringbuffer_create(samples, frame_size);
+    if(self->ring == NULL) return ALC_INVALID_VALUE;
+
+    self->params.device = -1;
+    if(!ConfigValueInt(NULL, "port", "capture", &self->params.device) ||
+       self->params.device < 0)
+        self->params.device = Pa_GetDefaultInputDevice();
+    self->params.suggestedLatency = 0.0f;
+    self->params.hostApiSpecificStreamInfo = NULL;
 
     switch(device->FmtType)
     {
         case DevFmtByte:
-            data->params.sampleFormat = paInt8;
+            self->params.sampleFormat = paInt8;
             break;
         case DevFmtUByte:
-            data->params.sampleFormat = paUInt8;
+            self->params.sampleFormat = paUInt8;
             break;
         case DevFmtShort:
-            data->params.sampleFormat = paInt16;
+            self->params.sampleFormat = paInt16;
             break;
         case DevFmtInt:
-            data->params.sampleFormat = paInt32;
+            self->params.sampleFormat = paInt32;
             break;
         case DevFmtFloat:
-            data->params.sampleFormat = paFloat32;
+            self->params.sampleFormat = paFloat32;
             break;
         case DevFmtUInt:
         case DevFmtUShort:
             ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
-            goto error;
+            return ALC_INVALID_VALUE;
     }
-    data->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
+    self->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
 
-    err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency,
-                        paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device);
+    err = Pa_OpenStream(&self->stream, &self->params, NULL,
+        device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
+        ALCportCapture_ReadCallback, self
+    );
     if(err != paNoError)
     {
         ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
-        goto error;
+        return ALC_INVALID_VALUE;
     }
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
+    al_string_copy_cstr(&device->DeviceName, name);
 
-    device->ExtraData = data;
     return ALC_NO_ERROR;
-
-error:
-    DestroyRingBuffer(data->ring);
-    free(data);
-    return ALC_INVALID_VALUE;
 }
 
-static void pa_close_capture(ALCdevice *device)
+static void ALCportCapture_close(ALCportCapture *self)
 {
-    pa_data *data = (pa_data*)device->ExtraData;
-    PaError err;
-
-    err = Pa_CloseStream(data->stream);
+    PaError err = Pa_CloseStream(self->stream);
     if(err != paNoError)
         ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
+    self->stream = NULL;
 
-    DestroyRingBuffer(data->ring);
-    data->ring = NULL;
-
-    free(data);
-    device->ExtraData = NULL;
+    ll_ringbuffer_free(self->ring);
+    self->ring = NULL;
 }
 
-static void pa_start_capture(ALCdevice *device)
-{
-    pa_data *data = device->ExtraData;
-    PaError err;
 
-    err = Pa_StartStream(data->stream);
+static ALCboolean ALCportCapture_start(ALCportCapture *self)
+{
+    PaError err = Pa_StartStream(self->stream);
     if(err != paNoError)
+    {
         ERR("Error starting stream: %s\n", Pa_GetErrorText(err));
+        return ALC_FALSE;
+    }
+    return ALC_TRUE;
 }
 
-static void pa_stop_capture(ALCdevice *device)
+static void ALCportCapture_stop(ALCportCapture *self)
 {
-    pa_data *data = (pa_data*)device->ExtraData;
-    PaError err;
-
-    err = Pa_StopStream(data->stream);
+    PaError err = Pa_StopStream(self->stream);
     if(err != paNoError)
         ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
 }
 
-static ALCenum pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+
+static ALCuint ALCportCapture_availableSamples(ALCportCapture *self)
 {
-    pa_data *data = device->ExtraData;
-    ReadRingBuffer(data->ring, buffer, samples);
-    return ALC_NO_ERROR;
+    return ll_ringbuffer_read_space(self->ring);
 }
 
-static ALCuint pa_available_samples(ALCdevice *device)
+static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples)
 {
-    pa_data *data = device->ExtraData;
-    return RingBufferSize(data->ring);
+    ll_ringbuffer_read(self->ring, buffer, samples);
+    return ALC_NO_ERROR;
 }
 
 
-static const BackendFuncs pa_funcs = {
-    pa_open_playback,
-    pa_close_playback,
-    pa_reset_playback,
-    pa_start_playback,
-    pa_stop_playback,
-    pa_open_capture,
-    pa_close_capture,
-    pa_start_capture,
-    pa_stop_capture,
-    pa_capture_samples,
-    pa_available_samples,
-    ALCdevice_GetLatencyDefault
-};
-
-ALCboolean alc_pa_init(BackendFuncs *func_list)
+typedef struct ALCportBackendFactory {
+    DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCportBackendFactory;
+#define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } }
+
+static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self);
+static void ALCportBackendFactory_deinit(ALCportBackendFactory *self);
+static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type);
+static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory);
+
+
+static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self))
 {
     if(!pa_load())
         return ALC_FALSE;
-    *func_list = pa_funcs;
     return ALC_TRUE;
 }
 
-void alc_pa_deinit(void)
+static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self))
 {
 #ifdef HAVE_DYNLOAD
     if(pa_handle)
@@ -455,7 +526,14 @@ void alc_pa_deinit(void)
 #endif
 }
 
-void alc_pa_probe(enum DevProbe type)
+static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback || type == ALCbackend_Capture)
+        return ALC_TRUE;
+    return ALC_FALSE;
+}
+
+static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type)
 {
     switch(type)
     {
@@ -467,3 +545,29 @@ void alc_pa_probe(enum DevProbe type)
             break;
     }
 }
+
+static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+    {
+        ALCportPlayback *backend;
+        NEW_OBJ(backend, ALCportPlayback)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+    if(type == ALCbackend_Capture)
+    {
+        ALCportCapture *backend;
+        NEW_OBJ(backend, ALCportCapture)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+
+    return NULL;
+}
+
+ALCbackendFactory *ALCportBackendFactory_getFactory(void)
+{
+    static ALCportBackendFactory factory = ALCPORTBACKENDFACTORY_INITIALIZER;
+    return STATIC_CAST(ALCbackendFactory, &factory);
+}

+ 165 - 140
libs/openal-soft/Alc/backends/pulseaudio.c

@@ -14,8 +14,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -34,13 +34,6 @@
 
 #if PA_API_VERSION == 12
 
-#ifndef PA_CHECK_VERSION
-#define PA_CHECK_VERSION(major,minor,micro)                             \
-    ((PA_MAJOR > (major)) ||                                            \
-     (PA_MAJOR == (major) && PA_MINOR > (minor)) ||                     \
-     (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
-#endif
-
 #ifdef HAVE_DYNLOAD
 static void *pa_handle;
 #define MAKE_FUNC(x) static __typeof(x) * p##x
@@ -108,13 +101,9 @@ MAKE_FUNC(pa_operation_unref);
 MAKE_FUNC(pa_proplist_new);
 MAKE_FUNC(pa_proplist_free);
 MAKE_FUNC(pa_proplist_set);
-#if PA_CHECK_VERSION(0,9,15)
 MAKE_FUNC(pa_channel_map_superset);
 MAKE_FUNC(pa_stream_set_buffer_attr_callback);
-#endif
-#if PA_CHECK_VERSION(0,9,16)
 MAKE_FUNC(pa_stream_begin_write);
-#endif
 #undef MAKE_FUNC
 
 #define pa_context_unref ppa_context_unref
@@ -181,13 +170,9 @@ MAKE_FUNC(pa_stream_begin_write);
 #define pa_proplist_new ppa_proplist_new
 #define pa_proplist_free ppa_proplist_free
 #define pa_proplist_set ppa_proplist_set
-#if PA_CHECK_VERSION(0,9,15)
 #define pa_channel_map_superset ppa_channel_map_superset
 #define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback
-#endif
-#if PA_CHECK_VERSION(0,9,16)
 #define pa_stream_begin_write ppa_stream_begin_write
-#endif
 
 #endif
 
@@ -278,18 +263,10 @@ static ALCboolean pulse_load(void)
         LOAD_FUNC(pa_proplist_new);
         LOAD_FUNC(pa_proplist_free);
         LOAD_FUNC(pa_proplist_set);
+        LOAD_FUNC(pa_channel_map_superset);
+        LOAD_FUNC(pa_stream_set_buffer_attr_callback);
+        LOAD_FUNC(pa_stream_begin_write);
 #undef LOAD_FUNC
-#define LOAD_OPTIONAL_FUNC(x) do {                                            \
-    p##x = GetSymbol(pa_handle, #x);                                          \
-} while(0)
-#if PA_CHECK_VERSION(0,9,15)
-        LOAD_OPTIONAL_FUNC(pa_channel_map_superset);
-        LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback);
-#endif
-#if PA_CHECK_VERSION(0,9,16)
-        LOAD_OPTIONAL_FUNC(pa_stream_begin_write);
-#endif
-#undef LOAD_OPTIONAL_FUNC
 
         if(ret == ALC_FALSE)
         {
@@ -428,8 +405,7 @@ error:
     return ALC_FALSE;
 }
 
-static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
-                        pa_stream *stream)
+static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream)
 {
     pa_threaded_mainloop_lock(loop);
 
@@ -438,10 +414,7 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context,
         pa_stream_set_state_callback(stream, NULL, NULL);
         pa_stream_set_moved_callback(stream, NULL, NULL);
         pa_stream_set_write_callback(stream, NULL, NULL);
-#if PA_CHECK_VERSION(0,9,15)
-        if(pa_stream_set_buffer_attr_callback)
-            pa_stream_set_buffer_attr_callback(stream, NULL, NULL);
-#endif
+        pa_stream_set_buffer_attr_callback(stream, NULL, NULL);
         pa_stream_disconnect(stream);
         pa_stream_unref(stream);
     }
@@ -544,6 +517,7 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
     pa_threaded_mainloop *loop = pdata;
     const DevMap *iter;
     DevMap entry;
+    int count;
 
     if(eol)
     {
@@ -553,18 +527,34 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p
 
 #define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0)
     VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME);
+    if(iter != VECTOR_ITER_END(PlaybackDevices)) return;
 #undef MATCH_INFO_NAME
-    if(iter != VECTOR_ITER_END(PlaybackDevices))
-        return;
-
-    TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
 
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.device_name);
 
-    al_string_copy_cstr(&entry.name, info->description);
     al_string_copy_cstr(&entry.device_name, info->name);
 
+    count = 0;
+    while(1)
+    {
+        al_string_copy_cstr(&entry.name, info->description);
+        if(count != 0)
+        {
+            char str[64];
+            snprintf(str, sizeof(str), " #%d", count+1);
+            al_string_append_cstr(&entry.name, str);
+        }
+
+#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+        VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY);
+        if(iter == VECTOR_ITER_END(PlaybackDevices)) break;
+#undef MATCH_ENTRY
+        count++;
+    }
+
+    TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name));
+
     VECTOR_PUSH_BACK(PlaybackDevices, entry);
 }
 
@@ -660,27 +650,44 @@ static void ALCpulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UN
 
 static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
 {
-    ALCpulsePlayback *self = pdata;
-    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
-    char chanmap_str[256] = "";
-    const struct {
-        const char *str;
+    static const struct {
         enum DevFmtChannels chans;
+        pa_channel_map map;
     } chanmaps[] = {
-        { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
-          DevFmtX71 },
-        { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
-          DevFmtX61 },
-        { "front-left,front-right,front-center,lfe,rear-left,rear-right",
-          DevFmtX51 },
-        { "front-left,front-right,front-center,lfe,side-left,side-right",
-          DevFmtX51Side },
-        { "front-left,front-right,rear-left,rear-right", DevFmtQuad },
-        { "front-left,front-right", DevFmtStereo },
-        { "mono", DevFmtMono },
-        { NULL, 0 }
+        { DevFmtX71, { 8, {
+            PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+            PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+            PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
+            PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
+        } } },
+        { DevFmtX61, { 7, {
+            PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+            PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+            PA_CHANNEL_POSITION_REAR_CENTER,
+            PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
+        } } },
+        { DevFmtX51, { 6, {
+            PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+            PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+            PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
+        } } },
+        { DevFmtX51Rear, { 6, {
+            PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+            PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
+            PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT
+        } } },
+        { DevFmtQuad, { 4, {
+            PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
+            PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT
+        } } },
+        { DevFmtStereo, { 2, {
+            PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT
+        } } },
+        { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } }
     };
-    int i;
+    ALCpulsePlayback *self = pdata;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+    size_t i;
 
     if(eol)
     {
@@ -688,26 +695,27 @@ static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const
         return;
     }
 
-    for(i = 0;chanmaps[i].str;i++)
+    for(i = 0;i < COUNTOF(chanmaps);i++)
     {
-        pa_channel_map map;
-        if(!pa_channel_map_parse(&map, chanmaps[i].str))
-            continue;
-
-        if(pa_channel_map_equal(&info->channel_map, &map)
-#if PA_CHECK_VERSION(0,9,15)
-           || (pa_channel_map_superset &&
-               pa_channel_map_superset(&info->channel_map, &map))
-#endif
-            )
+        if(pa_channel_map_superset(&info->channel_map, &chanmaps[i].map))
         {
-            device->FmtChans = chanmaps[i].chans;
-            return;
+            if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
+                device->FmtChans = chanmaps[i].chans;
+            break;
         }
     }
+    if(i == COUNTOF(chanmaps))
+    {
+        char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX] = "";
+        pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
+        WARN("Failed to find format for channel map:\n    %s\n", chanmap_str);
+    }
 
-    pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
-    ERR("Failed to find format for channel map:\n    %s\n", chanmap_str);
+    if(info->active_port)
+        TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description);
+    device->IsHeadphones = (info->active_port &&
+                            strcmp(info->active_port->name, "analog-output-headphones") == 0 &&
+                            device->FmtChans == DevFmtStereo);
 }
 
 static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata)
@@ -818,10 +826,7 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
             void *buf;
             pa_free_cb_t free_func = NULL;
 
-#if PA_CHECK_VERSION(0,9,16)
-            if(!pa_stream_begin_write ||
-               pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
-#endif
+            if(pa_stream_begin_write(self->stream, &buf, &newlen) < 0)
             {
                 buf = pa_xmalloc(newlen);
                 free_func = pa_xfree;
@@ -841,10 +846,10 @@ static int ALCpulsePlayback_mixerProc(void *ptr)
 
 static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name)
 {
+    const_al_string dev_name = AL_STRING_INIT_STATIC();
     const char *pulse_name = NULL;
     pa_stream_flags_t flags;
     pa_sample_spec spec;
-    pa_operation *o;
 
     if(name)
     {
@@ -859,6 +864,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
         if(iter == VECTOR_ITER_END(PlaybackDevices))
             return ALC_INVALID_VALUE;
         pulse_name = al_string_get_cstr(iter->device_name);
+        dev_name = iter->name;
     }
 
     if(!pulse_open(&self->loop, &self->context, ALCpulsePlayback_contextStateCallback, self))
@@ -868,7 +874,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
 
     flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
             PA_STREAM_FIX_CHANNELS;
-    if(!GetConfigValueBool("pulse", "allow-moves", 0))
+    if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
         flags |= PA_STREAM_DONT_MOVE;
 
     spec.format = PA_SAMPLE_S16NE;
@@ -889,10 +895,19 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name
     pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self);
 
     al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
-    o = pa_context_get_sink_info_by_name(self->context,
-                                         al_string_get_cstr(self->device_name),
-                                         ALCpulsePlayback_sinkNameCallback, self);
-    wait_for_operation(o, self->loop);
+    if(al_string_empty(dev_name))
+    {
+        pa_operation *o = pa_context_get_sink_info_by_name(
+            self->context, al_string_get_cstr(self->device_name),
+            ALCpulsePlayback_sinkNameCallback, self
+        );
+        wait_for_operation(o, self->loop);
+    }
+    else
+    {
+        ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
+        al_string_copy(&device->DeviceName, dev_name);
+    }
 
     pa_threaded_mainloop_unlock(self->loop);
 
@@ -915,37 +930,33 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
     pa_stream_flags_t flags = 0;
     const char *mapname = NULL;
     pa_channel_map chanmap;
+    pa_operation *o;
     ALuint len;
 
     pa_threaded_mainloop_lock(self->loop);
 
     if(self->stream)
     {
+        pa_stream_set_state_callback(self->stream, NULL, NULL);
         pa_stream_set_moved_callback(self->stream, NULL, NULL);
-#if PA_CHECK_VERSION(0,9,15)
-        if(pa_stream_set_buffer_attr_callback)
-            pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL);
-#endif
+        pa_stream_set_write_callback(self->stream, NULL, NULL);
+        pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL);
         pa_stream_disconnect(self->stream);
         pa_stream_unref(self->stream);
         self->stream = NULL;
     }
 
-    if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
-    {
-        pa_operation *o;
-        o = pa_context_get_sink_info_by_name(self->context,
-                                             al_string_get_cstr(self->device_name),
-                                             ALCpulsePlayback_sinkInfoCallback, self);
-        wait_for_operation(o, self->loop);
-    }
-    if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
-        flags |= PA_STREAM_FIX_RATE;
+    o = pa_context_get_sink_info_by_name(self->context, al_string_get_cstr(self->device_name),
+                                         ALCpulsePlayback_sinkInfoCallback, self);
+    wait_for_operation(o, self->loop);
 
+    if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) ||
+       !(device->Flags&DEVICE_FREQUENCY_REQUEST))
+        flags |= PA_STREAM_FIX_RATE;
     flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
     flags |= PA_STREAM_ADJUST_LATENCY;
     flags |= PA_STREAM_START_CORKED;
-    if(!GetConfigValueBool("pulse", "allow-moves", 0))
+    if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
         flags |= PA_STREAM_DONT_MOVE;
 
     switch(device->FmtType)
@@ -987,6 +998,9 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
         case DevFmtMono:
             mapname = "mono";
             break;
+        case DevFmtBFormat3D:
+            device->FmtChans = DevFmtStereo;
+            /*fall-through*/
         case DevFmtStereo:
             mapname = "front-left,front-right";
             break;
@@ -994,11 +1008,11 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
             mapname = "front-left,front-right,rear-left,rear-right";
             break;
         case DevFmtX51:
-            mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right";
-            break;
-        case DevFmtX51Side:
             mapname = "front-left,front-right,front-center,lfe,side-left,side-right";
             break;
+        case DevFmtX51Rear:
+            mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right";
+            break;
         case DevFmtX61:
             mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right";
             break;
@@ -1035,8 +1049,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
     self->spec = *(pa_stream_get_sample_spec(self->stream));
     if(device->Frequency != self->spec.rate)
     {
-        pa_operation *o;
-
         /* Server updated our playback rate, so modify the buffer attribs
          * accordingly. */
         device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency *
@@ -1053,15 +1065,10 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self)
         device->Frequency = self->spec.rate;
     }
 
-#if PA_CHECK_VERSION(0,9,15)
-    if(pa_stream_set_buffer_attr_callback)
-        pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
-#endif
+    pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self);
     ALCpulsePlayback_bufferAttrCallback(self->stream, self);
 
     len = self->attr.minreq / pa_frame_size(&self->spec);
-    if((CPUCapFlags&CPU_CAP_SSE))
-        len = (len+3)&~3;
     device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5);
     device->NumUpdates = clampu(device->NumUpdates, 2, 16);
     device->UpdateSize = len;
@@ -1083,10 +1090,18 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self)
     pa_operation *o;
     int res;
 
-    if(!self->stream)
+    if(!self->stream || self->killNow)
         return;
 
     self->killNow = AL_TRUE;
+    /* Signal the main loop in case PulseAudio isn't sending us audio requests
+     * (e.g. if the device is suspended). We need to lock the mainloop in case
+     * the mixer is between checking the killNow flag but before waiting for
+     * the signal.
+     */
+    pa_threaded_mainloop_lock(self->loop);
+    pa_threaded_mainloop_unlock(self->loop);
+    pa_threaded_mainloop_signal(self->loop, 0);
     althrd_join(self->thread, &res);
 
     pa_threaded_mainloop_lock(self->loop);
@@ -1199,6 +1214,7 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
     pa_threaded_mainloop *loop = pdata;
     const DevMap *iter;
     DevMap entry;
+    int count;
 
     if(eol)
     {
@@ -1208,18 +1224,34 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa
 
 #define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0)
     VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME);
+    if(iter != VECTOR_ITER_END(CaptureDevices)) return;
 #undef MATCH_INFO_NAME
-    if(iter != VECTOR_ITER_END(CaptureDevices))
-        return;
-
-    TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name);
 
     AL_STRING_INIT(entry.name);
     AL_STRING_INIT(entry.device_name);
 
-    al_string_copy_cstr(&entry.name, info->description);
     al_string_copy_cstr(&entry.device_name, info->name);
 
+    count = 0;
+    while(1)
+    {
+        al_string_copy_cstr(&entry.name, info->description);
+        if(count != 0)
+        {
+            char str[64];
+            snprintf(str, sizeof(str), " #%d", count+1);
+            al_string_append_cstr(&entry.name, str);
+        }
+
+#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0)
+        VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY);
+        if(iter == VECTOR_ITER_END(CaptureDevices)) break;
+#undef MATCH_ENTRY
+        count++;
+    }
+
+    TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name));
+
     VECTOR_PUSH_BACK(CaptureDevices, entry);
 }
 
@@ -1372,7 +1404,6 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
     const char *pulse_name = NULL;
     pa_stream_flags_t flags = 0;
     pa_channel_map chanmap;
-    pa_operation *o;
     ALuint samples;
 
     if(name)
@@ -1388,6 +1419,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
         if(iter == VECTOR_ITER_END(CaptureDevices))
             return ALC_INVALID_VALUE;
         pulse_name = al_string_get_cstr(iter->device_name);
+        al_string_copy(&device->DeviceName, iter->name);
     }
 
     if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self))
@@ -1445,7 +1477,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
                           pa_frame_size(&self->spec);
 
     flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
-    if(!GetConfigValueBool("pulse", "allow-moves", 0))
+    if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0))
         flags |= PA_STREAM_DONT_MOVE;
 
     TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
@@ -1461,10 +1493,14 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name)
     pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self);
 
     al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream));
-    o = pa_context_get_source_info_by_name(self->context,
-                                           al_string_get_cstr(self->device_name),
-                                           ALCpulseCapture_sourceNameCallback, self);
-    wait_for_operation(o, self->loop);
+    if(al_string_empty(device->DeviceName))
+    {
+        pa_operation *o = pa_context_get_source_info_by_name(
+            self->context, al_string_get_cstr(self->device_name),
+            ALCpulseCapture_sourceNameCallback, self
+        );
+        wait_for_operation(o, self->loop);
+    }
 
     pa_threaded_mainloop_unlock(self->loop);
     return ALC_NO_ERROR;
@@ -1607,11 +1643,6 @@ static void ALCpulseCapture_unlock(ALCpulseCapture *self)
 }
 
 
-static inline void AppendAllDevicesList2(const DevMap *entry)
-{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
-static inline void AppendCaptureDeviceList2(const DevMap *entry)
-{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
-
 typedef struct ALCpulseBackendFactory {
     DERIVE_FROM_TYPE(ALCbackendFactory);
 } ALCpulseBackendFactory;
@@ -1638,7 +1669,7 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel
         pa_threaded_mainloop *loop;
 
         pulse_ctx_flags = 0;
-        if(!GetConfigValueBool("pulse", "spawn-server", 1))
+        if(!GetConfigValueBool(NULL, "pulse", "spawn-server", 1))
             pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
 
         if((loop=pa_threaded_mainloop_new()) &&
@@ -1701,12 +1732,16 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e
     {
         case ALL_DEVICE_PROBE:
             ALCpulsePlayback_probeDevices();
-            VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
+#define APPEND_ALL_DEVICES_LIST(e)  AppendAllDevicesList(al_string_get_cstr((e)->name))
+            VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_ALL_DEVICES_LIST);
+#undef APPEND_ALL_DEVICES_LIST
             break;
 
         case CAPTURE_DEVICE_PROBE:
             ALCpulseCapture_probeDevices();
-            VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
+#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(al_string_get_cstr((e)->name))
+            VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_CAPTURE_DEVICE_LIST);
+#undef APPEND_CAPTURE_DEVICE_LIST
             break;
     }
 }
@@ -1716,25 +1751,15 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory*
     if(type == ALCbackend_Playback)
     {
         ALCpulsePlayback *backend;
-
-        backend = ALCpulsePlayback_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCpulsePlayback)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCpulsePlayback_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
     if(type == ALCbackend_Capture)
     {
         ALCpulseCapture *backend;
-
-        backend = ALCpulseCapture_New(sizeof(*backend));
+        NEW_OBJ(backend, ALCpulseCapture)(device);
         if(!backend) return NULL;
-        memset(backend, 0, sizeof(*backend));
-
-        ALCpulseCapture_Construct(backend, device);
-
         return STATIC_CAST(ALCbackend, backend);
     }
 

+ 108 - 352
libs/openal-soft/Alc/backends/qsa.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -53,12 +53,12 @@ typedef struct {
     int card;
     int dev;
 } DevMap;
+TYPEDEF_VECTOR(DevMap, vector_DevMap)
+
+static vector_DevMap DeviceNameMap;
+static vector_DevMap CaptureNameMap;
 
 static const ALCchar qsaDevice[] = "QSA Default";
-static DevMap* allDevNameMap;
-static ALuint numDevNames;
-static DevMap* allCaptureDevNameMap;
-static ALuint numCaptureDevNames;
 
 static const struct {
     int32_t format;
@@ -104,69 +104,57 @@ static const struct {
     {0},
 };
 
-static DevMap *deviceList(int type, ALuint *count)
+static void deviceList(int type, vector_DevMap *devmap)
 {
     snd_ctl_t* handle;
     snd_pcm_info_t pcminfo;
-    int max_cards, card, err, dev, num_devices, idx;
-    DevMap* dev_list;
+    int max_cards, card, err, dev;
+    DevMap entry;
     char name[1024];
     struct snd_ctl_hw_info info;
-    void* temp;
 
-    idx=0;
-    num_devices=0;
-    max_cards=snd_cards();
+    max_cards = snd_cards();
+    if(max_cards < 0)
+        return;
 
-    if (max_cards<=0)
-    {
-        return 0;
-    }
+    VECTOR_RESERVE(*devmap, max_cards+1);
+    VECTOR_RESIZE(*devmap, 0);
 
-    dev_list=malloc(sizeof(DevMap)*1);
-    dev_list[0].name=strdup(qsaDevice);
-    num_devices=1;
+    entry.name = strdup(qsaDevice);
+    entry.card = 0;
+    entry.dev = 0;
+    VECTOR_PUSH_BACK(*devmap, entry);
 
-    for (card=0; card<max_cards; card++)
+    for(card = 0;card < max_cards;card++)
     {
-        if ((err=snd_ctl_open(&handle, card))<0)
-        {
+        if((err=snd_ctl_open(&handle, card)) < 0)
             continue;
-        }
-        if ((err=snd_ctl_hw_info(handle, &info))<0)
+
+        if((err=snd_ctl_hw_info(handle, &info)) < 0)
         {
             snd_ctl_close(handle);
             continue;
         }
 
-        for (dev=0; dev<(int)info.pcmdevs; dev++)
+        for(dev = 0;dev < (int)info.pcmdevs;dev++)
         {
-            if ((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
-            {
+            if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
                 continue;
-            }
 
-            if ((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
-                (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
+            if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
+               (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
             {
-                temp=realloc(dev_list, sizeof(DevMap)*(num_devices+1));
-                if (temp)
-                {
-                    dev_list=temp;
-                    snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
-                    dev_list[num_devices].name=strdup(name);
-                    dev_list[num_devices].card=card;
-                    dev_list[num_devices].dev=dev;
-                    num_devices++;
-                }
+                snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
+                entry.name = strdup(name);
+                entry.card = card;
+                entry.dev = dev;
+
+                VECTOR_PUSH_BACK(*devmap, entry);
+                TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev);
             }
         }
-        snd_ctl_close (handle);
+        snd_ctl_close(handle);
     }
-
-    *count=num_devices;
-
-    return dev_list;
 }
 
 
@@ -266,71 +254,48 @@ FORCE_ALIGN static int qsa_proc_playback(void* ptr)
 
 static ALCenum qsa_open_playback(ALCdevice* device, const ALCchar* deviceName)
 {
-    qsa_data* data;
-    char driver[64];
-    int status;
+    qsa_data *data;
     int card, dev;
+    int status;
 
-    strncpy(driver, GetConfigValue("qsa", "device", qsaDevice), sizeof(driver)-1);
-    driver[sizeof(driver)-1]=0;
-
-    data=(qsa_data*)calloc(1, sizeof(qsa_data));
-    if (data==NULL)
-    {
+    data = (qsa_data*)calloc(1, sizeof(qsa_data));
+    if(data == NULL)
         return ALC_OUT_OF_MEMORY;
-    }
 
-    if (!deviceName)
-    {
-        deviceName=driver;
-    }
+    if(!deviceName)
+        deviceName = qsaDevice;
 
-    if (strcmp(deviceName, qsaDevice)==0)
-    {
-        if (!deviceName)
-        {
-            deviceName=qsaDevice;
-        }
-
-        status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
-    }
+    if(strcmp(deviceName, qsaDevice) == 0)
+        status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
     else
     {
-        size_t idx;
+        const DevMap *iter;
 
-        if (!allDevNameMap)
-        {
-            allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames);
-        }
+        if(VECTOR_SIZE(DeviceNameMap) == 0)
+            deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
 
-        for (idx=0; idx<numDevNames; idx++)
-        {
-            if (allDevNameMap[idx].name && strcmp(deviceName, allDevNameMap[idx].name)==0)
-            {
-                if (idx>0)
-                {
-                    break;
-                }
-            }
-        }
-        if (idx==numDevNames)
+#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
+        VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME);
+#undef MATCH_DEVNAME
+        if(iter == VECTOR_ITER_END(DeviceNameMap))
         {
             free(data);
             return ALC_INVALID_DEVICE;
         }
 
-        status=snd_pcm_open(&data->pcmHandle, allDevNameMap[idx].card, allDevNameMap[idx].dev, SND_PCM_OPEN_PLAYBACK);
+        status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK);
     }
 
-    if (status<0)
+    if(status < 0)
     {
         free(data);
         return ALC_INVALID_DEVICE;
     }
 
-    data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
-    if (data->audio_fd<0)
+    data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
+    if(data->audio_fd < 0)
     {
+        snd_pcm_close(data->pcmHandle);
         free(data);
         return ALC_INVALID_DEVICE;
     }
@@ -633,72 +598,51 @@ static void qsa_stop_playback(ALCdevice* device)
 
 static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
 {
-    qsa_data* data;
-    int format=-1;
-    char driver[64];
+    qsa_data *data;
     int card, dev;
+    int format=-1;
     int status;
 
-    strncpy(driver, GetConfigValue("qsa", "capture", qsaDevice), sizeof(driver)-1);
-    driver[sizeof(driver)-1]=0;
-
     data=(qsa_data*)calloc(1, sizeof(qsa_data));
     if (data==NULL)
     {
         return ALC_OUT_OF_MEMORY;
     }
 
-    if (!deviceName)
-    {
-        deviceName=driver;
-    }
+    if(!deviceName)
+        deviceName = qsaDevice;
 
-    if (strcmp(deviceName, qsaDevice)==0)
-    {
-        if (!deviceName)
-        {
-            deviceName=qsaDevice;
-        }
-
-        status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
-    }
+    if(strcmp(deviceName, qsaDevice) == 0)
+        status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
     else
     {
-        size_t idx;
+        const DevMap *iter;
 
-        if (!allCaptureDevNameMap)
-        {
-            allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numDevNames);
-        }
+        if(VECTOR_SIZE(CaptureNameMap) == 0)
+            deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
 
-        for (idx=0; idx<numDevNames; idx++)
-        {
-            if (allCaptureDevNameMap[idx].name && strcmp(deviceName, allCaptureDevNameMap[idx].name)==0)
-            {
-                if (idx>0)
-                {
-                    break;
-                }
-            }
-        }
-        if (idx==numDevNames)
+#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0)
+        VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME);
+#undef MATCH_DEVNAME
+        if(iter == VECTOR_ITER_END(CaptureNameMap))
         {
             free(data);
             return ALC_INVALID_DEVICE;
         }
 
-        status=snd_pcm_open(&data->pcmHandle, allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev, SND_PCM_OPEN_CAPTURE);
+        status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE);
     }
 
-    if (status<0)
+    if(status < 0)
     {
         free(data);
         return ALC_INVALID_DEVICE;
     }
 
-    data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
-    if (data->audio_fd<0)
+    data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
+    if(data->audio_fd < 0)
     {
+        snd_pcm_close(data->pcmHandle);
         free(data);
         return ALC_INVALID_DEVICE;
     }
@@ -753,170 +697,13 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName)
     data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans);
     data->cparams.format.format=format;
 
-    if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
-    {
-        int original_rate=data->cparams.format.rate;
-        int original_voices=data->cparams.format.voices;
-        int original_format=data->cparams.format.format;
-        int it;
-        int jt;
-
-        for (it=0; it<1; it++)
-        {
-            /* Check for second pass */
-            if (it==1)
-            {
-                original_rate=ratelist[0].rate;
-                original_voices=channellist[0].channels;
-                original_format=formatlist[0].format;
-            }
-
-            do {
-                /* At first downgrade sample format */
-                jt=0;
-                do {
-                    if (formatlist[jt].format==data->cparams.format.format)
-                    {
-                        data->cparams.format.format=formatlist[jt+1].format;
-                        break;
-                    }
-                    if (formatlist[jt].format==0)
-                    {
-                        data->cparams.format.format=0;
-                        break;
-                    }
-                    jt++;
-                } while(1);
-
-                if (data->cparams.format.format==0)
-                {
-                    data->cparams.format.format=original_format;
-
-                    /* At secod downgrade sample rate */
-                    jt=0;
-                    do {
-                        if (ratelist[jt].rate==data->cparams.format.rate)
-                        {
-                            data->cparams.format.rate=ratelist[jt+1].rate;
-                            break;
-                        }
-                        if (ratelist[jt].rate==0)
-                        {
-                            data->cparams.format.rate=0;
-                            break;
-                        }
-                        jt++;
-                    } while(1);
-
-                    if (data->cparams.format.rate==0)
-                    {
-                        data->cparams.format.rate=original_rate;
-                        data->cparams.format.format=original_format;
-
-                        /* At third downgrade channels number */
-                        jt=0;
-                        do {
-                            if(channellist[jt].channels==data->cparams.format.voices)
-                            {
-                                data->cparams.format.voices=channellist[jt+1].channels;
-                                break;
-                            }
-                            if (channellist[jt].channels==0)
-                            {
-                                data->cparams.format.voices=0;
-                                break;
-                            }
-                           jt++;
-                        } while(1);
-                    }
-
-                    if (data->cparams.format.voices==0)
-                    {
-                        break;
-                    }
-                }
-
-                data->cparams.buf.block.frag_size=device->UpdateSize*
-                    data->cparams.format.voices*
-                    snd_pcm_format_width(data->cparams.format.format)/8;
-                data->cparams.buf.block.frags_max=device->NumUpdates;
-                data->cparams.buf.block.frags_min=device->NumUpdates;
-                if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
-                {
-                    continue;
-                }
-                else
-                {
-                    break;
-                }
-            } while(1);
-
-            if (data->cparams.format.voices!=0)
-            {
-                break;
-            }
-        }
-
-        if (data->cparams.format.voices==0)
-        {
-            return ALC_INVALID_VALUE;
-        }
-    }
-
-    /* now fill back to the our AL device */
-    device->Frequency=data->cparams.format.rate;
-
-    switch (data->cparams.format.voices)
+    if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0)
     {
-        case 1:
-             device->FmtChans=DevFmtMono;
-             break;
-        case 2:
-             device->FmtChans=DevFmtStereo;
-             break;
-        case 4:
-             device->FmtChans=DevFmtQuad;
-             break;
-        case 6:
-             device->FmtChans=DevFmtX51;
-             break;
-        case 7:
-             device->FmtChans=DevFmtX61;
-             break;
-        case 8:
-             device->FmtChans=DevFmtX71;
-             break;
-        default:
-             device->FmtChans=DevFmtMono;
-             break;
-    }
+        snd_pcm_close(data->pcmHandle);
+        free(data);
+        device->ExtraData=NULL;
 
-    switch (data->cparams.format.format)
-    {
-        case SND_PCM_SFMT_S8:
-             device->FmtType=DevFmtByte;
-             break;
-        case SND_PCM_SFMT_U8:
-             device->FmtType=DevFmtUByte;
-             break;
-        case SND_PCM_SFMT_S16_LE:
-             device->FmtType=DevFmtShort;
-             break;
-        case SND_PCM_SFMT_U16_LE:
-             device->FmtType=DevFmtUShort;
-             break;
-        case SND_PCM_SFMT_S32_LE:
-             device->FmtType=DevFmtInt;
-             break;
-        case SND_PCM_SFMT_U32_LE:
-             device->FmtType=DevFmtUInt;
-             break;
-        case SND_PCM_SFMT_FLOAT_LE:
-             device->FmtType=DevFmtFloat;
-             break;
-        default:
-             device->FmtType=DevFmtShort;
-             break;
+        return ALC_INVALID_VALUE;
     }
 
     return ALC_NO_ERROR;
@@ -927,9 +714,8 @@ static void qsa_close_capture(ALCdevice* device)
     qsa_data* data=(qsa_data*)device->ExtraData;
 
     if (data->pcmHandle!=NULL)
-    {
         snd_pcm_close(data->pcmHandle);
-    }
+
     free(data);
     device->ExtraData=NULL;
 }
@@ -954,10 +740,6 @@ static void qsa_start_capture(ALCdevice* device)
     }
 
     snd_pcm_capture_go(data->pcmHandle);
-
-    device->UpdateSize=data->csetup.buf.block.frag_size/
-        (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType));
-    device->NumUpdates=data->csetup.buf.block.frags;
 }
 
 static void qsa_stop_capture(ALCdevice* device)
@@ -1073,16 +855,7 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s
     return ALC_NO_ERROR;
 }
 
-static ALint64 qsa_get_latency(ALCdevice* device)
-{
-    ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
-
-    return (ALint64)(device->UpdateSize*device->NumUpdates/frame_size)*
-        1000000000/device->Frequency;
-}
-
-BackendFuncs qsa_funcs=
-{
+static const BackendFuncs qsa_funcs= {
     qsa_open_playback,
     qsa_close_playback,
     qsa_reset_playback,
@@ -1093,69 +866,52 @@ BackendFuncs qsa_funcs=
     qsa_start_capture,
     qsa_stop_capture,
     qsa_capture_samples,
-    qsa_available_samples,
-    qsa_get_latency,
+    qsa_available_samples
 };
 
 ALCboolean alc_qsa_init(BackendFuncs* func_list)
 {
-    *func_list=qsa_funcs;
-
+    *func_list = qsa_funcs;
     return ALC_TRUE;
 }
 
 void alc_qsa_deinit(void)
 {
-    ALuint i;
-
-    for (i=0; i<numDevNames; ++i)
-    {
-        free(allDevNameMap[i].name);
-    }
-    free(allDevNameMap);
-    allDevNameMap=NULL;
-    numDevNames=0;
+#define FREE_NAME(iter) free((iter)->name)
+    VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
+    VECTOR_DEINIT(DeviceNameMap);
 
-    for (i=0; i<numCaptureDevNames; ++i)
-    {
-        free(allCaptureDevNameMap[i].name);
-    }
-    free(allCaptureDevNameMap);
-    allCaptureDevNameMap=NULL;
-    numCaptureDevNames=0;
+    VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
+    VECTOR_DEINIT(CaptureNameMap);
+#undef FREE_NAME
 }
 
 void alc_qsa_probe(enum DevProbe type)
 {
-    ALuint i;
-
     switch (type)
     {
         case ALL_DEVICE_PROBE:
-             for (i=0; i<numDevNames; ++i)
-             {
-                 free(allDevNameMap[i].name);
-             }
-             free(allDevNameMap);
-
-             allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames);
-             for (i=0; i<numDevNames; ++i)
-             {
-                 AppendAllDevicesList(allDevNameMap[i].name);
-             }
-             break;
+#define FREE_NAME(iter) free((iter)->name)
+            VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME);
+#undef FREE_NAME
+            VECTOR_RESIZE(DeviceNameMap, 0);
+
+            deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
+#define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name)
+            VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_DEVICE);
+#undef APPEND_DEVICE
+            break;
+
         case CAPTURE_DEVICE_PROBE:
-             for (i=0; i<numCaptureDevNames; ++i)
-             {
-                 free(allCaptureDevNameMap[i].name);
-             }
-             free(allCaptureDevNameMap);
-
-             allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numCaptureDevNames);
-             for (i=0; i<numCaptureDevNames; ++i)
-             {
-                 AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
-             }
-             break;
+#define FREE_NAME(iter) free((iter)->name)
+            VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME);
+#undef FREE_NAME
+            VECTOR_RESIZE(CaptureNameMap, 0);
+
+            deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
+#define APPEND_DEVICE(iter) AppendCaptureDeviceList((iter)->name)
+            VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_DEVICE);
+#undef APPEND_DEVICE
+            break;
     }
 }

+ 3 - 4
libs/openal-soft/Alc/backends/sndio.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -266,8 +266,7 @@ static const BackendFuncs sndio_funcs = {
     NULL,
     NULL,
     NULL,
-    NULL,
-    ALCdevice_GetLatencyDefault
+    NULL
 };
 
 ALCboolean alc_sndio_init(BackendFuncs *func_list)

+ 132 - 82
libs/openal-soft/Alc/backends/solaris.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -36,14 +36,14 @@
 #include "threads.h"
 #include "compat.h"
 
-#include <sys/audioio.h>
+#include "backends/base.h"
 
+#include <sys/audioio.h>
 
-static const ALCchar solaris_device[] = "Solaris Default";
 
-static const char *solaris_driver = "/dev/audio";
+typedef struct ALCsolarisBackend {
+    DERIVE_FROM_TYPE(ALCbackend);
 
-typedef struct {
     int fd;
 
     ALubyte *mix_data;
@@ -51,13 +51,58 @@ typedef struct {
 
     volatile int killNow;
     althrd_t thread;
-} solaris_data;
+} ALCsolarisBackend;
+
+static int ALCsolarisBackend_mixerProc(void *ptr);
+
+static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device);
+static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self);
+static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name);
+static void ALCsolarisBackend_close(ALCsolarisBackend *self);
+static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self);
+static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self);
+static void ALCsolarisBackend_stop(ALCsolarisBackend *self);
+static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend)
+
+DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend);
+
+
+static const ALCchar solaris_device[] = "Solaris Default";
+
+static const char *solaris_driver = "/dev/audio";
 
 
-static int SolarisProc(void *ptr)
+static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device)
 {
-    ALCdevice *Device = (ALCdevice*)ptr;
-    solaris_data *data = (solaris_data*)Device->ExtraData;
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCsolarisBackend, ALCbackend, self);
+
+    self->fd = -1;
+}
+
+static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self)
+{
+    if(self->fd != -1)
+        close(self->fd);
+    self->fd = -1;
+
+    free(self->mix_data);
+    self->mix_data = NULL;
+    self->data_size = 0;
+
+    ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+static int ALCsolarisBackend_mixerProc(void *ptr)
+{
+    ALCsolarisBackend *self = ptr;
+    ALCdevice *Device = STATIC_CAST(ALCbackend,self)->mDevice;
     ALint frameSize;
     int wrote;
 
@@ -66,27 +111,27 @@ static int SolarisProc(void *ptr)
 
     frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType);
 
-    while(!data->killNow && Device->Connected)
+    while(!self->killNow && Device->Connected)
     {
-        ALint len = data->data_size;
-        ALubyte *WritePtr = data->mix_data;
+        ALint len = self->data_size;
+        ALubyte *WritePtr = self->mix_data;
 
         aluMixData(Device, WritePtr, len/frameSize);
-        while(len > 0 && !data->killNow)
+        while(len > 0 && !self->killNow)
         {
-            wrote = write(data->fd, WritePtr, len);
+            wrote = write(self->fd, WritePtr, len);
             if(wrote < 0)
             {
                 if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
                 {
                     ERR("write failed: %s\n", strerror(errno));
-                    ALCdevice_Lock(Device);
+                    ALCsolarisBackend_lock(self);
                     aluHandleDisconnect(Device);
-                    ALCdevice_Unlock(Device);
+                    ALCsolarisBackend_unlock(self);
                     break;
                 }
 
-                al_nssleep(0, 1000000);
+                al_nssleep(1000000);
                 continue;
             }
 
@@ -99,43 +144,37 @@ static int SolarisProc(void *ptr)
 }
 
 
-static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
+static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name)
 {
-    solaris_data *data;
+    ALCdevice *device;
 
-    if(!deviceName)
-        deviceName = solaris_device;
-    else if(strcmp(deviceName, solaris_device) != 0)
+    if(!name)
+        name = solaris_device;
+    else if(strcmp(name, solaris_device) != 0)
         return ALC_INVALID_VALUE;
 
-    data = (solaris_data*)calloc(1, sizeof(solaris_data));
-    data->killNow = 0;
-
-    data->fd = open(solaris_driver, O_WRONLY);
-    if(data->fd == -1)
+    self->fd = open(solaris_driver, O_WRONLY);
+    if(self->fd == -1)
     {
-        free(data);
         ERR("Could not open %s: %s\n", solaris_driver, strerror(errno));
         return ALC_INVALID_VALUE;
     }
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
-    device->ExtraData = data;
+    device = STATIC_CAST(ALCbackend,self)->mDevice;
+    al_string_copy_cstr(&device->DeviceName, name);
+
     return ALC_NO_ERROR;
 }
 
-static void solaris_close_playback(ALCdevice *device)
+static void ALCsolarisBackend_close(ALCsolarisBackend *self)
 {
-    solaris_data *data = (solaris_data*)device->ExtraData;
-
-    close(data->fd);
-    free(data);
-    device->ExtraData = NULL;
+    close(self->fd);
+    self->fd = -1;
 }
 
-static ALCboolean solaris_reset_playback(ALCdevice *device)
+static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self)
 {
-    solaris_data *data = (solaris_data*)device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice;
     audio_info_t info;
     ALuint frameSize;
     int numChannels;
@@ -174,7 +213,7 @@ static ALCboolean solaris_reset_playback(ALCdevice *device)
     frameSize = numChannels * BytesFromDevFmt(device->FmtType);
     info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize;
 
-    if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0)
+    if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0)
     {
         ERR("ioctl failed: %s\n", strerror(errno));
         return ALC_FALSE;
@@ -201,74 +240,72 @@ static ALCboolean solaris_reset_playback(ALCdevice *device)
 
     SetDefaultChannelOrder(device);
 
+    free(self->mix_data);
+    self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    self->mix_data = calloc(1, self->data_size);
+
     return ALC_TRUE;
 }
 
-static ALCboolean solaris_start_playback(ALCdevice *device)
+static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self)
 {
-    solaris_data *data = (solaris_data*)device->ExtraData;
-
-    data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
-    data->mix_data = calloc(1, data->data_size);
-
-    data->killNow = 0;
-    if(althrd_create(&data->thread, SolarisProc, device) != althrd_success)
-    {
-        free(data->mix_data);
-        data->mix_data = NULL;
+    self->killNow = 0;
+    if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success)
         return ALC_FALSE;
-    }
-
     return ALC_TRUE;
 }
 
-static void solaris_stop_playback(ALCdevice *device)
+static void ALCsolarisBackend_stop(ALCsolarisBackend *self)
 {
-    solaris_data *data = (solaris_data*)device->ExtraData;
     int res;
 
-    if(data->killNow)
+    if(self->killNow)
         return;
 
-    data->killNow = 1;
-    althrd_join(data->thread, &res);
+    self->killNow = 1;
+    althrd_join(self->thread, &res);
 
-    if(ioctl(data->fd, AUDIO_DRAIN) < 0)
+    if(ioctl(self->fd, AUDIO_DRAIN) < 0)
         ERR("Error draining device: %s\n", strerror(errno));
-
-    free(data->mix_data);
-    data->mix_data = NULL;
 }
 
 
-static const BackendFuncs solaris_funcs = {
-    solaris_open_playback,
-    solaris_close_playback,
-    solaris_reset_playback,
-    solaris_start_playback,
-    solaris_stop_playback,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    ALCdevice_GetLatencyDefault
-};
-
-ALCboolean alc_solaris_init(BackendFuncs *func_list)
+typedef struct ALCsolarisBackendFactory {
+    DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCsolarisBackendFactory;
+#define ALCSOLARISBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void);
+
+static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self);
+static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type);
+static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory);
+
+
+ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void)
 {
-    ConfigValueStr("solaris", "device", &solaris_driver);
+    static ALCsolarisBackendFactory factory = ALCSOLARISBACKENDFACTORY_INITIALIZER;
+    return STATIC_CAST(ALCbackendFactory, &factory);
+}
 
-    *func_list = solaris_funcs;
+
+static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory* UNUSED(self))
+{
+    ConfigValueStr(NULL, "solaris", "device", &solaris_driver);
     return ALC_TRUE;
 }
 
-void alc_solaris_deinit(void)
+static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory* UNUSED(self), ALCbackend_Type type)
 {
+    if(type == ALCbackend_Playback)
+        return ALC_TRUE;
+    return ALC_FALSE;
 }
 
-void alc_solaris_probe(enum DevProbe type)
+static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type)
 {
     switch(type)
     {
@@ -286,3 +323,16 @@ void alc_solaris_probe(enum DevProbe type)
             break;
     }
 }
+
+ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+    {
+        ALCsolarisBackend *backend;
+        NEW_OBJ(backend, ALCsolarisBackend)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+
+    return NULL;
+}

+ 195 - 130
libs/openal-soft/Alc/backends/wave.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -24,26 +24,13 @@
 #include <stdio.h>
 #include <memory.h>
 #include <errno.h>
-#ifdef HAVE_WINDOWS_H
-#include <windows.h>
-#endif
 
 #include "alMain.h"
 #include "alu.h"
 #include "threads.h"
 #include "compat.h"
 
-
-typedef struct {
-    FILE *f;
-    long DataStart;
-
-    ALvoid *buffer;
-    ALuint size;
-
-    volatile int killNow;
-    althrd_t thread;
-} wave_data;
+#include "backends/base.h"
 
 
 static const ALCchar waveDevice[] = "Wave File Writer";
@@ -57,18 +44,15 @@ static const ALubyte SUBTYPE_FLOAT[] = {
     0x00, 0x38, 0x9b, 0x71
 };
 
-static const ALuint channel_masks[] = {
-    0, /* invalid */
-    0x4, /* Mono */
-    0x1 | 0x2, /* Stereo */
-    0, /* 3 channel */
-    0x1 | 0x2 | 0x10 | 0x20, /* Quad */
-    0, /* 5 channel */
-    0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */
-    0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */
-    0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */
+static const ALubyte SUBTYPE_BFORMAT_PCM[] = {
+    0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
+    0xca, 0x00, 0x00, 0x00
 };
 
+static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = {
+    0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1,
+    0xca, 0x00, 0x00, 0x00
+};
 
 static void fwrite16le(ALushort val, FILE *f)
 {
@@ -85,10 +69,57 @@ static void fwrite32le(ALuint val, FILE *f)
 }
 
 
-static int WaveProc(void *ptr)
+typedef struct ALCwaveBackend {
+    DERIVE_FROM_TYPE(ALCbackend);
+
+    FILE *mFile;
+    long mDataStart;
+
+    ALvoid *mBuffer;
+    ALuint mSize;
+
+    volatile int killNow;
+    althrd_t thread;
+} ALCwaveBackend;
+
+static int ALCwaveBackend_mixerProc(void *ptr);
+
+static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device);
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, Destruct)
+static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name);
+static void ALCwaveBackend_close(ALCwaveBackend *self);
+static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self);
+static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self);
+static void ALCwaveBackend_stop(ALCwaveBackend *self);
+static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALint64, getLatency)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend)
+
+DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend);
+
+
+static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device)
+{
+    ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+    SET_VTABLE2(ALCwaveBackend, ALCbackend, self);
+
+    self->mFile = NULL;
+    self->mDataStart = -1;
+
+    self->mBuffer = NULL;
+    self->mSize = 0;
+
+    self->killNow = 1;
+}
+
+
+static int ALCwaveBackend_mixerProc(void *ptr)
 {
-    ALCdevice *device = (ALCdevice*)ptr;
-    wave_data *data = (wave_data*)device->ExtraData;
+    ALCwaveBackend *self = (ALCwaveBackend*)ptr;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
     struct timespec now, start;
     ALint64 avail, done;
     ALuint frameSize;
@@ -106,7 +137,7 @@ static int WaveProc(void *ptr)
         ERR("Failed to get starting time\n");
         return 1;
     }
-    while(!data->killNow && device->Connected)
+    while(!self->killNow && device->Connected)
     {
         if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC)
         {
@@ -125,41 +156,41 @@ static int WaveProc(void *ptr)
         }
 
         if(avail-done < device->UpdateSize)
-            al_nssleep(0, restTime);
+            al_nssleep(restTime);
         else while(avail-done >= device->UpdateSize)
         {
-            aluMixData(device, data->buffer, device->UpdateSize);
+            aluMixData(device, self->mBuffer, device->UpdateSize);
             done += device->UpdateSize;
 
             if(!IS_LITTLE_ENDIAN)
             {
                 ALuint bytesize = BytesFromDevFmt(device->FmtType);
-                ALubyte *bytes = data->buffer;
+                ALubyte *bytes = self->mBuffer;
                 ALuint i;
 
                 if(bytesize == 1)
                 {
-                    for(i = 0;i < data->size;i++)
-                        fputc(bytes[i], data->f);
+                    for(i = 0;i < self->mSize;i++)
+                        fputc(bytes[i], self->mFile);
                 }
                 else if(bytesize == 2)
                 {
-                    for(i = 0;i < data->size;i++)
-                        fputc(bytes[i^1], data->f);
+                    for(i = 0;i < self->mSize;i++)
+                        fputc(bytes[i^1], self->mFile);
                 }
                 else if(bytesize == 4)
                 {
-                    for(i = 0;i < data->size;i++)
-                        fputc(bytes[i^3], data->f);
+                    for(i = 0;i < self->mSize;i++)
+                        fputc(bytes[i^3], self->mFile);
                 }
             }
             else
             {
-                fs = fwrite(data->buffer, frameSize, device->UpdateSize,
-                            data->f);
+                fs = fwrite(self->mBuffer, frameSize, device->UpdateSize,
+                            self->mFile);
                 (void)fs;
             }
-            if(ferror(data->f))
+            if(ferror(self->mFile))
             {
                 ERR("Error writing to file\n");
                 ALCdevice_Lock(device);
@@ -173,52 +204,52 @@ static int WaveProc(void *ptr)
     return 0;
 }
 
-static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
+
+static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name)
 {
-    wave_data *data;
+    ALCdevice *device;
     const char *fname;
 
-    fname = GetConfigValue("wave", "file", "");
-    if(!fname[0])
-        return ALC_INVALID_VALUE;
+    fname = GetConfigValue(NULL, "wave", "file", "");
+    if(!fname[0]) return ALC_INVALID_VALUE;
 
-    if(!deviceName)
-        deviceName = waveDevice;
-    else if(strcmp(deviceName, waveDevice) != 0)
+    if(!name)
+        name = waveDevice;
+    else if(strcmp(name, waveDevice) != 0)
         return ALC_INVALID_VALUE;
 
-    data = (wave_data*)calloc(1, sizeof(wave_data));
-
-    data->f = al_fopen(fname, "wb");
-    if(!data->f)
+    self->mFile = al_fopen(fname, "wb");
+    if(!self->mFile)
     {
-        free(data);
         ERR("Could not open file '%s': %s\n", fname, strerror(errno));
         return ALC_INVALID_VALUE;
     }
 
-    al_string_copy_cstr(&device->DeviceName, deviceName);
-    device->ExtraData = data;
+    device = STATIC_CAST(ALCbackend, self)->mDevice;
+    al_string_copy_cstr(&device->DeviceName, name);
+
     return ALC_NO_ERROR;
 }
 
-static void wave_close_playback(ALCdevice *device)
+static void ALCwaveBackend_close(ALCwaveBackend *self)
 {
-    wave_data *data = (wave_data*)device->ExtraData;
-
-    fclose(data->f);
-    free(data);
-    device->ExtraData = NULL;
+    if(self->mFile)
+        fclose(self->mFile);
+    self->mFile = NULL;
 }
 
-static ALCboolean wave_reset_playback(ALCdevice *device)
+static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self)
 {
-    wave_data *data = (wave_data*)device->ExtraData;
-    ALuint channels=0, bits=0;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+    ALuint channels=0, bits=0, chanmask=0;
+    int isbformat = 0;
     size_t val;
 
-    fseek(data->f, 0, SEEK_SET);
-    clearerr(data->f);
+    fseek(self->mFile, 0, SEEK_SET);
+    clearerr(self->mFile);
+
+    if(GetConfigValueBool(NULL, "wave", "bformat", 0))
+        device->FmtChans = DevFmtBFormat3D;
 
     switch(device->FmtType)
     {
@@ -237,135 +268,156 @@ static ALCboolean wave_reset_playback(ALCdevice *device)
         case DevFmtFloat:
             break;
     }
+    switch(device->FmtChans)
+    {
+        case DevFmtMono:   chanmask = 0x04; break;
+        case DevFmtStereo: chanmask = 0x01 | 0x02; break;
+        case DevFmtQuad:   chanmask = 0x01 | 0x02 | 0x10 | 0x20; break;
+        case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break;
+        case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break;
+        case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break;
+        case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break;
+        case DevFmtBFormat3D:
+            isbformat = 1;
+            chanmask = 0;
+            break;
+    }
     bits = BytesFromDevFmt(device->FmtType) * 8;
     channels = ChannelsFromDevFmt(device->FmtChans);
 
-    fprintf(data->f, "RIFF");
-    fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close
+    fprintf(self->mFile, "RIFF");
+    fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close
 
-    fprintf(data->f, "WAVE");
+    fprintf(self->mFile, "WAVE");
 
-    fprintf(data->f, "fmt ");
-    fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE
+    fprintf(self->mFile, "fmt ");
+    fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE
 
     // 16-bit val, format type id (extensible: 0xFFFE)
-    fwrite16le(0xFFFE, data->f);
+    fwrite16le(0xFFFE, self->mFile);
     // 16-bit val, channel count
-    fwrite16le(channels, data->f);
+    fwrite16le(channels, self->mFile);
     // 32-bit val, frequency
-    fwrite32le(device->Frequency, data->f);
+    fwrite32le(device->Frequency, self->mFile);
     // 32-bit val, bytes per second
-    fwrite32le(device->Frequency * channels * bits / 8, data->f);
+    fwrite32le(device->Frequency * channels * bits / 8, self->mFile);
     // 16-bit val, frame size
-    fwrite16le(channels * bits / 8, data->f);
+    fwrite16le(channels * bits / 8, self->mFile);
     // 16-bit val, bits per sample
-    fwrite16le(bits, data->f);
+    fwrite16le(bits, self->mFile);
     // 16-bit val, extra byte count
-    fwrite16le(22, data->f);
+    fwrite16le(22, self->mFile);
     // 16-bit val, valid bits per sample
-    fwrite16le(bits, data->f);
+    fwrite16le(bits, self->mFile);
     // 32-bit val, channel mask
-    fwrite32le(channel_masks[channels], data->f);
+    fwrite32le(chanmask, self->mFile);
     // 16 byte GUID, sub-type format
-    val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f);
+    val = fwrite(((bits==32) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) :
+                               (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM)), 1, 16, self->mFile);
     (void)val;
 
-    fprintf(data->f, "data");
-    fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close
+    fprintf(self->mFile, "data");
+    fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close
 
-    if(ferror(data->f))
+    if(ferror(self->mFile))
     {
         ERR("Error writing header: %s\n", strerror(errno));
         return ALC_FALSE;
     }
-    data->DataStart = ftell(data->f);
+    self->mDataStart = ftell(self->mFile);
 
     SetDefaultWFXChannelOrder(device);
 
     return ALC_TRUE;
 }
 
-static ALCboolean wave_start_playback(ALCdevice *device)
+static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self)
 {
-    wave_data *data = (wave_data*)device->ExtraData;
+    ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
 
-    data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
-    data->buffer = malloc(data->size);
-    if(!data->buffer)
+    self->mSize = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    self->mBuffer = malloc(self->mSize);
+    if(!self->mBuffer)
     {
         ERR("Buffer malloc failed\n");
         return ALC_FALSE;
     }
 
-    data->killNow = 0;
-    if(althrd_create(&data->thread, WaveProc, device) != althrd_success)
+    self->killNow = 0;
+    if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success)
     {
-        free(data->buffer);
-        data->buffer = NULL;
+        free(self->mBuffer);
+        self->mBuffer = NULL;
+        self->mSize = 0;
         return ALC_FALSE;
     }
 
     return ALC_TRUE;
 }
 
-static void wave_stop_playback(ALCdevice *device)
+static void ALCwaveBackend_stop(ALCwaveBackend *self)
 {
-    wave_data *data = (wave_data*)device->ExtraData;
     ALuint dataLen;
     long size;
     int res;
 
-    if(data->killNow)
+    if(self->killNow)
         return;
 
-    data->killNow = 1;
-    althrd_join(data->thread, &res);
+    self->killNow = 1;
+    althrd_join(self->thread, &res);
 
-    free(data->buffer);
-    data->buffer = NULL;
+    free(self->mBuffer);
+    self->mBuffer = NULL;
 
-    size = ftell(data->f);
+    size = ftell(self->mFile);
     if(size > 0)
     {
-        dataLen = size - data->DataStart;
-        if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0)
-            fwrite32le(dataLen, data->f); // 'data' header len
-        if(fseek(data->f, 4, SEEK_SET) == 0)
-            fwrite32le(size-8, data->f); // 'WAVE' header len
+        dataLen = size - self->mDataStart;
+        if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0)
+            fwrite32le(dataLen, self->mFile); // 'data' header len
+        if(fseek(self->mFile, 4, SEEK_SET) == 0)
+            fwrite32le(size-8, self->mFile); // 'WAVE' header len
     }
 }
 
 
-static const BackendFuncs wave_funcs = {
-    wave_open_playback,
-    wave_close_playback,
-    wave_reset_playback,
-    wave_start_playback,
-    wave_stop_playback,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    ALCdevice_GetLatencyDefault
-};
+typedef struct ALCwaveBackendFactory {
+    DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCwaveBackendFactory;
+#define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } }
+
+ALCbackendFactory *ALCwaveBackendFactory_getFactory(void);
+
+static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self);
+static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit)
+static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type);
+static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory);
+
 
-ALCboolean alc_wave_init(BackendFuncs *func_list)
+ALCbackendFactory *ALCwaveBackendFactory_getFactory(void)
 {
-    *func_list = wave_funcs;
-    return ALC_TRUE;
+    static ALCwaveBackendFactory factory = ALCWAVEBACKENDFACTORY_INITIALIZER;
+    return STATIC_CAST(ALCbackendFactory, &factory);
 }
 
-void alc_wave_deinit(void)
+
+static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self))
 {
+    return ALC_TRUE;
 }
 
-void alc_wave_probe(enum DevProbe type)
+static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type)
 {
-    if(!ConfigValueExists("wave", "file"))
-        return;
+    if(type == ALCbackend_Playback)
+        return !!ConfigValueExists(NULL, "wave", "file");
+    return ALC_FALSE;
+}
 
+static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type)
+{
     switch(type)
     {
         case ALL_DEVICE_PROBE:
@@ -375,3 +427,16 @@ void alc_wave_probe(enum DevProbe type)
             break;
     }
 }
+
+static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+    if(type == ALCbackend_Playback)
+    {
+        ALCwaveBackend *backend;
+        NEW_OBJ(backend, ALCwaveBackend)(device);
+        if(!backend) return NULL;
+        return STATIC_CAST(ALCbackend, backend);
+    }
+
+    return NULL;
+}

File diff suppressed because it is too large
+ 365 - 311
libs/openal-soft/Alc/backends/winmm.c


+ 6 - 17
libs/openal-soft/Alc/bs2b.c

@@ -29,9 +29,6 @@
 #include "bs2b.h"
 #include "alu.h"
 
-#ifndef M_PI
-#define M_PI  3.14159265358979323846
-#endif
 
 /* Set up all data. */
 static void init(struct bs2b *bs2b)
@@ -40,8 +37,6 @@ static void init(struct bs2b *bs2b)
     float G_lo,  G_hi;
     float x, g;
 
-    bs2b->srate = clampi(bs2b->srate, 2000, 192000);
-
     switch(bs2b->level)
     {
     case BS2B_LOW_CLEVEL: /* Low crossfeed level */
@@ -105,31 +100,25 @@ static void init(struct bs2b *bs2b)
     bs2b->a1_hi = -x * g;
 } /* init */
 
+
 /* Exported functions.
  * See descriptions in "bs2b.h"
  */
 
-void bs2b_set_level(struct bs2b *bs2b, int level)
+void bs2b_set_params(struct bs2b *bs2b, int level, int srate)
 {
-    if(level == bs2b->level)
-        return;
+    if(srate <= 0) srate = 1;
+
     bs2b->level = level;
+    bs2b->srate = srate;
     init(bs2b);
-} /* bs2b_set_level */
+} /* bs2b_set_params */
 
 int bs2b_get_level(struct bs2b *bs2b)
 {
     return bs2b->level;
 } /* bs2b_get_level */
 
-void bs2b_set_srate(struct bs2b *bs2b, int srate)
-{
-    if (srate == bs2b->srate)
-        return;
-    bs2b->srate = srate;
-    init(bs2b);
-} /* bs2b_set_srate */
-
 int bs2b_get_srate(struct bs2b *bs2b)
 {
     return bs2b->srate;

+ 12 - 14
libs/openal-soft/Alc/effects/autowah.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -31,15 +31,15 @@
 /* Auto-wah is simply a low-pass filter with a cutoff frequency that shifts up
  * or down depending on the input signal, and a resonant peak at the cutoff.
  *
- * Currently, we assume a cutoff frequency range of 500hz (no amplitude) to
- * 3khz (peak gain). Peak gain is assumed to be in normalized scale.
+ * Currently, we assume a cutoff frequency range of 20hz (no amplitude) to
+ * 20khz (peak gain). Peak gain is assumed to be in normalized scale.
  */
 
 typedef struct ALautowahState {
     DERIVE_FROM_TYPE(ALeffectState);
 
     /* Effect gains for each channel */
-    ALfloat Gain[MaxChannels];
+    ALfloat Gain[MAX_OUTPUT_CHANNELS];
 
     /* Effect parameters */
     ALfloat AttackRate;
@@ -66,7 +66,6 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *d
 static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, const ALeffectslot *slot)
 {
     ALfloat attackTime, releaseTime;
-    ALfloat gain;
 
     attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency;
     releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency;
@@ -76,19 +75,18 @@ static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, co
     state->PeakGain = slot->EffectProps.Autowah.PeakGain;
     state->Resonance = slot->EffectProps.Autowah.Resonance;
 
-    gain = sqrtf(1.0f / device->NumChan) * slot->Gain;
-    SetGains(device, gain, state->Gain);
+    ComputeAmbientGains(device, slot->Gain, state->Gain);
 }
 
-static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
+static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     ALuint it, kt;
     ALuint base;
 
     for(base = 0;base < SamplesToDo;)
     {
-        ALfloat temps[64];
-        ALuint td = minu(SamplesToDo-base, 64);
+        ALfloat temps[256];
+        ALuint td = minu(256, SamplesToDo-base);
         ALfloat gain = state->GainCtrl;
 
         for(it = 0;it < td;it++)
@@ -114,7 +112,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
              * ALfilterType_LowPass. However, instead of passing a bandwidth,
              * we use the resonance property for Q. This also inlines the call.
              */
-            w0 = F_2PI * cutoff / state->Frequency;
+            w0 = F_TAU * cutoff / state->Frequency;
 
             /* FIXME: Resonance controls the resonant peak, or Q. How? Not sure
              * that Q = resonance*0.1. */
@@ -137,10 +135,10 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo,
         }
         state->GainCtrl = gain;
 
-        for(kt = 0;kt < MaxChannels;kt++)
+        for(kt = 0;kt < NumChannels;kt++)
         {
             ALfloat gain = state->Gain[kt];
-            if(!(gain > GAIN_SILENCE_THRESHOLD))
+            if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
                 continue;
 
             for(it = 0;it < td;it++)

+ 14 - 12
libs/openal-soft/Alc/effects/chorus.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -46,7 +46,7 @@ typedef struct ALchorusState {
     ALint lfo_disp;
 
     /* Gains for left and right sides */
-    ALfloat Gain[2][MaxChannels];
+    ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
 
     /* effect parameters */
     enum ChorusWaveForm waveform;
@@ -93,6 +93,8 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev
 
 static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot)
 {
+    static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f };
+    static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f };
     ALfloat frequency = (ALfloat)Device->Frequency;
     ALfloat rate;
     ALint phase;
@@ -111,8 +113,8 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
     state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency);
 
     /* Gains for left and right sides */
-    ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]);
-    ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]);
+    ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]);
+    ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]);
 
     phase = Slot->EffectProps.Chorus.Phase;
     rate = Slot->EffectProps.Chorus.Rate;
@@ -132,7 +134,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons
                 state->lfo_scale = 4.0f / state->lfo_range;
                 break;
             case CWF_Sinusoid:
-                state->lfo_scale = F_2PI / state->lfo_range;
+                state->lfo_scale = F_TAU / state->lfo_range;
                 break;
         }
 
@@ -201,15 +203,15 @@ DECL_TEMPLATE(Sinusoid)
 
 #undef DECL_TEMPLATE
 
-static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     ALuint it, kt;
     ALuint base;
 
     for(base = 0;base < SamplesToDo;)
     {
-        ALfloat temps[64][2];
-        ALuint td = minu(SamplesToDo-base, 64);
+        ALfloat temps[128][2];
+        ALuint td = minu(128, SamplesToDo-base);
 
         switch(state->waveform)
         {
@@ -221,17 +223,17 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co
                 break;
         }
 
-        for(kt = 0;kt < MaxChannels;kt++)
+        for(kt = 0;kt < NumChannels;kt++)
         {
             ALfloat gain = state->Gain[0][kt];
-            if(gain > GAIN_SILENCE_THRESHOLD)
+            if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
             {
                 for(it = 0;it < td;it++)
                     SamplesOut[kt][it+base] += temps[it][0] * gain;
             }
 
             gain = state->Gain[1][kt];
-            if(gain > GAIN_SILENCE_THRESHOLD)
+            if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
             {
                 for(it = 0;it < td;it++)
                     SamplesOut[kt][it+base] += temps[it][1] * gain;

+ 11 - 14
libs/openal-soft/Alc/effects/compressor.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -31,7 +31,7 @@ typedef struct ALcompressorState {
     DERIVE_FROM_TYPE(ALeffectState);
 
     /* Effect gains for each channel */
-    ALfloat Gain[MaxChannels];
+    ALfloat Gain[MAX_OUTPUT_CHANNELS];
 
     /* Effect parameters */
     ALboolean Enabled;
@@ -55,25 +55,22 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev
     return AL_TRUE;
 }
 
-static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *Device, const ALeffectslot *Slot)
+static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *device, const ALeffectslot *slot)
 {
-    ALfloat gain;
+    state->Enabled = slot->EffectProps.Compressor.OnOff;
 
-    state->Enabled = Slot->EffectProps.Compressor.OnOff;
-
-    gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
-    SetGains(Device, gain, state->Gain);
+    ComputeAmbientGains(device, slot->Gain, state->Gain);
 }
 
-static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE])
+static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     ALuint it, kt;
     ALuint base;
 
     for(base = 0;base < SamplesToDo;)
     {
-        ALfloat temps[64];
-        ALuint td = minu(SamplesToDo-base, 64);
+        ALfloat temps[256];
+        ALuint td = minu(256, SamplesToDo-base);
 
         if(state->Enabled)
         {
@@ -119,10 +116,10 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples
         }
 
 
-        for(kt = 0;kt < MaxChannels;kt++)
+        for(kt = 0;kt < NumChannels;kt++)
         {
             ALfloat gain = state->Gain[kt];
-            if(!(gain > GAIN_SILENCE_THRESHOLD))
+            if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
                 continue;
 
             for(it = 0;it < td;it++)

+ 28 - 14
libs/openal-soft/Alc/effects/dedicated.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -32,7 +32,7 @@
 typedef struct ALdedicatedState {
     DERIVE_FROM_TYPE(ALeffectState);
 
-    ALfloat gains[MaxChannels];
+    ALfloat gains[MAX_OUTPUT_CHANNELS];
 } ALdedicatedState;
 
 
@@ -48,27 +48,41 @@ static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state),
 static ALvoid ALdedicatedState_update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot)
 {
     ALfloat Gain;
-    ALsizei s;
+    ALuint i;
+
+    for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+        state->gains[i] = 0.0f;
 
     Gain = Slot->Gain * Slot->EffectProps.Dedicated.Gain;
-    if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
-        ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains);
-    else if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
+    if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT)
+    {
+        int idx;
+        if((idx=GetChannelIdxByName(device, LFE)) != -1)
+            state->gains[idx] = Gain;
+    }
+    else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE)
     {
-        for(s = 0;s < MaxChannels;s++)
-            state->gains[s] = 0.0f;
-        state->gains[LFE] = Gain;
+        int idx;
+        /* Dialog goes to the front-center speaker if it exists, otherwise it
+         * plays from the front-center location. */
+        if((idx=GetChannelIdxByName(device, FrontCenter)) != -1)
+            state->gains[idx] = Gain;
+        else
+        {
+            static const ALfloat front_dir[3] = { 0.0f, 0.0f, -1.0f };
+            ComputeDirectionalGains(device, front_dir, Gain, state->gains);
+        }
     }
 }
 
-static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     const ALfloat *gains = state->gains;
     ALuint i, c;
 
-    for(c = 0;c < MaxChannels;c++)
+    for(c = 0;c < NumChannels;c++)
     {
-        if(!(gains[c] > GAIN_SILENCE_THRESHOLD))
+        if(!(fabsf(gains[c]) > GAIN_SILENCE_THRESHOLD))
             continue;
 
         for(i = 0;i < SamplesToDo;i++)
@@ -94,7 +108,7 @@ ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(fa
     if(!state) return NULL;
     SET_VTABLE2(ALdedicatedState, ALeffectState, state);
 
-    for(s = 0;s < MaxChannels;s++)
+    for(s = 0;s < MAX_OUTPUT_CHANNELS;s++)
         state->gains[s] = 0.0f;
 
     return STATIC_CAST(ALeffectState, state);

+ 18 - 20
libs/openal-soft/Alc/effects/distortion.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -34,7 +34,7 @@ typedef struct ALdistortionState {
     DERIVE_FROM_TYPE(ALeffectState);
 
     /* Effect gains for each channel */
-    ALfloat Gain[MaxChannels];
+    ALfloat Gain[MAX_OUTPUT_CHANNELS];
 
     /* Effect parameters */
     ALfilterState lowpass;
@@ -58,7 +58,6 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi
     ALfloat bandwidth;
     ALfloat cutoff;
     ALfloat edge;
-    ALfloat gain;
 
     /* Store distorted signal attenuation settings */
     state->attenuation = Slot->EffectProps.Distortion.Gain;
@@ -73,23 +72,23 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi
     /* Bandwidth value is constant in octaves */
     bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f);
     ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f,
-                            cutoff / (frequency*4.0f), bandwidth);
+        cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
+    );
 
     /* Bandpass filter */
     cutoff = Slot->EffectProps.Distortion.EQCenter;
     /* Convert bandwidth in Hz to octaves */
     bandwidth = Slot->EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f);
     ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f,
-                            cutoff / (frequency*4.0f), bandwidth);
+        cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth)
+    );
 
-    gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain;
-    SetGains(Device, gain, state->Gain);
+    ComputeAmbientGains(Device, Slot->Gain, state->Gain);
 }
 
-static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     const ALfloat fc = state->edge_coeff;
-    float oversample_buffer[64][4];
     ALuint base;
     ALuint it;
     ALuint ot;
@@ -97,8 +96,8 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples
 
     for(base = 0;base < SamplesToDo;)
     {
-        ALfloat temps[64];
-        ALuint td = minu(SamplesToDo-base, 64);
+        float oversample_buffer[64][4];
+        ALuint td = minu(64, SamplesToDo-base);
 
         /* Perform 4x oversampling to avoid aliasing.   */
         /* Oversampling greatly improves distortion     */
@@ -150,20 +149,19 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples
                 smp = ALfilterState_processSingle(&state->bandpass, smp);
                 oversample_buffer[it][ot] = smp;
             }
-
-            /* Fourth step, final, do attenuation and perform decimation, */
-            /* store only one sample out of 4.                            */
-            temps[it] = oversample_buffer[it][0] * state->attenuation;
         }
 
-        for(kt = 0;kt < MaxChannels;kt++)
+        for(kt = 0;kt < NumChannels;kt++)
         {
-            ALfloat gain = state->Gain[kt];
-            if(!(gain > GAIN_SILENCE_THRESHOLD))
+            /* Fourth step, final, do attenuation and perform decimation,
+             * store only one sample out of 4.
+             */
+            ALfloat gain = state->Gain[kt] * state->attenuation;
+            if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
                 continue;
 
             for(it = 0;it < td;it++)
-                SamplesOut[kt][base+it] += gain * temps[it];
+                SamplesOut[kt][base+it] += gain * oversample_buffer[it][0];
         }
 
         base += td;

+ 18 - 16
libs/openal-soft/Alc/effects/echo.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -43,7 +43,7 @@ typedef struct ALechoState {
     } Tap[2];
     ALuint Offset;
     /* The panning gains for the two taps */
-    ALfloat Gain[2][MaxChannels];
+    ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
 
     ALfloat FeedGain;
 
@@ -83,9 +83,9 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device)
 
 static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const ALeffectslot *Slot)
 {
+    ALfloat pandir[3] = { 0.0f, 0.0f, 0.0f };
     ALuint frequency = Device->Frequency;
-    ALfloat lrpan, gain;
-    ALfloat dirGain;
+    ALfloat gain, lrpan;
 
     state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1;
     state->Tap[1].delay = fastf2u(Slot->EffectProps.Echo.LRDelay * frequency);
@@ -95,21 +95,23 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL
 
     state->FeedGain = Slot->EffectProps.Echo.Feedback;
 
+    gain = minf(1.0f - Slot->EffectProps.Echo.Damping, 0.01f);
     ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf,
-                            1.0f - Slot->EffectProps.Echo.Damping,
-                            LOWPASSFREQREF/frequency, 0.0f);
+                            gain, LOWPASSFREQREF/frequency,
+                            calc_rcpQ_from_slope(gain, 0.75f));
 
     gain = Slot->Gain;
-    dirGain = fabsf(lrpan);
 
     /* First tap panning */
-    ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]);
+    pandir[0] = -lrpan;
+    ComputeDirectionalGains(Device, pandir, gain, state->Gain[0]);
 
     /* Second tap panning */
-    ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]);
+    pandir[0] = +lrpan;
+    ComputeDirectionalGains(Device, pandir, gain, state->Gain[1]);
 }
 
-static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     const ALuint mask = state->BufferLength-1;
     const ALuint tap1 = state->Tap[0].delay;
@@ -121,8 +123,8 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const
 
     for(base = 0;base < SamplesToDo;)
     {
-        ALfloat temps[64][2];
-        ALuint td = minu(SamplesToDo-base, 64);
+        ALfloat temps[128][2];
+        ALuint td = minu(128, SamplesToDo-base);
 
         for(i = 0;i < td;i++)
         {
@@ -138,17 +140,17 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const
             offset++;
         }
 
-        for(k = 0;k < MaxChannels;k++)
+        for(k = 0;k < NumChannels;k++)
         {
             ALfloat gain = state->Gain[0][k];
-            if(gain > GAIN_SILENCE_THRESHOLD)
+            if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
             {
                 for(i = 0;i < td;i++)
                     SamplesOut[k][i+base] += temps[i][0] * gain;
             }
 
             gain = state->Gain[1][k];
-            if(gain > GAIN_SILENCE_THRESHOLD)
+            if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
             {
                 for(i = 0;i < td;i++)
                     SamplesOut[k][i+base] += temps[i][1] * gain;

+ 30 - 23
libs/openal-soft/Alc/effects/equalizer.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -75,7 +75,7 @@ typedef struct ALequalizerState {
     DERIVE_FROM_TYPE(ALeffectState);
 
     /* Effect gains for each channel */
-    ALfloat Gain[MaxChannels];
+    ALfloat Gain[MAX_OUTPUT_CHANNELS];
 
     /* Effect parameters */
     ALfilterState filter[4];
@@ -93,33 +93,40 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state),
 static ALvoid ALequalizerState_update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot)
 {
     ALfloat frequency = (ALfloat)device->Frequency;
-    ALfloat gain = sqrtf(1.0f / device->NumChan) * slot->Gain;
+    ALfloat gain, freq_mult;
 
-    SetGains(device, gain, state->Gain);
+    ComputeAmbientGains(device, slot->Gain, state->Gain);
 
-    /* Calculate coefficients for the each type of filter */
+    /* Calculate coefficients for the each type of filter. Note that the shelf
+     * filters' gain is for the reference frequency, which is the centerpoint
+     * of the transition band.
+     */
+    gain = sqrtf(slot->EffectProps.Equalizer.LowGain);
+    freq_mult = slot->EffectProps.Equalizer.LowCutoff/frequency;
     ALfilterState_setParams(&state->filter[0], ALfilterType_LowShelf,
-                            sqrtf(slot->EffectProps.Equalizer.LowGain),
-                            slot->EffectProps.Equalizer.LowCutoff/frequency,
-                            0.0f);
+        gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
+    );
 
+    gain = slot->EffectProps.Equalizer.Mid1Gain;
+    freq_mult = slot->EffectProps.Equalizer.Mid1Center/frequency;
     ALfilterState_setParams(&state->filter[1], ALfilterType_Peaking,
-                            sqrtf(slot->EffectProps.Equalizer.Mid1Gain),
-                            slot->EffectProps.Equalizer.Mid1Center/frequency,
-                            slot->EffectProps.Equalizer.Mid1Width);
+        gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid1Width)
+    );
 
+    gain = slot->EffectProps.Equalizer.Mid2Gain;
+    freq_mult = slot->EffectProps.Equalizer.Mid2Center/frequency;
     ALfilterState_setParams(&state->filter[2], ALfilterType_Peaking,
-                            sqrtf(slot->EffectProps.Equalizer.Mid2Gain),
-                            slot->EffectProps.Equalizer.Mid2Center/frequency,
-                            slot->EffectProps.Equalizer.Mid2Width);
+        gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid2Width)
+    );
 
+    gain = sqrtf(slot->EffectProps.Equalizer.HighGain);
+    freq_mult = slot->EffectProps.Equalizer.HighCutoff/frequency;
     ALfilterState_setParams(&state->filter[3], ALfilterType_HighShelf,
-                            sqrtf(slot->EffectProps.Equalizer.HighGain),
-                            slot->EffectProps.Equalizer.HighCutoff/frequency,
-                            0.0f);
+        gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f)
+    );
 }
 
-static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     ALuint base;
     ALuint it;
@@ -128,8 +135,8 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo
 
     for(base = 0;base < SamplesToDo;)
     {
-        ALfloat temps[64];
-        ALuint td = minu(SamplesToDo-base, 64);
+        ALfloat temps[256];
+        ALuint td = minu(256, SamplesToDo-base);
 
         for(it = 0;it < td;it++)
         {
@@ -141,10 +148,10 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo
             temps[it] = smp;
         }
 
-        for(kt = 0;kt < MaxChannels;kt++)
+        for(kt = 0;kt < NumChannels;kt++)
         {
             ALfloat gain = state->Gain[kt];
-            if(!(gain > GAIN_SILENCE_THRESHOLD))
+            if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
                 continue;
 
             for(it = 0;it < td;it++)

+ 14 - 12
libs/openal-soft/Alc/effects/flanger.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -46,7 +46,7 @@ typedef struct ALflangerState {
     ALint lfo_disp;
 
     /* Gains for left and right sides */
-    ALfloat Gain[2][MaxChannels];
+    ALfloat Gain[2][MAX_OUTPUT_CHANNELS];
 
     /* effect parameters */
     enum FlangerWaveForm waveform;
@@ -93,6 +93,8 @@ static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *D
 
 static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, const ALeffectslot *Slot)
 {
+    static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f };
+    static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f };
     ALfloat frequency = (ALfloat)Device->Frequency;
     ALfloat rate;
     ALint phase;
@@ -111,8 +113,8 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
     state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency);
 
     /* Gains for left and right sides */
-    ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]);
-    ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]);
+    ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]);
+    ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]);
 
     phase = Slot->EffectProps.Flanger.Phase;
     rate = Slot->EffectProps.Flanger.Rate;
@@ -132,7 +134,7 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co
                 state->lfo_scale = 4.0f / state->lfo_range;
                 break;
             case FWF_Sinusoid:
-                state->lfo_scale = F_2PI / state->lfo_range;
+                state->lfo_scale = F_TAU / state->lfo_range;
                 break;
         }
 
@@ -201,15 +203,15 @@ DECL_TEMPLATE(Sinusoid)
 
 #undef DECL_TEMPLATE
 
-static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     ALuint it, kt;
     ALuint base;
 
     for(base = 0;base < SamplesToDo;)
     {
-        ALfloat temps[64][2];
-        ALuint td = minu(SamplesToDo-base, 64);
+        ALfloat temps[128][2];
+        ALuint td = minu(128, SamplesToDo-base);
 
         switch(state->waveform)
         {
@@ -221,17 +223,17 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo,
                 break;
         }
 
-        for(kt = 0;kt < MaxChannels;kt++)
+        for(kt = 0;kt < NumChannels;kt++)
         {
             ALfloat gain = state->Gain[0][kt];
-            if(gain > GAIN_SILENCE_THRESHOLD)
+            if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
             {
                 for(it = 0;it < td;it++)
                     SamplesOut[kt][it+base] += temps[it][0] * gain;
             }
 
             gain = state->Gain[1][kt];
-            if(gain > GAIN_SILENCE_THRESHOLD)
+            if(fabsf(gain) > GAIN_SILENCE_THRESHOLD)
             {
                 for(it = 0;it < td;it++)
                     SamplesOut[kt][it+base] += temps[it][1] * gain;

+ 16 - 17
libs/openal-soft/Alc/effects/modulator.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -42,7 +42,7 @@ typedef struct ALmodulatorState {
     ALuint index;
     ALuint step;
 
-    ALfloat Gain[MaxChannels];
+    ALfloat Gain[MAX_OUTPUT_CHANNELS];
 
     ALfilterState Filter;
 } ALmodulatorState;
@@ -53,7 +53,7 @@ typedef struct ALmodulatorState {
 
 static inline ALfloat Sin(ALuint index)
 {
-    return sinf(index*(F_2PI/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
+    return sinf(index*(F_TAU/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f;
 }
 
 static inline ALfloat Saw(ALuint index)
@@ -69,7 +69,7 @@ static inline ALfloat Square(ALuint index)
 #define DECL_TEMPLATE(func)                                                   \
 static void Process##func(ALmodulatorState *state, ALuint SamplesToDo,        \
   const ALfloat *restrict SamplesIn,                                          \
-  ALfloat (*restrict SamplesOut)[BUFFERSIZE])                                 \
+  ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)             \
 {                                                                             \
     const ALuint step = state->step;                                          \
     ALuint index = state->index;                                              \
@@ -77,8 +77,8 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo,        \
                                                                               \
     for(base = 0;base < SamplesToDo;)                                         \
     {                                                                         \
-        ALfloat temps[64];                                                    \
-        ALuint td = minu(SamplesToDo-base, 64);                               \
+        ALfloat temps[256];                                                   \
+        ALuint td = minu(256, SamplesToDo-base);                              \
         ALuint i, k;                                                          \
                                                                               \
         for(i = 0;i < td;i++)                                                 \
@@ -92,10 +92,10 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo,        \
             temps[i] = samp * func(index);                                    \
         }                                                                     \
                                                                               \
-        for(k = 0;k < MaxChannels;k++)                                        \
+        for(k = 0;k < NumChannels;k++)                                        \
         {                                                                     \
             ALfloat gain = state->Gain[k];                                    \
-            if(!(gain > GAIN_SILENCE_THRESHOLD))                              \
+            if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))                       \
                 continue;                                                     \
                                                                               \
             for(i = 0;i < td;i++)                                             \
@@ -125,7 +125,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state),
 
 static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot)
 {
-    ALfloat gain, cw, a;
+    ALfloat cw, a;
 
     if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
         state->Waveform = SINUSOID;
@@ -139,7 +139,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device
     if(state->step == 0) state->step = 1;
 
     /* Custom filter coeffs, which match the old version instead of a low-shelf. */
-    cw = cosf(F_2PI * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency);
+    cw = cosf(F_TAU * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency);
     a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f);
 
     state->Filter.b[0] = a;
@@ -149,24 +149,23 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device
     state->Filter.a[1] = -a;
     state->Filter.a[2] = 0.0f;
 
-    gain = sqrtf(1.0f/Device->NumChan) * Slot->Gain;
-    SetGains(Device, gain, state->Gain);
+    ComputeAmbientGains(Device, Slot->Gain, state->Gain);
 }
 
-static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE])
+static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels)
 {
     switch(state->Waveform)
     {
         case SINUSOID:
-            ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut);
+            ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
             break;
 
         case SAWTOOTH:
-            ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut);
+            ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
             break;
 
         case SQUARE:
-            ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut);
+            ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels);
             break;
     }
 }

+ 1 - 4
libs/openal-soft/Alc/effects/null.c

@@ -41,11 +41,8 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), ALCdevice* UNUSED(d
  * input to the output buffer. The result should be added to the output buffer,
  * not replace it.
  */
-static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloat (*restrict samplesOut)[BUFFERSIZE])
+static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels))
 {
-    /* NOTE: Couldn't use the UNUSED macro on samplesOut due to the way GCC's
-     * __attribute__ declaration interacts with the parenthesis. */
-    (void)samplesOut;
 }
 
 /* This allocates memory to store the object, before it gets constructed.

File diff suppressed because it is too large
+ 417 - 395
libs/openal-soft/Alc/effects/reverb.c


+ 655 - 93
libs/openal-soft/Alc/helpers.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -35,6 +35,9 @@
 #ifdef HAVE_MALLOC_H
 #include <malloc.h>
 #endif
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
 
 #ifndef AL_NO_UID_DEFS
 #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
@@ -55,10 +58,13 @@ DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc
 DEFINE_GUID(IID_IMMDeviceEnumerator,  0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6);
 DEFINE_GUID(IID_IAudioClient,         0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
 DEFINE_GUID(IID_IAudioRenderClient,   0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
+DEFINE_GUID(IID_IAudioCaptureClient,  0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17);
 
 #ifdef HAVE_MMDEVAPI
 #include <devpropdef.h>
+#include <propkeydef.h>
 DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
+DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
 #endif
 #endif
 #endif /* AL_NO_UID_DEFS */
@@ -82,7 +88,9 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
 #include <ieeefp.h>
 #endif
 
-#ifdef _WIN32_IE
+#ifndef _WIN32
+#include <unistd.h>
+#elif defined(_WIN32_IE)
 #include <shlobj.h>
 #endif
 
@@ -144,8 +152,12 @@ void FillCPUCaps(ALuint capfilter)
                 if((cpuinf[0].regs[3]&(1<<26)))
                 {
                     caps |= CPU_CAP_SSE2;
-                    if((cpuinf[0].regs[2]&(1<<19)))
-                        caps |= CPU_CAP_SSE4_1;
+                    if((cpuinf[0].regs[2]&(1<<0)))
+                    {
+                        caps |= CPU_CAP_SSE3;
+                        if((cpuinf[0].regs[2]&(1<<19)))
+                            caps |= CPU_CAP_SSE4_1;
+                    }
                 }
             }
         }
@@ -188,8 +200,12 @@ void FillCPUCaps(ALuint capfilter)
                 if((cpuinf[0].regs[3]&(1<<26)))
                 {
                     caps |= CPU_CAP_SSE2;
-                    if((cpuinf[0].regs[2]&(1<<19)))
-                        caps |= CPU_CAP_SSE4_1;
+                    if((cpuinf[0].regs[2]&(1<<0)))
+                    {
+                        caps |= CPU_CAP_SSE3;
+                        if((cpuinf[0].regs[2]&(1<<19)))
+                            caps |= CPU_CAP_SSE4_1;
+                    }
                 }
             }
         }
@@ -198,13 +214,16 @@ void FillCPUCaps(ALuint capfilter)
     /* Assume support for whatever's supported if we can't check for it */
 #if defined(HAVE_SSE4_1)
 #warning "Assuming SSE 4.1 run-time support!"
-    capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1;
+    caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
+#elif defined(HAVE_SSE3)
+#warning "Assuming SSE 3 run-time support!"
+    caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
 #elif defined(HAVE_SSE2)
 #warning "Assuming SSE 2 run-time support!"
-    capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
+    caps |= CPU_CAP_SSE | CPU_CAP_SSE2;
 #elif defined(HAVE_SSE)
 #warning "Assuming SSE run-time support!"
-    capfilter |= CPU_CAP_SSE;
+    caps |= CPU_CAP_SSE;
 #endif
 #endif
 #ifdef HAVE_NEON
@@ -212,9 +231,10 @@ void FillCPUCaps(ALuint capfilter)
     caps |= CPU_CAP_NEON;
 #endif
 
-    TRACE("Extensions:%s%s%s%s%s\n",
+    TRACE("Extensions:%s%s%s%s%s%s\n",
         ((capfilter&CPU_CAP_SSE)    ? ((caps&CPU_CAP_SSE)    ? " +SSE"    : " -SSE")    : ""),
         ((capfilter&CPU_CAP_SSE2)   ? ((caps&CPU_CAP_SSE2)   ? " +SSE2"   : " -SSE2")   : ""),
+        ((capfilter&CPU_CAP_SSE3)   ? ((caps&CPU_CAP_SSE3)   ? " +SSE3"   : " -SSE3")   : ""),
         ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
         ((capfilter&CPU_CAP_NEON)   ? ((caps&CPU_CAP_NEON)   ? " +Neon"   : " -Neon")   : ""),
         ((!capfilter) ? " -none-" : "")
@@ -240,7 +260,7 @@ void *al_malloc(size_t alignment, size_t size)
     if(ret != NULL)
     {
         *(ret++) = 0x00;
-        while(((ALintptrEXT)ret&(alignment-1)) != 0)
+        while(((ptrdiff_t)ret&(alignment-1)) != 0)
             *(ret++) = 0x55;
     }
     return ret;
@@ -278,6 +298,8 @@ void SetMixerFPUMode(FPUCtl *ctl)
 #ifdef HAVE_FENV_H
     fegetenv(STATIC_CAST(fenv_t, ctl));
 #if defined(__GNUC__) && defined(HAVE_SSE)
+    /* FIXME: Some fegetenv implementations can get the SSE environment too?
+     * How to tell when it does? */
     if((CPUCapFlags&CPU_CAP_SSE))
         __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state));
 #endif
@@ -421,55 +443,31 @@ FILE *al_fopen(const char *fname, const char *mode)
     return file;
 }
 
-#else
-
-#ifdef HAVE_DLFCN_H
-
-void *LoadLib(const char *name)
-{
-    const char *err;
-    void *handle;
-
-    dlerror();
-    handle = dlopen(name, RTLD_NOW);
-    if((err=dlerror()) != NULL)
-        handle = NULL;
-    return handle;
-}
-void CloseLib(void *handle)
-{ dlclose(handle); }
-void *GetSymbol(void *handle, const char *name)
-{
-    const char *err;
-    void *sym;
-
-    dlerror();
-    sym = dlsym(handle, name);
-    if((err=dlerror()) != NULL)
-    {
-        WARN("Failed to load %s: %s\n", name, err);
-        sym = NULL;
-    }
-    return sym;
-}
-
-#endif
-#endif
-
 
 void al_print(const char *type, const char *func, const char *fmt, ...)
 {
+    char str[1024];
+    WCHAR *wstr;
     va_list ap;
 
     va_start(ap, fmt);
-    fprintf(LogFile, "AL lib: %s %s: ", type, func);
-    vfprintf(LogFile, fmt, ap);
+    vsnprintf(str, sizeof(str), fmt, ap);
     va_end(ap);
 
+    str[sizeof(str)-1] = 0;
+    wstr = FromUTF8(str);
+    if(!wstr)
+        fprintf(LogFile, "AL lib: %s %s: <UTF-8 error> %s", type, func, str);
+    else
+    {
+        fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr);
+        free(wstr);
+        wstr = NULL;
+    }
     fflush(LogFile);
 }
 
-#ifdef _WIN32
+
 static inline int is_slash(int c)
 { return (c == '\\' || c == '/'); }
 
@@ -478,35 +476,42 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
     static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
     WCHAR *wname=NULL, *wsubdir=NULL;
     FILE *f;
-    int i;
+    size_t i;
 
-    /* If the path is absolute, open it directly. */
-    if(fname[0] != '\0' && fname[1] == ':' && is_slash(fname[2]))
+    wname = FromUTF8(fname);
+    if(!wname)
     {
-        if((f=al_fopen(fname, "rb")) != NULL)
-        {
-            TRACE("Opened %s\n", fname);
-            return f;
-        }
-        WARN("Could not open %s\n", fname);
+        ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
         return NULL;
     }
 
-    /* If it's relative, try the current directory first before the data directories. */
-    if((f=al_fopen(fname, "rb")) != NULL)
+    /* If the path is absolute, open it directly. */
+    if(wname[0] != '\0' && wname[1] == ':' && is_slash(wname[2]))
+    {
+        f = _wfopen(wname, L"rb");
+        if(f) TRACE("Opened %s\n", fname);
+        else WARN("Could not open %s\n", fname);
+        free(wname);
+        return f;
+    }
+
+    /* Try the current directory first before the data directories. */
+    if((f=_wfopen(wname, L"rb")) != NULL)
     {
         TRACE("Opened %s\n", fname);
+        free(wname);
         return f;
     }
-    WARN("Could not open %s\n", fname);
 
-    wname = FromUTF8(fname);
     wsubdir = FromUTF8(subdir);
-    if(!wname)
-        ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
-    else if(!wsubdir)
+    if(!wsubdir)
+    {
         ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir);
-    else for(i = 0;i < 2;i++)
+        free(wname);
+        return NULL;
+    }
+
+    for(i = 0;i < COUNTOF(ids);i++)
     {
         WCHAR buffer[PATH_MAX];
         size_t len;
@@ -528,17 +533,347 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
 
         if((f=_wfopen(buffer, L"rb")) != NULL)
         {
-            TRACE("Opened %ls\n", buffer);
-            return f;
+            al_string filepath = AL_STRING_INIT_STATIC();
+            al_string_copy_wcstr(&filepath, buffer);
+            TRACE("Opened %s\n", al_string_get_cstr(filepath));
+            al_string_deinit(&filepath);
+            break;
         }
-        WARN("Could not open %ls\n", buffer);
     }
     free(wname);
     free(wsubdir);
 
+    if(f == NULL)
+        WARN("Could not open %s\\%s\n", subdir, fname);
+    return f;
+}
+
+
+static const WCHAR *strchrW(const WCHAR *str, WCHAR ch)
+{
+    for(;*str != 0;++str)
+    {
+        if(*str == ch)
+            return str;
+    }
     return NULL;
 }
+
+static const WCHAR *strrchrW(const WCHAR *str, WCHAR ch)
+{
+    const WCHAR *ret = NULL;
+    for(;*str != 0;++str)
+    {
+        if(*str == ch)
+            ret = str;
+    }
+    return ret;
+}
+
+/* Compares the filename in the find data with the match string. The match
+ * string may contain the "%r" marker to signifiy a sample rate (really any
+ * positive integer), or "%%" to signify a single '%'.
+ */
+static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata)
+{
+    const WCHAR *name = fdata->cFileName;
+    int ret = 1;
+
+    do {
+        const WCHAR *p = strchrW(match, '%');
+        if(!p)
+            ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
+                                 match, -1, name, -1) == CSTR_EQUAL;
+        else
+        {
+            int len = p-match;
+            ret = lstrlenW(name) >= len;
+            if(ret)
+                ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
+                                     match, len, name, len) == CSTR_EQUAL;
+            if(ret)
+            {
+                match += len;
+                name += len;
+
+                ++p;
+                if(*p == 'r')
+                {
+                    unsigned long l = 0;
+                    while(*name >= '0' && *name <= '9')
+                    {
+                        l = l*10 + (*name-'0');
+                        ++name;
+                    }
+                    ret = l > 0;
+                    ++p;
+                }
+            }
+        }
+
+        match = p;
+    } while(ret && match && *match);
+
+    return ret;
+}
+
+static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_al_string *results)
+{
+    WIN32_FIND_DATAW fdata;
+    const WCHAR *sep, *p;
+    HANDLE hdl;
+
+    if(!match[0])
+        return;
+
+    /* Find the last directory separator and the next '%' marker in the match
+     * string. */
+    sep = strrchrW(match, '\\');
+    p = strchrW(match, '%');
+
+    /* If there's no separator, test the files in the specified path against
+     * the match string, and add the results. */
+    if(!sep)
+    {
+        al_string pathstr = AL_STRING_INIT_STATIC();
+        WCHAR *wpath;
+
+        TRACE("Searching %s for %ls\n", path, match);
+
+        al_string_append_cstr(&pathstr, path);
+        al_string_append_cstr(&pathstr, "\\*.*");
+        wpath = FromUTF8(al_string_get_cstr(pathstr));
+
+        hdl = FindFirstFileW(wpath, &fdata);
+        if(hdl != INVALID_HANDLE_VALUE)
+        {
+            do {
+                if(MatchFilter(match, &fdata))
+                {
+                    al_string str = AL_STRING_INIT_STATIC();
+                    al_string_copy_cstr(&str, path);
+                    al_string_append_char(&str, '\\');
+                    al_string_append_wcstr(&str, fdata.cFileName);
+                    TRACE("Got result %s\n", al_string_get_cstr(str));
+                    VECTOR_PUSH_BACK(*results, str);
+                }
+            } while(FindNextFileW(hdl, &fdata));
+            FindClose(hdl);
+        }
+
+        free(wpath);
+        al_string_deinit(&pathstr);
+
+        return;
+    }
+
+    /* If there's no '%' marker, or it's after the final separator, append the
+     * remaining directories to the path and recurse into it with the remaining
+     * filename portion. */
+    if(!p || p-sep >= 0)
+    {
+        al_string npath = AL_STRING_INIT_STATIC();
+        al_string_append_cstr(&npath, path);
+        al_string_append_char(&npath, '\\');
+        al_string_append_wrange(&npath, match, sep);
+
+        TRACE("Recursing into %s with %ls\n", al_string_get_cstr(npath), sep+1);
+        RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results);
+
+        al_string_deinit(&npath);
+        return;
+    }
+
+    /* Look for the last separator before the '%' marker, and the first
+     * separator after it. */
+    sep = strchrW(match, '\\');
+    if(sep-p >= 0) sep = NULL;
+    for(;;)
+    {
+        const WCHAR *next = strchrW(sep?sep+1:match, '\\');
+        if(next-p < 0)
+        {
+            al_string npath = AL_STRING_INIT_STATIC();
+            WCHAR *nwpath, *nwmatch;
+
+            /* Append up to the last directory before the one with a '%'. */
+            al_string_copy_cstr(&npath, path);
+            if(sep)
+            {
+                al_string_append_char(&npath, '\\');
+                al_string_append_wrange(&npath, match, sep);
+            }
+            al_string_append_cstr(&npath, "\\*.*");
+            nwpath = FromUTF8(al_string_get_cstr(npath));
+
+            /* Take the directory name containing a '%' as a new string to
+             * match against. */
+            if(!sep)
+            {
+                nwmatch = calloc(2, next-match+1);
+                memcpy(nwmatch, match, (next-match)*2);
+            }
+            else
+            {
+                nwmatch = calloc(2, next-(sep+1)+1);
+                memcpy(nwmatch, sep+1, (next-(sep+1))*2);
+            }
+
+            /* For each matching directory name, recurse into it with the
+             * remaining string. */
+            TRACE("Searching %s for %ls\n", al_string_get_cstr(npath), nwmatch);
+            hdl = FindFirstFileW(nwpath, &fdata);
+            if(hdl != INVALID_HANDLE_VALUE)
+            {
+                do {
+                    if(MatchFilter(nwmatch, &fdata))
+                    {
+                        al_string ndir = AL_STRING_INIT_STATIC();
+                        al_string_copy(&ndir, npath);
+                        al_string_append_char(&ndir, '\\');
+                        al_string_append_wcstr(&ndir, fdata.cFileName);
+                        TRACE("Recursing %s with %ls\n", al_string_get_cstr(ndir), next+1);
+                        RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results);
+                        al_string_deinit(&ndir);
+                    }
+                } while(FindNextFileW(hdl, &fdata));
+                FindClose(hdl);
+            }
+
+            free(nwmatch);
+            free(nwpath);
+            al_string_deinit(&npath);
+            break;
+        }
+        sep = next;
+    }
+}
+
+vector_al_string SearchDataFiles(const char *match, const char *subdir)
+{
+    static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
+    static RefCount search_lock;
+    vector_al_string results = VECTOR_INIT_STATIC();
+    WCHAR *wmatch;
+    size_t i;
+
+    while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
+        althrd_yield();
+
+    wmatch = FromUTF8(match);
+    if(!wmatch)
+    {
+        ERR("Failed to convert UTF-8 filename: \"%s\"\n", match);
+        return results;
+    }
+    for(i = 0;wmatch[i];++i)
+    {
+        if(wmatch[i] == '/')
+            wmatch[i] = '\\';
+    }
+
+    /* If the path is absolute, use it directly. */
+    if(isalpha(wmatch[0]) && wmatch[1] == ':' && is_slash(wmatch[2]))
+    {
+        char drv[3] = { (char)wmatch[0], ':', 0 };
+        RecurseDirectorySearch(drv, wmatch+3, &results);
+    }
+    else if(wmatch[0] == '\\' && wmatch[1] == '\\' && wmatch[2] == '?' && wmatch[3] == '\\')
+        RecurseDirectorySearch("\\\\?", wmatch+4, &results);
+    else
+    {
+        al_string path = AL_STRING_INIT_STATIC();
+        WCHAR *cwdbuf;
+
+        /* Search the CWD. */
+        if(!(cwdbuf=_wgetcwd(NULL, 0)))
+            al_string_copy_cstr(&path, ".");
+        else
+        {
+            al_string_copy_wcstr(&path, cwdbuf);
+            if(is_slash(VECTOR_BACK(path)))
+            {
+                VECTOR_POP_BACK(path);
+                *VECTOR_ITER_END(path) = 0;
+            }
+            free(cwdbuf);
+        }
+        RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results);
+
+        /* Search the local and global data dirs. */
+        for(i = 0;i < COUNTOF(ids);i++)
+        {
+            WCHAR buffer[PATH_MAX];
+            if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE)
+            {
+                al_string_copy_wcstr(&path, buffer);
+                if(!is_slash(VECTOR_BACK(path)))
+                    al_string_append_char(&path, '\\');
+                al_string_append_cstr(&path, subdir);
+#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0)
+                VECTOR_FOR_EACH(char, path, FIX_SLASH);
+#undef FIX_SLASH
+
+                RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results);
+            }
+        }
+
+        al_string_deinit(&path);
+    }
+
+    free(wmatch);
+    ATOMIC_STORE(&search_lock, 0);
+
+    return results;
+}
+
 #else
+
+#ifdef HAVE_DLFCN_H
+
+void *LoadLib(const char *name)
+{
+    const char *err;
+    void *handle;
+
+    dlerror();
+    handle = dlopen(name, RTLD_NOW);
+    if((err=dlerror()) != NULL)
+        handle = NULL;
+    return handle;
+}
+void CloseLib(void *handle)
+{ dlclose(handle); }
+void *GetSymbol(void *handle, const char *name)
+{
+    const char *err;
+    void *sym;
+
+    dlerror();
+    sym = dlsym(handle, name);
+    if((err=dlerror()) != NULL)
+    {
+        WARN("Failed to load %s: %s\n", name, err);
+        sym = NULL;
+    }
+    return sym;
+}
+
+#endif /* HAVE_DLFCN_H */
+
+void al_print(const char *type, const char *func, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    fprintf(LogFile, "AL lib: %s %s: ", type, func);
+    vfprintf(LogFile, fmt, ap);
+    va_end(ap);
+
+    fflush(LogFile);
+}
+
+
 FILE *OpenDataFile(const char *fname, const char *subdir)
 {
     char buffer[PATH_MAX] = "";
@@ -561,7 +896,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
         TRACE("Opened %s\n", fname);
         return f;
     }
-    WARN("Could not open %s\n", fname);
 
     if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
         snprintf(buffer, sizeof(buffer), "%s/%s/%s", str, subdir, fname);
@@ -574,7 +908,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
             TRACE("Opened %s\n", buffer);
             return f;
         }
-        WARN("Could not open %s\n", buffer);
     }
 
     if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
@@ -605,11 +938,221 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
             TRACE("Opened %s\n", buffer);
             return f;
         }
-        WARN("Could not open %s\n", buffer);
     }
+    WARN("Could not open %s/%s\n", subdir, fname);
 
     return NULL;
 }
+
+
+static const char *MatchString;
+static int MatchFilter(const struct dirent *dir)
+{
+    const char *match = MatchString;
+    const char *name = dir->d_name;
+    int ret = 1;
+
+    do {
+        const char *p = strchr(match, '%');
+        if(!p)
+            ret = strcmp(match, name) == 0;
+        else
+        {
+            size_t len = p-match;
+            ret = strncmp(match, name, len) == 0;
+            if(ret)
+            {
+                match += len;
+                name += len;
+
+                ++p;
+                if(*p == 'r')
+                {
+                    char *end;
+                    ret = strtoul(name, &end, 10) > 0;
+                    if(ret) name = end;
+                    ++p;
+                }
+            }
+        }
+
+        match = p;
+    } while(ret && match && *match);
+
+    return ret;
+}
+
+static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results)
+{
+    struct dirent **namelist;
+    char *sep, *p;
+    int n, i;
+
+    if(!match[0])
+        return;
+
+    sep = strrchr(match, '/');
+    p = strchr(match, '%');
+
+    if(!sep)
+    {
+        MatchString = match;
+        TRACE("Searching %s for %s\n", path?path:"/", match);
+        n = scandir(path?path:"/", &namelist, MatchFilter, alphasort);
+        if(n >= 0)
+        {
+            for(i = 0;i < n;++i)
+            {
+                al_string str = AL_STRING_INIT_STATIC();
+                if(path) al_string_copy_cstr(&str, path);
+                al_string_append_char(&str, '/');
+                al_string_append_cstr(&str, namelist[i]->d_name);
+                TRACE("Got result %s\n", al_string_get_cstr(str));
+                VECTOR_PUSH_BACK(*results, str);
+                free(namelist[i]);
+            }
+            free(namelist);
+        }
+
+        return;
+    }
+
+    if(!p || p-sep >= 0)
+    {
+        al_string npath = AL_STRING_INIT_STATIC();
+        if(path) al_string_append_cstr(&npath, path);
+        al_string_append_char(&npath, '/');
+        al_string_append_range(&npath, match, sep);
+
+        TRACE("Recursing into %s with %s\n", al_string_get_cstr(npath), sep+1);
+        RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results);
+
+        al_string_deinit(&npath);
+        return;
+    }
+
+    sep = strchr(match, '/');
+    if(sep-p >= 0) sep = NULL;
+    for(;;)
+    {
+        char *next = strchr(sep?sep+1:match, '/');
+        if(next-p < 0)
+        {
+            al_string npath = AL_STRING_INIT_STATIC();
+            al_string nmatch = AL_STRING_INIT_STATIC();
+
+            if(!sep)
+            {
+                al_string_append_cstr(&npath, path?path:"/.");
+                MatchString = match;
+            }
+            else
+            {
+                if(path) al_string_append_cstr(&npath, path);
+                al_string_append_char(&npath, '/');
+                al_string_append_range(&npath, match, sep);
+
+                al_string_append_range(&nmatch, sep+1, next);
+                MatchString = al_string_get_cstr(nmatch);
+            }
+
+            TRACE("Searching %s for %s\n", al_string_get_cstr(npath), MatchString);
+            n = scandir(al_string_get_cstr(npath), &namelist, MatchFilter, alphasort);
+            if(n >= 0)
+            {
+                al_string ndir = AL_STRING_INIT_STATIC();
+                for(i = 0;i < n;++i)
+                {
+                    al_string_copy(&ndir, npath);
+                    al_string_append_char(&ndir, '/');
+                    al_string_append_cstr(&ndir, namelist[i]->d_name);
+                    free(namelist[i]);
+                    TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1);
+                    RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results);
+                }
+                al_string_deinit(&ndir);
+                free(namelist);
+            }
+
+            al_string_deinit(&nmatch);
+            al_string_deinit(&npath);
+            break;
+        }
+
+        sep = next;
+    }
+}
+
+vector_al_string SearchDataFiles(const char *match, const char *subdir)
+{
+    static RefCount search_lock;
+    vector_al_string results = VECTOR_INIT_STATIC();
+
+    while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
+        althrd_yield();
+
+    if(match[0] == '/')
+        RecurseDirectorySearch(NULL, match+1, &results);
+    else
+    {
+        al_string path = AL_STRING_INIT_STATIC();
+        const char *str, *next;
+        char cwdbuf[PATH_MAX];
+
+        // Search CWD
+        if(!getcwd(cwdbuf, sizeof(cwdbuf)))
+            strcpy(cwdbuf, ".");
+        RecurseDirectorySearch(cwdbuf, match, &results);
+
+        // Search local data dir
+        if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
+        {
+            al_string_append_cstr(&path, str);
+            al_string_append_char(&path, '/');
+            al_string_append_cstr(&path, subdir);
+        }
+        else if((str=getenv("HOME")) != NULL && str[0] != '\0')
+        {
+            al_string_append_cstr(&path, str);
+            al_string_append_cstr(&path, "/.local/share/");
+            al_string_append_cstr(&path, subdir);
+        }
+        if(!al_string_empty(path))
+            RecurseDirectorySearch(al_string_get_cstr(path), match, &results);
+
+        // Search global data dirs
+        if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
+            str = "/usr/local/share/:/usr/share/";
+
+        next = str;
+        while((str=next) != NULL && str[0] != '\0')
+        {
+            next = strchr(str, ':');
+            if(!next)
+                al_string_copy_cstr(&path, str);
+            else
+            {
+                al_string_clear(&path);
+                al_string_append_range(&path, str, next);
+                ++next;
+            }
+            if(!al_string_empty(path))
+            {
+                al_string_append_char(&path, '/');
+                al_string_append_cstr(&path, subdir);
+
+                RecurseDirectorySearch(al_string_get_cstr(path), match, &results);
+            }
+        }
+
+        al_string_deinit(&path);
+    }
+
+    ATOMIC_STORE(&search_lock, 0);
+
+    return results;
+}
+
 #endif
 
 
@@ -638,25 +1181,20 @@ void SetRTPriority(void)
 }
 
 
-ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count, ALboolean exact)
+ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact)
 {
     vector_ *vecptr = (vector_*)ptr;
-    if(obj_count < 0)
-        return AL_FALSE;
     if((*vecptr ? (*vecptr)->Capacity : 0) < obj_count)
     {
-        ALsizei old_size = (*vecptr ? (*vecptr)->Size : 0);
+        size_t old_size = (*vecptr ? (*vecptr)->Size : 0);
         void *temp;
 
         /* Use the next power-of-2 size if we don't need to allocate the exact
          * amount. This is preferred when regularly increasing the vector since
          * it means fewer reallocations. Though it means it also wastes some
          * memory. */
-        if(exact == AL_FALSE)
-        {
+        if(exact == AL_FALSE && obj_count < INT_MAX)
             obj_count = NextPowerOf2((ALuint)obj_count);
-            if(obj_count < 0) return AL_FALSE;
-        }
 
         /* Need to be explicit with the caller type's base size, because it
          * could have extra padding before the start of the array (that is,
@@ -671,11 +1209,9 @@ ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei o
     return AL_TRUE;
 }
 
-ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count)
+ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count)
 {
     vector_ *vecptr = (vector_*)ptr;
-    if(obj_count < 0)
-        return AL_FALSE;
     if(*vecptr || obj_count > 0)
     {
         if(!vector_reserve((char*)vecptr, base_size, obj_size, obj_count, AL_TRUE))
@@ -696,12 +1232,12 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
         ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size;
 
         assert(numins > 0);
-        if(INT_MAX-VECTOR_SIZE(*vecptr) <= numins ||
+        if((size_t)numins + VECTOR_SIZE(*vecptr) < (size_t)numins ||
            !vector_reserve((char*)vecptr, base_size, obj_size, VECTOR_SIZE(*vecptr)+numins, AL_TRUE))
             return AL_FALSE;
 
         /* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */
-        if(ins_elem < (*vecptr)->Size)
+        if((size_t)ins_elem < (*vecptr)->Size)
         {
             memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size),
                     (char*)(*vecptr) + base_size + ((ins_elem       )*obj_size),
@@ -709,14 +1245,14 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
         }
         memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size),
                datstart, numins*obj_size);
-        (*vecptr)->Size += (ALsizei)numins;
+        (*vecptr)->Size += numins;
     }
     return AL_TRUE;
 }
 
 
 extern inline void al_string_deinit(al_string *str);
-extern inline ALsizei al_string_length(const_al_string str);
+extern inline size_t al_string_length(const_al_string str);
 extern inline ALboolean al_string_empty(const_al_string str);
 extern inline const al_string_char_type *al_string_get_cstr(const_al_string str);
 
@@ -730,10 +1266,10 @@ void al_string_clear(al_string *str)
     *VECTOR_ITER_END(*str) = 0;
 }
 
-static inline int al_string_compare(const al_string_char_type *str1, ALsizei str1len,
-                                    const al_string_char_type *str2, ALsizei str2len)
+static inline int al_string_compare(const al_string_char_type *str1, size_t str1len,
+                                    const al_string_char_type *str2, size_t str2len)
 {
-    ALsizei complen = mini(str1len, str2len);
+    size_t complen = (str1len < str2len) ? str1len : str2len;
     int ret = memcmp(str1, str2, complen);
     if(ret == 0)
     {
@@ -750,12 +1286,12 @@ int al_string_cmp(const_al_string str1, const_al_string str2)
 int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2)
 {
     return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
-                             str2, (ALsizei)strlen(str2));
+                             str2, strlen(str2));
 }
 
 void al_string_copy(al_string *str, const_al_string from)
 {
-    ALsizei len = VECTOR_SIZE(from);
+    size_t len = al_string_length(from);
     VECTOR_RESERVE(*str, len+1);
     VECTOR_RESIZE(*str, 0);
     VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len);
@@ -811,4 +1347,30 @@ void al_string_copy_wcstr(al_string *str, const wchar_t *from)
         *VECTOR_ITER_END(*str) = 0;
     }
 }
+
+void al_string_append_wcstr(al_string *str, const wchar_t *from)
+{
+    int len;
+    if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
+    {
+        size_t strlen = al_string_length(*str);
+        VECTOR_RESERVE(*str, strlen+len);
+        VECTOR_RESIZE(*str, strlen+len-1);
+        WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str) + strlen, len, NULL, NULL);
+        *VECTOR_ITER_END(*str) = 0;
+    }
+}
+
+void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to)
+{
+    int len;
+    if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0)
+    {
+        size_t strlen = al_string_length(*str);
+        VECTOR_RESERVE(*str, strlen+len+1);
+        VECTOR_RESIZE(*str, strlen+len);
+        WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str) + strlen, len+1, NULL, NULL);
+        *VECTOR_ITER_END(*str) = 0;
+    }
+}
 #endif

+ 255 - 175
libs/openal-soft/Alc/hrtf.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -30,6 +30,8 @@
 #include "alu.h"
 #include "hrtf.h"
 
+#include "compat.h"
+
 
 /* Current data set limits defined by the makehrtf utility. */
 #define MIN_IR_SIZE                  (8)
@@ -52,6 +54,7 @@ struct Hrtf {
     const ALshort *coeffs;
     const ALubyte *delays;
 
+    al_string filename;
     struct Hrtf *next;
 };
 
@@ -82,45 +85,12 @@ static void CalcEvIndices(ALuint evcount, ALfloat ev, ALuint *evidx, ALfloat *ev
  */
 static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *azmu)
 {
-    az = (F_2PI + az) * azcount / (F_2PI);
+    az = (F_TAU + az) * azcount / F_TAU;
     azidx[0] = fastf2u(az) % azcount;
     azidx[1] = (azidx[0] + 1) % azcount;
     *azmu = az - floorf(az);
 }
 
-/* Calculates the normalized HRTF transition factor (delta) from the changes
- * in gain and listener to source angle between updates.  The result is a
- * normalized delta factor that can be used to calculate moving HRIR stepping
- * values.
- */
-ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3])
-{
-    ALfloat gainChange, angleChange, change;
-
-    // Calculate the normalized dB gain change.
-    newGain = maxf(newGain, 0.0001f);
-    oldGain = maxf(oldGain, 0.0001f);
-    gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
-
-    // Calculate the angle change only when there is enough gain to notice it.
-    angleChange = 0.0f;
-    if(gainChange > 0.0001f || newGain > 0.0001f)
-    {
-        // No angle change when the directions are equal or degenerate (when
-        // both have zero length).
-        if(newdir[0] != olddir[0] || newdir[1] != olddir[1] || newdir[2] != olddir[2])
-        {
-            ALfloat dotp = olddir[0]*newdir[0] + olddir[1]*newdir[1] + olddir[2]*newdir[2];
-            angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI;
-        }
-    }
-
-    // Use the largest of the two changes for the delta factor, and apply a
-    // significance shaping function to it.
-    change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
-    return minf(change, 1.0f);
-}
-
 /* Calculates static HRIR coefficients and delays for the given polar
  * elevation and azimuth in radians.  Linear interpolation is used to
  * increase the apparent resolution of the HRIR data set.  The coefficients
@@ -183,24 +153,22 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
     {
         ALfloat c;
 
-        gain *= 1.0f/32767.0f;
-
         i = 0;
         c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
              Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
-        coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain;
+        coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
         c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
              Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
-        coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain;
+        coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
 
         for(i = 1;i < Hrtf->irSize;i++)
         {
             c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
                  Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
-            coeffs[i][0] = lerp(0.0f, c, dirfact) * gain;
+            coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
             c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
                  Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
-            coeffs[i][1] = lerp(0.0f, c, dirfact) * gain;
+            coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
         }
     }
     else
@@ -225,7 +193,7 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
     ALuint evidx[2], lidx[4], ridx[4];
     ALfloat mu[3], blend[4];
     ALfloat left, right;
-    ALfloat step;
+    ALfloat steps;
     ALuint i;
 
     /* Claculate elevation indices and interpolation factor. */
@@ -248,8 +216,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
     }
 
     // Calculate the stepping parameters.
-    delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f);
-    step = 1.0f / delta;
+    steps = maxf(floorf(delta*Hrtf->sampleRate + 0.5f), 1.0f);
+    delta = 1.0f / steps;
 
     /* Calculate 4 blending weights for 2D bilinear interpolation. */
     blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]);
@@ -271,8 +239,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
                          Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
                         dirfact + 0.5f) << HRTFDELAY_BITS;
 
-    delayStep[0] = fastf2i(step * (delays[0] - left));
-    delayStep[1] = fastf2i(step * (delays[1] - right));
+    delayStep[0] = fastf2i(delta * (delays[0] - left));
+    delayStep[1] = fastf2i(delta * (delays[1] - right));
 
     /* Calculate the sample offsets for the HRIR indices. */
     lidx[0] *= Hrtf->irSize;
@@ -294,21 +262,19 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
     {
         ALfloat c;
 
-        gain *= 1.0f/32767.0f;
-
         i = 0;
         left = coeffs[i][0] - (coeffStep[i][0] * counter);
         right = coeffs[i][1] - (coeffStep[i][1] * counter);
 
         c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
              Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
-        coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain;
+        coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
         c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
              Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
-        coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain;
+        coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
 
-        coeffStep[i][0] = step * (coeffs[i][0] - left);
-        coeffStep[i][1] = step * (coeffs[i][1] - right);
+        coeffStep[i][0] = delta * (coeffs[i][0] - left);
+        coeffStep[i][1] = delta * (coeffs[i][1] - right);
 
         for(i = 1;i < Hrtf->irSize;i++)
         {
@@ -317,13 +283,13 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
 
             c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
                  Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
-            coeffs[i][0] = lerp(0.0f, c, dirfact) * gain;
+            coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
             c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
                  Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
-            coeffs[i][1] = lerp(0.0f, c, dirfact) * gain;
+            coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
 
-            coeffStep[i][0] = step * (coeffs[i][0] - left);
-            coeffStep[i][1] = step * (coeffs[i][1] - right);
+            coeffStep[i][0] = delta * (coeffs[i][0] - left);
+            coeffStep[i][1] = delta * (coeffs[i][1] - right);
         }
     }
     else
@@ -336,8 +302,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
             coeffs[i][0] = 0.0f;
             coeffs[i][1] = 0.0f;
 
-            coeffStep[i][0] = step * -left;
-            coeffStep[i][1] = step * -right;
+            coeffStep[i][0] = delta * -left;
+            coeffStep[i][1] = delta * -right;
         }
     }
 
@@ -345,13 +311,118 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
      * complete its transition.  The mixer will only apply stepping for this
      * many samples.
      */
-    return fastf2u(delta);
+    return fastf2u(steps);
+}
+
+
+/* Calculates HRTF coefficients for B-Format channels (only up to first-order).
+ * Note that these will decode a B-Format output mix, which uses FuMa ordering
+ * and scaling, not N3D!
+ */
+void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list)
+{
+    ALuint elev_idx, azi_idx;
+    ALfloat scale;
+    ALuint i, c;
+
+    assert(num_chans <= 4);
+
+    for(c = 0;c < num_chans;c++)
+    {
+        ALfloat (*coeffs)[2] = coeffs_list[c];
+        ALuint *delay = delay_list[c];
+
+        for(i = 0;i < Hrtf->irSize;i++)
+        {
+            coeffs[i][0] = 0.0f;
+            coeffs[i][1] = 0.0f;
+        }
+        delay[0] = 0;
+        delay[1] = 0;
+    }
+
+    /* NOTE: HRTF coefficients are generated by combining all the HRIRs in the
+     * dataset, with each entry scaled according to how much it contributes to
+     * the given B-Format channel based on its direction (including negative
+     * contributions!).
+     */
+    scale = 0.0f;
+    for(elev_idx = 0;elev_idx < Hrtf->evCount;elev_idx++)
+    {
+        ALfloat elev = (ALfloat)elev_idx/(ALfloat)(Hrtf->evCount-1)*F_PI - F_PI_2;
+        ALuint evoffset = Hrtf->evOffset[elev_idx];
+        ALuint azcount = Hrtf->azCount[elev_idx];
+
+        scale += (ALfloat)azcount;
+
+        for(azi_idx = 0;azi_idx < azcount;azi_idx++)
+        {
+            ALuint lidx, ridx;
+            ALfloat ambi_coeffs[4];
+            ALfloat az, gain;
+            ALfloat x, y, z;
+
+            lidx = evoffset + azi_idx;
+            ridx = evoffset + ((azcount-azi_idx) % azcount);
+
+            az = (ALfloat)azi_idx / (ALfloat)azcount * F_TAU;
+            if(az > F_PI) az -= F_TAU;
+
+            x = cosf(-az) * cosf(elev);
+            y = sinf(-az) * cosf(elev);
+            z = sinf(elev);
+
+            ambi_coeffs[0] = 1.414213562f;
+            ambi_coeffs[1] = x;
+            ambi_coeffs[2] = y;
+            ambi_coeffs[3] = z;
+
+            for(c = 0;c < num_chans;c++)
+            {
+                ALfloat (*coeffs)[2] = coeffs_list[c];
+                ALuint *delay = delay_list[c];
+
+                /* NOTE: Always include the total delay average since the
+                 * channels need to have matching delays. */
+                delay[0] += Hrtf->delays[lidx];
+                delay[1] += Hrtf->delays[ridx];
+
+                gain = ambi_coeffs[c];
+                if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
+                    continue;
+
+                for(i = 0;i < Hrtf->irSize;i++)
+                {
+                    coeffs[i][0] += Hrtf->coeffs[lidx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain;
+                    coeffs[i][1] += Hrtf->coeffs[ridx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain;
+                }
+            }
+        }
+    }
+
+    scale = 1.0f/scale;
+
+    for(c = 0;c < num_chans;c++)
+    {
+        ALfloat (*coeffs)[2] = coeffs_list[c];
+        ALuint *delay = delay_list[c];
+
+        for(i = 0;i < Hrtf->irSize;i++)
+        {
+            coeffs[i][0] *= scale;
+            coeffs[i][1] *= scale;
+        }
+        delay[0] = minu((ALuint)((ALfloat)delay[0] * scale), HRTF_HISTORY_LENGTH-1);
+        delay[0] <<= HRTFDELAY_BITS;
+        delay[1] = minu((ALuint)((ALfloat)delay[1] * scale), HRTF_HISTORY_LENGTH-1);
+        delay[1] <<= HRTFDELAY_BITS;
+    }
 }
 
 
-static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
+static struct Hrtf *LoadHrtf00(FILE *f)
 {
-    const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
+    const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
     struct Hrtf *Hrtf = NULL;
     ALboolean failed = AL_FALSE;
     ALuint rate = 0, irCount = 0;
@@ -376,12 +447,6 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
 
     evCount = fgetc(f);
 
-    if(rate != deviceRate)
-    {
-        ERR("HRIR rate does not match device rate: rate=%d (%d)\n",
-            rate, deviceRate);
-        failed = AL_TRUE;
-    }
     if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
     {
         ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
@@ -504,6 +569,7 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
         Hrtf->evOffset = evOffset;
         Hrtf->coeffs = coeffs;
         Hrtf->delays = delays;
+        AL_STRING_INIT(Hrtf->filename);
         Hrtf->next = NULL;
         return Hrtf;
     }
@@ -516,9 +582,9 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate)
 }
 
 
-static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
+static struct Hrtf *LoadHrtf01(FILE *f)
 {
-    const ALubyte maxDelay = SRC_HISTORY_LENGTH-1;
+    const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
     struct Hrtf *Hrtf = NULL;
     ALboolean failed = AL_FALSE;
     ALuint rate = 0, irCount = 0;
@@ -538,12 +604,6 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
 
     evCount = fgetc(f);
 
-    if(rate != deviceRate)
-    {
-        ERR("HRIR rate does not match device rate: rate=%d (%d)\n",
-                rate, deviceRate);
-        failed = AL_TRUE;
-    }
     if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
     {
         ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
@@ -649,6 +709,7 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
         Hrtf->evOffset = evOffset;
         Hrtf->coeffs = coeffs;
         Hrtf->delays = delays;
+        AL_STRING_INIT(Hrtf->filename);
         Hrtf->next = NULL;
         return Hrtf;
     }
@@ -661,144 +722,167 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate)
 }
 
 
-static struct Hrtf *LoadHrtf(ALuint deviceRate)
+static void AddFileEntry(vector_HrtfEntry *list, al_string *filename)
 {
-    const char *fnamelist = "default-%r.mhr";
+    HrtfEntry entry = { AL_STRING_INIT_STATIC(), *filename, NULL };
+    HrtfEntry *iter;
+    const char *name;
+    int i;
+
+    name = strrchr(al_string_get_cstr(entry.filename), '/');
+    if(!name) name = strrchr(al_string_get_cstr(entry.filename), '\\');
+    if(!name) name = al_string_get_cstr(entry.filename);
+    else ++name;
+
+    entry.hrtf = LoadedHrtfs;
+    while(entry.hrtf)
+    {
+        if(al_string_cmp(entry.filename, entry.hrtf->filename) == 0)
+            break;
+        entry.hrtf = entry.hrtf->next;
+    }
 
-    ConfigValueStr(NULL, "hrtf_tables", &fnamelist);
-    while(*fnamelist != '\0')
+    if(!entry.hrtf)
     {
-        struct Hrtf *Hrtf = NULL;
-        char fname[PATH_MAX];
-        const char *next;
+        struct Hrtf *hrtf = NULL;
         ALchar magic[8];
-        ALuint i;
         FILE *f;
 
-        i = 0;
-        while(isspace(*fnamelist) || *fnamelist == ',')
-            fnamelist++;
-        next = fnamelist;
-        while(*(fnamelist=next) != '\0' && *fnamelist != ',')
-        {
-            next = strpbrk(fnamelist, "%,");
-            while(fnamelist != next && *fnamelist && i < sizeof(fname))
-                fname[i++] = *(fnamelist++);
-
-            if(!next || *next == ',')
-                break;
-
-            /* *next == '%' */
-            next++;
-            if(*next == 'r')
-            {
-                int wrote = snprintf(&fname[i], sizeof(fname)-i, "%u", deviceRate);
-                i += minu(wrote, sizeof(fname)-i);
-                next++;
-            }
-            else if(*next == '%')
-            {
-                if(i < sizeof(fname))
-                    fname[i++] = '%';
-                next++;
-            }
-            else
-                ERR("Invalid marker '%%%c'\n", *next);
-        }
-        i = minu(i, sizeof(fname)-1);
-        fname[i] = '\0';
-        while(i > 0 && isspace(fname[i-1]))
-            i--;
-        fname[i] = '\0';
-
-        if(fname[0] == '\0')
-            continue;
-
-        TRACE("Loading %s...\n", fname);
-        f = OpenDataFile(fname, "openal/hrtf");
+        TRACE("Loading %s...\n", al_string_get_cstr(entry.filename));
+        f = al_fopen(al_string_get_cstr(entry.filename), "rb");
         if(f == NULL)
         {
-            ERR("Could not open %s\n", fname);
-            continue;
+            ERR("Could not open %s\n", al_string_get_cstr(entry.filename));
+            goto error;
         }
 
         if(fread(magic, 1, sizeof(magic), f) != sizeof(magic))
-            ERR("Failed to read header from %s\n", fname);
+            ERR("Failed to read header from %s\n", al_string_get_cstr(entry.filename));
         else
         {
             if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0)
             {
                 TRACE("Detected data set format v0\n");
-                Hrtf = LoadHrtf00(f, deviceRate);
+                hrtf = LoadHrtf00(f);
             }
             else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0)
             {
                 TRACE("Detected data set format v1\n");
-                Hrtf = LoadHrtf01(f, deviceRate);
+                hrtf = LoadHrtf01(f);
             }
             else
-                ERR("Invalid header in %s: \"%.8s\"\n", fname, magic);
+                ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(entry.filename), magic);
         }
-
         fclose(f);
-        f = NULL;
 
-        if(Hrtf)
+        if(!hrtf)
         {
-            Hrtf->next = LoadedHrtfs;
-            LoadedHrtfs = Hrtf;
-            TRACE("Loaded HRTF support for format: %s %uhz\n",
-                  DevFmtChannelsString(DevFmtStereo), Hrtf->sampleRate);
-            return Hrtf;
+            ERR("Failed to load %s\n", al_string_get_cstr(entry.filename));
+            goto error;
         }
 
-        ERR("Failed to load %s\n", fname);
+        al_string_copy(&hrtf->filename, entry.filename);
+        hrtf->next = LoadedHrtfs;
+        LoadedHrtfs = hrtf;
+        TRACE("Loaded HRTF support for format: %s %uhz\n",
+                DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
+        entry.hrtf = hrtf;
     }
 
-    return NULL;
+    /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
+     * format update). */
+
+    i = 0;
+    do {
+        al_string_copy_cstr(&entry.name, name);
+        if(i != 0)
+        {
+            char str[64];
+            snprintf(str, sizeof(str), " #%d", i+1);
+            al_string_append_cstr(&entry.name, str);
+        }
+        ++i;
+
+#define MATCH_NAME(i)  (al_string_cmp(entry.name, (i)->name) == 0)
+        VECTOR_FIND_IF(iter, HrtfEntry, *list, MATCH_NAME);
+#undef MATCH_NAME
+    } while(iter != VECTOR_ITER_END(*list));
+
+    TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name),
+          al_string_get_cstr(entry.filename));
+    VECTOR_PUSH_BACK(*list, entry);
+    return;
+
+error:
+    al_string_deinit(&entry.filename);
 }
 
-const struct Hrtf *GetHrtf(enum DevFmtChannels chans, ALCuint srate)
+vector_HrtfEntry EnumerateHrtf(const_al_string devname)
 {
-    if(chans == DevFmtStereo)
+    vector_HrtfEntry list = VECTOR_INIT_STATIC();
+    const char *fnamelist = "default-%r.mhr";
+
+    ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf_tables", &fnamelist);
+    while(fnamelist && *fnamelist)
     {
-        struct Hrtf *Hrtf = LoadedHrtfs;
-        while(Hrtf != NULL)
+        while(isspace(*fnamelist) || *fnamelist == ',')
+            fnamelist++;
+        if(*fnamelist != '\0')
         {
-            if(srate == Hrtf->sampleRate)
-                return Hrtf;
-            Hrtf = Hrtf->next;
-        }
+            const char *next, *end;
+
+            next = strchr(fnamelist, ',');
+            if(!next)
+                end = fnamelist + strlen(fnamelist);
+            else
+                end = next++;
+
+            while(end != fnamelist && isspace(*(end-1)))
+                --end;
+            if(end != fnamelist)
+            {
+                al_string fname = AL_STRING_INIT_STATIC();
+                vector_al_string flist;
+
+                al_string_append_range(&fname, fnamelist, end);
+
+                flist = SearchDataFiles(al_string_get_cstr(fname), "openal/hrtf");
+                VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list);
+                VECTOR_DEINIT(flist);
 
-        Hrtf = LoadHrtf(srate);
-        if(Hrtf != NULL)
-            return Hrtf;
+                al_string_deinit(&fname);
+            }
+
+            fnamelist = next;
+        }
     }
-    ERR("Incompatible format: %s %uhz\n", DevFmtChannelsString(chans), srate);
-    return NULL;
+
+    return list;
 }
 
-ALCboolean FindHrtfFormat(enum DevFmtChannels *chans, ALCuint *srate)
+void FreeHrtfList(vector_HrtfEntry *list)
 {
-    const struct Hrtf *hrtf = LoadedHrtfs;
-    while(hrtf != NULL)
-    {
-        if(*srate == hrtf->sampleRate)
-            break;
-        hrtf = hrtf->next;
-    }
+#define CLEAR_ENTRY(i) do {           \
+    al_string_deinit(&(i)->name);     \
+    al_string_deinit(&(i)->filename); \
+} while(0)
+    VECTOR_FOR_EACH(HrtfEntry, *list, CLEAR_ENTRY);
+    VECTOR_DEINIT(*list);
+#undef CLEAR_ENTRY
+}
 
-    if(hrtf == NULL)
-    {
-        hrtf = LoadHrtf(*srate);
-        if(hrtf == NULL) return ALC_FALSE;
-    }
 
-    *chans = DevFmtStereo;
-    *srate = hrtf->sampleRate;
-    return ALC_TRUE;
+ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf)
+{
+    return Hrtf->sampleRate;
+}
+
+ALuint GetHrtfIrSize(const struct Hrtf *Hrtf)
+{
+    return Hrtf->irSize;
 }
 
+
 void FreeHrtfs(void)
 {
     struct Hrtf *Hrtf = NULL;
@@ -810,11 +894,7 @@ void FreeHrtfs(void)
         free((void*)Hrtf->evOffset);
         free((void*)Hrtf->coeffs);
         free((void*)Hrtf->delays);
+        al_string_deinit(&Hrtf->filename);
         free(Hrtf);
     }
 }
-
-ALuint GetHrtfIrSize (const struct Hrtf *Hrtf)
-{
-    return Hrtf->irSize;
-}

+ 16 - 4
libs/openal-soft/Alc/hrtf.h

@@ -4,10 +4,20 @@
 #include "AL/al.h"
 #include "AL/alc.h"
 
+#include "alstring.h"
+
 enum DevFmtChannels;
 
 struct Hrtf;
 
+typedef struct HrtfEntry {
+    al_string name;
+    al_string filename;
+
+    const struct Hrtf *hrtf;
+} HrtfEntry;
+TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry)
+
 #define HRIR_BITS        (7)
 #define HRIR_LENGTH      (1<<HRIR_BITS)
 #define HRIR_MASK        (HRIR_LENGTH-1)
@@ -15,14 +25,16 @@ struct Hrtf;
 #define HRTFDELAY_FRACONE (1<<HRTFDELAY_BITS)
 #define HRTFDELAY_MASK    (HRTFDELAY_FRACONE-1)
 
-const struct Hrtf *GetHrtf(enum DevFmtChannels chans, ALCuint srate);
-ALCboolean FindHrtfFormat(enum DevFmtChannels *chans, ALCuint *srate);
-
 void FreeHrtfs(void);
 
+vector_HrtfEntry EnumerateHrtf(const_al_string devname);
+void FreeHrtfList(vector_HrtfEntry *list);
+
+ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf);
 ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
-ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]);
+
 void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
 ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep);
+void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list);
 
 #endif /* ALC_HRTF_H */

+ 253 - 125
libs/openal-soft/Alc/mixer.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -38,8 +38,32 @@
 #include "mixer_defs.h"
 
 
+static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
+              "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
+
 extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size);
 
+alignas(16) union ResamplerCoeffs ResampleCoeffs;
+
+
+enum Resampler {
+    PointResampler,
+    LinearResampler,
+    FIR4Resampler,
+    FIR8Resampler,
+    BSincResampler,
+
+    ResamplerDefault = LinearResampler
+};
+
+/* FIR8 requires 3 extra samples before the current position, and 4 after. */
+static_assert(MAX_PRE_SAMPLES >= 3, "MAX_PRE_SAMPLES must be at least 3!");
+static_assert(MAX_POST_SAMPLES >= 4, "MAX_POST_SAMPLES must be at least 4!");
+
+
+static HrtfMixerFunc MixHrtfSamples = MixHrtf_C;
+static MixerFunc MixSamples = Mix_C;
+static ResamplerFunc ResampleSamples = Resample_point32_C;
 
 static inline HrtfMixerFunc SelectHrtfMixer(void)
 {
@@ -69,11 +93,9 @@ static inline MixerFunc SelectMixer(void)
     return Mix_C;
 }
 
-static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
+static inline ResamplerFunc SelectResampler(enum Resampler resampler)
 {
-    if(increment == FRACTIONONE)
-        return Resample_copy32_C;
-    switch(Resampler)
+    switch(resampler)
     {
         case PointResampler:
             return Resample_point32_C;
@@ -87,17 +109,181 @@ static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint inc
                 return Resample_lerp32_SSE2;
 #endif
             return Resample_lerp32_C;
-        case CubicResampler:
-            return Resample_cubic32_C;
-        case ResamplerMax:
-            /* Shouldn't happen */
-            break;
+        case FIR4Resampler:
+#ifdef HAVE_SSE4_1
+            if((CPUCapFlags&CPU_CAP_SSE4_1))
+                return Resample_fir4_32_SSE41;
+#endif
+#ifdef HAVE_SSE3
+            if((CPUCapFlags&CPU_CAP_SSE3))
+                return Resample_fir4_32_SSE3;
+#endif
+            return Resample_fir4_32_C;
+        case FIR8Resampler:
+#ifdef HAVE_SSE4_1
+            if((CPUCapFlags&CPU_CAP_SSE4_1))
+                return Resample_fir8_32_SSE41;
+#endif
+#ifdef HAVE_SSE3
+            if((CPUCapFlags&CPU_CAP_SSE3))
+                return Resample_fir8_32_SSE3;
+#endif
+            return Resample_fir8_32_C;
+        case BSincResampler:
+#ifdef HAVE_SSE
+            if((CPUCapFlags&CPU_CAP_SSE))
+                return Resample_bsinc32_SSE;
+#endif
+            return Resample_bsinc32_C;
     }
 
     return Resample_point32_C;
 }
 
 
+/* The sinc resampler makes use of a Kaiser window to limit the needed sample
+ * points to 4 and 8, respectively.
+ */
+
+#ifndef M_PI
+#define M_PI                         (3.14159265358979323846)
+#endif
+static inline double Sinc(double x)
+{
+    if(x == 0.0) return 1.0;
+    return sin(x*M_PI) / (x*M_PI);
+}
+
+/* The zero-order modified Bessel function of the first kind, used for the
+ * Kaiser window.
+ *
+ *   I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
+ *          = sum_{k=0}^inf ((x / 2)^k / k!)^2
+ */
+static double BesselI_0(double x)
+{
+    double term, sum, x2, y, last_sum;
+    int k;
+
+    /* Start at k=1 since k=0 is trivial. */
+    term = 1.0;
+    sum = 1.0;
+    x2 = x / 2.0;
+    k = 1;
+
+    /* Let the integration converge until the term of the sum is no longer
+     * significant.
+     */
+    do {
+        y = x2 / k;
+        k ++;
+        last_sum = sum;
+        term *= y * y;
+        sum += term;
+    } while(sum != last_sum);
+    return sum;
+}
+
+/* Calculate a Kaiser window from the given beta value and a normalized k
+ * [-1, 1].
+ *
+ *   w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B),  -1 <= k <= 1
+ *          { 0,                              elsewhere.
+ *
+ * Where k can be calculated as:
+ *
+ *   k = i / l,         where -l <= i <= l.
+ *
+ * or:
+ *
+ *   k = 2 i / M - 1,   where 0 <= i <= M.
+ */
+static inline double Kaiser(double b, double k)
+{
+    if(k <= -1.0 || k >= 1.0) return 0.0;
+    return BesselI_0(b * sqrt(1.0 - (k*k))) / BesselI_0(b);
+}
+
+static inline double CalcKaiserBeta(double rejection)
+{
+    if(rejection > 50.0)
+        return 0.1102 * (rejection - 8.7);
+    if(rejection >= 21.0)
+        return (0.5842 * pow(rejection - 21.0, 0.4)) +
+               (0.07886 * (rejection - 21.0));
+    return 0.0;
+}
+
+static float SincKaiser(double r, double x)
+{
+    /* Limit rippling to -60dB. */
+    return (float)(Kaiser(CalcKaiserBeta(60.0), x / r) * Sinc(x));
+}
+
+
+void aluInitMixer(void)
+{
+    enum Resampler resampler = ResamplerDefault;
+    const char *str;
+    ALuint i;
+
+    if(ConfigValueStr(NULL, NULL, "resampler", &str))
+    {
+        if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0)
+            resampler = PointResampler;
+        else if(strcasecmp(str, "linear") == 0)
+            resampler = LinearResampler;
+        else if(strcasecmp(str, "sinc4") == 0)
+            resampler = FIR4Resampler;
+        else if(strcasecmp(str, "sinc8") == 0)
+            resampler = FIR8Resampler;
+        else if(strcasecmp(str, "bsinc") == 0)
+            resampler = BSincResampler;
+        else if(strcasecmp(str, "cubic") == 0)
+        {
+            WARN("Resampler option \"cubic\" is deprecated, using sinc4\n");
+            resampler = FIR4Resampler;
+        }
+        else
+        {
+            char *end;
+            long n = strtol(str, &end, 0);
+            if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler))
+                resampler = n;
+            else
+                WARN("Invalid resampler: %s\n", str);
+        }
+    }
+
+    if(resampler == FIR8Resampler)
+        for(i = 0;i < FRACTIONONE;i++)
+        {
+            ALdouble mu = (ALdouble)i / FRACTIONONE;
+            ResampleCoeffs.FIR8[i][0] = SincKaiser(4.0, mu - -3.0);
+            ResampleCoeffs.FIR8[i][1] = SincKaiser(4.0, mu - -2.0);
+            ResampleCoeffs.FIR8[i][2] = SincKaiser(4.0, mu - -1.0);
+            ResampleCoeffs.FIR8[i][3] = SincKaiser(4.0, mu -  0.0);
+            ResampleCoeffs.FIR8[i][4] = SincKaiser(4.0, mu -  1.0);
+            ResampleCoeffs.FIR8[i][5] = SincKaiser(4.0, mu -  2.0);
+            ResampleCoeffs.FIR8[i][6] = SincKaiser(4.0, mu -  3.0);
+            ResampleCoeffs.FIR8[i][7] = SincKaiser(4.0, mu -  4.0);
+        }
+    else if(resampler == FIR4Resampler)
+        for(i = 0;i < FRACTIONONE;i++)
+        {
+            ALdouble mu = (ALdouble)i / FRACTIONONE;
+            ResampleCoeffs.FIR4[i][0] = SincKaiser(2.0, mu - -1.0);
+            ResampleCoeffs.FIR4[i][1] = SincKaiser(2.0, mu -  0.0);
+            ResampleCoeffs.FIR4[i][2] = SincKaiser(2.0, mu -  1.0);
+            ResampleCoeffs.FIR4[i][3] = SincKaiser(2.0, mu -  2.0);
+        }
+
+    MixHrtfSamples = SelectHrtfMixer();
+    MixSamples = SelectMixer();
+    ResampleSamples = SelectResampler(resampler);
+}
+
+
 static inline ALfloat Sample_ALbyte(ALbyte val)
 { return val * (1.0f/127.0f); }
 
@@ -108,7 +294,7 @@ static inline ALfloat Sample_ALfloat(ALfloat val)
 { return val; }
 
 #define DECL_TEMPLATE(T)                                                      \
-static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
+static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\
 {                                                                             \
     ALuint i;                                                                 \
     for(i = 0;i < samples;i++)                                                \
@@ -137,7 +323,7 @@ static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum Fm
     }
 }
 
-static void SilenceSamples(ALfloat *dst, ALuint samples)
+static inline void SilenceSamples(ALfloat *dst, ALuint samples)
 {
     ALuint i;
     for(i = 0;i < samples;i++)
@@ -153,20 +339,24 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter
     switch(type)
     {
         case AF_None:
+            ALfilterState_processPassthru(lpfilter, src, numsamples);
+            ALfilterState_processPassthru(hpfilter, src, numsamples);
             break;
 
         case AF_LowPass:
             ALfilterState_process(lpfilter, dst, src, numsamples);
+            ALfilterState_processPassthru(hpfilter, dst, numsamples);
             return dst;
         case AF_HighPass:
+            ALfilterState_processPassthru(lpfilter, src, numsamples);
             ALfilterState_process(hpfilter, dst, src, numsamples);
             return dst;
 
         case AF_BandPass:
             for(i = 0;i < numsamples;)
             {
-                ALfloat temp[64];
-                ALuint todo = minu(64, numsamples-i);
+                ALfloat temp[256];
+                ALuint todo = minu(256, numsamples-i);
 
                 ALfilterState_process(lpfilter, temp, src+i, todo);
                 ALfilterState_process(hpfilter, dst+i, temp, todo);
@@ -178,22 +368,19 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter
 }
 
 
-ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
+ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
 {
-    MixerFunc Mix;
-    HrtfMixerFunc HrtfMix;
     ResamplerFunc Resample;
-    ALsource *Source = src->Source;
     ALbufferlistitem *BufferListItem;
     ALuint DataPosInt, DataPosFrac;
     ALboolean Looping;
     ALuint increment;
-    enum Resampler Resampler;
     ALenum State;
     ALuint OutPos;
     ALuint NumChannels;
     ALuint SampleSize;
     ALint64 DataSize64;
+    ALuint IrSize;
     ALuint chan, j;
 
     /* Get source info */
@@ -202,19 +389,17 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
     DataPosInt     = Source->position;
     DataPosFrac    = Source->position_fraction;
     Looping        = Source->Looping;
-    increment      = src->Step;
-    Resampler      = (increment==FRACTIONONE) ? PointResampler : Source->Resampler;
     NumChannels    = Source->NumChannels;
     SampleSize     = Source->SampleSize;
+    increment      = voice->Step;
 
-    Mix = SelectMixer();
-    HrtfMix = SelectHrtfMixer();
-    Resample = SelectResampler(Resampler, increment);
+    IrSize = (Device->Hrtf ? GetHrtfIrSize(Device->Hrtf) : 0);
+
+    Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ?
+                Resample_copy32_C : ResampleSamples);
 
     OutPos = 0;
     do {
-        const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
-        const ALuint BufferPadding = ResamplerPadding[Resampler];
         ALuint SrcBufferSize, DstBufferSize;
 
         /* Figure out how many buffer samples will be needed */
@@ -222,13 +407,13 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
         DataSize64 *= increment;
         DataSize64 += DataPosFrac+FRACTIONMASK;
         DataSize64 >>= FRACTIONBITS;
-        DataSize64 += BufferPadding+BufferPrePadding;
+        DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
 
         SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE);
 
         /* Figure out how many samples we can actually mix from this. */
         DataSize64  = SrcBufferSize;
-        DataSize64 -= BufferPadding+BufferPrePadding;
+        DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES;
         DataSize64 <<= FRACTIONBITS;
         DataSize64 -= DataPosFrac;
 
@@ -244,7 +429,11 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
         {
             const ALfloat *ResampledData;
             ALfloat *SrcData = Device->SourceData;
-            ALuint SrcDataSize = 0;
+            ALuint SrcDataSize;
+
+            /* Load the previous samples into the source data first. */
+            memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat));
+            SrcDataSize = MAX_PRE_SAMPLES;
 
             if(Source->SourceType == AL_STATIC)
             {
@@ -253,29 +442,20 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
                 ALuint DataSize;
                 ALuint pos;
 
+                /* Offset buffer data to current channel */
+                Data += chan*SampleSize;
+
                 /* If current pos is beyond the loop range, do not loop */
                 if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd)
                 {
                     Looping = AL_FALSE;
 
-                    if(DataPosInt >= BufferPrePadding)
-                        pos = DataPosInt - BufferPrePadding;
-                    else
-                    {
-                        DataSize = BufferPrePadding - DataPosInt;
-                        DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
-
-                        SilenceSamples(&SrcData[SrcDataSize], DataSize);
-                        SrcDataSize += DataSize;
-
-                        pos = 0;
-                    }
-
-                    /* Copy what's left to play in the source buffer, and clear the
-                     * rest of the temp buffer */
+                    /* Load what's left to play from the source buffer, and
+                     * clear the rest of the temp buffer */
+                    pos = DataPosInt;
                     DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos);
 
-                    LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
+                    LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
                                 NumChannels, ALBuffer->FmtType, DataSize);
                     SrcDataSize += DataSize;
 
@@ -287,33 +467,13 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
                     ALuint LoopStart = ALBuffer->LoopStart;
                     ALuint LoopEnd   = ALBuffer->LoopEnd;
 
-                    if(DataPosInt >= LoopStart)
-                    {
-                        pos = DataPosInt-LoopStart;
-                        while(pos < BufferPrePadding)
-                            pos += LoopEnd-LoopStart;
-                        pos -= BufferPrePadding;
-                        pos += LoopStart;
-                    }
-                    else if(DataPosInt >= BufferPrePadding)
-                        pos = DataPosInt - BufferPrePadding;
-                    else
-                    {
-                        DataSize = BufferPrePadding - DataPosInt;
-                        DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
-
-                        SilenceSamples(&SrcData[SrcDataSize], DataSize);
-                        SrcDataSize += DataSize;
-
-                        pos = 0;
-                    }
-
-                    /* Copy what's left of this loop iteration, then copy repeats
-                     * of the loop section */
+                    /* Load what's left of this loop iteration, then load
+                     * repeats of the loop section */
+                    pos = DataPosInt;
                     DataSize = LoopEnd - pos;
                     DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
 
-                    LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize],
+                    LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize],
                                 NumChannels, ALBuffer->FmtType, DataSize);
                     SrcDataSize += DataSize;
 
@@ -322,7 +482,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
                     {
                         DataSize = minu(SrcBufferSize - SrcDataSize, DataSize);
 
-                        LoadSamples(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize],
+                        LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize],
                                     NumChannels, ALBuffer->FmtType, DataSize);
                         SrcDataSize += DataSize;
                     }
@@ -332,45 +492,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
             {
                 /* Crawl the buffer queue to fill in the temp buffer */
                 ALbufferlistitem *tmpiter = BufferListItem;
-                ALuint pos;
-
-                if(DataPosInt >= BufferPrePadding)
-                    pos = DataPosInt - BufferPrePadding;
-                else
-                {
-                    pos = BufferPrePadding - DataPosInt;
-                    while(pos > 0)
-                    {
-                        ALbufferlistitem *prev;
-                        if((prev=tmpiter->prev) != NULL)
-                            tmpiter = prev;
-                        else if(Looping)
-                        {
-                            while(tmpiter->next)
-                                tmpiter = tmpiter->next;
-                        }
-                        else
-                        {
-                            ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos);
-
-                            SilenceSamples(&SrcData[SrcDataSize], DataSize);
-                            SrcDataSize += DataSize;
-
-                            pos = 0;
-                            break;
-                        }
-
-                        if(tmpiter->buffer)
-                        {
-                            if((ALuint)tmpiter->buffer->SampleLen > pos)
-                            {
-                                pos = tmpiter->buffer->SampleLen - pos;
-                                break;
-                            }
-                            pos -= tmpiter->buffer->SampleLen;
-                        }
-                    }
-                }
+                ALuint pos = DataPosInt;
 
                 while(tmpiter && SrcBufferSize > SrcDataSize)
                 {
@@ -406,13 +528,19 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
                 }
             }
 
+            /* Store the last source samples used for next time. */
+            memcpy(voice->PrevSamples[chan],
+                &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS],
+                MAX_PRE_SAMPLES*sizeof(ALfloat)
+            );
+
             /* Now resample, then filter and mix to the appropriate outputs. */
-            ResampledData = Resample(
-                &SrcData[BufferPrePadding], DataPosFrac, increment,
+            ResampledData = Resample(&voice->SincState,
+                &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment,
                 Device->ResampledData, DstBufferSize
             );
             {
-                DirectParams *parms = &src->Direct;
+                DirectParams *parms = &voice->Direct;
                 const ALfloat *samples;
 
                 samples = DoFilters(
@@ -420,18 +548,18 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
                     Device->FilteredData, ResampledData, DstBufferSize,
                     parms->Filters[chan].ActiveType
                 );
-                if(!src->IsHrtf)
-                    Mix(samples, MaxChannels, parms->OutBuffer, parms->Mix.Gains[chan],
-                        parms->Counter, OutPos, DstBufferSize);
+                if(!voice->IsHrtf)
+                    MixSamples(samples, parms->OutChannels, parms->OutBuffer, parms->Gains[chan],
+                               parms->Counter, OutPos, DstBufferSize);
                 else
-                    HrtfMix(parms->OutBuffer, samples, parms->Counter, src->Offset,
-                            OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan],
-                            &parms->Mix.Hrtf.State[chan], DstBufferSize);
+                    MixHrtfSamples(parms->OutBuffer, samples, parms->Counter, voice->Offset,
+                                   OutPos, IrSize, &parms->Hrtf[chan].Params,
+                                   &parms->Hrtf[chan].State, DstBufferSize);
             }
 
             for(j = 0;j < Device->NumAuxSends;j++)
             {
-                SendParams *parms = &src->Send[j];
+                SendParams *parms = &voice->Send[j];
                 const ALfloat *samples;
 
                 if(!parms->OutBuffer)
@@ -442,8 +570,8 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
                     Device->FilteredData, ResampledData, DstBufferSize,
                     parms->Filters[chan].ActiveType
                 );
-                Mix(samples, 1, parms->OutBuffer, &parms->Gain,
-                    parms->Counter, OutPos, DstBufferSize);
+                MixSamples(samples, 1, parms->OutBuffer, &parms->Gains[chan],
+                           parms->Counter, OutPos, DstBufferSize);
             }
         }
         /* Update positions */
@@ -452,10 +580,10 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo)
         DataPosFrac &= FRACTIONMASK;
 
         OutPos += DstBufferSize;
-        src->Offset += DstBufferSize;
-        src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize;
+        voice->Offset += DstBufferSize;
+        voice->Direct.Counter = maxu(voice->Direct.Counter, DstBufferSize) - DstBufferSize;
         for(j = 0;j < Device->NumAuxSends;j++)
-            src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize;
+            voice->Send[j].Counter = maxu(voice->Send[j].Counter, DstBufferSize) - DstBufferSize;
 
         /* Handle looping sources */
         while(1)

+ 69 - 14
libs/openal-soft/Alc/mixer_c.c

@@ -12,13 +12,15 @@ static inline ALfloat point32(const ALfloat *vals, ALuint UNUSED(frac))
 { return vals[0]; }
 static inline ALfloat lerp32(const ALfloat *vals, ALuint frac)
 { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); }
-static inline ALfloat cubic32(const ALfloat *vals, ALuint frac)
-{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); }
+static inline ALfloat fir4_32(const ALfloat *vals, ALuint frac)
+{ return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); }
+static inline ALfloat fir8_32(const ALfloat *vals, ALuint frac)
+{ return resample_fir8(vals[-3], vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], vals[4], frac); }
 
-const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
-  ALuint increment, ALfloat *restrict dst, ALuint numsamples)
+
+const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat *src, ALuint UNUSED(frac),
+  ALuint UNUSED(increment), ALfloat *restrict dst, ALuint numsamples)
 {
-    assert(increment==FRACTIONONE);
 #if defined(HAVE_SSE) || defined(HAVE_NEON)
     /* Avoid copying the source data if it's aligned like the destination. */
     if((((intptr_t)src)&15) == (((intptr_t)dst)&15))
@@ -29,8 +31,9 @@ const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac),
 }
 
 #define DECL_TEMPLATE(Sampler)                                                \
-const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac,        \
-  ALuint increment, ALfloat *restrict dst, ALuint numsamples)                 \
+const ALfloat *Resample_##Sampler##_C(const BsincState* UNUSED(state),        \
+  const ALfloat *src, ALuint frac, ALuint increment,                          \
+  ALfloat *restrict dst, ALuint numsamples)                                   \
 {                                                                             \
     ALuint i;                                                                 \
     for(i = 0;i < numsamples;i++)                                             \
@@ -46,10 +49,49 @@ const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac,        \
 
 DECL_TEMPLATE(point32)
 DECL_TEMPLATE(lerp32)
-DECL_TEMPLATE(cubic32)
+DECL_TEMPLATE(fir4_32)
+DECL_TEMPLATE(fir8_32)
 
 #undef DECL_TEMPLATE
 
+const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac,
+                                  ALuint increment, ALfloat *restrict dst, ALuint dstlen)
+{
+    const ALfloat *fil, *scd, *phd, *spd;
+    const ALfloat sf = state->sf;
+    const ALuint m = state->m;
+    const ALint l = state->l;
+    ALuint j_f, pi, i;
+    ALfloat pf, r;
+    ALint j_s;
+
+    for(i = 0;i < dstlen;i++)
+    {
+        // Calculate the phase index and factor.
+#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
+        pi = frac >> FRAC_PHASE_BITDIFF;
+        pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
+#undef FRAC_PHASE_BITDIFF
+
+        fil = state->coeffs[pi].filter;
+        scd = state->coeffs[pi].scDelta;
+        phd = state->coeffs[pi].phDelta;
+        spd = state->coeffs[pi].spDelta;
+
+        // Apply the scale and phase interpolated filter.
+        r = 0.0f;
+        for(j_f = 0,j_s = l;j_f < m;j_f++,j_s++)
+            r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) *
+                    src[j_s];
+        dst[i] = r;
+
+        frac += increment;
+        src  += frac>>FRACTIONBITS;
+        frac &= FRACTIONMASK;
+    }
+    return dst;
+}
+
 
 void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples)
 {
@@ -59,6 +101,18 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const
 }
 
 
+static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
+                               const HrtfParams *hrtfparams,
+                               ALuint IrSize, ALuint Counter)
+{
+    ALuint c;
+    for(c = 0;c < IrSize;c++)
+    {
+        OutCoeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter);
+        OutCoeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter);
+    }
+}
+
 static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
                                    const ALuint IrSize,
                                    ALfloat (*restrict Coeffs)[2],
@@ -90,9 +144,9 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
     }
 }
 
-#define SUFFIX C
+#define MixHrtf MixHrtf_C
 #include "mixer_inc.c"
-#undef SUFFIX
+#undef MixHrtf
 
 
 void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
@@ -106,19 +160,20 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B
         ALuint pos = 0;
         gain = Gains[c].Current;
         step = Gains[c].Step;
-        if(step != 1.0f && Counter > 0)
+        if(step != 0.0f && Counter > 0)
         {
-            for(;pos < BufferSize && pos < Counter;pos++)
+            ALuint minsize = minu(BufferSize, Counter);
+            for(;pos < minsize;pos++)
             {
                 OutBuffer[c][OutPos+pos] += data[pos]*gain;
-                gain *= step;
+                gain += step;
             }
             if(pos == Counter)
                 gain = Gains[c].Target;
             Gains[c].Current = gain;
         }
 
-        if(!(gain > GAIN_SILENCE_THRESHOLD))
+        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
             continue;
         for(;pos < BufferSize;pos++)
             OutBuffer[c][OutPos+pos] += data[pos]*gain;

+ 22 - 7
libs/openal-soft/Alc/mixer_defs.h

@@ -12,10 +12,12 @@ struct HrtfParams;
 struct HrtfState;
 
 /* C resamplers */
-const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
-const ALfloat *Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen);
 
 
 /* C mixers */
@@ -24,7 +26,7 @@ void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
                const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate,
                ALuint BufferSize);
 void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-                 struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
+           struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize);
 
 /* SSE mixers */
 void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
@@ -49,10 +51,23 @@ inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_a
     }
 }
 
-const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
+const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac,
+                                    ALuint increment, ALfloat *restrict dst, ALuint dstlen);
+
+const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
                                     ALfloat *restrict dst, ALuint numsamples);
-const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
+const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
+                                     ALfloat *restrict dst, ALuint numsamples);
+
+const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
+                                     ALfloat *restrict dst, ALuint numsamples);
+const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
+                                      ALfloat *restrict dst, ALuint numsamples);
+
+const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
                                      ALfloat *restrict dst, ALuint numsamples);
+const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment,
+                                      ALfloat *restrict dst, ALuint numsamples);
 
 /* Neon mixers */
 void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,

+ 18 - 32
libs/openal-soft/Alc/mixer_inc.c

@@ -8,12 +8,9 @@
 #include "align.h"
 
 
-#define REAL_MERGE(a,b) a##b
-#define MERGE(a,b) REAL_MERGE(a,b)
-
-#define MixHrtf MERGE(MixHrtf_,SUFFIX)
-
-
+static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
+                               const HrtfParams *hrtfparams,
+                               ALuint IrSize, ALuint Counter);
 static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
                                    const ALuint irSize,
                                    ALfloat (*restrict Coeffs)[2],
@@ -33,24 +30,20 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
     ALuint Delay[2];
     ALfloat left, right;
     ALuint pos;
-    ALuint c;
 
-    for(c = 0;c < IrSize;c++)
-    {
-        Coeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter);
-        Coeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter);
-    }
+    SetupCoeffs(Coeffs, hrtfparams, IrSize, Counter);
     Delay[0] = hrtfparams->Delay[0] - (hrtfparams->DelayStep[0]*Counter);
     Delay[1] = hrtfparams->Delay[1] - (hrtfparams->DelayStep[1]*Counter);
 
-    for(pos = 0;pos < BufferSize && pos < Counter;pos++)
+    pos = 0;
+    for(;pos < BufferSize && pos < Counter;pos++)
     {
-        hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
-        left  = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
-                     hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
+        hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos];
+        left  = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK],
+                     hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK],
                      (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
-        right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK],
-                     hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK],
+        right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK],
+                     hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK],
                      (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE));
 
         Delay[0] += hrtfparams->DelayStep[0];
@@ -61,8 +54,8 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
         Offset++;
 
         ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->CoeffStep, left, right);
-        OutBuffer[FrontLeft][OutPos]  += hrtfstate->Values[Offset&HRIR_MASK][0];
-        OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
+        OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
+        OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
         OutPos++;
     }
 
@@ -70,24 +63,17 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data,
     Delay[1] >>= HRTFDELAY_BITS;
     for(;pos < BufferSize;pos++)
     {
-        hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos];
-        left = hrtfstate->History[(Offset-Delay[0])&SRC_HISTORY_MASK];
-        right = hrtfstate->History[(Offset-Delay[1])&SRC_HISTORY_MASK];
+        hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos];
+        left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK];
+        right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK];
 
         hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f;
         hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f;
         Offset++;
 
         ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right);
-        OutBuffer[FrontLeft][OutPos]  += hrtfstate->Values[Offset&HRIR_MASK][0];
-        OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
-
+        OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0];
+        OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1];
         OutPos++;
     }
 }
-
-
-#undef MixHrtf
-
-#undef MERGE
-#undef REAL_MERGE

+ 32 - 11
libs/openal-soft/Alc/mixer_neon.c

@@ -9,6 +9,25 @@
 #include "hrtf.h"
 
 
+static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
+                               const HrtfParams *hrtfparams,
+                               ALuint IrSize, ALuint Counter)
+{
+    ALuint c;
+    float32x4_t counter4;
+    {
+        float32x2_t counter2 = vdup_n_f32(-(float)Counter);
+        counter4 = vcombine_f32(counter2, counter2);
+    }
+    for(c = 0;c < IrSize;c += 2)
+    {
+        float32x4_t step4 = vld1q_f32((float32_t*)hrtfparams->CoeffStep[c]);
+        float32x4_t coeffs = vld1q_f32((float32_t*)hrtfparams->Coeffs[c]);
+        coeffs = vmlaq_f32(coeffs, step4, counter4);
+        vst1q_f32((float32_t*)OutCoeffs[c], coeffs);
+    }
+}
+
 static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
                                    const ALuint IrSize,
                                    ALfloat (*restrict Coeffs)[2],
@@ -69,14 +88,13 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
     }
 }
 
-
-#define SUFFIX Neon
+#define MixHrtf MixHrtf_Neon
 #include "mixer_inc.c"
-#undef SUFFIX
+#undef MixHrtf
 
 
-void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
-                    MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
+void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
+              MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
 {
     ALfloat gain, step;
     float32x4_t gain4;
@@ -87,29 +105,32 @@ void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict Out
         ALuint pos = 0;
         gain = Gains[c].Current;
         step = Gains[c].Step;
-        if(step != 1.0f && Counter > 0)
+        if(step != 0.0f && Counter > 0)
         {
-            for(;pos < BufferSize && pos < Counter;pos++)
+            ALuint minsize = minu(BufferSize, Counter);
+            for(;pos < minsize;pos++)
             {
                 OutBuffer[c][OutPos+pos] += data[pos]*gain;
-                gain *= step;
+                gain += step;
             }
             if(pos == Counter)
                 gain = Gains[c].Target;
             Gains[c].Current = gain;
+
             /* Mix until pos is aligned with 4 or the mix is done. */
-            for(;pos < BufferSize && (pos&3) != 0;pos++)
+            minsize = minu(BufferSize, (pos+3)&~3);
+            for(;pos < minsize;pos++)
                 OutBuffer[c][OutPos+pos] += data[pos]*gain;
         }
 
-        if(!(gain > GAIN_SILENCE_THRESHOLD))
+        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
             continue;
         gain4 = vdupq_n_f32(gain);
         for(;BufferSize-pos > 3;pos += 4)
         {
             const float32x4_t val4 = vld1q_f32(&data[pos]);
             float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]);
-            dry4 = vaddq_f32(dry4, vmulq_f32(val4, gain4));
+            dry4 = vmlaq_f32(dry4, val4, gain4);
             vst1q_f32(&OutBuffer[c][OutPos+pos], dry4);
         }
         for(;pos < BufferSize;pos++)

+ 99 - 22
libs/openal-soft/Alc/mixer_sse.c

@@ -1,12 +1,5 @@
 #include "config.h"
 
-#ifdef IN_IDE_PARSER
-/* KDevelop's parser won't recognize these defines that get added by the -msse
- * switch used to compile this source. Without them, xmmintrin.h fails to
- * declare anything. */
-#define __MMX__
-#define __SSE__
-#endif
 #include <xmmintrin.h>
 
 #include "AL/al.h"
@@ -19,6 +12,82 @@
 #include "mixer_defs.h"
 
 
+const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac,
+                                    ALuint increment, ALfloat *restrict dst, ALuint dstlen)
+{
+    const __m128 sf4 = _mm_set1_ps(state->sf);
+    const ALuint m = state->m;
+    const ALint l = state->l;
+    const ALfloat *fil, *scd, *phd, *spd;
+    ALuint pi, j_f, i;
+    ALfloat pf;
+    ALint j_s;
+    __m128 r4;
+
+    for(i = 0;i < dstlen;i++)
+    {
+        // Calculate the phase index and factor.
+#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS)
+        pi = frac >> FRAC_PHASE_BITDIFF;
+        pf = (frac & ((1<<FRAC_PHASE_BITDIFF)-1)) * (1.0f/(1<<FRAC_PHASE_BITDIFF));
+#undef FRAC_PHASE_BITDIFF
+
+        fil = state->coeffs[pi].filter;
+        scd = state->coeffs[pi].scDelta;
+        phd = state->coeffs[pi].phDelta;
+        spd = state->coeffs[pi].spDelta;
+
+        // Apply the scale and phase interpolated filter.
+        r4 = _mm_setzero_ps();
+        {
+            const __m128 pf4 = _mm_set1_ps(pf);
+            for(j_f = 0,j_s = l;j_f < m;j_f+=4,j_s+=4)
+            {
+                const __m128 f4 = _mm_add_ps(
+                    _mm_add_ps(
+                        _mm_load_ps(&fil[j_f]),
+                        _mm_mul_ps(sf4, _mm_load_ps(&scd[j_f]))
+                    ),
+                    _mm_mul_ps(
+                        pf4,
+                        _mm_add_ps(
+                            _mm_load_ps(&phd[j_f]),
+                            _mm_mul_ps(sf4, _mm_load_ps(&spd[j_f]))
+                        )
+                    )
+                );
+                r4 = _mm_add_ps(r4, _mm_mul_ps(f4, _mm_loadu_ps(&src[j_s])));
+            }
+        }
+        r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3)));
+        r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4));
+        dst[i] = _mm_cvtss_f32(r4);
+
+        frac += increment;
+        src  += frac>>FRACTIONBITS;
+        frac &= FRACTIONMASK;
+    }
+    return dst;
+}
+
+
+static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2],
+                               const HrtfParams *hrtfparams,
+                               ALuint IrSize, ALuint Counter)
+{
+    const __m128 counter4 = _mm_set1_ps((float)Counter);
+    __m128 coeffs, step4;
+    ALuint i;
+
+    for(i = 0;i < IrSize;i += 2)
+    {
+        step4  = _mm_load_ps(&hrtfparams->CoeffStep[i][0]);
+        coeffs = _mm_load_ps(&hrtfparams->Coeffs[i][0]);
+        coeffs = _mm_sub_ps(coeffs, _mm_mul_ps(step4, counter4));
+        _mm_store_ps(&OutCoeffs[i][0], coeffs);
+    }
+}
+
 static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2],
                                    const ALuint IrSize,
                                    ALfloat (*restrict Coeffs)[2],
@@ -133,16 +202,16 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2],
     }
 }
 
-#define SUFFIX SSE
+#define MixHrtf MixHrtf_SSE
 #include "mixer_inc.c"
-#undef SUFFIX
+#undef MixHrtf
 
 
 void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE],
              MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize)
 {
     ALfloat gain, step;
-    __m128 gain4, step4;
+    __m128 gain4;
     ALuint c;
 
     for(c = 0;c < OutChans;c++)
@@ -150,43 +219,51 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)
         ALuint pos = 0;
         gain = Gains[c].Current;
         step = Gains[c].Step;
-        if(step != 1.0f && Counter > 0)
+        if(step != 0.0f && Counter > 0)
         {
+            ALuint minsize = minu(BufferSize, Counter);
             /* Mix with applying gain steps in aligned multiples of 4. */
-            if(BufferSize-pos > 3 && Counter-pos > 3)
+            if(minsize-pos > 3)
             {
+                __m128 step4;
                 gain4 = _mm_setr_ps(
                     gain,
-                    gain * step,
-                    gain * step * step,
-                    gain * step * step * step
+                    gain + step,
+                    gain + step + step,
+                    gain + step + step + step
                 );
-                step4 = _mm_set1_ps(step * step * step * step);
+                step4 = _mm_set1_ps(step + step + step + step);
                 do {
                     const __m128 val4 = _mm_load_ps(&data[pos]);
                     __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]);
                     dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4));
-                    gain4 = _mm_mul_ps(gain4, step4);
+                    gain4 = _mm_add_ps(gain4, step4);
                     _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4);
                     pos += 4;
-                } while(BufferSize-pos > 3 && Counter-pos > 3);
+                } while(minsize-pos > 3);
+                /* NOTE: gain4 now represents the next four gains after the
+                 * last four mixed samples, so the lowest element represents
+                 * the next gain to apply.
+                 */
                 gain = _mm_cvtss_f32(gain4);
             }
             /* Mix with applying left over gain steps that aren't aligned multiples of 4. */
-            for(;pos < BufferSize && pos < Counter;pos++)
+            for(;pos < minsize;pos++)
             {
                 OutBuffer[c][OutPos+pos] += data[pos]*gain;
-                gain *= step;
+                gain += step;
             }
             if(pos == Counter)
                 gain = Gains[c].Target;
             Gains[c].Current = gain;
+
             /* Mix until pos is aligned with 4 or the mix is done. */
-            for(;pos < BufferSize && (pos&3) != 0;pos++)
+            minsize = minu(BufferSize, (pos+3)&~3);
+            for(;pos < minsize;pos++)
                 OutBuffer[c][OutPos+pos] += data[pos]*gain;
         }
 
-        if(!(gain > GAIN_SILENCE_THRESHOLD))
+        if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
             continue;
         gain4 = _mm_set1_ps(gain);
         for(;BufferSize-pos > 3;pos += 4)

+ 6 - 3
libs/openal-soft/Alc/mixer_sse2.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -27,7 +27,7 @@
 #include "mixer_defs.h"
 
 
-const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment,
+const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
                                     ALfloat *restrict dst, ALuint numsamples)
 {
     const __m128i increment4 = _mm_set1_epi32(increment*4);
@@ -63,6 +63,9 @@ const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint incr
         _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4));
     }
 
+    /* NOTE: These four elements represent the position *after* the last four
+     * samples, so the lowest element is the next position to resample.
+     */
     pos = pos_.i[0];
     frac = _mm_cvtsi128_si32(frac4);
 

+ 145 - 3
libs/openal-soft/Alc/mixer_sse41.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -28,7 +28,7 @@
 #include "mixer_defs.h"
 
 
-const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment,
+const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
                                      ALfloat *restrict dst, ALuint numsamples)
 {
     const __m128i increment4 = _mm_set1_epi32(increment*4);
@@ -67,6 +67,9 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc
         pos_.i[3] = _mm_extract_epi32(pos4, 3);
     }
 
+    /* NOTE: These four elements represent the position *after* the last four
+     * samples, so the lowest element is the next position to resample.
+     */
     pos = pos_.i[0];
     frac = _mm_cvtsi128_si32(frac4);
 
@@ -80,3 +83,142 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc
     }
     return dst;
 }
+
+const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
+                                      ALfloat *restrict dst, ALuint numsamples)
+{
+    const __m128i increment4 = _mm_set1_epi32(increment*4);
+    const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+    alignas(16) union { ALuint i[4]; float f[4]; } pos_;
+    alignas(16) union { ALuint i[4]; float f[4]; } frac_;
+    __m128i frac4, pos4;
+    ALuint pos;
+    ALuint i;
+
+    InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+    frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+    pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+    --src;
+    for(i = 0;numsamples-i > 3;i += 4)
+    {
+        const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]]);
+        const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]);
+        const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]);
+        const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]);
+        __m128 k0 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[0]]);
+        __m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]);
+        __m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]);
+        __m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]);
+        __m128 out;
+
+        k0 = _mm_mul_ps(k0, val0);
+        k1 = _mm_mul_ps(k1, val1);
+        k2 = _mm_mul_ps(k2, val2);
+        k3 = _mm_mul_ps(k3, val3);
+        k0 = _mm_hadd_ps(k0, k1);
+        k2 = _mm_hadd_ps(k2, k3);
+        out = _mm_hadd_ps(k0, k2);
+
+        _mm_store_ps(&dst[i], out);
+
+        frac4 = _mm_add_epi32(frac4, increment4);
+        pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+        frac4 = _mm_and_si128(frac4, fracMask4);
+
+        pos_.i[0] = _mm_extract_epi32(pos4, 0);
+        pos_.i[1] = _mm_extract_epi32(pos4, 1);
+        pos_.i[2] = _mm_extract_epi32(pos4, 2);
+        pos_.i[3] = _mm_extract_epi32(pos4, 3);
+        frac_.i[0] = _mm_extract_epi32(frac4, 0);
+        frac_.i[1] = _mm_extract_epi32(frac4, 1);
+        frac_.i[2] = _mm_extract_epi32(frac4, 2);
+        frac_.i[3] = _mm_extract_epi32(frac4, 3);
+    }
+
+    pos = pos_.i[0];
+    frac = frac_.i[0];
+
+    for(;i < numsamples;i++)
+    {
+        dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac);
+
+        frac += increment;
+        pos  += frac>>FRACTIONBITS;
+        frac &= FRACTIONMASK;
+    }
+    return dst;
+}
+
+const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment,
+                                      ALfloat *restrict dst, ALuint numsamples)
+{
+    const __m128i increment4 = _mm_set1_epi32(increment*4);
+    const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK);
+    alignas(16) union { ALuint i[4]; float f[4]; } pos_;
+    alignas(16) union { ALuint i[4]; float f[4]; } frac_;
+    __m128i frac4, pos4;
+    ALuint pos;
+    ALuint i, j;
+
+    InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4);
+
+    frac4 = _mm_castps_si128(_mm_load_ps(frac_.f));
+    pos4 = _mm_castps_si128(_mm_load_ps(pos_.f));
+
+    src -= 3;
+    for(i = 0;numsamples-i > 3;i += 4)
+    {
+        __m128 out[2];
+        for(j = 0;j < 8;j+=4)
+        {
+            const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]+j]);
+            const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]+j]);
+            const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]+j]);
+            const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]+j]);
+            __m128 k0 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[0]][j]);
+            __m128 k1 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[1]][j]);
+            __m128 k2 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[2]][j]);
+            __m128 k3 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[3]][j]);
+
+            k0 = _mm_mul_ps(k0, val0);
+            k1 = _mm_mul_ps(k1, val1);
+            k2 = _mm_mul_ps(k2, val2);
+            k3 = _mm_mul_ps(k3, val3);
+            k0 = _mm_hadd_ps(k0, k1);
+            k2 = _mm_hadd_ps(k2, k3);
+            out[j>>2] = _mm_hadd_ps(k0, k2);
+        }
+
+        out[0] = _mm_add_ps(out[0], out[1]);
+        _mm_store_ps(&dst[i], out[0]);
+
+        frac4 = _mm_add_epi32(frac4, increment4);
+        pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS));
+        frac4 = _mm_and_si128(frac4, fracMask4);
+
+        pos_.i[0] = _mm_extract_epi32(pos4, 0);
+        pos_.i[1] = _mm_extract_epi32(pos4, 1);
+        pos_.i[2] = _mm_extract_epi32(pos4, 2);
+        pos_.i[3] = _mm_extract_epi32(pos4, 3);
+        frac_.i[0] = _mm_extract_epi32(frac4, 0);
+        frac_.i[1] = _mm_extract_epi32(frac4, 1);
+        frac_.i[2] = _mm_extract_epi32(frac4, 2);
+        frac_.i[3] = _mm_extract_epi32(frac4, 3);
+    }
+
+    pos = pos_.i[0];
+    frac = frac_.i[0];
+
+    for(;i < numsamples;i++)
+    {
+        dst[i] = resample_fir8(src[pos  ], src[pos+1], src[pos+2], src[pos+3],
+                               src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac);
+
+        frac += increment;
+        pos  += frac>>FRACTIONBITS;
+        frac &= FRACTIONMASK;
+    }
+    return dst;
+}

+ 452 - 345
libs/openal-soft/Alc/panning.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -30,421 +30,528 @@
 #include "AL/al.h"
 #include "AL/alc.h"
 #include "alu.h"
-
-extern inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels]);
-
-static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChannels],
-                                  enum Channel Speaker2Chan[MaxChannels], ALint chans)
+#include "bool.h"
+
+
+#define ZERO_ORDER_SCALE    0.0f
+#define FIRST_ORDER_SCALE   1.0f
+#define SECOND_ORDER_SCALE  (1.0f / 1.22474f)
+#define THIRD_ORDER_SCALE   (1.0f / 1.30657f)
+
+
+static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = {
+    0,  /* W */
+    3,  /* X */
+    1,  /* Y */
+    2,  /* Z */
+    6,  /* R */
+    7,  /* S */
+    5,  /* T */
+    8,  /* U */
+    4,  /* V */
+    12, /* K */
+    13, /* L */
+    11, /* M */
+    14, /* N */
+    10, /* O */
+    15, /* P */
+    9,  /* Q */
+};
+
+/* NOTE: These are scale factors as applied to Ambisonics content. FuMa
+ * decoder coefficients should be divided by these values to get N3D decoder
+ * coefficients.
+ */
+static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
+    1.414213562f, /* ACN  0 (W), sqrt(2) */
+    1.732050808f, /* ACN  1 (Y), sqrt(3) */
+    1.732050808f, /* ACN  2 (Z), sqrt(3) */
+    1.732050808f, /* ACN  3 (X), sqrt(3) */
+    1.936491673f, /* ACN  4 (V), sqrt(15)/2 */
+    1.936491673f, /* ACN  5 (T), sqrt(15)/2 */
+    2.236067978f, /* ACN  6 (R), sqrt(5) */
+    1.936491673f, /* ACN  7 (S), sqrt(15)/2 */
+    1.936491673f, /* ACN  8 (U), sqrt(15)/2 */
+    2.091650066f, /* ACN  9 (Q), sqrt(35/8) */
+    1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
+    2.231093404f, /* ACN 11 (M), sqrt(224/45) */
+    2.645751311f, /* ACN 12 (K), sqrt(7) */
+    2.231093404f, /* ACN 13 (L), sqrt(224/45) */
+    1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
+    2.091650066f, /* ACN 15 (P), sqrt(35/8) */
+};
+
+
+void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
 {
-    char *confkey, *next;
-    char *layout_str;
-    char *sep, *end;
-    enum Channel val;
-    const char *str;
-    int i;
-
-    if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str))
-        return;
+    ALuint i;
 
-    layout_str = strdup(str);
-    next = confkey = layout_str;
-    while(next && *next)
+    for(i = 0;i < device->NumChannels;i++)
     {
-        confkey = next;
-        next = strchr(confkey, ',');
-        if(next)
-        {
-            *next = 0;
-            do {
-                next++;
-            } while(isspace(*next) || *next == ',');
-        }
-
-        sep = strchr(confkey, '=');
-        if(!sep || confkey == sep)
-        {
-            ERR("Malformed speaker key: %s\n", confkey);
-            continue;
-        }
-
-        end = sep - 1;
-        while(isspace(*end) && end != confkey)
-            end--;
-        *(++end) = 0;
-
-        if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
-            val = FrontLeft;
-        else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
-            val = FrontRight;
-        else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
-            val = FrontCenter;
-        else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
-            val = BackLeft;
-        else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
-            val = BackRight;
-        else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
-            val = BackCenter;
-        else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
-            val = SideLeft;
-        else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
-            val = SideRight;
-        else
-        {
-            ERR("Unknown speaker for %s: \"%s\"\n", name, confkey);
-            continue;
-        }
-
-        *(sep++) = 0;
-        while(isspace(*sep))
-            sep++;
-
-        for(i = 0;i < chans;i++)
-        {
-            if(Speaker2Chan[i] == val)
-            {
-                long angle = strtol(sep, NULL, 10);
-                if(angle >= -180 && angle <= 180)
-                    SpeakerAngle[i] = DEG2RAD(angle);
-                else
-                    ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
-                break;
-            }
-        }
+        // The W coefficients are based on a mathematical average of the
+        // output. The square root of the base average provides for a more
+        // perceptual average volume, better suited to non-directional gains.
+        gains[i] = sqrtf(device->AmbiCoeffs[i][0]) * ingain;
     }
-    free(layout_str);
-    layout_str = NULL;
+    for(;i < MAX_OUTPUT_CHANNELS;i++)
+        gains[i] = 0.0f;
+}
 
-    for(i = 0;i < chans;i++)
+void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
+{
+    ALfloat dir[3] = {
+        sinf(angle) * cosf(elevation),
+        sinf(elevation),
+        -cosf(angle) * cosf(elevation)
+    };
+    ComputeDirectionalGains(device, dir, ingain, gains);
+}
+
+void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
+{
+    ALfloat coeffs[MAX_AMBI_COEFFS];
+    ALuint i, j;
+    /* Convert from OpenAL coords to Ambisonics. */
+    ALfloat x = -dir[2];
+    ALfloat y = -dir[0];
+    ALfloat z =  dir[1];
+
+    /* Zeroth-order */
+    coeffs[0]  = 1.0f; /* ACN 0 = 1 */
+    /* First-order */
+    coeffs[1]  = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */
+    coeffs[2]  = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */
+    coeffs[3]  = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */
+    /* Second-order */
+    coeffs[4]  = 3.872983346f * x * y;             /* ACN 4 = sqrt(15) * X * Y */
+    coeffs[5]  = 3.872983346f * y * z;             /* ACN 5 = sqrt(15) * Y * Z */
+    coeffs[6]  = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
+    coeffs[7]  = 3.872983346f * x * z;             /* ACN 7 = sqrt(15) * X * Z */
+    coeffs[8]  = 1.936491673f * (x*x - y*y);       /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
+    /* Third-order */
+    coeffs[9]  =  2.091650066f * y * (3.0f*x*x - y*y);  /* ACN  9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
+    coeffs[10] = 10.246950766f * z * x * y;             /* ACN 10 = sqrt(105) * Z * X * Y */
+    coeffs[11] =  1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
+    coeffs[12] =  1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
+    coeffs[13] =  1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
+    coeffs[14] =  5.123475383f * z * (x*x - y*y);       /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
+    coeffs[15] =  2.091650066f * x * (x*x - 3.0f*y*y);  /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
+
+    for(i = 0;i < device->NumChannels;i++)
     {
-        int min = i;
-        int i2;
+        float gain = 0.0f;
+        for(j = 0;j < MAX_AMBI_COEFFS;j++)
+            gain += device->AmbiCoeffs[i][j]*coeffs[j];
+        gains[i] = gain * ingain;
+    }
+    for(;i < MAX_OUTPUT_CHANNELS;i++)
+        gains[i] = 0.0f;
+}
 
-        for(i2 = i+1;i2 < chans;i2++)
-        {
-            if(SpeakerAngle[i2] < SpeakerAngle[min])
-                min = i2;
-        }
+void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
+{
+    ALuint i, j;
 
-        if(min != i)
-        {
-            ALfloat tmpf;
-            enum Channel tmpc;
+    for(i = 0;i < device->NumChannels;i++)
+    {
+        float gain = 0.0f;
+        for(j = 0;j < 4;j++)
+            gain += device->AmbiCoeffs[i][j] * mtx[j];
+        gains[i] = gain * ingain;
+    }
+    for(;i < MAX_OUTPUT_CHANNELS;i++)
+        gains[i] = 0.0f;
+}
 
-            tmpf = SpeakerAngle[i];
-            SpeakerAngle[i] = SpeakerAngle[min];
-            SpeakerAngle[min] = tmpf;
 
-            tmpc = Speaker2Chan[i];
-            Speaker2Chan[i] = Speaker2Chan[min];
-            Speaker2Chan[min] = tmpc;
-        }
+DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel)
+{
+    switch(channel)
+    {
+        case FrontLeft: return "front-left";
+        case FrontRight: return "front-right";
+        case FrontCenter: return "front-center";
+        case LFE: return "lfe";
+        case BackLeft: return "back-left";
+        case BackRight: return "back-right";
+        case BackCenter: return "back-center";
+        case SideLeft: return "side-left";
+        case SideRight: return "side-right";
+
+        case BFormatW: return "bformat-w";
+        case BFormatX: return "bformat-x";
+        case BFormatY: return "bformat-y";
+        case BFormatZ: return "bformat-z";
+
+        case InvalidChannel: break;
     }
+    return "(unknown)";
 }
 
 
-void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels])
+typedef struct ChannelMap {
+    enum Channel ChanName;
+    ChannelConfig Config;
+} ChannelMap;
+
+static void SetChannelMap(ALCdevice *device, const ChannelMap *chanmap, size_t count, ALfloat ambiscale, ALboolean isfuma)
 {
-    ALfloat tmpgains[MaxChannels] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
-    enum Channel Speaker2Chan[MaxChannels];
-    ALfloat SpeakerAngle[MaxChannels];
-    ALfloat langle, rangle;
-    ALfloat a;
+    size_t j, k;
     ALuint i;
 
-    for(i = 0;i < device->NumChan;i++)
-        Speaker2Chan[i] = device->Speaker2Chan[i];
-    for(i = 0;i < device->NumChan;i++)
-        SpeakerAngle[i] = device->SpeakerAngle[i];
-
-    /* Some easy special-cases first... */
-    if(device->NumChan <= 1 || hwidth >= F_PI)
+    device->AmbiScale = ambiscale;
+    for(i = 0;i < MAX_OUTPUT_CHANNELS && device->ChannelName[i] != InvalidChannel;i++)
     {
-        /* Full coverage for all speakers. */
-        for(i = 0;i < MaxChannels;i++)
-            gains[i] = 0.0f;
-        for(i = 0;i < device->NumChan;i++)
+        if(device->ChannelName[i] == LFE)
         {
-            enum Channel chan = Speaker2Chan[i];
-            gains[chan] = ingain;
+            for(j = 0;j < MAX_AMBI_COEFFS;j++)
+                device->AmbiCoeffs[i][j] = 0.0f;
+            continue;
         }
-        return;
-    }
-    if(hwidth <= 0.0f)
-    {
-        /* Infinitely small sound point. */
-        for(i = 0;i < MaxChannels;i++)
-            gains[i] = 0.0f;
-        for(i = 0;i < device->NumChan-1;i++)
+
+        for(j = 0;j < count;j++)
         {
-            if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1])
+            if(device->ChannelName[i] == chanmap[j].ChanName)
             {
-                /* Sound is between speakers i and i+1 */
-                a =             (angle-SpeakerAngle[i]) /
-                    (SpeakerAngle[i+1]-SpeakerAngle[i]);
-                gains[Speaker2Chan[i]]   = sqrtf(1.0f-a) * ingain;
-                gains[Speaker2Chan[i+1]] = sqrtf(     a) * ingain;
-                return;
+                if(isfuma)
+                {
+                    /* Reformat FuMa -> ACN/N3D */
+                    for(k = 0;k < MAX_AMBI_COEFFS;++k)
+                    {
+                        ALuint acn = FuMa2ACN[k];
+                        device->AmbiCoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn];
+                    }
+                }
+                else
+                {
+                    for(k = 0;k < MAX_AMBI_COEFFS;++k)
+                        device->AmbiCoeffs[i][k] = chanmap[j].Config[k];
+                }
+                break;
             }
         }
-        /* Sound is between last and first speakers */
-        if(angle < SpeakerAngle[0])
-            angle += F_2PI;
-        a =                   (angle-SpeakerAngle[i]) /
-            (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
-        gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain;
-        gains[Speaker2Chan[0]] = sqrtf(     a) * ingain;
-        return;
+        if(j == count)
+            ERR("Failed to match %s channel (%u) in config\n", GetLabelFromChannel(device->ChannelName[i]), i);
     }
+    device->NumChannels = i;
+}
 
-    if(fabsf(angle)+hwidth > F_PI)
+static bool LoadChannelSetup(ALCdevice *device)
+{
+    static const enum Channel mono_chans[1] = {
+        FrontCenter
+    }, stereo_chans[2] = {
+        FrontLeft, FrontRight
+    }, quad_chans[4] = {
+        FrontLeft, FrontRight,
+        BackLeft, BackRight
+    }, surround51_chans[5] = {
+        FrontLeft, FrontRight, FrontCenter,
+        SideLeft, SideRight
+    }, surround51rear_chans[5] = {
+        FrontLeft, FrontRight, FrontCenter,
+        BackLeft, BackRight
+    }, surround61_chans[6] = {
+        FrontLeft, FrontRight,
+        FrontCenter, BackCenter,
+        SideLeft, SideRight
+    }, surround71_chans[7] = {
+        FrontLeft, FrontRight, FrontCenter,
+        BackLeft, BackRight,
+        SideLeft, SideRight
+    };
+    ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
+    const enum Channel *channels = NULL;
+    const char *layout = NULL;
+    ALfloat ambiscale = 1.0f;
+    size_t count = 0;
+    int isfuma;
+    int order;
+    size_t i;
+
+    switch(device->FmtChans)
     {
-        /* The coverage area would go outside of -pi...+pi. Instead, rotate the
-         * speaker angles so it would be as if angle=0, and keep them wrapped
-         * within -pi...+pi. */
-        if(angle > 0.0f)
-        {
-            ALuint done;
-            ALuint i = 0;
-            while(i < device->NumChan && device->SpeakerAngle[i]-angle < -F_PI)
-                i++;
-            for(done = 0;i < device->NumChan;done++)
-            {
-                SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
-                Speaker2Chan[done] = device->Speaker2Chan[i];
-                i++;
-            }
-            for(i = 0;done < device->NumChan;i++)
-            {
-                SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_2PI;
-                Speaker2Chan[done] = device->Speaker2Chan[i];
-                done++;
-            }
-        }
-        else
-        {
-            /* NOTE: '< device->NumChan' on the iterators is correct here since
-             * we need to handle index 0. Because the iterators are unsigned,
-             * they'll underflow and wrap to become 0xFFFFFFFF, which will
-             * break as expected. */
-            ALuint done;
-            ALuint i = device->NumChan-1;
-            while(i < device->NumChan && device->SpeakerAngle[i]-angle > F_PI)
-                i--;
-            for(done = device->NumChan-1;i < device->NumChan;done--)
-            {
-                SpeakerAngle[done] = device->SpeakerAngle[i]-angle;
-                Speaker2Chan[done] = device->Speaker2Chan[i];
-                i--;
-            }
-            for(i = device->NumChan-1;done < device->NumChan;i--)
-            {
-                SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_2PI;
-                Speaker2Chan[done] = device->Speaker2Chan[i];
-                done--;
-            }
-        }
-        angle = 0.0f;
+        case DevFmtMono:
+            layout = "mono";
+            channels = mono_chans;
+            count = COUNTOF(mono_chans);
+            break;
+        case DevFmtStereo:
+            layout = "stereo";
+            channels = stereo_chans;
+            count = COUNTOF(stereo_chans);
+            break;
+        case DevFmtQuad:
+            layout = "quad";
+            channels = quad_chans;
+            count = COUNTOF(quad_chans);
+            break;
+        case DevFmtX51:
+            layout = "surround51";
+            channels = surround51_chans;
+            count = COUNTOF(surround51_chans);
+            break;
+        case DevFmtX51Rear:
+            layout = "surround51rear";
+            channels = surround51rear_chans;
+            count = COUNTOF(surround51rear_chans);
+            break;
+        case DevFmtX61:
+            layout = "surround61";
+            channels = surround61_chans;
+            count = COUNTOF(surround61_chans);
+            break;
+        case DevFmtX71:
+            layout = "surround71";
+            channels = surround71_chans;
+            count = COUNTOF(surround71_chans);
+            break;
+        case DevFmtBFormat3D:
+            break;
     }
-    langle = angle - hwidth;
-    rangle = angle + hwidth;
 
-    /* First speaker */
-    i = 0;
-    do {
-        ALuint last = device->NumChan-1;
-        enum Channel chan = Speaker2Chan[i];
+    if(!layout)
+        return false;
+    else
+    {
+        char name[32] = {0};
+        const char *type;
+        char eol;
 
-        if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
-        {
-            tmpgains[chan] = 1.0f;
-            continue;
-        }
+        snprintf(name, sizeof(name), "%s/type", layout);
+        if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", name, &type))
+            return false;
 
-        if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
+        if(sscanf(type, " %31[^: ] : %d%c", name, &order, &eol) != 2)
         {
-            a =            (langle-SpeakerAngle[i]) /
-                (SpeakerAngle[i+1]-SpeakerAngle[i]);
-            tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
+            ERR("Invalid type value '%s' (expected name:order) for layout %s\n", type, layout);
+            return false;
         }
-        if(SpeakerAngle[i] > rangle)
-        {
-            a =          (F_2PI + rangle-SpeakerAngle[last]) /
-                (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
-            tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
-        }
-        else if(SpeakerAngle[last] < rangle)
-        {
-            a =                  (rangle-SpeakerAngle[last]) /
-                (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]);
-            tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
-        }
-    } while(0);
 
-    for(i = 1;i < device->NumChan-1;i++)
-    {
-        enum Channel chan = Speaker2Chan[i];
-        if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
+        if(strcasecmp(name, "fuma") == 0)
+            isfuma = 1;
+        else if(strcasecmp(name, "n3d") == 0)
+            isfuma = 0;
+        else
         {
-            tmpgains[chan] = 1.0f;
-            continue;
+            ERR("Unhandled type name '%s' (expected FuMa or N3D) for layout %s\n", name, layout);
+            return false;
         }
 
-        if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle)
-        {
-            a =            (langle-SpeakerAngle[i]) /
-                (SpeakerAngle[i+1]-SpeakerAngle[i]);
-            tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
-        }
-        if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
+        if(order == 3)
+            ambiscale = THIRD_ORDER_SCALE;
+        else if(order == 2)
+            ambiscale = SECOND_ORDER_SCALE;
+        else if(order == 1)
+            ambiscale = FIRST_ORDER_SCALE;
+        else if(order == 0)
+            ambiscale = ZERO_ORDER_SCALE;
+        else
         {
-            a =          (rangle-SpeakerAngle[i-1]) /
-                (SpeakerAngle[i]-SpeakerAngle[i-1]);
-            tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
+            ERR("Unhandled type order %d (expected 0, 1, 2, or 3) for layout %s\n", order, layout);
+            return false;
         }
     }
 
-    /* Last speaker */
-    i = device->NumChan-1;
-    do {
-        enum Channel chan = Speaker2Chan[i];
-        if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle)
-        {
-            tmpgains[Speaker2Chan[i]] = 1.0f;
-            continue;
-        }
-        if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle)
+    for(i = 0;i < count;i++)
+    {
+        float coeffs[MAX_AMBI_COEFFS] = {0.0f};
+        const char *channame;
+        char chanlayout[32];
+        const char *value;
+        int props = 0;
+        char eol = 0;
+        int j;
+
+        chanmap[i].ChanName = channels[i];
+        channame = GetLabelFromChannel(channels[i]);
+
+        snprintf(chanlayout, sizeof(chanlayout), "%s/%s", layout, channame);
+        if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", chanlayout, &value))
         {
-            a =          (rangle-SpeakerAngle[i-1]) /
-                (SpeakerAngle[i]-SpeakerAngle[i-1]);
-            tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a);
+            ERR("Missing channel %s\n", channame);
+            return false;
         }
-        if(SpeakerAngle[i] < langle)
+        if(order == 3)
+            props = sscanf(value, " %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %c",
+                &coeffs[0],  &coeffs[1],  &coeffs[2],  &coeffs[3],
+                &coeffs[4],  &coeffs[5],  &coeffs[6],  &coeffs[7],
+                &coeffs[8],  &coeffs[9],  &coeffs[10], &coeffs[11],
+                &coeffs[12], &coeffs[13], &coeffs[14], &coeffs[15],
+                &eol
+            );
+        else if(order == 2)
+            props = sscanf(value, " %f %f %f %f %f %f %f %f %f %c",
+                &coeffs[0], &coeffs[1], &coeffs[2],
+                &coeffs[3], &coeffs[4], &coeffs[5],
+                &coeffs[6], &coeffs[7], &coeffs[8],
+                &eol
+            );
+        else if(order == 1)
+            props = sscanf(value, " %f %f %f %f %c",
+                &coeffs[0], &coeffs[1],
+                &coeffs[2], &coeffs[3],
+                &eol
+            );
+        else if(order == 0)
+            props = sscanf(value, " %f %c", &coeffs[0], &eol);
+        if(props == 0)
         {
-            a =                  (langle-SpeakerAngle[i]) /
-                (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
-            tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
+            ERR("Failed to parse option %s properties\n", chanlayout);
+            return false;
         }
-        else if(SpeakerAngle[0] > langle)
+
+        if(props > (order+1)*(order+1))
         {
-            a =          (F_2PI + langle-SpeakerAngle[i]) /
-                (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]);
-            tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a);
+            ERR("Excess elements in option %s (expected %d)\n", chanlayout, (order+1)*(order+1));
+            return false;
         }
-    } while(0);
 
-    for(i = 0;i < device->NumChan;i++)
-    {
-        enum Channel chan = device->Speaker2Chan[i];
-        gains[chan] = sqrtf(tmpgains[chan]) * ingain;
+        for(j = 0;j < MAX_AMBI_COEFFS;++j)
+            chanmap[i].Config[j] = coeffs[j];
     }
+    SetChannelMap(device, chanmap, count, ambiscale, isfuma);
+    return true;
 }
 
-
-ALvoid aluInitPanning(ALCdevice *Device)
+ALvoid aluInitPanning(ALCdevice *device)
 {
-    const char *layoutname = NULL;
-    enum Channel *Speaker2Chan;
-    ALfloat *SpeakerAngle;
+    /* NOTE: These decoder coefficients are using FuMa channel ordering and
+     * normalization, since that's what was produced by the Ambisonic Decoder
+     * Toolbox. SetChannelMap will convert them to N3D.
+     */
+    static const ChannelMap MonoCfg[1] = {
+        { FrontCenter, { 1.414213562f } },
+    }, StereoCfg[2] = {
+        { FrontLeft,   { 0.707106781f, 0.0f,  0.5f, 0.0f } },
+        { FrontRight,  { 0.707106781f, 0.0f, -0.5f, 0.0f } },
+    }, QuadCfg[4] = {
+        { FrontLeft,   { 0.353553f,  0.306184f,  0.306184f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f,  0.117186f } },
+        { FrontRight,  { 0.353553f,  0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f, -0.117186f } },
+        { BackLeft,    { 0.353553f, -0.306184f,  0.306184f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f, -0.117186f } },
+        { BackRight,   { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f,  0.117186f } },
+    }, X51SideCfg[5] = {
+        { FrontLeft,   { 0.208954f,  0.212846f,  0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f,  0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f,  0.047490f } },
+        { FrontRight,  { 0.208954f,  0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } },
+        { FrontCenter, { 0.109403f,  0.179490f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f,  0.142031f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.072024f,  0.000000f } },
+        { SideLeft,    { 0.470936f, -0.369626f,  0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } },
+        { SideRight,   { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f,  0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f,  0.043968f } },
+    }, X51RearCfg[5] = {
+        { FrontLeft,   { 0.208954f,  0.212846f,  0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f,  0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f,  0.047490f } },
+        { FrontRight,  { 0.208954f,  0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } },
+        { FrontCenter, { 0.109403f,  0.179490f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f,  0.142031f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.072024f,  0.000000f } },
+        { BackLeft,    { 0.470936f, -0.369626f,  0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } },
+        { BackRight,   { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f,  0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f,  0.043968f } },
+    }, X61Cfg[6] = {
+        { FrontLeft,   { 0.167065f,  0.200583f,  0.172695f, 0.0f, 0.0f, 0.0f, 0.0f,  0.029855f,  0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f,  0.068910f } },
+        { FrontRight,  { 0.167065f,  0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f,  0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } },
+        { FrontCenter, { 0.109403f,  0.179490f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f,  0.142031f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.072024f,  0.000000f } },
+        { BackCenter,  { 0.353556f, -0.461940f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f,  0.165723f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f,  0.000000f } },
+        { SideLeft,    { 0.289151f, -0.081301f,  0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.010099f, -0.032897f } },
+        { SideRight,   { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f,  0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.010099f,  0.032897f } },
+    }, X71Cfg[7] = {
+        { FrontLeft,   { 0.167065f,  0.200583f,  0.172695f, 0.0f, 0.0f, 0.0f, 0.0f,  0.029855f,  0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f,  0.068910f } },
+        { FrontRight,  { 0.167065f,  0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f,  0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } },
+        { FrontCenter, { 0.109403f,  0.179490f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f,  0.142031f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.072024f,  0.000000f } },
+        { BackLeft,    { 0.224752f, -0.295009f,  0.170325f, 0.0f, 0.0f, 0.0f, 0.0f,  0.105349f, -0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f,  0.065799f } },
+        { BackRight,   { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f,  0.105349f,  0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f, -0.065799f } },
+        { SideLeft,    { 0.224739f,  0.000000f,  0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f, -0.065795f } },
+        { SideRight,   { 0.224739f,  0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f,  0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.000000f,  0.065795f } },
+    }, BFormat3D[4] = {
+        { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
+        { BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } },
+        { BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } },
+        { BFormatZ, { 0.0f, 0.0f, 0.0f, 1.0f } },
+    };
+    const ChannelMap *chanmap = NULL;
+    ALfloat ambiscale = 1.0f;
+    size_t count = 0;
+
+    device->AmbiScale = 1.0f;
+    memset(device->AmbiCoeffs, 0, sizeof(device->AmbiCoeffs));
+    device->NumChannels = 0;
+
+    if(device->Hrtf)
+    {
+        ALfloat (*coeffs_list[4])[2];
+        ALuint *delay_list[4];
+        ALuint i;
+
+        count = COUNTOF(BFormat3D);
+        chanmap = BFormat3D;
+        ambiscale = 1.0f;
+
+        for(i = 0;i < count;i++)
+            device->ChannelName[i] = chanmap[i].ChanName;
+        for(;i < MAX_OUTPUT_CHANNELS;i++)
+            device->ChannelName[i] = InvalidChannel;
+        SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE);
+
+        for(i = 0;i < 4;++i)
+        {
+            static const enum Channel inputs[4] = { BFormatW, BFormatX, BFormatY, BFormatZ };
+            int chan = GetChannelIdxByName(device, inputs[i]);
+            coeffs_list[i] = device->Hrtf_Params[chan].Coeffs;
+            delay_list[i] = device->Hrtf_Params[chan].Delay;
+        }
+        GetBFormatHrtfCoeffs(device->Hrtf, 4, coeffs_list, delay_list);
+
+        return;
+    }
+
+    if(LoadChannelSetup(device))
+        return;
 
-    Speaker2Chan = Device->Speaker2Chan;
-    SpeakerAngle = Device->SpeakerAngle;
-    switch(Device->FmtChans)
+    switch(device->FmtChans)
     {
         case DevFmtMono:
-            Device->NumChan = 1;
-            Speaker2Chan[0] = FrontCenter;
-            SpeakerAngle[0] = DEG2RAD(0.0f);
-            layoutname = NULL;
+            count = COUNTOF(MonoCfg);
+            chanmap = MonoCfg;
+            ambiscale = ZERO_ORDER_SCALE;
             break;
 
         case DevFmtStereo:
-            Device->NumChan = 2;
-            Speaker2Chan[0] = FrontLeft;
-            Speaker2Chan[1] = FrontRight;
-            SpeakerAngle[0] = DEG2RAD(-90.0f);
-            SpeakerAngle[1] = DEG2RAD( 90.0f);
-            layoutname = "layout_stereo";
+            count = COUNTOF(StereoCfg);
+            chanmap = StereoCfg;
+            ambiscale = FIRST_ORDER_SCALE;
             break;
 
         case DevFmtQuad:
-            Device->NumChan = 4;
-            Speaker2Chan[0] = BackLeft;
-            Speaker2Chan[1] = FrontLeft;
-            Speaker2Chan[2] = FrontRight;
-            Speaker2Chan[3] = BackRight;
-            SpeakerAngle[0] = DEG2RAD(-135.0f);
-            SpeakerAngle[1] = DEG2RAD( -45.0f);
-            SpeakerAngle[2] = DEG2RAD(  45.0f);
-            SpeakerAngle[3] = DEG2RAD( 135.0f);
-            layoutname = "layout_quad";
+            count = COUNTOF(QuadCfg);
+            chanmap = QuadCfg;
+            ambiscale = SECOND_ORDER_SCALE;
             break;
 
         case DevFmtX51:
-            Device->NumChan = 5;
-            Speaker2Chan[0] = BackLeft;
-            Speaker2Chan[1] = FrontLeft;
-            Speaker2Chan[2] = FrontCenter;
-            Speaker2Chan[3] = FrontRight;
-            Speaker2Chan[4] = BackRight;
-            SpeakerAngle[0] = DEG2RAD(-110.0f);
-            SpeakerAngle[1] = DEG2RAD( -30.0f);
-            SpeakerAngle[2] = DEG2RAD(   0.0f);
-            SpeakerAngle[3] = DEG2RAD(  30.0f);
-            SpeakerAngle[4] = DEG2RAD( 110.0f);
-            layoutname = "layout_surround51";
+            count = COUNTOF(X51SideCfg);
+            chanmap = X51SideCfg;
+            ambiscale = THIRD_ORDER_SCALE;
             break;
 
-        case DevFmtX51Side:
-            Device->NumChan = 5;
-            Speaker2Chan[0] = SideLeft;
-            Speaker2Chan[1] = FrontLeft;
-            Speaker2Chan[2] = FrontCenter;
-            Speaker2Chan[3] = FrontRight;
-            Speaker2Chan[4] = SideRight;
-            SpeakerAngle[0] = DEG2RAD(-90.0f);
-            SpeakerAngle[1] = DEG2RAD(-30.0f);
-            SpeakerAngle[2] = DEG2RAD(  0.0f);
-            SpeakerAngle[3] = DEG2RAD( 30.0f);
-            SpeakerAngle[4] = DEG2RAD( 90.0f);
-            layoutname = "layout_side51";
+        case DevFmtX51Rear:
+            count = COUNTOF(X51RearCfg);
+            chanmap = X51RearCfg;
+            ambiscale = THIRD_ORDER_SCALE;
             break;
 
         case DevFmtX61:
-            Device->NumChan = 6;
-            Speaker2Chan[0] = SideLeft;
-            Speaker2Chan[1] = FrontLeft;
-            Speaker2Chan[2] = FrontCenter;
-            Speaker2Chan[3] = FrontRight;
-            Speaker2Chan[4] = SideRight;
-            Speaker2Chan[5] = BackCenter;
-            SpeakerAngle[0] = DEG2RAD(-90.0f);
-            SpeakerAngle[1] = DEG2RAD(-30.0f);
-            SpeakerAngle[2] = DEG2RAD(  0.0f);
-            SpeakerAngle[3] = DEG2RAD( 30.0f);
-            SpeakerAngle[4] = DEG2RAD( 90.0f);
-            SpeakerAngle[5] = DEG2RAD(180.0f);
-            layoutname = "layout_surround61";
+            count = COUNTOF(X61Cfg);
+            chanmap = X61Cfg;
+            ambiscale = THIRD_ORDER_SCALE;
             break;
 
         case DevFmtX71:
-            Device->NumChan = 7;
-            Speaker2Chan[0] = BackLeft;
-            Speaker2Chan[1] = SideLeft;
-            Speaker2Chan[2] = FrontLeft;
-            Speaker2Chan[3] = FrontCenter;
-            Speaker2Chan[4] = FrontRight;
-            Speaker2Chan[5] = SideRight;
-            Speaker2Chan[6] = BackRight;
-            SpeakerAngle[0] = DEG2RAD(-150.0f);
-            SpeakerAngle[1] = DEG2RAD( -90.0f);
-            SpeakerAngle[2] = DEG2RAD( -30.0f);
-            SpeakerAngle[3] = DEG2RAD(   0.0f);
-            SpeakerAngle[4] = DEG2RAD(  30.0f);
-            SpeakerAngle[5] = DEG2RAD(  90.0f);
-            SpeakerAngle[6] = DEG2RAD( 150.0f);
-            layoutname = "layout_surround71";
+            count = COUNTOF(X71Cfg);
+            chanmap = X71Cfg;
+            ambiscale = THIRD_ORDER_SCALE;
+            break;
+
+        case DevFmtBFormat3D:
+            count = COUNTOF(BFormat3D);
+            chanmap = BFormat3D;
+            ambiscale = 1.0f;
             break;
     }
-    if(layoutname && Device->Type != Loopback)
-        SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan);
+
+    SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE);
 }

+ 26 - 8
libs/openal-soft/Alc/vector.h

@@ -7,21 +7,21 @@
 
 /* "Base" vector type, designed to alias with the actual vector types. */
 typedef struct vector__s {
-    ALsizei Capacity;
-    ALsizei Size;
+    size_t Capacity;
+    size_t Size;
 } *vector_;
 
 #define TYPEDEF_VECTOR(T, N) typedef struct {                                 \
-    ALsizei Capacity;                                                         \
-    ALsizei Size;                                                             \
+    size_t Capacity;                                                          \
+    size_t Size;                                                              \
     T Data[];                                                                 \
 } _##N;                                                                       \
 typedef _##N* N;                                                              \
 typedef const _##N* const_##N;
 
 #define VECTOR(T) struct {                                                    \
-    ALsizei Capacity;                                                         \
-    ALsizei Size;                                                             \
+    size_t Capacity;                                                          \
+    size_t Size;                                                              \
     T Data[];                                                                 \
 }*
 
@@ -30,10 +30,10 @@ typedef const _##N* const_##N;
 #define VECTOR_DEINIT(_x)     do { free((_x)); (_x) = NULL; } while(0)
 
 /* Helper to increase a vector's reserve. Do not call directly. */
-ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count, ALboolean exact);
+ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact);
 #define VECTOR_RESERVE(_x, _c) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c), AL_TRUE))
 
-ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count);
+ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count);
 #define VECTOR_RESIZE(_x, _c) (vector_resize((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c)))
 
 #define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0)
@@ -73,6 +73,13 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
         _f(_iter);                                                            \
 } while(0)
 
+#define VECTOR_FOR_EACH_PARAMS(_t, _x, _f, ...)  do {                         \
+    _t *_iter = VECTOR_ITER_BEGIN((_x));                                      \
+    _t *_end = VECTOR_ITER_END((_x));                                         \
+    for(;_iter != _end;++_iter)                                               \
+        _f(__VA_ARGS__, _iter);                                               \
+} while(0)
+
 #define VECTOR_FIND_IF(_i, _t, _x, _f)  do {                                  \
     _t *_iter = VECTOR_ITER_BEGIN((_x));                                      \
     _t *_end = VECTOR_ITER_END((_x));                                         \
@@ -84,4 +91,15 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
     (_i) = _iter;                                                             \
 } while(0)
 
+#define VECTOR_FIND_IF_PARMS(_i, _t, _x, _f, ...)  do {                       \
+    _t *_iter = VECTOR_ITER_BEGIN((_x));                                      \
+    _t *_end = VECTOR_ITER_END((_x));                                         \
+    for(;_iter != _end;++_iter)                                               \
+    {                                                                         \
+        if(_f(__VA_ARGS__, _iter))                                            \
+            break;                                                            \
+    }                                                                         \
+    (_i) = _iter;                                                             \
+} while(0)
+
 #endif /* AL_VECTOR_H */

+ 167 - 117
libs/openal-soft/CMakeLists.txt

@@ -34,9 +34,11 @@ OPTION(ALSOFT_UTILS          "Build and install utility programs"         OFF)
 OPTION(ALSOFT_NO_CONFIG_UTIL "Disable building the alsoft-config utility" OFF)
 
 OPTION(ALSOFT_EXAMPLES  "Build and install example programs"  OFF)
+OPTION(ALSOFT_TESTS     "Build and install test programs"     OFF)
 
 OPTION(ALSOFT_CONFIG "Install alsoft.conf sample configuration file" OFF)
-OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" ON)
+OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" OFF)
+OPTION(ALSOFT_INSTALL "Install headers and libraries" ON)
 
 
 IF(WIN32)
@@ -89,7 +91,7 @@ IF(NOT LIBTYPE)
 ENDIF()
 
 SET(LIB_MAJOR_VERSION "1")
-SET(LIB_MINOR_VERSION "16")
+SET(LIB_MINOR_VERSION "17")
 SET(LIB_REVISION "0")
 SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}")
 
@@ -101,9 +103,14 @@ CHECK_TYPE_SIZE("long" SIZEOF_LONG)
 CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
 
 
-CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99)
-IF(HAVE_STD_C99)
-    SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
+CHECK_C_COMPILER_FLAG(-std=c11 HAVE_STD_C11)
+IF(HAVE_STD_C11)
+    SET(CMAKE_C_FLAGS "-std=c11 ${CMAKE_C_FLAGS}")
+ELSE()
+    CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99)
+    IF(HAVE_STD_C99)
+        SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}")
+    ENDIF()
 ENDIF()
 
 # MSVC may need workarounds for C99 restrict and inline
@@ -188,7 +195,7 @@ HAVE_C11_ALIGNAS)
 # Check if we have C11 _Atomic
 CHECK_C_SOURCE_COMPILES(
 "#include <stdatomic.h>
- int _Atomic foo;
+ const int _Atomic foo = ATOMIC_VAR_INIT(~0);
  int main()
  {
      return atomic_load(&foo);
@@ -216,11 +223,6 @@ IF(NOT CMAKE_DEBUG_POSTFIX)
 ENDIF()
 
 IF(MSVC)
-    # ???
-    SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEBUG")
-    SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -DNDEBUG")
-    SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG")
-    SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
     ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS)
     ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
     ADD_DEFINITIONS("/wd4098")
@@ -232,9 +234,6 @@ IF(MSVC)
     ENDIF()
     IF(DXSDK_DIR)
         MESSAGE(STATUS "Using DirectX SDK directory: ${DXSDK_DIR}")
-        SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} "${DXSDK_DIR}/Include")
-        INCLUDE_DIRECTORIES("${DXSDK_DIR}/Include")
-        LINK_DIRECTORIES("${DXSDK_DIR}/Lib")
     ENDIF()
 
     OPTION(FORCE_STATIC_VCRT "Force /MT for static VC runtimes" OFF)
@@ -258,27 +257,24 @@ ELSE()
         ADD_DEFINITIONS(-Werror)
     ENDIF()
 
-    # Force enable PIC if available. The static common library will be linked
-    # into the dynamic openal library, which requires all its code to be
-    # position-independent, and CMake doesn't automatically enable PIC for
-    # static library targets (Windows code is always position-independent).
-    CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH)
-    IF(HAVE_FPIC_SWITCH AND NOT WIN32)
-        ADD_DEFINITIONS(-fPIC)
+    # Force enable -fPIC for CMake versions before 2.8.9 (later versions have
+    # the POSITION_INDEPENDENT_CODE target property). The static common library
+    # will be linked into the dynamic openal library, which requires all its
+    # code to be position-independent.
+    IF(CMAKE_VERSION VERSION_LESS "2.8.9" AND NOT WIN32)
+        CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH)
+        IF(HAVE_FPIC_SWITCH)
+            ADD_DEFINITIONS(-fPIC)
+        ENDIF()
     ENDIF()
 
-    SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O2 -D_DEBUG" CACHE STRING
-        "Flags used by the compiler during Release with Debug Info builds."
-        FORCE)
-    SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" CACHE STRING
-        "Flags used by the compiler during release minsize builds."
-        FORCE)
-    SET(CMAKE_C_FLAGS_RELEASE "-O2 -fomit-frame-pointer -DNDEBUG" CACHE STRING
-        "Flags used by the compiler during release builds"
-        FORCE)
-    SET(CMAKE_C_FLAGS_DEBUG "-g3 -D_DEBUG" CACHE STRING
-        "Flags used by the compiler during debug builds."
-        FORCE)
+    # We want RelWithDebInfo to actually include debug stuff (define _DEBUG
+    # instead of NDEBUG)
+    FOREACH(flag_var  CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+        IF(${flag_var} MATCHES "-DNDEBUG")
+            STRING(REGEX REPLACE "-DNDEBUG" "-D_DEBUG" ${flag_var} "${${flag_var}}")
+        ENDIF()
+    ENDFOREACH()
 
     CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
                              int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
@@ -337,6 +333,10 @@ IF(NOT MSVC)
     IF(HAVE_MSSE2_SWITCH)
         SET(SSE2_SWITCH "-msse2")
     ENDIF()
+    CHECK_C_COMPILER_FLAG(-msse3 HAVE_MSSE3_SWITCH)
+    IF(HAVE_MSSE3_SWITCH)
+        SET(SSE3_SWITCH "-msse3")
+    ENDIF()
     CHECK_C_COMPILER_FLAG(-msse4.1 HAVE_MSSE4_1_SWITCH)
     IF(HAVE_MSSE4_1_SWITCH)
         SET(SSE4_1_SWITCH "-msse4.1")
@@ -349,7 +349,7 @@ CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(pri
 CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H)
 CHECK_INCLUDE_FILE(stdalign.h HAVE_STDALIGN_H)
 CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H)
-CHECK_INCLUDE_FILE(ftw.h HAVE_FTW_H)
+CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H)
 CHECK_INCLUDE_FILE(io.h HAVE_IO_H)
 CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H)
 CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H)
@@ -368,7 +368,7 @@ IF(HAVE_CPUID_H)
         int main()
         {
             unsigned int eax, ebx, ecx, edx;
-            return __get_cpuid(0, eax, ebx, ecx, edx);
+            return __get_cpuid(0, &eax, &ebx, &ecx, &edx);
         }" HAVE_GCC_GET_CPUID)
 ENDIF()
 
@@ -394,6 +394,7 @@ CHECK_SYMBOL_EXISTS(aligned_alloc    stdlib.h HAVE_ALIGNED_ALLOC)
 CHECK_SYMBOL_EXISTS(posix_memalign   stdlib.h HAVE_POSIX_MEMALIGN)
 CHECK_SYMBOL_EXISTS(_aligned_malloc  malloc.h HAVE__ALIGNED_MALLOC)
 CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF)
+CHECK_SYMBOL_EXISTS(modff  math.h HAVE_MODFF)
 IF(NOT HAVE_C99_VLA)
     CHECK_SYMBOL_EXISTS(alloca malloc.h HAVE_ALLOCA)
     IF(NOT HAVE_ALLOCA)
@@ -405,12 +406,6 @@ IF(HAVE_FLOAT_H)
     CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP)
     CHECK_SYMBOL_EXISTS(__control87_2 float.h HAVE___CONTROL87_2)
 ENDIF()
-IF(HAVE_FTW_H)
-    CHECK_SYMBOL_EXISTS(ftw ftw.h HAVE_FTW)
-ENDIF()
-IF(HAVE_IO_H)
-    CHECK_SYMBOL_EXISTS(_wfindfirst io.h HAVE__WFINDFIRST)
-ENDIF()
 
 CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF)
 CHECK_FUNCTION_EXISTS(stat HAVE_STAT)
@@ -515,12 +510,18 @@ IF(NOT HAVE_WINDOWS_H)
 
     CHECK_SYMBOL_EXISTS(pthread_setschedparam pthread.h HAVE_PTHREAD_SETSCHEDPARAM)
 
-    CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
-    IF(NOT HAVE_PTHREAD_SETNAME_NP)
-        CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP)
-    ENDIF()
     IF(HAVE_PTHREAD_NP_H)
+        CHECK_SYMBOL_EXISTS(pthread_setname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SETNAME_NP)
+        IF(NOT HAVE_PTHREAD_SETNAME_NP)
+            CHECK_SYMBOL_EXISTS(pthread_set_name_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SET_NAME_NP)
+        ENDIF()
         CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np "pthread.h;pthread_np.h" HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
+    ELSE()
+        CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
+        IF(NOT HAVE_PTHREAD_SETNAME_NP)
+            CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP)
+        ENDIF()
+        CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np pthread.h HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
     ENDIF()
 
     CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK)
@@ -561,11 +562,7 @@ SET(OPENAL_OBJS  OpenAL32/alAuxEffectSlot.c
                  OpenAL32/alError.c
                  OpenAL32/alExtension.c
                  OpenAL32/alFilter.c
-                 OpenAL32/alFontsound.c
                  OpenAL32/alListener.c
-                 OpenAL32/alMidi.c
-                 OpenAL32/alPreset.c
-                 OpenAL32/alSoundfont.c
                  OpenAL32/alSource.c
                  OpenAL32/alState.c
                  OpenAL32/alThunk.c
@@ -588,6 +585,7 @@ SET(ALC_OBJS  Alc/ALc.c
               Alc/effects/null.c
               Alc/effects/reverb.c
               Alc/helpers.c
+              Alc/bsinc.c
               Alc/hrtf.c
               Alc/panning.c
               Alc/mixer.c
@@ -598,11 +596,10 @@ SET(ALC_OBJS  Alc/ALc.c
 SET(CPU_EXTS "Default")
 SET(HAVE_SSE        0)
 SET(HAVE_SSE2       0)
+SET(HAVE_SSE3       0)
 SET(HAVE_SSE4_1     0)
 SET(HAVE_NEON       0)
 
-SET(HAVE_FLUIDSYNTH 0)
-
 SET(HAVE_ALSA       0)
 SET(HAVE_OSS        0)
 SET(HAVE_SOLARIS    0)
@@ -658,6 +655,26 @@ IF(ALSOFT_REQUIRE_SSE2 AND NOT HAVE_SSE2)
     MESSAGE(FATAL_ERROR "Failed to enable required SSE2 CPU extensions")
 ENDIF()
 
+OPTION(ALSOFT_REQUIRE_SSE2 "Require SSE3 support" OFF)
+CHECK_INCLUDE_FILE(pmmintrin.h HAVE_PMMINTRIN_H "${SSE3_SWITCH}")
+IF(HAVE_EMMINTRIN_H)
+    OPTION(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON)
+    IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE3)
+        IF(ALIGN_DECL OR HAVE_C11_ALIGNAS)
+            SET(HAVE_SSE3 1)
+            SET(ALC_OBJS  ${ALC_OBJS} Alc/mixer_sse3.c)
+            IF(SSE2_SWITCH)
+                SET_SOURCE_FILES_PROPERTIES(Alc/mixer_sse3.c PROPERTIES
+                                            COMPILE_FLAGS "${SSE3_SWITCH}")
+            ENDIF()
+            SET(CPU_EXTS "${CPU_EXTS}, SSE3")
+        ENDIF()
+    ENDIF()
+ENDIF()
+IF(ALSOFT_REQUIRE_SSE3 AND NOT HAVE_SSE3)
+    MESSAGE(FATAL_ERROR "Failed to enable required SSE3 CPU extensions")
+ENDIF()
+
 OPTION(ALSOFT_REQUIRE_SSE4_1 "Require SSE4.1 support" OFF)
 CHECK_INCLUDE_FILE(smmintrin.h HAVE_SMMINTRIN_H "${SSE4_1_SWITCH}")
 IF(HAVE_SMMINTRIN_H)
@@ -705,32 +722,6 @@ ELSE()
     ENDMACRO()
 ENDIF()
 
-SET(ALC_OBJS  ${ALC_OBJS}
-              Alc/midi/base.c
-              Alc/midi/sf2load.c
-              Alc/midi/dummy.c
-              Alc/midi/fluidsynth.c
-              Alc/midi/soft.c
-)
-
-# Check for FluidSynth support
-OPTION(ALSOFT_REQUIRE_FLUIDSYNTH "Require FluidSynth MIDI" OFF)
-FIND_PACKAGE(FluidSynth)
-IF(FLUIDSYNTH_FOUND)
-    OPTION(ALSOFT_MIDI_FLUIDSYNTH "Enable FluidSynth MIDI" ON)
-    IF(ALSOFT_MIDI_FLUIDSYNTH)
-        SET(HAVE_FLUIDSYNTH 1)
-        ADD_BACKEND_LIBS(${FLUIDSYNTH_LIBRARIES})
-        IF(CMAKE_VERSION VERSION_LESS "2.8.8")
-            INCLUDE_DIRECTORIES(${FLUIDSYNTH_INCLUDE_DIR})
-        ENDIF()
-    ENDIF()
-ENDIF()
-IF(ALSOFT_REQUIRE_FLUIDSYNTH AND NOT HAVE_FLUIDSYNTH)
-    MESSAGE(FATAL_ERROR "Failed to enabled required FluidSynth support")
-ENDIF()
-
-
 SET(BACKENDS "")
 SET(ALC_OBJS  ${ALC_OBJS}
               Alc/backends/base.c
@@ -926,6 +917,25 @@ IF(ALSOFT_REQUIRE_PULSEAUDIO AND NOT HAVE_PULSEAUDIO)
     MESSAGE(FATAL_ERROR "Failed to enabled required PulseAudio backend")
 ENDIF()
 
+# Check JACK backend
+OPTION(ALSOFT_REQUIRE_JACK "Require JACK backend" OFF)
+FIND_PACKAGE(JACK)
+IF(JACK_FOUND)
+    OPTION(ALSOFT_BACKEND_JACK "Enable JACK backend" ON)
+    IF(ALSOFT_BACKEND_JACK)
+        SET(HAVE_JACK 1)
+        SET(BACKENDS  "${BACKENDS} JACK${IS_LINKED},")
+        SET(ALC_OBJS  ${ALC_OBJS} Alc/backends/jack.c)
+        ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES})
+        IF(CMAKE_VERSION VERSION_LESS "2.8.8")
+            INCLUDE_DIRECTORIES(${JACK_INCLUDE_DIRS})
+        ENDIF()
+    ENDIF()
+ENDIF()
+IF(ALSOFT_REQUIRE_JACK AND NOT HAVE_JACK)
+    MESSAGE(FATAL_ERROR "Failed to enabled required JACK backend")
+ENDIF()
+
 # Check CoreAudio backend
 OPTION(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" OFF)
 FIND_LIBRARY(COREAUDIO_FRAMEWORK
@@ -1030,17 +1040,21 @@ CONFIGURE_FILE(
 
 # Build a common library with reusable helpers
 ADD_LIBRARY(common STATIC ${COMMON_OBJS})
+IF(NOT LIBTYPE STREQUAL "STATIC")
+    SET_PROPERTY(TARGET common PROPERTY POSITION_INDEPENDENT_CODE TRUE)
+ENDIF()
 
 # Build main library
-ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
+IF(LIBTYPE STREQUAL "STATIC")
+    ADD_LIBRARY(${LIBNAME} STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS})
+ELSE()
+    ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS})
+ENDIF()
 SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES)
 IF(WIN32 AND ALSOFT_NO_UID_DEFS)
     SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS)
 ENDIF()
 SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc")
-IF(FLUIDSYNTH_FOUND)
-    SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${FLUIDSYNTH_INCLUDE_DIR})
-ENDIF()
 IF(HAVE_ALSA)
     SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS})
 ENDIF()
@@ -1065,6 +1079,9 @@ ENDIF()
 IF(HAVE_PULSEAUDIO)
     SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS})
 ENDIF()
+IF(HAVE_JACK)
+    SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS})
+ENDIF()
 SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION}
                                             SOVERSION ${LIB_MAJOR_VERSION})
 IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
@@ -1096,25 +1113,28 @@ ENDIF()
 TARGET_LINK_LIBRARIES(${LIBNAME} common ${EXTRA_LIBS})
 TARGET_INCLUDE_DIRECTORIES(${LIBNAME} PUBLIC include)
 
-# Add an install target here
-IF(NOT MEGA)
-INSTALL(TARGETS ${LIBNAME}
-        RUNTIME DESTINATION bin
-        LIBRARY DESTINATION "lib${LIB_SUFFIX}"
-        ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
-)
-INSTALL(FILES include/AL/al.h
-              include/AL/alc.h
-              include/AL/alext.h
-              include/AL/efx.h
-              include/AL/efx-creative.h
-              include/AL/efx-presets.h
-        DESTINATION include/AL
-)
-INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
-        DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
+IF(ALSOFT_INSTALL)
+    # Add an install target here
+    IF(NOT MEGA)
+    INSTALL(TARGETS ${LIBNAME}
+            RUNTIME DESTINATION bin
+            LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+            ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+    )
+    INSTALL(FILES include/AL/al.h
+                  include/AL/alc.h
+                  include/AL/alext.h
+                  include/AL/efx.h
+                  include/AL/efx-creative.h
+                  include/AL/efx-presets.h
+            DESTINATION include/AL
+    )
+    INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
+            DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
+    ENDIF()
 ENDIF()
 
+
 MESSAGE(STATUS "")
 MESSAGE(STATUS "Building OpenAL with support for the following backends:")
 MESSAGE(STATUS "    ${BACKENDS}")
@@ -1122,10 +1142,6 @@ MESSAGE(STATUS "")
 MESSAGE(STATUS "Building with support for CPU extensions:")
 MESSAGE(STATUS "    ${CPU_EXTS}")
 MESSAGE(STATUS "")
-IF(HAVE_FLUIDSYNTH)
-    MESSAGE(STATUS "FluidSynth support for ALC_SOFT_midi_interface enabled")
-    MESSAGE(STATUS "")
-ENDIF()
 
 IF(WIN32)
     IF(NOT HAVE_DSOUND)
@@ -1163,11 +1179,18 @@ IF(ALSOFT_UTILS)
         TARGET_LINK_LIBRARIES(makehrtf m)
     ENDIF()
 
-    INSTALL(TARGETS openal-info makehrtf
-            RUNTIME DESTINATION bin
-            LIBRARY DESTINATION "lib${LIB_SUFFIX}"
-            ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
-    )
+    ADD_EXECUTABLE(bsincgen utils/bsincgen.c)
+    IF(HAVE_LIBM)
+        TARGET_LINK_LIBRARIES(bsincgen m)
+    ENDIF()
+
+    IF(ALSOFT_INSTALL)
+        INSTALL(TARGETS openal-info makehrtf bsincgen
+                RUNTIME DESTINATION bin
+                LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+                ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+        )
+    ENDIF()
 
     MESSAGE(STATUS "Building utility programs")
     IF(TARGET alsoft-config)
@@ -1176,6 +1199,24 @@ IF(ALSOFT_UTILS)
     MESSAGE(STATUS "")
 ENDIF()
 
+IF(ALSOFT_TESTS)
+        ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c)
+
+        ADD_EXECUTABLE(altonegen examples/altonegen.c)
+        TARGET_LINK_LIBRARIES(altonegen test-common ${LIBNAME})
+
+        IF(ALSOFT_INSTALL)
+            INSTALL(TARGETS altonegen
+                    RUNTIME DESTINATION bin
+                    LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+                    ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+            )
+        ENDIF()
+
+        MESSAGE(STATUS "Building test programs")
+        MESSAGE(STATUS "")
+ENDIF()
+
 IF(ALSOFT_EXAMPLES)
     IF(SDL2_FOUND AND SDL_SOUND_FOUND)
         ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c
@@ -1203,11 +1244,18 @@ IF(ALSOFT_EXAMPLES)
         SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
                                                                            ${SDL_SOUND_INCLUDE_DIR})
 
-        INSTALL(TARGETS alstream alreverb allatency alloopback
-                RUNTIME DESTINATION bin
-                LIBRARY DESTINATION "lib${LIB_SUFFIX}"
-                ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
-        )
+        ADD_EXECUTABLE(alhrtf examples/alhrtf.c)
+        TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME})
+        SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
+                                                                       ${SDL_SOUND_INCLUDE_DIR})
+
+        IF(ALSOFT_INSTALL)
+            INSTALL(TARGETS alstream alreverb allatency alloopback
+                    RUNTIME DESTINATION bin
+                    LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+                    ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+            )
+        ENDIF()
 
         SET(FFVER_OK FALSE)
         IF(FFMPEG_FOUND)
@@ -1239,11 +1287,13 @@ IF(ALSOFT_EXAMPLES)
             SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
                                                                              ${FFMPEG_INCLUDE_DIRS})
 
-            INSTALL(TARGETS alffplay
-                    RUNTIME DESTINATION bin
-                    LIBRARY DESTINATION "lib${LIB_SUFFIX}"
-                    ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
-            )
+            IF(ALSOFT_INSTALL)
+                INSTALL(TARGETS alffplay
+                        RUNTIME DESTINATION bin
+                        LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+                        ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+                )
+            ENDIF()
             MESSAGE(STATUS "Building SDL and FFmpeg example programs")
         ELSE()
             MESSAGE(STATUS "Building SDL example programs")

+ 10 - 13
libs/openal-soft/COPYING

@@ -1,17 +1,15 @@
- 
-		  GNU LIBRARY GENERAL PUBLIC LICENSE
-		       Version 2, June 1991
-
+                  GNU LIBRARY GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
 
  Copyright (C) 1991 Free Software Foundation, Inc.
-                    675 Mass Ave, Cambridge, MA 02139, USA
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
 [This is the first released version of the library GPL.  It is
  numbered 2 because it goes with version 2 of the ordinary GPL.]
 
-			    Preamble
+                            Preamble
 
   The licenses for most software are designed to take away your
 freedom to share and change it.  By contrast, the GNU General Public
@@ -101,7 +99,7 @@ works together with the library.
   Note that it is possible for a library to be covered by the ordinary
 General Public License rather than by this special one.
 
-		  GNU LIBRARY GENERAL PUBLIC LICENSE
+                  GNU LIBRARY GENERAL PUBLIC LICENSE
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
   0. This License Agreement applies to any software library which
@@ -413,7 +411,7 @@ decision will be guided by the two goals of preserving the free status
 of all derivatives of our free software and of promoting the sharing
 and reuse of software generally.
 
-			    NO WARRANTY
+                            NO WARRANTY
 
   15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
 WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
@@ -436,9 +434,9 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 DAMAGES.
 
-		     END OF TERMS AND CONDITIONS
+                     END OF TERMS AND CONDITIONS
 
-     Appendix: How to Apply These Terms to Your New Libraries
+           How to Apply These Terms to Your New Libraries
 
   If you develop a new library, and you want it to be of the greatest
 possible use to the public, we recommend making it free software that
@@ -465,8 +463,8 @@ convey the exclusion of warranty; and each file should have at least the
     Library General Public License for more details.
 
     You should have received a copy of the GNU Library General Public
-    License along with this library; if not, write to the Free
-    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
 Also add information on how to contact you by electronic and paper mail.
 
@@ -481,4 +479,3 @@ necessary.  Here is a sample; alter the names:
   Ty Coon, President of Vice
 
 That's all there is to it!
-

+ 58 - 0
libs/openal-soft/ChangeLog

@@ -1,3 +1,61 @@
+openal-soft-1.17.0:
+
+    Implemented a JACK playback backend.
+
+    Implemented the AL_EXT_BFORMAT and AL_EXT_MULAW_BFORMAT extensions.
+
+    Implemented the ALC_SOFT_HRTF extension.
+
+    Implemented C, SSE3, and SSE4.1 based 4- and 8-point Sinc resamplers.
+
+    Implemented a C and SSE based band-limited Sinc resampler. This does 12- to
+    24-point Sinc resampling, and performs anti-aliasing.
+
+    Implemented B-Format output support for the wave file writer. This creates
+    FuMa-style first-order Ambisonics wave files (AMB format).
+
+    Implemented a stereo-mode config option for treating stereo modes as either
+    speakers or headphones.
+
+    Implemented per-device configuration options.
+
+    Fixed handling of PulseAudio and MMDevAPI devices that have identical
+    descriptions.
+
+    Fixed a potential lockup when stopping playback of suspended PulseAudio devices.
+
+    Fixed logging of Unicode characters on Windows.
+
+    Fixed 5.1 surround sound channels. By default it will now use the side
+    channels for the surround output. A configuration using rear channels is
+    still available.
+
+    Fixed the QSA backend potentially altering the capture format.
+
+    Fixed detecting MMDevAPI's default device.
+
+    Fixed returning the default capture device name.
+
+    Fixed mixing property calculations when deferring context updates.
+
+    Altered the behavior of alcSuspendContext and alcProcessContext to better
+    match certain Windows drivers.
+
+    Altered the panning algorithm, utilizing Ambisonics for better side and
+    back positioning cues with surround sound output.
+
+    Improved support for certain older Windows apps.
+
+    Improved the alffplay example to support surround sound streams.
+
+    Improved support for building as a sub-project.
+
+    Added an HRTF playback example.
+
+    Added a tone generator output test.
+
+    Added a toolchain to help with cross-compiling to Android.
+
 openal-soft-1.16.0:
 
     Implemented EFX Chorus, Flanger, Distortion, Equalizer, and Compressor

+ 2 - 2
libs/openal-soft/OpenAL32/Include/alAuxEffectSlot.h

@@ -22,7 +22,7 @@ struct ALeffectStateVtable {
 
     ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device);
     void (*const update)(ALeffectState *state, ALCdevice *device, const struct ALeffectslot *slot);
-    void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE]);
+    void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels);
 
     void (*const Delete)(void *ptr);
 };
@@ -31,7 +31,7 @@ struct ALeffectStateVtable {
 DECLARE_THUNK(T, ALeffectState, void, Destruct)                               \
 DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*)         \
 DECLARE_THUNK2(T, ALeffectState, void, update, ALCdevice*, const ALeffectslot*) \
-DECLARE_THUNK3(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict) \
+DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \
 static void T##_ALeffectState_Delete(void *ptr)                               \
 { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); }  \
                                                                               \

+ 6 - 2
libs/openal-soft/OpenAL32/Include/alBuffer.h

@@ -32,6 +32,8 @@ enum UserFmtChannels {
     UserFmtX51    = AL_5POINT1_SOFT, /* (WFX order) */
     UserFmtX61    = AL_6POINT1_SOFT, /* (WFX order) */
     UserFmtX71    = AL_7POINT1_SOFT, /* (WFX order) */
+    UserFmtBFormat2D = 0x10000000, /* WXY */
+    UserFmtBFormat3D, /* WXYZ */
 };
 
 ALuint BytesFromUserFmt(enum UserFmtType type) DECL_CONST;
@@ -56,6 +58,8 @@ enum FmtChannels {
     FmtX51    = UserFmtX51,
     FmtX61    = UserFmtX61,
     FmtX71    = UserFmtX71,
+    FmtBFormat2D = UserFmtBFormat2D,
+    FmtBFormat3D = UserFmtBFormat3D,
 };
 #define MAX_INPUT_CHANNELS  (8)
 
@@ -85,8 +89,8 @@ typedef struct ALbuffer {
     ALsizei  LoopStart;
     ALsizei  LoopEnd;
 
-    ALsizei UnpackAlign;
-    ALsizei PackAlign;
+    ATOMIC(ALsizei) UnpackAlign;
+    ATOMIC(ALsizei) PackAlign;
 
     /* Number of times buffer was attached to a source (deletion can only occur when 0) */
     RefCount ref;

+ 0 - 1
libs/openal-soft/OpenAL32/Include/alEffect.h

@@ -132,7 +132,6 @@ typedef union ALeffectProps {
     } Echo;
 
     struct {
-        ALfloat Delay;
         ALfloat LowCutoff;
         ALfloat LowGain;
         ALfloat Mid1Center;

+ 37 - 8
libs/openal-soft/OpenAL32/Include/alFilter.h

@@ -3,6 +3,8 @@
 
 #include "alMain.h"
 
+#include "math_defs.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -11,23 +13,29 @@ extern "C" {
 #define HIGHPASSFREQREF  (250.0f)
 
 
-/* Filters implementation is based on the "Cookbook formulae for audio   *
- * EQ biquad filter coefficients" by Robert Bristow-Johnson              *
- * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt                   */
+/* Filters implementation is based on the "Cookbook formulae for audio
+ * EQ biquad filter coefficients" by Robert Bristow-Johnson
+ * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+ */
+/* Implementation note: For the shelf filters, the specified gain is for the
+ * reference frequency, which is the centerpoint of the transition band. This
+ * better matches EFX filter design. To set the gain for the shelf itself, use
+ * the square root of the desired linear gain (or halve the dB gain).
+ */
 
 typedef enum ALfilterType {
     /** EFX-style low-pass filter, specifying a gain and reference frequency. */
     ALfilterType_HighShelf,
     /** EFX-style high-pass filter, specifying a gain and reference frequency. */
     ALfilterType_LowShelf,
-    /** Peaking filter, specifying a gain, reference frequency, and bandwidth. */
+    /** Peaking filter, specifying a gain and reference frequency. */
     ALfilterType_Peaking,
 
-    /** Low-pass cut-off filter, specifying a cut-off frequency and bandwidth. */
+    /** Low-pass cut-off filter, specifying a cut-off frequency. */
     ALfilterType_LowPass,
-    /** High-pass cut-off filter, specifying a cut-off frequency and bandwidth. */
+    /** High-pass cut-off filter, specifying a cut-off frequency. */
     ALfilterType_HighPass,
-    /** Band-pass filter, specifying a center frequency and bandwidth. */
+    /** Band-pass filter, specifying a center frequency. */
     ALfilterType_BandPass,
 } ALfilterType;
 
@@ -41,8 +49,27 @@ typedef struct ALfilterState {
 } ALfilterState;
 #define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__))
 
+/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the
+ * reference gain and shelf slope parameter.
+ * 0 < gain
+ * 0 < slope <= 1
+ */
+inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope)
+{
+    return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f);
+}
+/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency
+ * multiple (i.e. ref_freq / sampling_freq) and bandwidth.
+ * 0 < freq_mult < 0.5.
+ */
+inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth)
+{
+    ALfloat w0 = F_TAU * freq_mult;
+    return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0));
+}
+
 void ALfilterState_clear(ALfilterState *filter);
-void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth);
+void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ);
 
 inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample)
 {
@@ -63,6 +90,8 @@ inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample
 
 void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples);
 
+void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples);
+
 
 typedef struct ALfilter {
     // Filter type (AL_FILTER_NULL, ...)

+ 5 - 4
libs/openal-soft/OpenAL32/Include/alListener.h

@@ -2,22 +2,23 @@
 #define _AL_LISTENER_H_
 
 #include "alMain.h"
+#include "alu.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 typedef struct ALlistener {
-    volatile ALfloat Position[3];
-    volatile ALfloat Velocity[3];
+    aluVector Position;
+    aluVector Velocity;
     volatile ALfloat Forward[3];
     volatile ALfloat Up[3];
     volatile ALfloat Gain;
     volatile ALfloat MetersPerUnit;
 
     struct {
-        ALfloat Matrix[4][4];
-        ALfloat Velocity[3];
+        aluMatrixd Matrix;
+        aluVector  Velocity;
     } Params;
 } ALlistener;
 

+ 135 - 289
libs/openal-soft/OpenAL32/Include/alMain.h

@@ -37,209 +37,7 @@
 #include "vector.h"
 #include "alstring.h"
 
-#ifndef ALC_SOFT_HRTF
-#define ALC_SOFT_HRTF 1
-#define ALC_HRTF_SOFT                            0x1992
-#endif
-
-#ifndef ALC_SOFT_midi_interface
-#define ALC_SOFT_midi_interface 1
-/* Global properties */
-#define AL_MIDI_CLOCK_SOFT                       0x9999
-#define AL_MIDI_STATE_SOFT                       0x9986
-#define AL_MIDI_GAIN_SOFT                        0x9998
-#define AL_SOUNDFONTS_SIZE_SOFT                  0x9995
-#define AL_SOUNDFONTS_SOFT                       0x9994
-
-/* Soundfont properties */
-#define AL_PRESETS_SIZE_SOFT                     0x9993
-#define AL_PRESETS_SOFT                          0x9992
-
-/* Preset properties */
-#define AL_MIDI_PRESET_SOFT                      0x9997
-#define AL_MIDI_BANK_SOFT                        0x9996
-#define AL_FONTSOUNDS_SIZE_SOFT                  0x9991
-#define AL_FONTSOUNDS_SOFT                       0x9990
-
-/* Fontsound properties */
-/* AL_BUFFER */
-#define AL_SAMPLE_START_SOFT                     0x2000
-#define AL_SAMPLE_END_SOFT                       0x2001
-#define AL_SAMPLE_LOOP_START_SOFT                0x2002
-#define AL_SAMPLE_LOOP_END_SOFT                  0x2003
-#define AL_SAMPLE_RATE_SOFT                      0x2004
-#define AL_BASE_KEY_SOFT                         0x2005
-#define AL_KEY_CORRECTION_SOFT                   0x2006
-#define AL_SAMPLE_TYPE_SOFT                      0x2007
-#define AL_FONTSOUND_LINK_SOFT                   0x2008
-#define AL_MOD_LFO_TO_PITCH_SOFT                 0x0005
-#define AL_VIBRATO_LFO_TO_PITCH_SOFT             0x0006
-#define AL_MOD_ENV_TO_PITCH_SOFT                 0x0007
-#define AL_FILTER_CUTOFF_SOFT                    0x0008
-#define AL_FILTER_RESONANCE_SOFT                 0x0009
-#define AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT         0x000A
-#define AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT         0x000B
-#define AL_MOD_LFO_TO_VOLUME_SOFT                0x000D
-#define AL_CHORUS_SEND_SOFT                      0x000F
-#define AL_REVERB_SEND_SOFT                      0x0010
-#define AL_PAN_SOFT                              0x0011
-#define AL_MOD_LFO_DELAY_SOFT                    0x0015
-#define AL_MOD_LFO_FREQUENCY_SOFT                0x0016
-#define AL_VIBRATO_LFO_DELAY_SOFT                0x0017
-#define AL_VIBRATO_LFO_FREQUENCY_SOFT            0x0018
-#define AL_MOD_ENV_DELAYTIME_SOFT                0x0019
-#define AL_MOD_ENV_ATTACKTIME_SOFT               0x001A
-#define AL_MOD_ENV_HOLDTIME_SOFT                 0x001B
-#define AL_MOD_ENV_DECAYTIME_SOFT                0x001C
-#define AL_MOD_ENV_SUSTAINVOLUME_SOFT            0x001D
-#define AL_MOD_ENV_RELEASETIME_SOFT              0x002E
-#define AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT          0x001F
-#define AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT         0x0020
-#define AL_VOLUME_ENV_DELAYTIME_SOFT             0x0021
-#define AL_VOLUME_ENV_ATTACKTIME_SOFT            0x0022
-#define AL_VOLUME_ENV_HOLDTIME_SOFT              0x0023
-#define AL_VOLUME_ENV_DECAYTIME_SOFT             0x0024
-#define AL_VOLUME_ENV_SUSTAINVOLUME_SOFT         0x0025
-#define AL_VOLUME_ENV_RELEASETIME_SOFT           0x0026
-#define AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT       0x0027
-#define AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT      0x0028
-#define AL_KEY_RANGE_SOFT                        0x002B
-#define AL_VELOCITY_RANGE_SOFT                   0x002C
-#define AL_ATTENUATION_SOFT                      0x0030
-#define AL_TUNING_COARSE_SOFT                    0x0033
-#define AL_TUNING_FINE_SOFT                      0x0034
-#define AL_LOOP_MODE_SOFT                        0x0036
-#define AL_TUNING_SCALE_SOFT                     0x0038
-#define AL_EXCLUSIVE_CLASS_SOFT                  0x0039
-
-/* Sample Types */
-/* AL_MONO_SOFT */
-#define AL_RIGHT_SOFT                            0x0002
-#define AL_LEFT_SOFT                             0x0004
-
-/* Loop Modes */
-/* AL_NONE */
-#define AL_LOOP_CONTINUOUS_SOFT                  0x0001
-#define AL_LOOP_UNTIL_RELEASE_SOFT               0x0003
-
-/* Fontsound modulator stage properties */
-#define AL_SOURCE0_INPUT_SOFT                    0x998F
-#define AL_SOURCE0_TYPE_SOFT                     0x998E
-#define AL_SOURCE0_FORM_SOFT                     0x998D
-#define AL_SOURCE1_INPUT_SOFT                    0x998C
-#define AL_SOURCE1_TYPE_SOFT                     0x998B
-#define AL_SOURCE1_FORM_SOFT                     0x998A
-#define AL_AMOUNT_SOFT                           0x9989
-#define AL_TRANSFORM_OP_SOFT                     0x9988
-#define AL_DESTINATION_SOFT                      0x9987
-
-/* Sounce Inputs */
-#define AL_ONE_SOFT                              0x0080
-#define AL_NOTEON_VELOCITY_SOFT                  0x0082
-#define AL_NOTEON_KEY_SOFT                       0x0083
-/* AL_KEYPRESSURE_SOFT */
-/* AL_CHANNELPRESSURE_SOFT */
-/* AL_PITCHBEND_SOFT */
-#define AL_PITCHBEND_SENSITIVITY_SOFT            0x0090
-/* CC 0...127 */
-
-/* Source Types */
-#define AL_UNORM_SOFT                            0x0000
-#define AL_UNORM_REV_SOFT                        0x0100
-#define AL_SNORM_SOFT                            0x0200
-#define AL_SNORM_REV_SOFT                        0x0300
-
-/* Source Forms */
-#define AL_LINEAR_SOFT                           0x0000
-#define AL_CONCAVE_SOFT                          0x0400
-#define AL_CONVEX_SOFT                           0x0800
-#define AL_SWITCH_SOFT                           0x0C00
-
-/* Transform Ops */
-/* AL_LINEAR_SOFT */
-#define AL_ABSOLUTE_SOFT                         0x0002
-
-/* Events */
-#define AL_NOTEOFF_SOFT                          0x0080
-#define AL_NOTEON_SOFT                           0x0090
-#define AL_KEYPRESSURE_SOFT                      0x00A0
-#define AL_CONTROLLERCHANGE_SOFT                 0x00B0
-#define AL_PROGRAMCHANGE_SOFT                    0x00C0
-#define AL_CHANNELPRESSURE_SOFT                  0x00D0
-#define AL_PITCHBEND_SOFT                        0x00E0
-
-typedef void (AL_APIENTRY*LPALGENSOUNDFONTSSOFT)(ALsizei n, ALuint *ids);
-typedef void (AL_APIENTRY*LPALDELETESOUNDFONTSSOFT)(ALsizei n, const ALuint *ids);
-typedef ALboolean (AL_APIENTRY*LPALISSOUNDFONTSOFT)(ALuint id);
-typedef void (AL_APIENTRY*LPALGETSOUNDFONTIVSOFT)(ALuint id, ALenum param, ALint *values);
-typedef void (AL_APIENTRY*LPALSOUNDFONTPRESETSSOFT)(ALuint id, ALsizei count, const ALuint *pids);
-typedef void (AL_APIENTRY*LPALGENPRESETSSOFT)(ALsizei n, ALuint *ids);
-typedef void (AL_APIENTRY*LPALDELETEPRESETSSOFT)(ALsizei n, const ALuint *ids);
-typedef ALboolean (AL_APIENTRY*LPALISPRESETSOFT)(ALuint id);
-typedef void (AL_APIENTRY*LPALPRESETISOFT)(ALuint id, ALenum param, ALint value);
-typedef void (AL_APIENTRY*LPALPRESETIVSOFT)(ALuint id, ALenum param, const ALint *values);
-typedef void (AL_APIENTRY*LPALPRESETFONTSOUNDSSOFT)(ALuint id, ALsizei count, const ALuint *fsids);
-typedef void (AL_APIENTRY*LPALGETPRESETIVSOFT)(ALuint id, ALenum param, ALint *values);
-typedef void (AL_APIENTRY*LPALGENFONTSOUNDSSOFT)(ALsizei n, ALuint *ids);
-typedef void (AL_APIENTRY*LPALDELETEFONTSOUNDSSOFT)(ALsizei n, const ALuint *ids);
-typedef ALboolean (AL_APIENTRY*LPALISFONTSOUNDSOFT)(ALuint id);
-typedef void (AL_APIENTRY*LPALFONTSOUNDISOFT)(ALuint id, ALenum param, ALint value);
-typedef void (AL_APIENTRY*LPALFONTSOUND2ISOFT)(ALuint id, ALenum param, ALint value1, ALint value2);
-typedef void (AL_APIENTRY*LPALFONTSOUNDIVSOFT)(ALuint id, ALenum param, const ALint *values);
-typedef void (AL_APIENTRY*LPALGETFONTSOUNDIVSOFT)(ALuint id, ALenum param, ALint *values);
-typedef void (AL_APIENTRY*LPALFONTSOUNDMOFULATORISOFT)(ALuint id, ALsizei stage, ALenum param, ALint value);
-typedef void (AL_APIENTRY*LPALGETFONTSOUNDMODULATORIVSOFT)(ALuint id, ALsizei stage, ALenum param, ALint *values);
-typedef void (AL_APIENTRY*LPALMIDISOUNDFONTSOFT)(ALuint id);
-typedef void (AL_APIENTRY*LPALMIDISOUNDFONTVSOFT)(ALsizei count, const ALuint *ids);
-typedef void (AL_APIENTRY*LPALMIDIEVENTSOFT)(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2);
-typedef void (AL_APIENTRY*LPALMIDISYSEXSOFT)(ALuint64SOFT time, const ALbyte *data, ALsizei size);
-typedef void (AL_APIENTRY*LPALMIDIPLAYSOFT)(void);
-typedef void (AL_APIENTRY*LPALMIDIPAUSESOFT)(void);
-typedef void (AL_APIENTRY*LPALMIDISTOPSOFT)(void);
-typedef void (AL_APIENTRY*LPALMIDIRESETSOFT)(void);
-typedef void (AL_APIENTRY*LPALMIDIGAINSOFT)(ALfloat value);
-typedef ALint64SOFT (AL_APIENTRY*LPALGETINTEGER64SOFT)(ALenum pname);
-typedef void (AL_APIENTRY*LPALGETINTEGER64VSOFT)(ALenum pname, ALint64SOFT *values);
-typedef void (AL_APIENTRY*LPALLOADSOUNDFONTSOFT)(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user);
-#ifdef AL_ALEXT_PROTOTYPES
-AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids);
-AL_API void AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids);
-AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id);
-AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values);
-AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids);
-
-AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids);
-AL_API void AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids);
-AL_API ALboolean AL_APIENTRY alIsPresetSOFT(ALuint id);
-AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value);
-AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *values);
-AL_API void AL_APIENTRY alGetPresetivSOFT(ALuint id, ALenum param, ALint *values);
-AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids);
-
-AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids);
-AL_API void AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids);
-AL_API ALboolean AL_APIENTRY alIsFontsoundSOFT(ALuint id);
-AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value);
-AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1, ALint value2);
-AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *values);
-AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *values);
-AL_API void AL_APIENTRY alFontsoundModulatoriSOFT(ALuint id, ALsizei stage, ALenum param, ALint value);
-AL_API void AL_APIENTRY alGetFontsoundModulatorivSOFT(ALuint id, ALsizei stage, ALenum param, ALint *values);
-
-AL_API void AL_APIENTRY alMidiSoundfontSOFT(ALuint id);
-AL_API void AL_APIENTRY alMidiSoundfontvSOFT(ALsizei count, const ALuint *ids);
-AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2);
-AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, ALsizei size);
-AL_API void AL_APIENTRY alMidiPlaySOFT(void);
-AL_API void AL_APIENTRY alMidiPauseSOFT(void);
-AL_API void AL_APIENTRY alMidiStopSOFT(void);
-AL_API void AL_APIENTRY alMidiResetSOFT(void);
-AL_API void AL_APIENTRY alMidiGainSOFT(ALfloat value);
-AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname);
-AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values);
-AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user);
-#endif
-#endif
+#include "hrtf.h"
 
 #ifndef ALC_SOFT_device_clock
 #define ALC_SOFT_device_clock 1
@@ -253,19 +51,9 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
 #endif
 
 
-#ifdef IN_IDE_PARSER
-/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
- * recent versions (at least 4.5.1) do recognize GCC's __restrict. */
-#define restrict __restrict
-#endif
-
-
 typedef ALint64SOFT ALint64;
 typedef ALuint64SOFT ALuint64;
 
-typedef ptrdiff_t ALintptrEXT;
-typedef ptrdiff_t ALsizeiptrEXT;
-
 #ifndef U64
 #if defined(_MSC_VER)
 #define U64(x) ((ALuint64)(x##ui64))
@@ -385,9 +173,13 @@ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b)            \
 static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
 { return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
 
+#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); }
+
 #define DECLARE_DEFAULT_ALLOCATORS(T)                                         \
-static void* T##_New(size_t size) { return malloc(size); }                    \
-static void T##_Delete(void *ptr) { free(ptr); }
+static void* T##_New(size_t size) { return al_malloc(16, size); }             \
+static void T##_Delete(void *ptr) { al_free(ptr); }
 
 /* Helper to extract an argument list for VCALL. Not used directly. */
 #define EXTRACT_VCALL_ARGS(...)  __VA_ARGS__))
@@ -406,6 +198,18 @@ static void T##_Delete(void *ptr) { free(ptr); }
 } while(0)
 
 
+#define EXTRACT_NEW_ARGS(...)  __VA_ARGS__);                                  \
+    }                                                                         \
+} while(0)
+
+#define NEW_OBJ(_res, T) do {                                                 \
+    _res = T##_New(sizeof(T));                                                \
+    if(_res)                                                                  \
+    {                                                                         \
+        memset(_res, 0, sizeof(T));                                           \
+        T##_Construct(_res, EXTRACT_NEW_ARGS
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -472,25 +276,11 @@ typedef struct {
     void (*StopCapture)(ALCdevice*);
     ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint);
     ALCuint (*AvailableSamples)(ALCdevice*);
-
-    ALint64 (*GetLatency)(ALCdevice*);
 } BackendFuncs;
 
-ALCboolean alc_solaris_init(BackendFuncs *func_list);
-void alc_solaris_deinit(void);
-void alc_solaris_probe(enum DevProbe type);
 ALCboolean alc_sndio_init(BackendFuncs *func_list);
 void alc_sndio_deinit(void);
 void alc_sndio_probe(enum DevProbe type);
-ALCboolean alcWinMMInit(BackendFuncs *FuncList);
-void alcWinMMDeinit(void);
-void alcWinMMProbe(enum DevProbe type);
-ALCboolean alc_pa_init(BackendFuncs *func_list);
-void alc_pa_deinit(void);
-void alc_pa_probe(enum DevProbe type);
-ALCboolean alc_wave_init(BackendFuncs *func_list);
-void alc_wave_deinit(void);
-void alc_wave_probe(enum DevProbe type);
 ALCboolean alc_ca_init(BackendFuncs *func_list);
 void alc_ca_deinit(void);
 void alc_ca_probe(enum DevProbe type);
@@ -516,14 +306,6 @@ enum DistanceModel {
     DefaultDistanceModel = InverseDistanceClamped
 };
 
-enum Resampler {
-    PointResampler,
-    LinearResampler,
-    CubicResampler,
-
-    ResamplerMax,
-};
-
 enum Channel {
     FrontLeft = 0,
     FrontRight,
@@ -535,7 +317,12 @@ enum Channel {
     SideLeft,
     SideRight,
 
-    MaxChannels,
+    BFormatW,
+    BFormatX,
+    BFormatY,
+    BFormatZ,
+
+    InvalidChannel
 };
 
 
@@ -559,11 +346,14 @@ enum DevFmtChannels {
     DevFmtX61    = ALC_6POINT1_SOFT,
     DevFmtX71    = ALC_7POINT1_SOFT,
 
-    /* Similar to 5.1, except using the side channels instead of back */
-    DevFmtX51Side = 0x80000000,
+    /* Similar to 5.1, except using rear channels instead of sides */
+    DevFmtX51Rear = 0x80000000,
+
+    DevFmtBFormat3D,
 
     DevFmtChannelsDefault = DevFmtStereo
 };
+#define MAX_OUTPUT_CHANNELS  (8)
 
 ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST;
 ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST;
@@ -588,6 +378,38 @@ enum DeviceType {
 };
 
 
+enum HrtfMode {
+    DisabledHrtf,
+    BasicHrtf,
+    FullHrtf
+};
+
+
+/* The maximum number of Ambisonics coefficients. For a given order (o), the
+ * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4,
+ * second-order has 9, and third-order has 16. */
+#define MAX_AMBI_COEFFS 16
+
+typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS];
+
+
+#define HRTF_HISTORY_BITS   (6)
+#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
+#define HRTF_HISTORY_MASK   (HRTF_HISTORY_LENGTH-1)
+
+typedef struct HrtfState {
+    alignas(16) ALfloat History[HRTF_HISTORY_LENGTH];
+    alignas(16) ALfloat Values[HRIR_LENGTH][2];
+} HrtfState;
+
+typedef struct HrtfParams {
+    alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
+    alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
+    ALuint Delay[2];
+    ALint DelayStep[2];
+} HrtfParams;
+
+
 /* Size for temporary storage of buffer data, in ALfloats. Larger values need
  * more memory, while smaller values may need more iterations. The value needs
  * to be a sensible size, however, as it constrains the max stepping value used
@@ -595,7 +417,6 @@ enum DeviceType {
  */
 #define BUFFERSIZE (2048u)
 
-
 struct ALCdevice_struct
 {
     RefCount ref;
@@ -608,6 +429,7 @@ struct ALCdevice_struct
     ALuint       NumUpdates;
     enum DevFmtChannels FmtChans;
     enum DevFmtType     FmtType;
+    ALboolean    IsHeadphones;
 
     al_string DeviceName;
 
@@ -631,36 +453,26 @@ struct ALCdevice_struct
     // Map of Filters for this device
     UIntMap FilterMap;
 
-    // Map of Soundfonts for this device
-    UIntMap SfontMap;
-
-    // Map of Presets for this device
-    UIntMap PresetMap;
-
-    // Map of Fontsounds for this device
-    UIntMap FontsoundMap;
-
-    /* Default soundfont (accessible as ID 0) */
-    struct ALsoundfont *DefaultSfont;
-
-    /* MIDI synth engine */
-    struct MidiSynth *Synth;
-
     /* HRTF filter tables */
+    vector_HrtfEntry Hrtf_List;
+    al_string Hrtf_Name;
     const struct Hrtf *Hrtf;
+    ALCenum Hrtf_Status;
+    enum HrtfMode Hrtf_Mode;
+    HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS];
+    HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS];
+    ALuint Hrtf_Offset;
 
     // Stereo-to-binaural filter
     struct bs2b *Bs2b;
-    ALCint       Bs2bLevel;
 
     // Device flags
-    ALuint       Flags;
-
-    ALuint ChannelOffsets[MaxChannels];
+    ALuint Flags;
 
-    enum Channel Speaker2Chan[MaxChannels];
-    ALfloat SpeakerAngle[MaxChannels];
-    ALuint  NumChan;
+    enum Channel ChannelName[MAX_OUTPUT_CHANNELS];
+    ChannelConfig AmbiCoeffs[MAX_OUTPUT_CHANNELS];
+    ALfloat AmbiScale; /* Scale for first-order XYZ inputs using AmbCoeffs. */
+    ALuint NumChannels;
 
     ALuint64 ClockBase;
     ALuint SamplesDone;
@@ -670,8 +482,8 @@ struct ALCdevice_struct
     alignas(16) ALfloat ResampledData[BUFFERSIZE];
     alignas(16) ALfloat FilteredData[BUFFERSIZE];
 
-    // Dry path buffer mix
-    alignas(16) ALfloat DryBuffer[MaxChannels][BUFFERSIZE];
+    /* Dry path buffer mix. */
+    alignas(16) ALfloat (*DryBuffer)[BUFFERSIZE];
 
     /* Running count of the mixer invocations, in 31.1 fixed point. This
      * actually increments *twice* when mixing, first at the start and then at
@@ -702,11 +514,6 @@ struct ALCdevice_struct
 #define DEVICE_CHANNELS_REQUEST                  (1<<2)
 // Sample type was requested by the config file
 #define DEVICE_SAMPLE_TYPE_REQUEST               (1<<3)
-// HRTF was requested by the app
-#define DEVICE_HRTF_REQUEST                      (1<<4)
-
-// Stereo sources cover 120-degree angles around +/-90
-#define DEVICE_WIDE_STEREO                       (1<<16)
 
 // Specifies if the DSP is paused at user request
 #define DEVICE_PAUSED                            (1<<30)
@@ -714,9 +521,6 @@ struct ALCdevice_struct
 // Specifies if the device is currently running
 #define DEVICE_RUNNING                           (1<<31)
 
-/* Invalid channel offset */
-#define INVALID_OFFSET                           (~0u)
-
 
 /* Nanosecond resolution for the device clock time. */
 #define DEVICE_CLOCK_RES  U64(1000000000)
@@ -726,6 +530,8 @@ struct ALCdevice_struct
  * compatibility with pthread_setname_np limitations. */
 #define MIXER_THREAD_NAME "alsoft-mixer"
 
+#define RECORD_THREAD_NAME "alsoft-record"
+
 
 struct ALCcontext_struct
 {
@@ -748,9 +554,9 @@ struct ALCcontext_struct
     volatile ALfloat SpeedOfSound;
     volatile ALenum  DeferUpdates;
 
-    struct ALactivesource **ActiveSources;
-    ALsizei ActiveSourceCount;
-    ALsizei MaxActiveSources;
+    struct ALvoice *Voices;
+    ALsizei VoiceCount;
+    ALsizei MaxVoices;
 
     VECTOR(struct ALeffectslot*) ActiveAuxSlots;
 
@@ -771,11 +577,11 @@ void ALCcontext_DecRef(ALCcontext *context);
 void AppendAllDevicesList(const ALCchar *name);
 void AppendCaptureDeviceList(const ALCchar *name);
 
-ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device);
-
 void ALCdevice_Lock(ALCdevice *device);
 void ALCdevice_Unlock(ALCdevice *device);
-ALint64 ALCdevice_GetLatency(ALCdevice *device);
+
+void ALCcontext_DeferUpdates(ALCcontext *context);
+void ALCcontext_ProcessUpdates(ALCcontext *context);
 
 inline void LockContext(ALCcontext *context)
 { ALCdevice_Lock(context->Device); }
@@ -810,15 +616,35 @@ ALsizei RingBufferSize(RingBuffer *ring);
 void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len);
 void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len);
 
+typedef struct ll_ringbuffer ll_ringbuffer_t;
+typedef struct ll_ringbuffer_data {
+    char *buf;
+    size_t len;
+} ll_ringbuffer_data_t;
+ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz);
+void ll_ringbuffer_free(ll_ringbuffer_t *rb);
+void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
+void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec);
+size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt);
+size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt);
+void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt);
+size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb);
+int ll_ringbuffer_mlock(ll_ringbuffer_t *rb);
+void ll_ringbuffer_reset(ll_ringbuffer_t *rb);
+size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt);
+void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt);
+size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb);
+
 void ReadALConfig(void);
 void FreeALConfig(void);
-int ConfigValueExists(const char *blockName, const char *keyName);
-const char *GetConfigValue(const char *blockName, const char *keyName, const char *def);
-int GetConfigValueBool(const char *blockName, const char *keyName, int def);
-int ConfigValueStr(const char *blockName, const char *keyName, const char **ret);
-int ConfigValueInt(const char *blockName, const char *keyName, int *ret);
-int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret);
-int ConfigValueFloat(const char *blockName, const char *keyName, float *ret);
+int ConfigValueExists(const char *devName, const char *blockName, const char *keyName);
+const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def);
+int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def);
+int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret);
+int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret);
+int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret);
+int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret);
+int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret);
 
 void SetRTPriority(void);
 
@@ -828,10 +654,27 @@ void SetDefaultWFXChannelOrder(ALCdevice *device);
 const ALCchar *DevFmtTypeString(enum DevFmtType type) DECL_CONST;
 const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST;
 
+/**
+ * GetChannelIdxByName
+ *
+ * Returns the device's channel index given a channel name (e.g. FrontCenter),
+ * or -1 if it doesn't exist.
+ */
+inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan)
+{
+    ALint i = 0;
+    for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
+    {
+        if(device->ChannelName[i] == chan)
+            return i;
+    }
+    return -1;
+}
+
 
 extern FILE *LogFile;
 
-#if defined(__GNUC__) && !defined(IN_IDE_PARSER)
+#if defined(__GNUC__) && !defined(_WIN32) && !defined(IN_IDE_PARSER)
 #define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__)
 #else
 void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4);
@@ -875,14 +718,17 @@ extern ALuint CPUCapFlags;
 enum {
     CPU_CAP_SSE    = 1<<0,
     CPU_CAP_SSE2   = 1<<1,
-    CPU_CAP_SSE4_1 = 1<<2,
-    CPU_CAP_NEON   = 1<<3,
+    CPU_CAP_SSE3   = 1<<2,
+    CPU_CAP_SSE4_1 = 1<<3,
+    CPU_CAP_NEON   = 1<<4,
 };
 
 void FillCPUCaps(ALuint capfilter);
 
 FILE *OpenDataFile(const char *fname, const char *subdir);
 
+vector_al_string SearchDataFiles(const char *match, const char *subdir);
+
 /* Small hack to use a pointer-to-array type as a normal argument type.
  * Shouldn't be used directly. */
 typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE];

+ 14 - 13
libs/openal-soft/OpenAL32/Include/alSource.h

@@ -11,10 +11,8 @@
 extern "C" {
 #endif
 
-extern enum Resampler DefaultResampler;
-
-extern const ALsizei ResamplerPadding[ResamplerMax];
-extern const ALsizei ResamplerPrePadding[ResamplerMax];
+struct ALbuffer;
+struct ALsource;
 
 
 typedef struct ALbufferlistitem {
@@ -24,11 +22,11 @@ typedef struct ALbufferlistitem {
 } ALbufferlistitem;
 
 
-typedef struct ALactivesource {
-    struct ALsource *Source;
+typedef struct ALvoice {
+    struct ALsource *volatile Source;
 
     /** Method to update mixing parameters. */
-    ALvoid (*Update)(struct ALactivesource *self, const ALCcontext *context);
+    ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const ALCcontext *context);
 
     /** Current target parameters used for mixing. */
     ALint Step;
@@ -37,9 +35,13 @@ typedef struct ALactivesource {
 
     ALuint Offset; /* Number of output samples mixed since starting. */
 
+    alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES];
+
+    BsincState SincState;
+
     DirectParams Direct;
     SendParams Send[MAX_SENDS];
-} ALactivesource;
+} ALvoice;
 
 
 typedef struct ALsource {
@@ -54,9 +56,10 @@ typedef struct ALsource {
     volatile ALfloat   RefDistance;
     volatile ALfloat   MaxDistance;
     volatile ALfloat   RollOffFactor;
-    volatile ALfloat   Position[3];
-    volatile ALfloat   Velocity[3];
-    volatile ALfloat   Orientation[3];
+    aluVector Position;
+    aluVector Velocity;
+    aluVector Direction;
+    volatile ALfloat   Orientation[2][3];
     volatile ALboolean HeadRelative;
     volatile ALboolean Looping;
     volatile enum DistanceModel DistanceModel;
@@ -73,8 +76,6 @@ typedef struct ALsource {
 
     volatile ALfloat Radius;
 
-    enum Resampler Resampler;
-
     /**
      * Last user-specified offset, and the offset type (bytes, samples, or
      * seconds).

+ 158 - 64
libs/openal-soft/OpenAL32/Include/alu.h

@@ -16,30 +16,111 @@
 
 #include "hrtf.h"
 #include "align.h"
+#include "math_defs.h"
 
 
-#define F_PI    (3.14159265358979323846f)
-#define F_PI_2  (1.57079632679489661923f)
-#define F_2PI   (6.28318530717958647692f)
+#define MAX_PITCH  (255)
 
-#ifndef FLT_EPSILON
-#define FLT_EPSILON (1.19209290e-07f)
+/* Maximum number of buffer samples before the current pos needed for resampling. */
+#define MAX_PRE_SAMPLES 12
+
+/* Maximum number of buffer samples after the current pos needed for resampling. */
+#define MAX_POST_SAMPLES 12
+
+
+#ifdef __cplusplus
+extern "C" {
 #endif
 
-#define DEG2RAD(x)  ((ALfloat)(x) * (F_PI/180.0f))
-#define RAD2DEG(x)  ((ALfloat)(x) * (180.0f/F_PI))
+struct ALsource;
+struct ALvoice;
+
+
+/* The number of distinct scale and phase intervals within the filter table. */
+#define BSINC_SCALE_BITS  4
+#define BSINC_SCALE_COUNT (1<<BSINC_SCALE_BITS)
+#define BSINC_PHASE_BITS  4
+#define BSINC_PHASE_COUNT (1<<BSINC_PHASE_BITS)
 
+/* Interpolator state.  Kind of a misnomer since the interpolator itself is
+ * stateless.  This just keeps it from having to recompute scale-related
+ * mappings for every sample.
+ */
+typedef struct BsincState {
+    ALfloat sf; /* Scale interpolation factor. */
+    ALuint m;   /* Coefficient count. */
+    ALint l;    /* Left coefficient offset. */
+    struct {
+        const ALfloat *filter;   /* Filter coefficients. */
+        const ALfloat *scDelta;  /* Scale deltas. */
+        const ALfloat *phDelta;  /* Phase deltas. */
+        const ALfloat *spDelta;  /* Scale-phase deltas. */
+    } coeffs[BSINC_PHASE_COUNT];
+} BsincState;
 
-#define SRC_HISTORY_BITS   (6)
-#define SRC_HISTORY_LENGTH (1<<SRC_HISTORY_BITS)
-#define SRC_HISTORY_MASK   (SRC_HISTORY_LENGTH-1)
 
-#define MAX_PITCH  (10)
+typedef union aluVector {
+    alignas(16) ALfloat v[4];
+} aluVector;
 
+inline void aluVectorSet(aluVector *vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w)
+{
+    vector->v[0] = x;
+    vector->v[1] = y;
+    vector->v[2] = z;
+    vector->v[3] = w;
+}
+
+
+typedef union aluMatrixf {
+    alignas(16) ALfloat m[4][4];
+} aluMatrixf;
+
+inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
+                             ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3)
+{
+    matrix->m[row][0] = m0;
+    matrix->m[row][1] = m1;
+    matrix->m[row][2] = m2;
+    matrix->m[row][3] = m3;
+}
+
+inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
+                                              ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
+                                              ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
+                                              ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33)
+{
+    aluMatrixfSetRow(matrix, 0, m00, m01, m02, m03);
+    aluMatrixfSetRow(matrix, 1, m10, m11, m12, m13);
+    aluMatrixfSetRow(matrix, 2, m20, m21, m22, m23);
+    aluMatrixfSetRow(matrix, 3, m30, m31, m32, m33);
+}
+
+
+typedef union aluMatrixd {
+    alignas(16) ALdouble m[4][4];
+} aluMatrixd;
+
+inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
+                             ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3)
+{
+    matrix->m[row][0] = m0;
+    matrix->m[row][1] = m1;
+    matrix->m[row][2] = m2;
+    matrix->m[row][3] = m3;
+}
+
+inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
+                                              ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
+                                              ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
+                                              ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33)
+{
+    aluMatrixdSetRow(matrix, 0, m00, m01, m02, m03);
+    aluMatrixdSetRow(matrix, 1, m10, m11, m12, m13);
+    aluMatrixdSetRow(matrix, 2, m20, m21, m22, m23);
+    aluMatrixdSetRow(matrix, 3, m30, m31, m32, m33);
+}
 
-#ifdef __cplusplus
-extern "C" {
-#endif
 
 enum ActiveFilters {
     AF_None = 0,
@@ -49,19 +130,6 @@ enum ActiveFilters {
 };
 
 
-typedef struct HrtfState {
-    alignas(16) ALfloat History[SRC_HISTORY_LENGTH];
-    alignas(16) ALfloat Values[HRIR_LENGTH][2];
-} HrtfState;
-
-typedef struct HrtfParams {
-    alignas(16) ALfloat Coeffs[HRIR_LENGTH][2];
-    alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2];
-    ALuint Delay[2];
-    ALint DelayStep[2];
-} HrtfParams;
-
-
 typedef struct MixGains {
     ALfloat Current;
     ALfloat Step;
@@ -71,11 +139,15 @@ typedef struct MixGains {
 
 typedef struct DirectParams {
     ALfloat (*OutBuffer)[BUFFERSIZE];
+    ALuint OutChannels;
 
     /* If not 'moving', gain/coefficients are set directly without fading. */
     ALboolean Moving;
     /* Stepping counter for gain/coefficient fading. */
     ALuint Counter;
+    /* Last direction (relative to listener) and gain of a moving source. */
+    aluVector LastDir;
+    ALfloat LastGain;
 
     struct {
         enum ActiveFilters ActiveType;
@@ -83,17 +155,11 @@ typedef struct DirectParams {
         ALfilterState HighPass;
     } Filters[MAX_INPUT_CHANNELS];
 
-    union {
-        struct {
-            HrtfParams Params[MAX_INPUT_CHANNELS];
-            HrtfState State[MAX_INPUT_CHANNELS];
-            ALuint IrSize;
-            ALfloat Gain;
-            ALfloat Dir[3];
-        } Hrtf;
-
-        MixGains Gains[MAX_INPUT_CHANNELS][MaxChannels];
-    } Mix;
+    struct {
+        HrtfParams Params;
+        HrtfState State;
+    } Hrtf[MAX_INPUT_CHANNELS];
+    MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
 } DirectParams;
 
 typedef struct SendParams {
@@ -108,14 +174,15 @@ typedef struct SendParams {
         ALfilterState HighPass;
     } Filters[MAX_INPUT_CHANNELS];
 
-    /* Gain control, which applies to all input channels to a single (mono)
+    /* Gain control, which applies to each input channel to a single (mono)
      * output buffer. */
-    MixGains Gain;
+    MixGains Gains[MAX_INPUT_CHANNELS];
 } SendParams;
 
 
-typedef const ALfloat* (*ResamplerFunc)(const ALfloat *src, ALuint frac, ALuint increment,
-                                        ALfloat *restrict dst, ALuint dstlen);
+typedef const ALfloat* (*ResamplerFunc)(const BsincState *state,
+    const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen
+);
 
 typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans,
                           ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains,
@@ -131,7 +198,7 @@ typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const A
 #define SPEEDOFSOUNDMETRESPERSEC  (343.3f)
 #define AIRABSORBGAINHF           (0.99426f) /* -0.05dB */
 
-#define FRACTIONBITS (14)
+#define FRACTIONBITS (12)
 #define FRACTIONONE  (1<<FRACTIONBITS)
 #define FRACTIONMASK (FRACTIONONE-1)
 
@@ -179,47 +246,75 @@ inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max)
 { return minu64(max, maxu64(min, val)); }
 
 
+union ResamplerCoeffs {
+    ALfloat FIR4[FRACTIONONE][4];
+    ALfloat FIR8[FRACTIONONE][8];
+};
+extern alignas(16) union ResamplerCoeffs ResampleCoeffs;
+
+extern alignas(16) const ALfloat bsincTab[18840];
+
+
 inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu)
 {
     return val1 + (val2-val1)*mu;
 }
-inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu)
+inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac)
 {
-    ALfloat mu2 = mu*mu;
-    ALfloat a0 = -0.5f*val0 +  1.5f*val1 + -1.5f*val2 +  0.5f*val3;
-    ALfloat a1 =       val0 + -2.5f*val1 +  2.0f*val2 + -0.5f*val3;
-    ALfloat a2 = -0.5f*val0              +  0.5f*val2;
-    ALfloat a3 =                    val1;
-
-    return a0*mu*mu2 + a1*mu2 + a2*mu + a3;
+    const ALfloat *k = ResampleCoeffs.FIR4[frac];
+    return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3;
+}
+inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac)
+{
+    const ALfloat *k = ResampleCoeffs.FIR8[frac];
+    return k[0]*val0 + k[1]*val1 + k[2]*val2 + k[3]*val3 +
+           k[4]*val4 + k[5]*val5 + k[6]*val6 + k[7]*val7;
 }
 
 
+void aluInitMixer(void);
+
 ALvoid aluInitPanning(ALCdevice *Device);
 
+/**
+ * ComputeDirectionalGains
+ *
+ * Sets channel gains based on a direction. The direction must be a 3-component
+ * vector no longer than 1 unit.
+ */
+void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
+
 /**
  * ComputeAngleGains
  *
- * Sets channel gains based on a given source's angle and its half-width. The
- * angle and hwidth parameters are in radians.
+ * Sets channel gains based on angle and elevation. The angle and elevation
+ * parameters are in radians, going right and up respectively.
  */
-void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels]);
+void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
 
 /**
- * SetGains
+ * ComputeAmbientGains
  *
- * Helper to set the appropriate channels to the specified gain.
+ * Sets channel gains for ambient, omni-directional sounds.
  */
-inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels])
-{
-    ComputeAngleGains(device, 0.0f, F_PI, ingain, gains);
-}
+void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
 
+/**
+ * ComputeBFormatGains
+ *
+ * Sets channel gains for a given (first-order) B-Format channel. The matrix is
+ * a 1x4 'slice' of the rotation matrix for a given channel used to orient the
+ * coefficients.
+ */
+void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]);
 
-ALvoid CalcSourceParams(struct ALactivesource *src, const ALCcontext *ALContext);
-ALvoid CalcNonAttnSourceParams(struct ALactivesource *src, const ALCcontext *ALContext);
 
-ALvoid MixSource(struct ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo);
+ALvoid UpdateContextSources(ALCcontext *context);
+
+ALvoid CalcSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext);
+ALvoid CalcNonAttnSourceParams(struct ALvoice *voice, const struct ALsource *source, const ALCcontext *ALContext);
+
+ALvoid MixSource(struct ALvoice *voice, struct ALsource *source, ALCdevice *Device, ALuint SamplesToDo);
 
 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
 /* Caller must lock the device. */
@@ -233,4 +328,3 @@ extern ALfloat ZScale;
 #endif
 
 #endif
-

+ 4 - 7
libs/openal-soft/OpenAL32/Include/bs2b.h

@@ -69,19 +69,16 @@ struct bs2b {
     } last_sample;
 };
 
-/* Clear buffers and set new coefficients with new crossfeed level value.
+/* Clear buffers and set new coefficients with new crossfeed level and sample
+ * rate values.
  * level - crossfeed level of *LEVEL values.
+ * srate - sample rate by Hz.
  */
-void bs2b_set_level(struct bs2b *bs2b, int level);
+void bs2b_set_params(struct bs2b *bs2b, int level, int srate);
 
 /* Return current crossfeed level value */
 int bs2b_get_level(struct bs2b *bs2b);
 
-/* Clear buffers and set new coefficients with new sample rate value.
- * srate - sample rate by Hz.
- */
-void bs2b_set_srate(struct bs2b *bs2b, int srate);
-
 /* Return current sample rate value */
 int bs2b_get_srate(struct bs2b *bs2b);
 

+ 2 - 2
libs/openal-soft/OpenAL32/alAuxEffectSlot.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 

+ 41 - 11
libs/openal-soft/OpenAL32/alBuffer.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -151,7 +151,7 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
     if(DecomposeUserFormat(format, &srcchannels, &srctype) == AL_FALSE)
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
 
-    align = albuf->UnpackAlign;
+    align = ATOMIC_LOAD(&albuf->UnpackAlign);
     if(SanitizeAlignment(srctype, &align) == AL_FALSE)
         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
     switch(srctype)
@@ -189,6 +189,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
                 case UserFmtX51: newformat = AL_FORMAT_51CHN32; break;
                 case UserFmtX61: newformat = AL_FORMAT_61CHN32; break;
                 case UserFmtX71: newformat = AL_FORMAT_71CHN32; break;
+                case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_FLOAT32; break;
+                case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_FLOAT32; break;
             }
             err = LoadData(albuf, freq, newformat, size/framesize*align,
                            srcchannels, srctype, data, align, AL_TRUE);
@@ -211,6 +213,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
                 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
                 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
                 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+                case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
+                case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
             }
             err = LoadData(albuf, freq, newformat, size/framesize*align,
                            srcchannels, srctype, data, align, AL_TRUE);
@@ -233,6 +237,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
                 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
                 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
                 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+                case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
+                case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
             }
             err = LoadData(albuf, freq, newformat, size/framesize*align,
                            srcchannels, srctype, data, align, AL_TRUE);
@@ -255,6 +261,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi
                 case UserFmtX51: newformat = AL_FORMAT_51CHN16; break;
                 case UserFmtX61: newformat = AL_FORMAT_61CHN16; break;
                 case UserFmtX71: newformat = AL_FORMAT_71CHN16; break;
+                case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break;
+                case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break;
             }
             err = LoadData(albuf, freq, newformat, size/framesize*align,
                            srcchannels, srctype, data, align, AL_TRUE);
@@ -291,7 +299,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
 
     WriteLock(&albuf->lock);
-    align = albuf->UnpackAlign;
+    align = ATOMIC_LOAD(&albuf->UnpackAlign);
     if(SanitizeAlignment(srctype, &align) == AL_FALSE)
     {
         WriteUnlock(&albuf->lock);
@@ -368,7 +376,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer,
     if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE)
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
 
-    align = albuf->UnpackAlign;
+    align = ATOMIC_LOAD(&albuf->UnpackAlign);
     if(SanitizeAlignment(type, &align) == AL_FALSE)
         SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
     if((samples%align) != 0)
@@ -404,7 +412,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer,
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
 
     WriteLock(&albuf->lock);
-    align = albuf->UnpackAlign;
+    align = ATOMIC_LOAD(&albuf->UnpackAlign);
     if(SanitizeAlignment(type, &align) == AL_FALSE)
     {
         WriteUnlock(&albuf->lock);
@@ -457,7 +465,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer,
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
 
     ReadLock(&albuf->lock);
-    align = albuf->PackAlign;
+    align = ATOMIC_LOAD(&albuf->PackAlign);
     if(SanitizeAlignment(type, &align) == AL_FALSE)
     {
         ReadUnlock(&albuf->lock);
@@ -596,13 +604,13 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value)
     case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
         if(!(value >= 0))
             SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-        ExchangeInt(&albuf->UnpackAlign, value);
+        ATOMIC_STORE(&albuf->UnpackAlign, value);
         break;
 
     case AL_PACK_BLOCK_ALIGNMENT_SOFT:
         if(!(value >= 0))
             SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-        ExchangeInt(&albuf->PackAlign, value);
+        ATOMIC_STORE(&albuf->PackAlign, value);
         break;
 
     default:
@@ -834,11 +842,11 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value
         break;
 
     case AL_UNPACK_BLOCK_ALIGNMENT_SOFT:
-        *value = albuf->UnpackAlign;
+        *value = ATOMIC_LOAD(&albuf->UnpackAlign);
         break;
 
     case AL_PACK_BLOCK_ALIGNMENT_SOFT:
-        *value = albuf->PackAlign;
+        *value = ATOMIC_LOAD(&albuf->PackAlign);
         break;
 
     default:
@@ -1045,6 +1053,8 @@ ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
     case UserFmtX51: return 6;
     case UserFmtX61: return 7;
     case UserFmtX71: return 8;
+    case UserFmtBFormat2D: return 3;
+    case UserFmtBFormat3D: return 4;
     }
     return 0;
 }
@@ -1101,6 +1111,16 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
         { AL_FORMAT_71CHN16,     UserFmtX71, UserFmtShort },
         { AL_FORMAT_71CHN32,     UserFmtX71, UserFmtFloat },
         { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw },
+
+        { AL_FORMAT_BFORMAT2D_8,       UserFmtBFormat2D, UserFmtUByte },
+        { AL_FORMAT_BFORMAT2D_16,      UserFmtBFormat2D, UserFmtShort },
+        { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat },
+        { AL_FORMAT_BFORMAT2D_MULAW,   UserFmtBFormat2D, UserFmtMulaw },
+
+        { AL_FORMAT_BFORMAT3D_8,       UserFmtBFormat3D, UserFmtUByte },
+        { AL_FORMAT_BFORMAT3D_16,      UserFmtBFormat3D, UserFmtShort },
+        { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat },
+        { AL_FORMAT_BFORMAT3D_MULAW,   UserFmtBFormat3D, UserFmtMulaw },
     };
     ALuint i;
 
@@ -1138,6 +1158,8 @@ ALuint ChannelsFromFmt(enum FmtChannels chans)
     case FmtX51: return 6;
     case FmtX61: return 7;
     case FmtX71: return 8;
+    case FmtBFormat2D: return 3;
+    case FmtBFormat3D: return 4;
     }
     return 0;
 }
@@ -1178,6 +1200,14 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm
         { AL_7POINT1_8_SOFT,   FmtX71, FmtByte  },
         { AL_7POINT1_16_SOFT,  FmtX71, FmtShort },
         { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat },
+
+        { AL_FORMAT_BFORMAT2D_8,       FmtBFormat2D, FmtByte },
+        { AL_FORMAT_BFORMAT2D_16,      FmtBFormat2D, FmtShort },
+        { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat },
+
+        { AL_FORMAT_BFORMAT3D_8,       FmtBFormat3D, FmtByte },
+        { AL_FORMAT_BFORMAT3D_16,      FmtBFormat3D, FmtShort },
+        { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat },
     };
     ALuint i;
 

+ 16 - 2
libs/openal-soft/OpenAL32/alEffect.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -402,13 +402,27 @@ static void InitEffectParams(ALeffect *effect, ALenum type)
         effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION;
         effect->Props.Reverb.Gain   = AL_REVERB_DEFAULT_GAIN;
         effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF;
+        effect->Props.Reverb.GainLF = 1.0f;
         effect->Props.Reverb.DecayTime    = AL_REVERB_DEFAULT_DECAY_TIME;
         effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO;
+        effect->Props.Reverb.DecayLFRatio = 1.0f;
         effect->Props.Reverb.ReflectionsGain   = AL_REVERB_DEFAULT_REFLECTIONS_GAIN;
         effect->Props.Reverb.ReflectionsDelay  = AL_REVERB_DEFAULT_REFLECTIONS_DELAY;
+        effect->Props.Reverb.ReflectionsPan[0] = 0.0f;
+        effect->Props.Reverb.ReflectionsPan[1] = 0.0f;
+        effect->Props.Reverb.ReflectionsPan[2] = 0.0f;
         effect->Props.Reverb.LateReverbGain   = AL_REVERB_DEFAULT_LATE_REVERB_GAIN;
         effect->Props.Reverb.LateReverbDelay  = AL_REVERB_DEFAULT_LATE_REVERB_DELAY;
+        effect->Props.Reverb.LateReverbPan[0] = 0.0f;
+        effect->Props.Reverb.LateReverbPan[1] = 0.0f;
+        effect->Props.Reverb.LateReverbPan[2] = 0.0f;
+        effect->Props.Reverb.EchoTime  = 0.25f;
+        effect->Props.Reverb.EchoDepth = 0.0f;
+        effect->Props.Reverb.ModulationTime  = 0.25f;
+        effect->Props.Reverb.ModulationDepth = 0.0f;
         effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
+        effect->Props.Reverb.HFReference = 5000.0f;
+        effect->Props.Reverb.LFReference = 250.0f;
         effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
         effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT;
         SET_VTABLE1(ALreverb, effect);

+ 2 - 2
libs/openal-soft/OpenAL32/alError.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 

+ 2 - 2
libs/openal-soft/OpenAL32/alExtension.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 

+ 57 - 37
libs/openal-soft/OpenAL32/alFilter.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -32,6 +32,8 @@
 extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id);
 extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id);
 extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample);
+extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope);
+extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth);
 
 static void InitFilterParams(ALfilter *filter, ALenum type);
 
@@ -336,72 +338,72 @@ void ALfilterState_clear(ALfilterState *filter)
     filter->y[1] = 0.0f;
 }
 
-void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth)
+void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ)
 {
-    ALfloat alpha;
-    ALfloat w0;
+    ALfloat alpha, sqrtgain_alpha_2;
+    ALfloat w0, sin_w0, cos_w0;
 
     // Limit gain to -100dB
     gain = maxf(gain, 0.00001f);
 
-    w0 = F_2PI * freq_mult;
+    w0 = F_TAU * freq_mult;
+    sin_w0 = sinf(w0);
+    cos_w0 = cosf(w0);
+    alpha = sin_w0/2.0f * rcpQ;
 
     /* Calculate filter coefficients depending on filter type */
     switch(type)
     {
         case ALfilterType_HighShelf:
-            alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f);
-            filter->b[0] =       gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha);
-            filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cosf(w0)                         );
-            filter->b[2] =       gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha);
-            filter->a[0] =             (gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha;
-            filter->a[1] =  2.0f*     ((gain-1.0f) - (gain+1.0f)*cosf(w0)                         );
-            filter->a[2] =             (gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha;
+            sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
+            filter->b[0] =       gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
+            filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0                   );
+            filter->b[2] =       gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
+            filter->a[0] =             (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
+            filter->a[1] =  2.0f*     ((gain-1.0f) - (gain+1.0f)*cos_w0                   );
+            filter->a[2] =             (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
             break;
         case ALfilterType_LowShelf:
-            alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f);
-            filter->b[0] =       gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha);
-            filter->b[1] =  2.0f*gain*((gain-1.0f) - (gain+1.0f)*cosf(w0)                         );
-            filter->b[2] =       gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha);
-            filter->a[0] =             (gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha;
-            filter->a[1] = -2.0f*     ((gain-1.0f) + (gain+1.0f)*cosf(w0)                         );
-            filter->a[2] =             (gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha;
+            sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha;
+            filter->b[0] =       gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
+            filter->b[1] =  2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0                   );
+            filter->b[2] =       gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
+            filter->a[0] =             (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
+            filter->a[1] = -2.0f*     ((gain-1.0f) + (gain+1.0f)*cos_w0                   );
+            filter->a[2] =             (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
             break;
         case ALfilterType_Peaking:
-            alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
+            gain = sqrtf(gain);
             filter->b[0] =  1.0f + alpha * gain;
-            filter->b[1] = -2.0f * cosf(w0);
+            filter->b[1] = -2.0f * cos_w0;
             filter->b[2] =  1.0f - alpha * gain;
             filter->a[0] =  1.0f + alpha / gain;
-            filter->a[1] = -2.0f * cosf(w0);
+            filter->a[1] = -2.0f * cos_w0;
             filter->a[2] =  1.0f - alpha / gain;
             break;
 
         case ALfilterType_LowPass:
-            alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
-            filter->b[0] = (1.0f - cosf(w0)) / 2.0f;
-            filter->b[1] =  1.0f - cosf(w0);
-            filter->b[2] = (1.0f - cosf(w0)) / 2.0f;
+            filter->b[0] = (1.0f - cos_w0) / 2.0f;
+            filter->b[1] =  1.0f - cos_w0;
+            filter->b[2] = (1.0f - cos_w0) / 2.0f;
             filter->a[0] =  1.0f + alpha;
-            filter->a[1] = -2.0f * cosf(w0);
+            filter->a[1] = -2.0f * cos_w0;
             filter->a[2] =  1.0f - alpha;
             break;
         case ALfilterType_HighPass:
-            alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
-            filter->b[0] = (1.0f + cosf(w0)) / 2.0f;
-            filter->b[1] =  1.0f + cosf(w0);
-            filter->b[2] = (1.0f + cosf(w0)) / 2.0f;
-            filter->a[0] =  1.0f + alpha;
-            filter->a[1] = -2.0f * cosf(w0);
-            filter->a[2] =  1.0f - alpha;
+            filter->b[0] =  (1.0f + cos_w0) / 2.0f;
+            filter->b[1] = -(1.0f + cos_w0);
+            filter->b[2] =  (1.0f + cos_w0) / 2.0f;
+            filter->a[0] =   1.0f + alpha;
+            filter->a[1] =  -2.0f * cos_w0;
+            filter->a[2] =   1.0f - alpha;
             break;
         case ALfilterType_BandPass:
-            alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0));
             filter->b[0] =  alpha;
             filter->b[1] =  0;
             filter->b[2] = -alpha;
             filter->a[0] =  1.0f + alpha;
-            filter->a[1] = -2.0f * cosf(w0);
+            filter->a[1] = -2.0f * cos_w0;
             filter->a[2] =  1.0f - alpha;
             break;
     }
@@ -416,6 +418,24 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g
     filter->process = ALfilterState_processC;
 }
 
+void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples)
+{
+    if(numsamples >= 2)
+    {
+        filter->x[1] = src[numsamples-2];
+        filter->x[0] = src[numsamples-1];
+        filter->y[1] = src[numsamples-2];
+        filter->y[0] = src[numsamples-1];
+    }
+    else if(numsamples == 1)
+    {
+        filter->x[1] = filter->x[0];
+        filter->x[0] = src[0];
+        filter->y[1] = filter->y[0];
+        filter->y[0] = src[0];
+    }
+}
+
 
 static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val))
 { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); }

+ 16 - 20
libs/openal-soft/OpenAL32/alListener.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -74,9 +74,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
             SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
 
         LockContext(context);
-        context->Listener->Position[0] = value1;
-        context->Listener->Position[1] = value2;
-        context->Listener->Position[2] = value3;
+        aluVectorSet(&context->Listener->Position, value1, value2, value3, 1.0f);
         ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
         UnlockContext(context);
         break;
@@ -86,9 +84,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val
             SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
 
         LockContext(context);
-        context->Listener->Velocity[0] = value1;
-        context->Listener->Velocity[1] = value2;
-        context->Listener->Velocity[2] = value3;
+        aluVectorSet(&context->Listener->Velocity, value1, value2, value3, 0.0f);
         ATOMIC_STORE(&context->UpdateSources, AL_TRUE);
         UnlockContext(context);
         break;
@@ -282,17 +278,17 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat
     {
     case AL_POSITION:
         LockContext(context);
-        *value1 = context->Listener->Position[0];
-        *value2 = context->Listener->Position[1];
-        *value3 = context->Listener->Position[2];
+        *value1 = context->Listener->Position.v[0];
+        *value2 = context->Listener->Position.v[1];
+        *value3 = context->Listener->Position.v[2];
         UnlockContext(context);
         break;
 
     case AL_VELOCITY:
         LockContext(context);
-        *value1 = context->Listener->Velocity[0];
-        *value2 = context->Listener->Velocity[1];
-        *value3 = context->Listener->Velocity[2];
+        *value1 = context->Listener->Velocity.v[0];
+        *value2 = context->Listener->Velocity.v[1];
+        *value3 = context->Listener->Velocity.v[2];
         UnlockContext(context);
         break;
 
@@ -383,17 +379,17 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu
     {
     case AL_POSITION:
         LockContext(context);
-        *value1 = (ALint)context->Listener->Position[0];
-        *value2 = (ALint)context->Listener->Position[1];
-        *value3 = (ALint)context->Listener->Position[2];
+        *value1 = (ALint)context->Listener->Position.v[0];
+        *value2 = (ALint)context->Listener->Position.v[1];
+        *value3 = (ALint)context->Listener->Position.v[2];
         UnlockContext(context);
         break;
 
     case AL_VELOCITY:
         LockContext(context);
-        *value1 = (ALint)context->Listener->Velocity[0];
-        *value2 = (ALint)context->Listener->Velocity[1];
-        *value3 = (ALint)context->Listener->Velocity[2];
+        *value1 = (ALint)context->Listener->Velocity.v[0];
+        *value2 = (ALint)context->Listener->Velocity.v[1];
+        *value3 = (ALint)context->Listener->Velocity.v[2];
         UnlockContext(context);
         break;
 

File diff suppressed because it is too large
+ 410 - 345
libs/openal-soft/OpenAL32/alSource.c


+ 5 - 172
libs/openal-soft/OpenAL32/alState.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -28,9 +28,8 @@
 #include "alError.h"
 #include "alSource.h"
 #include "alAuxEffectSlot.h"
-#include "alMidi.h"
 
-#include "midi/base.h"
+#include "backends/base.h"
 
 
 static const ALchar alVendor[] = "OpenAL Community";
@@ -159,7 +158,6 @@ done:
 
 AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
 {
-    ALCdevice *device;
     ALCcontext *context;
     ALdouble value = 0.0;
 
@@ -188,16 +186,6 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
         value = (ALdouble)context->DeferUpdates;
         break;
 
-    case AL_MIDI_GAIN_SOFT:
-        device = context->Device;
-        value = (ALdouble)MidiSynth_getGain(device->Synth);
-        break;
-
-    case AL_MIDI_STATE_SOFT:
-        device = context->Device;
-        value = (ALdouble)MidiSynth_getState(device->Synth);
-        break;
-
     default:
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
     }
@@ -210,7 +198,6 @@ done:
 
 AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
 {
-    ALCdevice *device;
     ALCcontext *context;
     ALfloat value = 0.0f;
 
@@ -239,16 +226,6 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
         value = (ALfloat)context->DeferUpdates;
         break;
 
-    case AL_MIDI_GAIN_SOFT:
-        device = context->Device;
-        value = MidiSynth_getGain(device->Synth);
-        break;
-
-    case AL_MIDI_STATE_SOFT:
-        device = context->Device;
-        value = (ALfloat)MidiSynth_getState(device->Synth);
-        break;
-
     default:
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
     }
@@ -262,8 +239,6 @@ done:
 AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
 {
     ALCcontext *context;
-    ALCdevice *device;
-    MidiSynth *synth;
     ALint value = 0;
 
     context = GetContextRef();
@@ -291,17 +266,6 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
         value = (ALint)context->DeferUpdates;
         break;
 
-    case AL_SOUNDFONTS_SIZE_SOFT:
-        device = context->Device;
-        synth = device->Synth;
-        value = synth->NumSoundfonts;
-        break;
-
-    case AL_MIDI_STATE_SOFT:
-        device = context->Device;
-        value = MidiSynth_getState(device->Synth);
-        break;
-
     default:
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
     }
@@ -315,8 +279,6 @@ done:
 AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
 {
     ALCcontext *context;
-    ALCdevice *device;
-    MidiSynth *synth;
     ALint64SOFT value = 0;
 
     context = GetContextRef();
@@ -344,24 +306,6 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
         value = (ALint64SOFT)context->DeferUpdates;
         break;
 
-    case AL_MIDI_CLOCK_SOFT:
-        device = context->Device;
-        ALCdevice_Lock(device);
-        value = MidiSynth_getTime(device->Synth);
-        ALCdevice_Unlock(device);
-        break;
-
-    case AL_SOUNDFONTS_SIZE_SOFT:
-        device = context->Device;
-        synth = device->Synth;
-        value = (ALint64SOFT)synth->NumSoundfonts;
-        break;
-
-    case AL_MIDI_STATE_SOFT:
-        device = context->Device;
-        value = (ALint64SOFT)MidiSynth_getState(device->Synth);
-        break;
-
     default:
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
     }
@@ -418,8 +362,6 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
             case AL_DISTANCE_MODEL:
             case AL_SPEED_OF_SOUND:
             case AL_DEFERRED_UPDATES_SOFT:
-            case AL_MIDI_GAIN_SOFT:
-            case AL_MIDI_STATE_SOFT:
                 values[0] = alGetDouble(pname);
                 return;
         }
@@ -453,8 +395,6 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
             case AL_DISTANCE_MODEL:
             case AL_SPEED_OF_SOUND:
             case AL_DEFERRED_UPDATES_SOFT:
-            case AL_MIDI_GAIN_SOFT:
-            case AL_MIDI_STATE_SOFT:
                 values[0] = alGetFloat(pname);
                 return;
         }
@@ -478,9 +418,6 @@ done:
 AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
 {
     ALCcontext *context;
-    ALCdevice *device;
-    MidiSynth *synth;
-    ALsizei i;
 
     if(values)
     {
@@ -491,8 +428,6 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
             case AL_DISTANCE_MODEL:
             case AL_SPEED_OF_SOUND:
             case AL_DEFERRED_UPDATES_SOFT:
-            case AL_SOUNDFONTS_SIZE_SOFT:
-            case AL_MIDI_STATE_SOFT:
                 values[0] = alGetInteger(pname);
                 return;
         }
@@ -503,18 +438,6 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
 
     switch(pname)
     {
-    case AL_SOUNDFONTS_SOFT:
-        device = context->Device;
-        synth = device->Synth;
-        if(synth->NumSoundfonts > 0)
-        {
-            if(!(values))
-                SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-            for(i = 0;i < synth->NumSoundfonts;i++)
-                values[i] = synth->Soundfonts[i]->id;
-        }
-        break;
-
     default:
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
     }
@@ -526,9 +449,6 @@ done:
 AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
 {
     ALCcontext *context;
-    ALCdevice *device;
-    MidiSynth *synth;
-    ALsizei i;
 
     if(values)
     {
@@ -539,9 +459,6 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
             case AL_DISTANCE_MODEL:
             case AL_SPEED_OF_SOUND:
             case AL_DEFERRED_UPDATES_SOFT:
-            case AL_MIDI_CLOCK_SOFT:
-            case AL_SOUNDFONTS_SIZE_SOFT:
-            case AL_MIDI_STATE_SOFT:
                 values[0] = alGetInteger64SOFT(pname);
                 return;
         }
@@ -552,18 +469,6 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
 
     switch(pname)
     {
-    case AL_SOUNDFONTS_SOFT:
-        device = context->Device;
-        synth = device->Synth;
-        if(synth->NumSoundfonts > 0)
-        {
-            if(!(values))
-                SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done);
-            for(i = 0;i < synth->NumSoundfonts;i++)
-                values[i] = (ALint64SOFT)synth->Soundfonts[i]->id;
-        }
-        break;
-
     default:
         SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done);
     }
@@ -712,54 +617,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void)
     context = GetContextRef();
     if(!context) return;
 
-    if(!context->DeferUpdates)
-    {
-        ALboolean UpdateSources;
-        ALactivesource **src, **src_end;
-        ALeffectslot **slot, **slot_end;
-        FPUCtl oldMode;
-
-        SetMixerFPUMode(&oldMode);
-
-        LockContext(context);
-        context->DeferUpdates = AL_TRUE;
-
-        /* Make sure all pending updates are performed */
-        UpdateSources = ATOMIC_EXCHANGE(ALenum, &context->UpdateSources, AL_FALSE);
-
-        src = context->ActiveSources;
-        src_end = src + context->ActiveSourceCount;
-        while(src != src_end)
-        {
-            ALsource *source = (*src)->Source;
-
-            if(source->state != AL_PLAYING && source->state != AL_PAUSED)
-            {
-                ALactivesource *temp = *(--src_end);
-                *src_end = *src;
-                *src = temp;
-                --(context->ActiveSourceCount);
-                continue;
-            }
-
-            if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || UpdateSources)
-                (*src)->Update(*src, context);
-
-            src++;
-        }
-
-        slot = VECTOR_ITER_BEGIN(context->ActiveAuxSlots);
-        slot_end = VECTOR_ITER_END(context->ActiveAuxSlots);
-        while(slot != slot_end)
-        {
-            if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
-                V((*slot)->EffectState,update)(context->Device, *slot);
-            slot++;
-        }
-
-        UnlockContext(context);
-        RestoreFPUMode(&oldMode);
-    }
+    ALCcontext_DeferUpdates(context);
 
     ALCcontext_DecRef(context);
 }
@@ -771,32 +629,7 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void)
     context = GetContextRef();
     if(!context) return;
 
-    if(ExchangeInt(&context->DeferUpdates, AL_FALSE))
-    {
-        ALsizei pos;
-
-        LockContext(context);
-        LockUIntMapRead(&context->SourceMap);
-        for(pos = 0;pos < context->SourceMap.size;pos++)
-        {
-            ALsource *Source = context->SourceMap.array[pos].value;
-            ALenum new_state;
-
-            if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) &&
-               Source->Offset >= 0.0)
-            {
-                ReadLock(&Source->queue_lock);
-                ApplyOffset(Source);
-                ReadUnlock(&Source->queue_lock);
-            }
-
-            new_state = ExchangeInt(&Source->new_state, AL_NONE);
-            if(new_state)
-                SetSourceState(Source, context, new_state);
-        }
-        UnlockUIntMapRead(&context->SourceMap);
-        UnlockContext(context);
-    }
+    ALCcontext_ProcessUpdates(context);
 
     ALCcontext_DecRef(context);
 }

+ 28 - 14
libs/openal-soft/OpenAL32/alThunk.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -26,33 +26,33 @@
 #include "alThunk.h"
 
 
-static ALenum *ThunkArray;
-static ALuint  ThunkArraySize;
-static RWLock  ThunkLock;
+static ATOMIC(ALenum) *ThunkArray;
+static ALuint          ThunkArraySize;
+static RWLock ThunkLock;
 
 void ThunkInit(void)
 {
     RWLockInit(&ThunkLock);
     ThunkArraySize = 1;
-    ThunkArray = calloc(1, ThunkArraySize * sizeof(*ThunkArray));
+    ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray));
 }
 
 void ThunkExit(void)
 {
-    free(ThunkArray);
+    al_free(ThunkArray);
     ThunkArray = NULL;
     ThunkArraySize = 0;
 }
 
 ALenum NewThunkEntry(ALuint *index)
 {
-    ALenum *NewList;
+    void *NewList;
     ALuint i;
 
     ReadLock(&ThunkLock);
     for(i = 0;i < ThunkArraySize;i++)
     {
-        if(ExchangeInt(&ThunkArray[i], AL_TRUE) == AL_FALSE)
+        if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
         {
             ReadUnlock(&ThunkLock);
             *index = i+1;
@@ -62,18 +62,32 @@ ALenum NewThunkEntry(ALuint *index)
     ReadUnlock(&ThunkLock);
 
     WriteLock(&ThunkLock);
-    NewList = realloc(ThunkArray, ThunkArraySize*2 * sizeof(*ThunkArray));
+    /* Double-check that there's still no free entries, in case another
+     * invocation just came through and increased the size of the array.
+     */
+    for(;i < ThunkArraySize;i++)
+    {
+        if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE)
+        {
+            WriteUnlock(&ThunkLock);
+            *index = i+1;
+            return AL_NO_ERROR;
+        }
+    }
+
+    NewList = al_calloc(16, ThunkArraySize*2 * sizeof(*ThunkArray));
     if(!NewList)
     {
         WriteUnlock(&ThunkLock);
         ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2);
         return AL_OUT_OF_MEMORY;
     }
-    memset(&NewList[ThunkArraySize], 0, ThunkArraySize*sizeof(*ThunkArray));
-    ThunkArraySize *= 2;
+    memcpy(NewList, ThunkArray, ThunkArraySize*sizeof(*ThunkArray));
+    al_free(ThunkArray);
     ThunkArray = NewList;
+    ThunkArraySize *= 2;
 
-    ThunkArray[i] = AL_TRUE;
+    ATOMIC_STORE(&ThunkArray[i], AL_TRUE);
     WriteUnlock(&ThunkLock);
 
     *index = i+1;
@@ -84,6 +98,6 @@ void FreeThunkEntry(ALuint index)
 {
     ReadLock(&ThunkLock);
     if(index > 0 && index <= ThunkArraySize)
-        ExchangeInt(&ThunkArray[index-1], AL_FALSE);
+        ATOMIC_STORE(&ThunkArray[index-1], AL_FALSE);
     ReadUnlock(&ThunkLock);
 }

+ 6 - 4
libs/openal-soft/README

@@ -45,9 +45,11 @@ Special thanks go to:
 Creative Labs for the original source code this is based off of.
 
 Christopher Fitzgerald for the current reverb effect implementation, and
-helping with the low-pass filter.
+helping with the low-pass and HRTF filters.
 
-Christian Borss for the 3D panning code the current implementation is heavilly
-based on.
+Christian Borss for the 3D panning code previous versions used as a base.
 
-Ben Davis for the idea behind the current click-removal code.
+Ben Davis for the idea behind a previous version of the click-removal code.
+
+Richard Furse for helping with my understanding of Ambisonics that is used by
+the various parts of the library.

+ 12 - 5
libs/openal-soft/XCompile.txt

@@ -1,7 +1,6 @@
-# Cross-compiling requires CMake 2.6 or newer. To use it from build/, call it
-# like this:
-# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-pc-mingw32
-# Where 'i686-pc-mingw32' is the host prefix for your cross-compiler. If you
+# Cross-compiling requires CMake 2.6 or newer. Example:
+# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-w64-mingw32
+# Where 'i686-w64-mingw32' is the host prefix for your cross-compiler. If you
 # already have a toolchain file setup, you may use that instead of this file.
 
 # the name of the target operating system
@@ -10,12 +9,13 @@ SET(CMAKE_SYSTEM_NAME Windows)
 # which compilers to use for C and C++
 SET(CMAKE_C_COMPILER "${HOST}-gcc")
 SET(CMAKE_CXX_COMPILER "${HOST}-g++")
+SET(CMAKE_RC_COMPILER "${HOST}-windres")
 
 # here is the target environment located
 SET(CMAKE_FIND_ROOT_PATH "/usr/${HOST}")
 
 # here is where stuff gets installed to
-SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}/usr" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
+SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE STRING "Install path prefix, prepended onto install directories." FORCE)
 
 # adjust the default behaviour of the FIND_XXX() commands:
 # search headers and libraries in the target environment, search 
@@ -28,3 +28,10 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
 # .pc files (as there seems to be no way to force using ${HOST}-pkg-config)
 set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
 set(ENV{PKG_CONFIG_PATH} "")
+
+# Qt4 tools
+SET(QT_QMAKE_EXECUTABLE ${HOST}-qmake)
+SET(QT_MOC_EXECUTABLE ${HOST}-moc)
+SET(QT_RCC_EXECUTABLE ${HOST}-rcc)
+SET(QT_UIC_EXECUTABLE ${HOST}-uic)
+SET(QT_LRELEASE_EXECUTABLE ${HOST}-lrelease)

+ 123 - 125
libs/openal-soft/alsoftrc.sample

@@ -8,12 +8,18 @@
 # specifying "$HOME/file.ext" would typically result in something like
 # "/home/user/file.ext". To specify an actual "$" character, use "$$".
 #
+# Device-specific values may be specified by including the device name in the
+# block name, with "general" replaced by the device name. That is, general
+# options for the device "Name of Device" would be in the [Name of Device]
+# block, while ALSA options would be in the [alsa/Name of Device] block.
+# Options marked as "(global)" are not influenced by the device.
+#
 # The system-wide settings can be put in /etc/openal/alsoft.conf and user-
 # specific override settings in $HOME/.alsoftrc.
 # For Windows, these settings should go into $AppData\alsoft.ini
 #
-# Option and block names are case-insenstive. The supplied values are only
-# hints and may not be honored (though generally it'll try to get as close as
+# Option and block names are case-senstive. The supplied values are only hints
+# and may not be honored (though generally it'll try to get as close as
 # possible). Note: options that are left unset may default to app- or system-
 # specified values. These are the current available settings:
 
@@ -22,18 +28,27 @@
 ##
 [general]
 
-## disable-cpu-exts:
+## disable-cpu-exts: (global)
 #  Disables use of specialized methods that use specific CPU intrinsics.
 #  Certain methods may utilize CPU extensions for improved performance, and
 #  this option is useful for preventing some or all of those methods from being
-#  used. The available extensions are: sse, sse2, sse4.1, and neon. Specifying
-#  'all' disables use of all such specialized methods.
+#  used. The available extensions are: sse, sse2, sse3, sse4.1, and neon.
+#  Specifying 'all' disables use of all such specialized methods.
 #disable-cpu-exts =
 
+## drivers: (global)
+#  Sets the backend driver list order, comma-seperated. Unknown backends and
+#  duplicated names are ignored. Unlisted backends won't be considered for use
+#  unless the list is ended with a comma (e.g. 'oss,' will try OSS first before
+#  other backends, while 'oss' will try OSS only). Backends prepended with -
+#  won't be considered for use (e.g. '-oss,' will try all available backends
+#  except OSS). An empty list means to try all backends.
+#drivers =
+
 ## channels:
 #  Sets the output channel configuration. If left unspecified, one will try to
 #  be detected from the system, and defaulting to stereo. The available values
-#  are: mono, stereo, quad, surround51, surround61, surround71
+#  are: mono, stereo, quad, surround51, surround51rear, surround61, surround71
 #channels =
 
 ## sample-type:
@@ -48,14 +63,40 @@
 #  float32 - 32-bit float
 #sample-type = float32
 
-## hrtf:
-#  Enables HRTF filters. These filters provide for better sound spatialization
-#  while using headphones. The default filter will only work when output is
-#  44100hz stereo. While HRTF is active, the cf_level option is disabled.
-#  Default is disabled since stereo speaker output quality may suffer.
-#hrtf = false
+## frequency:
+#  Sets the output frequency. If left unspecified it will try to detect a
+#  default from the system, otherwise it will default to 44100.
+#frequency =
+
+## period_size:
+#  Sets the update period size, in frames. This is the number of frames needed
+#  for each mixing update. Acceptable values range between 64 and 8192.
+#period_size = 1024
+
+## periods:
+#  Sets the number of update periods. Higher values create a larger mix ahead,
+#  which helps protect against skips when the CPU is under load, but increases
+#  the delay between a sound getting mixed and being heard. Acceptable values
+#  range between 2 and 16.
+#periods = 4
+
+## stereo-mode:
+#  Specifies if stereo output is treated as being headphones or speakers. With
+#  headphones, HRTF or crossfeed filters may be used for better audio quality.
+#  Valid settings are auto, speakers, and headphones.
+#stereo-mode = auto
 
-## hrtf_tables
+## hrtf:
+#  Controls HRTF processing. These filters provide better spatialization of
+#  sounds while using headphones, but do require a bit more CPU power. The
+#  default filters will only work with 44100hz or 48000hz stereo output. While
+#  HRTF is used, the cf_level option is ignored. Setting this to auto (default)
+#  will allow HRTF to be used when headphones are detected or the app requests
+#  it, while setting true or false will forcefully enable or disable HRTF
+#  respectively.
+#hrtf = auto
+
+## hrtf_tables:
 #  Specifies a comma-separated list of files containing HRTF data sets. The
 #  format of the files are described in hrtf.txt. The filenames may contain
 #  these markers, which will be replaced as needed:
@@ -84,28 +125,18 @@
 #  stereo modes.
 #cf_level = 0
 
-## wide-stereo:
-#  Specifies that stereo sources are given a width of about 120 degrees on each
-#  channel, centering on -90 (left) and +90 (right), as opposed to being points
-#  placed at -30 (left) and +30 (right). This can be useful for surround-sound
-#  to give stereo sources a more encompassing sound. Note that the sound's
-#  overall volume will be slightly reduced to account for the extra output.
-#wide-stereo = false
-
-## frequency:
-#  Sets the output frequency. If left unspecified it will try to detect a
-#  default from the system, otherwise it will default to 44100.
-#frequency =
-
-## resampler:
+## resampler: (global)
 #  Selects the resampler used when mixing sources. Valid values are:
 #  point - nearest sample, no interpolation
 #  linear - extrapolates samples using a linear slope between samples
-#  cubic - extrapolates samples using a Catmull-Rom spline
+#  sinc4 - extrapolates samples using a 4-point Sinc filter
+#  sinc8 - extrapolates samples using an 8-point Sinc filter
+#  bsinc - extrapolates samples using a band-limited Sinc filter (varying
+#          between 12 and 24 points, with anti-aliasing)
 #  Specifying other values will result in using the default (linear).
 #resampler = linear
 
-## rt-prio:
+## rt-prio: (global)
 #  Sets real-time priority for the mixing thread. Not all drivers may use this
 #  (eg. PortAudio) as they already control the priority of the mixing thread.
 #  0 and negative values will disable it. Note that this may constitute a
@@ -114,39 +145,11 @@
 #  disabled.
 #rt-prio = 0
 
-## period_size:
-#  Sets the update period size, in frames. This is the number of frames needed
-#  for each mixing update. Acceptable values range between 64 and 8192.
-#period_size = 1024
-
-## periods:
-#  Sets the number of update periods. Higher values create a larger mix ahead,
-#  which helps protect against skips when the CPU is under load, but increases
-#  the delay between a sound getting mixed and being heard. Acceptable values
-#  range between 2 and 16.
-#periods = 4
-
 ## sources:
 #  Sets the maximum number of allocatable sources. Lower values may help for
 #  systems with apps that try to play more sounds than the CPU can handle.
 #sources = 256
 
-## drivers:
-#  Sets the backend driver list order, comma-seperated. Unknown backends and
-#  duplicated names are ignored. Unlisted backends won't be considered for use
-#  unless the list is ended with a comma (e.g. 'oss,' will try OSS first before
-#  other backends, while 'oss' will try OSS only). Backends prepended with -
-#  won't be considered for use (e.g. '-oss,' will try all available backends
-#  except OSS). An empty list means to try all backends.
-#drivers =
-
-## excludefx:
-#  Sets which effects to exclude, preventing apps from using them. This can
-#  help for apps that try to use effects which are too CPU intensive for the
-#  system to handle. Available effects are: eaxreverb,reverb,autowah,chorus,
-#  compressor,distortion,echo,equalizer,flanger,modulator,dedicated
-#excludefx =
-
 ## slots:
 #  Sets the maximum number of Auxiliary Effect Slots an app can create. A slot
 #  can use a non-negligible amount of CPU time if an effect is set on it even
@@ -160,26 +163,14 @@
 #  possible is 4.
 #sends =
 
-## layout:
-#  Sets the virtual speaker layout. Values are specified in degrees, where 0 is
-#  straight in front, negative goes left, and positive goes right. Unspecified
-#  speakers will remain at their default positions (which are dependant on the
-#  output format). Available speakers are back-left(bl), side-left(sl), front-
-#  left(fl), front-center(fc), front-right(fr), side-right(sr), back-right(br),
-#  and back-center(bc).
-#layout =
-
-## layout_*:
-#  Channel-specific layouts may be specified to override the layout option. The
-#  same speakers as the layout option are available, and the default settings
-#  are shown below.
-#layout_stereo     = fl=-90, fr=90
-#layout_quad       = fl=-45, fr=45, bl=-135, br=135
-#layout_surround51 = fl=-30, fr=30, fc=0, bl=-110, br=110
-#layout_surround61 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bc=180
-#layout_surround71 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bl=-150, br=150
-
-## default-reverb:
+## excludefx: (global)
+#  Sets which effects to exclude, preventing apps from using them. This can
+#  help for apps that try to use effects which are too CPU intensive for the
+#  system to handle. Available effects are: eaxreverb,reverb,chorus,compressor,
+#  distortion,echo,equalizer,flanger,modulator,dedicated
+#excludefx =
+
+## default-reverb: (global)
 #  A reverb preset that applies by default to all sources on send 0
 #  (applications that set their own slots on send 0 will override this).
 #  Available presets are: None, Generic, PaddedCell, Room, Bathroom,
@@ -188,54 +179,31 @@
 #  Quarry, Plain, ParkingLot, SewerPipe, Underwater, Drugged, Dizzy, Psychotic.
 #default-reverb =
 
-## trap-alc-error:
+## trap-alc-error: (global)
 #  Generates a SIGTRAP signal when an ALC device error is generated, on systems
 #  that support it. This helps when debugging, while trying to find the cause
 #  of a device error. On Windows, a breakpoint exception is generated.
 #trap-alc-error = false
 
-## trap-al-error:
+## trap-al-error: (global)
 #  Generates a SIGTRAP signal when an AL context error is generated, on systems
 #  that support it. This helps when debugging, while trying to find the cause
 #  of a context error. On Windows, a breakpoint exception is generated.
 #trap-al-error = false
 
-##
-## MIDI stuff (EXPERIMENTAL)
-##
-[midi]
-
-## soundfont:
-#  A default soundfont (sf2 format). Used when an app requests the system
-#  default. The listed file is relative to system-dependant data directories.
-#  On Windows this is:
-#  $AppData\openal\soundfonts
-#  And on other systems, it's (in order):
-#  $XDG_DATA_HOME/openal/soundfonts
-#  $XDG_DATA_DIRS/openal/soundfonts
-#  An absolute path may also be specified, if the given file is elsewhere.
-#soundfont =
-
-## volume:
-#  Additional attenuation applied to MIDI output, expressed in decibels. This
-#  is used to help keep the mix from clipping, and so must be 0 or less. The
-#  value is logarithmic, so -6 will be about half amplitude, and -12 about
-#  1/4th. The default is roughly -13.9794 (0.2, or 1/5th).
-#volume =
-
 ##
 ## Reverb effect stuff (includes EAX reverb)
 ##
 [reverb]
 
-## boost:
+## boost: (global)
 #  A global amplification for reverb output, expressed in decibels. The value
 #  is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will be a
 #  scale of 4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
 #  value of 0 means no change.
 #boost = 0
 
-## emulate-eax:
+## emulate-eax: (global)
 #  Allows the standard reverb effect to be used in place of EAX reverb. EAX
 #  reverb processing is a bit more CPU intensive than standard, so this option
 #  allows a simpler effect to be used at the loss of some quality.
@@ -246,52 +214,59 @@
 ##
 [pulse]
 
-## spawn-server:
+## spawn-server: (global)
 #  Attempts to autospawn a PulseAudio server whenever needed (initializing the
 #  backend, enumerating devices, etc). Setting autospawn to false in Pulse's
 #  client.conf will still prevent autospawning even if this is set to true.
 #spawn-server = true
 
-## allow-moves:
+## allow-moves: (global)
 #  Allows PulseAudio to move active streams to different devices. Note that the
 #  device specifier (seen by applications) will not be updated when this
 #  occurs, and neither will the AL device configuration (sample rate, format,
 #  etc).
 #allow-moves = false
 
+## fix-rate:
+#  Specifies whether to match the playback stream's sample rate to the device's
+#  sample rate. Enabling this forces OpenAL Soft to mix sources and effects
+#  directly to the actual output rate, avoiding a second resample pass by the
+#  PulseAudio server.
+#fix-rate = false
+
 ##
 ## ALSA backend stuff
 ##
 [alsa]
 
-## device:
+## device: (global)
 #  Sets the device name for the default playback device.
 #device = default
 
-## device-prefix:
+## device-prefix: (global)
 #  Sets the prefix used by the discovered (non-default) playback devices. This
 #  will be appended with "CARD=c,DEV=d", where c is the card id and d is the
 #  device index for the requested device name.
 #device-prefix = plughw:
 
-## device-prefix-*:
+## device-prefix-*: (global)
 #  Card- and device-specific prefixes may be used to override the device-prefix
 #  option. The option may specify the card id (eg, device-prefix-NVidia), or
 #  the card id and device index (eg, device-prefix-NVidia-0). The card id is
 #  case-sensitive.
 #device-prefix- =
 
-## capture:
+## capture: (global)
 #  Sets the device name for the default capture device.
 #capture = default
 
-## capture-prefix:
+## capture-prefix: (global)
 #  Sets the prefix used by the discovered (non-default) capture devices. This
 #  will be appended with "CARD=c,DEV=d", where c is the card id and d is the
 #  device number for the requested device name.
 #capture-prefix = plughw:
 
-## capture-prefix-*:
+## capture-prefix-*: (global)
 #  Card- and device-specific prefixes may be used to override the
 #  capture-prefix option. The option may specify the card id (eg,
 #  capture-prefix-NVidia), or the card id and device index (eg,
@@ -305,16 +280,23 @@
 #  and anything else will force mmap off.
 #mmap = true
 
+## allow-resampler:
+#  Specifies whether to allow ALSA's built-in resampler. Enabling this will
+#  allow the playback device to be set to a different sample rate than the
+#  actual output, causing ALSA to apply its own resampling pass after OpenAL
+#  Soft resamples and mixes the sources and effects for output.
+#allow-resampler = false
+
 ##
 ## OSS backend stuff
 ##
 [oss]
 
-## device:
+## device: (global)
 #  Sets the device name for OSS output.
 #device = /dev/dsp
 
-## capture:
+## capture: (global)
 #  Sets the device name for OSS capture.
 #capture = /dev/dsp
 
@@ -323,7 +305,7 @@
 ##
 [solaris]
 
-## device:
+## device: (global)
 #  Sets the device name for Solaris output.
 #device = /dev/audio
 
@@ -332,13 +314,24 @@
 ##
 [qsa]
 
-## device:
-#  Sets the device name for the default playback device.
-#device = default
-
-## capture:
-#  Sets the device name for the default capture device.
-#capture = default
+##
+## JACK backend stuff
+##
+[jack]
+
+## spawn-server: (global)
+#  Attempts to autospawn a JACK server whenever needed (initializing the
+#  backend, opening devices, etc).
+#spawn-server = false
+
+## buffer-size:
+#  Sets the update buffer size, in samples, that the backend will keep buffered
+#  to handle the server's real-time processing requests. This value must be a
+#  power of 2, or else it will be rounded up to the next power of 2. If it is
+#  less than JACK's buffer update size, it will be clamped. This option may
+#  be useful in case the server's update size is too small and doesn't give the
+#  mixer time to keep enough audio available for the processing requests.
+#buffer-size = 0
 
 ##
 ## MMDevApi backend stuff
@@ -360,12 +353,12 @@
 ##
 [port]
 
-## device:
+## device: (global)
 #  Sets the device index for output. Negative values will use the default as
 #  given by PortAudio itself.
 #device = -1
 
-## capture:
+## capture: (global)
 #  Sets the device index for capture. Negative values will use the default as
 #  given by PortAudio itself.
 #capture = -1
@@ -375,8 +368,13 @@
 ##
 [wave]
 
-## file:
+## file: (global)
 #  Sets the filename of the wave file to write to. An empty name prevents the
 #  backend from opening, even when explicitly requested.
 #  THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION!
 #file =
+
+## bformat: (global)
+#  Creates AMB format files using first-order ambisonics instead of a standard
+#  single- or multi-channel .wav file.
+#bformat = false

+ 2 - 2
libs/openal-soft/cmake/CheckFileOffsetBits.cmake

@@ -17,12 +17,12 @@ MACRO(CHECK_FILE_OFFSET_BITS)
   IF(NOT DEFINED _FILE_OFFSET_BITS)
     MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files")
     TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64
-      ${CMAKE_BINARY_DIR}
+      ${CMAKE_CURRENT_BINARY_DIR}
       ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
       COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS})
     IF(NOT __WITHOUT_FILE_OFFSET_BITS_64)
       TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64
-        ${CMAKE_BINARY_DIR}
+        ${CMAKE_CURRENT_BINARY_DIR}
         ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c
         COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64)
     ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64)

+ 7 - 7
libs/openal-soft/cmake/CheckSharedFunctionExists.cmake

@@ -58,12 +58,12 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE)
       "${CMAKE_CONFIGURABLE_FILE_CONTENT}\nvoid cmakeRequireSymbol(int dummy,...){(void)dummy;}\nint main()\n{\n  cmakeRequireSymbol(0,&${SYMBOL});\n  return 0;\n}\n")
 
     CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in"
-      "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY)
+      "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY)
 
     MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY}")
     TRY_COMPILE(${VARIABLE}
-      ${CMAKE_BINARY_DIR}
-      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c
+      ${CMAKE_CURRENT_BINARY_DIR}
+      ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c
       COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
       CMAKE_FLAGS 
       -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS}
@@ -74,18 +74,18 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE)
     IF(${VARIABLE})
       MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - found")
       SET(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}")
-      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 
+      FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
         "Determining if the ${SYMBOL} "
         "exist in ${LIBRARY} passed with the following output:\n"
-        "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
+        "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
         "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
     ELSE(${VARIABLE})
       MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - not found.")
       SET(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}")
-      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 
+      FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
         "Determining if the ${SYMBOL} "
         "exist in ${LIBRARY} failed with the following output:\n"
-        "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
+        "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n"
         "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n")
     ENDIF(${VARIABLE})
   ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")

+ 4 - 2
libs/openal-soft/cmake/FindDSound.cmake

@@ -9,14 +9,16 @@
 #
 
 find_path(DSOUND_INCLUDE_DIR
-          PATHS "${DXSDK_DIR}/include"
           NAMES dsound.h
+          PATHS "${DXSDK_DIR}"
+          PATH_SUFFIXES include
           DOC "The DirectSound include directory"
 )
 
 find_library(DSOUND_LIBRARY
-             PATHS "${DXSDK_DIR}/lib"
              NAMES dsound
+             PATHS "${DXSDK_DIR}"
+             PATH_SUFFIXES lib lib/x86 lib/x64
              DOC "The DirectSound library"
 )
 

+ 218 - 169
libs/openal-soft/cmake/FindSDL_sound.cmake

@@ -146,196 +146,219 @@ if(SDL2_FOUND OR SDL_FOUND)
         # The ;-framework Cocoa seems to be confusing CMake once the OS X
         # framework support was added. I was told that breaking up the list
         # would fix the problem.
-        set(TMP_TRY_LIBS)
+        set(TMP_LIBS "")
         if(SDL2_FOUND)
+            set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY})
             foreach(lib ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY})
-                set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"")
+                set(TMP_LIBS "${TMP_LIBS} \"${lib}\"")
             endforeach()
             set(TMP_INCLUDE_DIRS ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
         else()
+            set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
             foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY})
-                set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"")
+                set(TMP_LIBS "${TMP_LIBS} \"${lib}\"")
             endforeach()
             set(TMP_INCLUDE_DIRS ${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR})
         endif()
 
-        # message("TMP_TRY_LIBS ${TMP_TRY_LIBS}")
+        # Keep trying to build a temp project until we find all missing libs.
+        set(TRY_AGAIN TRUE)
+        WHILE(TRY_AGAIN)
+            set(TRY_AGAIN FALSE)
+            # message("TMP_TRY_LIBS ${TMP_TRY_LIBS}")
 
-        # Write the CMakeLists.txt and test project
-        # Weird, this is still sketchy. If I don't quote the variables
-        # in the TARGET_LINK_LIBRARIES, I seem to loose everything
-        # in the SDL2_LIBRARY string after the "-framework".
-        # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
-        file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
-            "cmake_minimum_required(VERSION 2.8)
-            project(DetermineSoundLibs C)
-            include_directories(${TMP_INCLUDE_DIRS})
-            add_executable(DetermineSoundLibs DetermineSoundLibs.c)
-            target_link_libraries(DetermineSoundLibs ${TMP_TRY_LIBS})"
-        )
-        unset(TMP_INCLUDE_DIRS)
-        unset(TMP_TRY_LIBS)
+            # Write the CMakeLists.txt and test project
+            # Weird, this is still sketchy. If I don't quote the variables
+            # in the TARGET_LINK_LIBRARIES, I seem to loose everything
+            # in the SDL2_LIBRARY string after the "-framework".
+            # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work.
+            file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt
+                "cmake_minimum_required(VERSION 2.8)
+                project(DetermineSoundLibs C)
+                include_directories(${TMP_INCLUDE_DIRS})
+                add_executable(DetermineSoundLibs DetermineSoundLibs.c)
+                target_link_libraries(DetermineSoundLibs ${TMP_LIBS})"
+            )
 
-        try_compile(
-            MY_RESULT
-            ${PROJECT_BINARY_DIR}/CMakeTmp
-            ${PROJECT_BINARY_DIR}/CMakeTmp
-            DetermineSoundLibs
-            OUTPUT_VARIABLE MY_OUTPUT
-        )
-        # message("${MY_RESULT}")
-        # message(${MY_OUTPUT})
+            try_compile(
+                MY_RESULT
+                ${PROJECT_BINARY_DIR}/CMakeTmp
+                ${PROJECT_BINARY_DIR}/CMakeTmp
+                DetermineSoundLibs
+                OUTPUT_VARIABLE MY_OUTPUT
+            )
+            # message("${MY_RESULT}")
+            # message(${MY_OUTPUT})
 
-        if(NOT MY_RESULT)
-            # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
-            # I think Timidity is also compiled in statically.
-            # I've never had to explcitly link against Quicktime, so I'll skip that for now.
+            if(NOT MY_RESULT)
+                # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically.
+                # I think Timidity is also compiled in statically.
+                # I've never had to explcitly link against Quicktime, so I'll skip that for now.
 
-            set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY})
+                # Find libmath
+                if("${MY_OUTPUT}" MATCHES "cos@@GLIBC")
+                    find_library(MATH_LIBRARY NAMES m)
+                    if(MATH_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MATH_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MATH_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif(MATH_LIBRARY)
+                endif("${MY_OUTPUT}" MATCHES "cos@@GLIBC")
 
-            # Find MikMod
-            if("${MY_OUTPUT}" MATCHES "MikMod_")
-                find_library(MIKMOD_LIBRARY
-                    NAMES libmikmod-coreaudio mikmod
-                    PATHS
-                        ENV MIKMODDIR
-                        ENV SDLSOUNDDIR
-                        ENV SDLDIR
-                        /sw
-                        /opt/local
-                        /opt/csw
-                        /opt
-                    PATH_SUFFIXES lib
-                )
-                if(MIKMOD_LIBRARY)
-                    set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
-                endif(MIKMOD_LIBRARY)
-            endif("${MY_OUTPUT}" MATCHES "MikMod_")
+                # Find MikMod
+                if("${MY_OUTPUT}" MATCHES "MikMod_")
+                    find_library(MIKMOD_LIBRARY
+                        NAMES libmikmod-coreaudio mikmod
+                        PATHS
+                            ENV MIKMODDIR
+                            ENV SDLSOUNDDIR
+                            ENV SDLDIR
+                            /sw
+                            /opt/local
+                            /opt/csw
+                            /opt
+                        PATH_SUFFIXES lib
+                    )
+                    if(MIKMOD_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MIKMOD_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif(MIKMOD_LIBRARY)
+                endif("${MY_OUTPUT}" MATCHES "MikMod_")
 
-            # Find ModPlug
-            if("${MY_OUTPUT}" MATCHES "MODPLUG_")
-                find_library(MODPLUG_LIBRARY
-                    NAMES modplug
-                    PATHS
-                        ENV MODPLUGDIR
-                        ENV SDLSOUNDDIR
-                        ENV SDLDIR
-                        /sw
-                        /opt/local
-                        /opt/csw
-                        /opt
-                    PATH_SUFFIXES lib
-                )
-                if(MODPLUG_LIBRARY)
-                    set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
+                # Find ModPlug
+                if("${MY_OUTPUT}" MATCHES "MODPLUG_")
+                    find_library(MODPLUG_LIBRARY
+                        NAMES modplug
+                        PATHS
+                            ENV MODPLUGDIR
+                            ENV SDLSOUNDDIR
+                            ENV SDLDIR
+                            /sw
+                            /opt/local
+                            /opt/csw
+                            /opt
+                        PATH_SUFFIXES lib
+                    )
+                    if(MODPLUG_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MODPLUG_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif()
                 endif()
-            endif()
 
-            # Find Ogg and Vorbis
-            if("${MY_OUTPUT}" MATCHES "ov_")
-                find_library(VORBIS_LIBRARY
-                    NAMES vorbis Vorbis VORBIS
-                    PATHS
-                        ENV VORBISDIR
-                        ENV OGGDIR
-                        ENV SDLSOUNDDIR
-                        ENV SDLDIR
-                        /sw
-                        /opt/local
-                        /opt/csw
-                        /opt
-                    PATH_SUFFIXES lib
-                )
-                if(VORBIS_LIBRARY)
-                    set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
-                endif()
-                find_library(OGG_LIBRARY
-                    NAMES ogg Ogg OGG
-                    PATHS
-                        ENV OGGDIR
-                        ENV VORBISDIR
-                        ENV SDLSOUNDDIR
-                        ENV SDLDIR
-                        /sw
-                        /opt/local
-                        /opt/csw
-                        /opt
-                    PATH_SUFFIXES lib
-                )
-                if(OGG_LIBRARY)
-                    set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
-                endif()
-            endif()
+                # Find Ogg and Vorbis
+                if("${MY_OUTPUT}" MATCHES "ov_")
+                    find_library(VORBISFILE_LIBRARY
+                        NAMES vorbisfile VorbisFile VORBISFILE
+                        PATHS
+                            ENV VORBISDIR
+                            ENV OGGDIR
+                            ENV SDLSOUNDDIR
+                            ENV SDLDIR
+                            /sw
+                            /opt/local
+                            /opt/csw
+                            /opt
+                        PATH_SUFFIXES lib
+                    )
+                    if(VORBISFILE_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBISFILE_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${VORBISFILE_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif()
 
-            # Find SMPEG
-            if("${MY_OUTPUT}" MATCHES "SMPEG_")
-                find_library(SMPEG_LIBRARY
-                    NAMES smpeg SMPEG Smpeg SMpeg
-                    PATHS
-                        ENV SMPEGDIR
-                        ENV SDLSOUNDDIR
-                        ENV SDLDIR
-                        /sw
-                        /opt/local
-                        /opt/csw
-                        /opt
-                    PATH_SUFFIXES lib
-                )
-                if(SMPEG_LIBRARY)
-                    set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
-                endif()
-            endif()
+                    find_library(VORBIS_LIBRARY
+                        NAMES vorbis Vorbis VORBIS
+                        PATHS
+                            ENV OGGDIR
+                            ENV VORBISDIR
+                            ENV SDLSOUNDDIR
+                            ENV SDLDIR
+                            /sw
+                            /opt/local
+                            /opt/csw
+                            /opt
+                        PATH_SUFFIXES lib
+                    )
+                    if(VORBIS_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${VORBIS_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif()
 
+                    find_library(OGG_LIBRARY
+                        NAMES ogg Ogg OGG
+                        PATHS
+                            ENV OGGDIR
+                            ENV VORBISDIR
+                            ENV SDLSOUNDDIR
+                            ENV SDLDIR
+                            /sw
+                            /opt/local
+                            /opt/csw
+                            /opt
+                        PATH_SUFFIXES lib
+                    )
+                    if(OGG_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${OGG_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif()
+                endif()
 
-            # Find FLAC
-            if("${MY_OUTPUT}" MATCHES "FLAC_")
-                find_library(FLAC_LIBRARY
-                    NAMES flac FLAC
-                    PATHS
-                        ENV FLACDIR
-                        ENV SDLSOUNDDIR
-                        ENV SDLDIR
-                        /sw
-                        /opt/local
-                        /opt/csw
-                        /opt
-                    PATH_SUFFIXES lib
-                )
-                if(FLAC_LIBRARY)
-                    set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
+                # Find SMPEG
+                if("${MY_OUTPUT}" MATCHES "SMPEG_")
+                    find_library(SMPEG_LIBRARY
+                        NAMES smpeg SMPEG Smpeg SMpeg
+                        PATHS
+                            ENV SMPEGDIR
+                            ENV SDLSOUNDDIR
+                            ENV SDLDIR
+                            /sw
+                            /opt/local
+                            /opt/csw
+                            /opt
+                        PATH_SUFFIXES lib
+                    )
+                    if(SMPEG_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${SMPEG_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif()
                 endif()
-            endif()
 
 
-            # Hmmm...Speex seems to depend on Ogg. This might be a problem if
-            # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
-            # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
-            # above for here or if two ogg entries will screw up things.
-            if("${MY_OUTPUT}" MATCHES "speex_")
-                find_library(SPEEX_LIBRARY
-                    NAMES speex SPEEX
-                    PATHS
-                        ENV SPEEXDIR
-                        ENV SDLSOUNDDIR
-                        ENV SDLDIR
-                        /sw
-                        /opt/local
-                        /opt/csw
-                        /opt
-                    PATH_SUFFIXES lib
-                )
-                if(SPEEX_LIBRARY)
-                    set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
+                # Find FLAC
+                if("${MY_OUTPUT}" MATCHES "FLAC_")
+                    find_library(FLAC_LIBRARY
+                        NAMES flac FLAC
+                        PATHS
+                            ENV FLACDIR
+                            ENV SDLSOUNDDIR
+                            ENV SDLDIR
+                            /sw
+                            /opt/local
+                            /opt/csw
+                            /opt
+                        PATH_SUFFIXES lib
+                    )
+                    if(FLAC_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${FLAC_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif()
                 endif()
 
-                # Find OGG (needed for Speex)
-                # We might have already found Ogg for Vorbis, so skip it if so.
-                if(NOT OGG_LIBRARY)
-                    find_library(OGG_LIBRARY
-                        NAMES ogg Ogg OGG
+
+                # Hmmm...Speex seems to depend on Ogg. This might be a problem if
+                # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull
+                # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff
+                # above for here or if two ogg entries will screw up things.
+                if("${MY_OUTPUT}" MATCHES "speex_")
+                    find_library(SPEEX_LIBRARY
+                        NAMES speex SPEEX
                         PATHS
-                            ENV OGGDIR
-                            ENV VORBISDIR
                             ENV SPEEXDIR
                             ENV SDLSOUNDDIR
                             ENV SDLDIR
@@ -345,16 +368,42 @@ if(SDL2_FOUND OR SDL_FOUND)
                             /opt
                         PATH_SUFFIXES lib
                     )
-                    if(OGG_LIBRARY)
-                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+                    if(SPEEX_LIBRARY)
+                        set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY})
+                        set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${SPEEX_LIBRARY}\"")
+                        set(TRY_AGAIN TRUE)
+                    endif()
+
+                    # Find OGG (needed for Speex)
+                    # We might have already found Ogg for Vorbis, so skip it if so.
+                    if(NOT OGG_LIBRARY)
+                        find_library(OGG_LIBRARY
+                            NAMES ogg Ogg OGG
+                            PATHS
+                                ENV OGGDIR
+                                ENV VORBISDIR
+                                ENV SPEEXDIR
+                                ENV SDLSOUNDDIR
+                                ENV SDLDIR
+                                /sw
+                                /opt/local
+                                /opt/csw
+                                /opt
+                            PATH_SUFFIXES lib
+                        )
+                        if(OGG_LIBRARY)
+                            set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY})
+                            set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${OGG_LIBRARY}\"")
+                            set(TRY_AGAIN TRUE)
+                        endif()
                     endif()
                 endif()
             endif()
+        ENDWHILE()
+        unset(TMP_INCLUDE_DIRS)
+        unset(TMP_LIBS)
 
-            set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries")
-        else()
-            set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARY} CACHE INTERNAL "SDL_sound and dependent libraries")
-        endif()
+        set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries")
     endif()
 endif()
 

+ 5 - 5
libs/openal-soft/common/threads.c

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -733,11 +733,11 @@ int altimespec_get(struct timespec *ts, int base)
 #endif
 
 
-void al_nssleep(time_t sec, long nsec)
+void al_nssleep(unsigned long nsec)
 {
     struct timespec ts, rem;
-    ts.tv_sec = sec;
-    ts.tv_nsec = nsec;
+    ts.tv_sec = nsec / 1000000000ul;
+    ts.tv_nsec = nsec % 1000000000ul;
 
     while(althrd_sleep(&ts, &rem) == -1)
         ts = rem;

+ 10 - 12
libs/openal-soft/config.h.in

@@ -9,7 +9,7 @@
 /* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but
  * recent versions (at least 4.5.1) do recognize GCC's __restrict. */
 #define restrict __restrict
-#endif 
+#endif
 
 /* Define any available alignment declaration */
 #define ALIGN(x) ${ALIGN_DECL}
@@ -26,14 +26,12 @@
 /* Define if we have SSE CPU extensions */
 #cmakedefine HAVE_SSE
 #cmakedefine HAVE_SSE2
+#cmakedefine HAVE_SSE3
 #cmakedefine HAVE_SSE4_1
 
 /* Define if we have ARM Neon CPU extensions */
 #cmakedefine HAVE_NEON
 
-/* Define if we have FluidSynth support */
-#cmakedefine HAVE_FLUIDSYNTH
-
 /* Define if we have the ALSA backend */
 #cmakedefine HAVE_ALSA
 
@@ -64,6 +62,9 @@
 /* Define if we have the PulseAudio backend */
 #cmakedefine HAVE_PULSEAUDIO
 
+/* Define if we have the JACK backend */
+#cmakedefine HAVE_JACK
+
 /* Define if we have the CoreAudio backend */
 #cmakedefine HAVE_COREAUDIO
 
@@ -79,6 +80,9 @@
 /* Define if we have the lrintf function */
 #cmakedefine HAVE_LRINTF
 
+/* Define if we have the modff function */
+#cmakedefine HAVE_MODFF
+
 /* Define if we have the strtof function */
 #cmakedefine HAVE_STRTOF
 
@@ -136,8 +140,8 @@
 /* Define if we have malloc.h */
 #cmakedefine HAVE_MALLOC_H
 
-/* Define if we have ftw.h */
-#cmakedefine HAVE_FTW_H
+/* Define if we have dirent.h */
+#cmakedefine HAVE_DIRENT_H
 
 /* Define if we have io.h */
 #cmakedefine HAVE_IO_H
@@ -181,12 +185,6 @@
 /* Define if we have __control87_2() */
 #cmakedefine HAVE___CONTROL87_2
 
-/* Define if we have ftw() */
-#cmakedefine HAVE_FTW
-
-/* Define if we have _wfindfirst() */
-#cmakedefine HAVE__WFINDFIRST
-
 /* Define if we have pthread_setschedparam() */
 #cmakedefine HAVE_PTHREAD_SETSCHEDPARAM
 

+ 10 - 0
libs/openal-soft/env-vars.txt

@@ -69,3 +69,13 @@ sound (i.e., sounds that are supposed to be behind you sound like they're in
 front, and vice-versa). Setting this to "true" or "1" will negate the localized
 Z coordinate to attempt to fix output for apps that have incorrect front/back
 panning.
+
+__ALSOFT_SUSPEND_CONTEXT
+Due to the OpenAL spec not being very clear about them, behavior of the
+alcSuspendContext and alcProcessContext methods has varied, and because of
+that, previous versions of OpenAL Soft had them no-op. Creative's hardware
+drivers and the Rapture3D driver, however, use these methods to batch changes,
+which some applications make use of to protect against partial updates. In an
+attempt to standardize on that behavior, OpenAL Soft has changed those methods
+accordingly. Setting this to "ignore" restores the previous no-op behavior for
+applications that interact poorly with the new behavior.

+ 64 - 10
libs/openal-soft/examples/alffplay.c

@@ -548,6 +548,7 @@ static int audio_thread(void *userdata)
     MovieState *movState = (MovieState*)userdata;
     uint8_t *samples = NULL;
     ALsizei buffer_len;
+    ALenum fmt;
 
     alGenBuffers(AUDIO_BUFFER_QUEUE_SIZE, movState->audio.buffer);
     alGenSources(1, &movState->audio.source);
@@ -557,56 +558,107 @@ static int audio_thread(void *userdata)
 
     av_new_packet(&movState->audio.pkt, 0);
 
-    /* Find a suitable format for OpenAL. Currently does not handle surround
-     * sound (everything non-mono becomes stereo). */
+    /* Find a suitable format for OpenAL. */
+    movState->audio.format = AL_NONE;
     if(movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8 ||
        movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8P)
     {
         movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_U8;
         movState->audio.frame_size = 1;
+        if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
+           alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+           (fmt=alGetEnumValue("AL_FORMAT_71CHN8")) != AL_NONE && fmt != -1)
+        {
+            movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+            movState->audio.frame_size *= 8;
+            movState->audio.format = fmt;
+        }
+        if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
+            movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
+           alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+           (fmt=alGetEnumValue("AL_FORMAT_51CHN8")) != AL_NONE && fmt != -1)
+        {
+            movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+            movState->audio.frame_size *= 6;
+            movState->audio.format = fmt;
+        }
         if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
         {
             movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
             movState->audio.frame_size *= 1;
             movState->audio.format = AL_FORMAT_MONO8;
         }
-        else
+        if(movState->audio.format == AL_NONE)
         {
             movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
             movState->audio.frame_size *= 2;
             movState->audio.format = AL_FORMAT_STEREO8;
         }
     }
-    else if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT ||
-             movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) &&
-            alIsExtensionPresent("AL_EXT_FLOAT32"))
+    if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT ||
+        movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) &&
+       alIsExtensionPresent("AL_EXT_FLOAT32"))
     {
         movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_FLT;
         movState->audio.frame_size = 4;
+        if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
+           alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+           (fmt=alGetEnumValue("AL_FORMAT_71CHN32")) != AL_NONE && fmt != -1)
+        {
+            movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+            movState->audio.frame_size *= 8;
+            movState->audio.format = fmt;
+        }
+        if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
+            movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
+           alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+           (fmt=alGetEnumValue("AL_FORMAT_51CHN32")) != AL_NONE && fmt != -1)
+        {
+            movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+            movState->audio.frame_size *= 6;
+            movState->audio.format = fmt;
+        }
         if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
         {
             movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
             movState->audio.frame_size *= 1;
             movState->audio.format = AL_FORMAT_MONO_FLOAT32;
         }
-        else
+        if(movState->audio.format == AL_NONE)
         {
             movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
             movState->audio.frame_size *= 2;
             movState->audio.format = AL_FORMAT_STEREO_FLOAT32;
         }
     }
-    else
+    if(movState->audio.format == AL_NONE)
     {
         movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_S16;
         movState->audio.frame_size = 2;
+        if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 &&
+           alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+           (fmt=alGetEnumValue("AL_FORMAT_71CHN16")) != AL_NONE && fmt != -1)
+        {
+            movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+            movState->audio.frame_size *= 8;
+            movState->audio.format = fmt;
+        }
+        if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 ||
+            movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) &&
+           alIsExtensionPresent("AL_EXT_MCFORMATS") &&
+           (fmt=alGetEnumValue("AL_FORMAT_51CHN16")) != AL_NONE && fmt != -1)
+        {
+            movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout;
+            movState->audio.frame_size *= 6;
+            movState->audio.format = fmt;
+        }
         if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO)
         {
             movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO;
             movState->audio.frame_size *= 1;
             movState->audio.format = AL_FORMAT_MONO16;
         }
-        else
+        if(movState->audio.format == AL_NONE)
         {
             movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO;
             movState->audio.frame_size *= 2;
@@ -632,7 +684,9 @@ static int audio_thread(void *userdata)
         movState->audio.dst_ch_layout,
         movState->audio.dst_sample_fmt,
         movState->audio.st->codec->sample_rate,
-        movState->audio.st->codec->channel_layout,
+        movState->audio.st->codec->channel_layout ?
+            movState->audio.st->codec->channel_layout :
+            av_get_default_channel_layout(movState->audio.st->codec->channels),
         movState->audio.st->codec->sample_fmt,
         movState->audio.st->codec->sample_rate,
         0, NULL

+ 3 - 3
libs/openal-soft/examples/alloopback.c

@@ -65,13 +65,13 @@ void SDLCALL RenderSDLSamples(void *userdata, Uint8 *stream, int len)
  * buffer ID. */
 static ALuint CreateSineWave(void)
 {
-    ALshort data[44100];
+    ALshort data[44100*4];
     ALuint buffer;
     ALenum err;
     ALuint i;
 
-    for(i = 0;i < 44100;i++)
-        data[i] = (ALshort)(sin(i * 441.0 / 44100.0 * 2.0*M_PI)*32767.0);
+    for(i = 0;i < 44100*4;i++)
+        data[i] = (ALshort)(sin(i/44100.0 * 1000.0 * 2.0*M_PI) * 32767.0);
 
     /* Buffer the audio data into a new buffer object. */
     buffer = 0;

+ 1 - 1
libs/openal-soft/hrtf.txt

@@ -14,7 +14,7 @@ sides.
 
 The default data set is based on the KEMAR HRTF data provided by MIT, which can
 be found at <http://sound.media.mit.edu/resources/KEMAR.html>. It's only
-available when using 44100hz playback.
+available when using 44100hz or 48000hz playback.
 
 
 Custom HRTF Data Sets

+ 40 - 2
libs/openal-soft/include/AL/alext.h

@@ -13,8 +13,8 @@
  *
  * You should have received a copy of the GNU Library General Public
  *  License along with this library; if not, write to the
- *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- *  Boston, MA  02111-1307, USA.
+ *  Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  * Or go to http://www.gnu.org/copyleft/lgpl.html
  */
 
@@ -393,6 +393,44 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device);
 #endif
 #endif
 
+#ifndef AL_EXT_BFORMAT
+#define AL_EXT_BFORMAT 1
+#define AL_FORMAT_BFORMAT2D_8                    0x20021
+#define AL_FORMAT_BFORMAT2D_16                   0x20022
+#define AL_FORMAT_BFORMAT2D_FLOAT32              0x20023
+#define AL_FORMAT_BFORMAT3D_8                    0x20031
+#define AL_FORMAT_BFORMAT3D_16                   0x20032
+#define AL_FORMAT_BFORMAT3D_FLOAT32              0x20033
+#endif
+
+#ifndef AL_EXT_MULAW_BFORMAT
+#define AL_EXT_MULAW_BFORMAT 1
+#define AL_FORMAT_BFORMAT2D_MULAW                0x10031
+#define AL_FORMAT_BFORMAT3D_MULAW                0x10032
+#endif
+
+#ifndef ALC_SOFT_HRTF
+#define ALC_SOFT_HRTF 1
+#define ALC_HRTF_SOFT                            0x1992
+#define ALC_DONT_CARE_SOFT                       0x0002
+#define ALC_HRTF_STATUS_SOFT                     0x1993
+#define ALC_HRTF_DISABLED_SOFT                   0x0000
+#define ALC_HRTF_ENABLED_SOFT                    0x0001
+#define ALC_HRTF_DENIED_SOFT                     0x0002
+#define ALC_HRTF_REQUIRED_SOFT                   0x0003
+#define ALC_HRTF_HEADPHONES_DETECTED_SOFT        0x0004
+#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT         0x0005
+#define ALC_NUM_HRTF_SPECIFIERS_SOFT             0x1994
+#define ALC_HRTF_SPECIFIER_SOFT                  0x1995
+#define ALC_HRTF_ID_SOFT                         0x1996
+typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index);
+typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index);
+ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs);
+#endif
+#endif
+
 #ifdef __cplusplus
 }
 #endif

+ 1 - 1
libs/openal-soft/include/AL/efx-presets.h

@@ -345,7 +345,7 @@ typedef struct {
 /* Driving Presets */
 
 #define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \
-    { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
+    { 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 }
 
 #define EFX_REVERB_PRESET_DRIVING_PITGARAGE \
     { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 }

+ 4 - 4
libs/openal-soft/include/align.h

@@ -1,16 +1,16 @@
 #ifndef AL_ALIGN_H
 #define AL_ALIGN_H
 
-#ifdef HAVE_STDALIGN_H
+#if defined(HAVE_STDALIGN_H) && defined(HAVE_C11_ALIGNAS)
 #include <stdalign.h>
 #endif
 
 #ifndef alignas
-#ifdef HAVE_C11_ALIGNAS
-#define alignas _Alignas
-#elif defined(IN_IDE_PARSER)
+#if defined(IN_IDE_PARSER)
 /* KDevelop has problems with our align macro, so just use nothing for parsing. */
 #define alignas(x)
+#elif defined(HAVE_C11_ALIGNAS)
+#define alignas _Alignas
 #else
 /* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For
  * maximum compatibility, only provide constant integer values to alignas. */

+ 99 - 78
libs/openal-soft/include/atomic.h

@@ -8,74 +8,81 @@
 extern "C" {
 #endif
 
-typedef void *volatile XchgPtr;
-
 /* Atomics using C11 */
 #ifdef HAVE_C11_ATOMIC
 
 #include <stdatomic.h>
 
-inline int ExchangeInt(volatile int *ptr, int newval)
-{ return atomic_exchange(ptr, newval); }
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{ return atomic_exchange(ptr, newval); }
+#define almemory_order memory_order
+#define almemory_order_relaxed memory_order_relaxed
+#define almemory_order_consume memory_order_consume
+#define almemory_order_acquire memory_order_acquire
+#define almemory_order_release memory_order_release
+#define almemory_order_acq_rel memory_order_acq_rel
+#define almemory_order_seq_cst memory_order_seq_cst
 
+#define ATOMIC(T)  T _Atomic
 
-#define ATOMIC(T)  struct { T _Atomic value; }
+#define ATOMIC_INIT(_val, _newval)  atomic_init((_val), (_newval))
+#define ATOMIC_INIT_STATIC(_newval) ATOMIC_VAR_INIT(_newval)
 
-#define ATOMIC_INIT(_val, _newval) atomic_init(&(_val)->value, (_newval))
-#define ATOMIC_INIT_STATIC(_newval) {ATOMIC_VAR_INIT(_newval)}
+#define PARAM2(f, a, b, ...)           (f((a), (b)))
+#define PARAM3(f, a, b, c, ...)        (f((a), (b), (c)))
+#define PARAM5(f, a, b, c, d, e, ...)  (f((a), (b), (c), (d), (e)))
 
-#define ATOMIC_LOAD(_val)            atomic_load(&(_val)->value)
-#define ATOMIC_STORE(_val, _newval)  atomic_store(&(_val)->value, (_newval))
+#define ATOMIC_LOAD(...)   PARAM2(atomic_load_explicit, __VA_ARGS__, memory_order_seq_cst)
+#define ATOMIC_STORE(...)  PARAM3(atomic_store_explicit, __VA_ARGS__, memory_order_seq_cst)
 
-#define ATOMIC_ADD(T, _val, _incr) atomic_fetch_add(&(_val)->value, (_incr))
-#define ATOMIC_SUB(T, _val, _decr) atomic_fetch_sub(&(_val)->value, (_decr))
+#define ATOMIC_ADD(T, ...) PARAM3(atomic_fetch_add_explicit, __VA_ARGS__, memory_order_seq_cst)
+#define ATOMIC_SUB(T, ...) PARAM3(atomic_fetch_sub_explicit, __VA_ARGS__, memory_order_seq_cst)
 
-#define ATOMIC_EXCHANGE(T, _val, _newval) atomic_exchange(&(_val)->value, (_newval))
-#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval)             \
-    atomic_compare_exchange_strong(&(_val)->value, (_oldval), (_newval))
-#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, _val, _oldval, _newval)               \
-    atomic_compare_exchange_weak(&(_val)->value, (_oldval), (_newval))
+#define ATOMIC_EXCHANGE(T, ...) PARAM3(atomic_exchange_explicit, __VA_ARGS__, memory_order_seq_cst)
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, ...)                                \
+    PARAM5(atomic_compare_exchange_strong_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst)
+#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...)                                  \
+    PARAM5(atomic_compare_exchange_weak_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst)
 
 /* Atomics using GCC intrinsics */
 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
 
-inline int ExchangeInt(volatile int *ptr, int newval)
-{ return __sync_lock_test_and_set(ptr, newval); }
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{ return __sync_lock_test_and_set(ptr, newval); }
-
+enum almemory_order {
+    almemory_order_relaxed,
+    almemory_order_consume,
+    almemory_order_acquire,
+    almemory_order_release,
+    almemory_order_acq_rel,
+    almemory_order_seq_cst
+};
 
 #define ATOMIC(T)  struct { T volatile value; }
 
 #define ATOMIC_INIT(_val, _newval)  do { (_val)->value = (_newval); } while(0)
 #define ATOMIC_INIT_STATIC(_newval) {(_newval)}
 
-#define ATOMIC_LOAD(_val)  __extension__({      \
+#define ATOMIC_LOAD(_val, ...)  __extension__({ \
     __typeof((_val)->value) _r = (_val)->value; \
     __asm__ __volatile__("" ::: "memory");      \
     _r;                                         \
 })
-#define ATOMIC_STORE(_val, _newval)  do {  \
-    __asm__ __volatile__("" ::: "memory"); \
-    (_val)->value = (_newval);             \
+#define ATOMIC_STORE(_val, _newval, ...)  do { \
+    __asm__ __volatile__("" ::: "memory");     \
+    (_val)->value = (_newval);                 \
 } while(0)
 
-#define ATOMIC_ADD(T, _val, _incr)  __extension__({                           \
+#define ATOMIC_ADD(T, _val, _incr, ...)  __extension__({                      \
     static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
     __sync_fetch_and_add(&(_val)->value, (_incr));                            \
 })
-#define ATOMIC_SUB(T, _val, _decr)  __extension__({                           \
+#define ATOMIC_SUB(T, _val, _decr, ...)  __extension__({                      \
     static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
     __sync_fetch_and_sub(&(_val)->value, (_decr));                            \
 })
 
-#define ATOMIC_EXCHANGE(T, _val, _newval)  __extension__({                    \
+#define ATOMIC_EXCHANGE(T, _val, _newval, ...)  __extension__({               \
     static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
     __sync_lock_test_and_set(&(_val)->value, (_newval));                      \
 })
-#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) __extension__({ \
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \
     static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
     T _o = *(_oldval);                                                        \
     *(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval));  \
@@ -112,41 +119,38 @@ inline void *ExchangePtr(XchgPtr *ptr, void *newval)
 )
 
 
-inline int ExchangeInt(volatile int *dest, int newval)
-{ int ret; WRAP_XCHG("l", ret, dest, newval); return ret; }
-
-#ifdef __i386__
-inline void *ExchangePtr(XchgPtr *dest, void *newval)
-{ void *ret; WRAP_XCHG("l", ret, dest, newval); return ret; }
-#else
-inline void *ExchangePtr(XchgPtr *dest, void *newval)
-{ void *ret; WRAP_XCHG("q", ret, dest, newval); return ret; }
-#endif
-
+enum almemory_order {
+    almemory_order_relaxed,
+    almemory_order_consume,
+    almemory_order_acquire,
+    almemory_order_release,
+    almemory_order_acq_rel,
+    almemory_order_seq_cst
+};
 
 #define ATOMIC(T)  struct { T volatile value; }
 
 #define ATOMIC_INIT(_val, _newval)  do { (_val)->value = (_newval); } while(0)
 #define ATOMIC_INIT_STATIC(_newval) {(_newval)}
 
-#define ATOMIC_LOAD(_val)  __extension__({      \
+#define ATOMIC_LOAD(_val, ...)  __extension__({ \
     __typeof((_val)->value) _r = (_val)->value; \
     __asm__ __volatile__("" ::: "memory");      \
     _r;                                         \
 })
-#define ATOMIC_STORE(_val, _newval)  do {  \
-    __asm__ __volatile__("" ::: "memory"); \
-    (_val)->value = (_newval);             \
+#define ATOMIC_STORE(_val, _newval, ...)  do { \
+    __asm__ __volatile__("" ::: "memory");     \
+    (_val)->value = (_newval);                 \
 } while(0)
 
-#define ATOMIC_ADD(T, _val, _incr)  __extension__({                           \
+#define ATOMIC_ADD(T, _val, _incr, ...)  __extension__({                      \
     static_assert(sizeof(T)==4, "Type "#T" has incorrect size!");             \
     static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
     T _r;                                                                     \
     WRAP_ADD(_r, &(_val)->value, (T)(_incr));                                 \
     _r;                                                                       \
 })
-#define ATOMIC_SUB(T, _val, _decr)  __extension__({                           \
+#define ATOMIC_SUB(T, _val, _decr, ...)  __extension__({                      \
     static_assert(sizeof(T)==4, "Type "#T" has incorrect size!");             \
     static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
     T _r;                                                                     \
@@ -154,7 +158,7 @@ inline void *ExchangePtr(XchgPtr *dest, void *newval)
     _r;                                                                       \
 })
 
-#define ATOMIC_EXCHANGE(T, _val, _newval)  __extension__({                    \
+#define ATOMIC_EXCHANGE(T, _val, _newval, ...)  __extension__({               \
     static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \
     static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
     T _r;                                                                     \
@@ -162,7 +166,7 @@ inline void *ExchangePtr(XchgPtr *dest, void *newval)
     else if(sizeof(T) == 8) WRAP_XCHG("q", _r, &(_val)->value, (T)(_newval)); \
     _r;                                                                       \
 })
-#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) __extension__({ \
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \
     static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \
     static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \
     T _old = *(_oldval);                                                      \
@@ -222,42 +226,40 @@ inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG
 #define WRAP_XCHG(T, _func, _ptr, _newval)  ((T(*)(T volatile*,T))_func)((_ptr), (_newval))
 #define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) ((bool(*)(T volatile*,T,T*))_func)((_ptr), (_newval), (_oldval))
 
-inline int ExchangeInt(volatile int *ptr, int newval)
-{ return WRAP_XCHG(int,AtomicSwap32,ptr,newval); }
-
-#ifdef _WIN64
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{ return WRAP_XCHG(void*,AtomicSwap64,ptr,newval); }
-#else
-inline void *ExchangePtr(XchgPtr *ptr, void *newval)
-{ return WRAP_XCHG(void*,AtomicSwap32,ptr,newval); }
-#endif
 
+enum almemory_order {
+    almemory_order_relaxed,
+    almemory_order_consume,
+    almemory_order_acquire,
+    almemory_order_release,
+    almemory_order_acq_rel,
+    almemory_order_seq_cst
+};
 
 #define ATOMIC(T)  struct { T volatile value; }
 
 #define ATOMIC_INIT(_val, _newval)  do { (_val)->value = (_newval); } while(0)
 #define ATOMIC_INIT_STATIC(_newval) {(_newval)}
 
-#define ATOMIC_LOAD(_val)  ((_val)->value)
-#define ATOMIC_STORE(_val, _newval)  do {  \
-    (_val)->value = (_newval);             \
+#define ATOMIC_LOAD(_val, ...)  ((_val)->value)
+#define ATOMIC_STORE(_val, _newval, ...)  do {  \
+    (_val)->value = (_newval);                  \
 } while(0)
 
 int _al_invalid_atomic_size(); /* not defined */
 
-#define ATOMIC_ADD(T, _val, _incr)                                            \
+#define ATOMIC_ADD(T, _val, _incr, ...)                                       \
     ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicAdd32, &(_val)->value, (_incr)) :  \
      (T)_al_invalid_atomic_size())
-#define ATOMIC_SUB(T, _val, _decr)                                            \
+#define ATOMIC_SUB(T, _val, _decr, ...)                                       \
     ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicSub32, &(_val)->value, (_decr)) :  \
      (T)_al_invalid_atomic_size())
 
-#define ATOMIC_EXCHANGE(T, _val, _newval)                                     \
+#define ATOMIC_EXCHANGE(T, _val, _newval, ...)                                \
     ((sizeof(T)==4) ? WRAP_XCHG(T, AtomicSwap32, &(_val)->value, (_newval)) : \
      (sizeof(T)==8) ? WRAP_XCHG(T, AtomicSwap64, &(_val)->value, (_newval)) : \
      (T)_al_invalid_atomic_size())
-#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval)             \
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...)        \
     ((sizeof(T)==4) ? WRAP_CMPXCHG(T, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \
      (sizeof(T)==8) ? WRAP_CMPXCHG(T, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \
      (bool)_al_invalid_atomic_size())
@@ -273,26 +275,22 @@ int _al_invalid_atomic_size(); /* not defined */
 #define ATOMIC_LOAD_UNSAFE(_val)  (0)
 #define ATOMIC_STORE_UNSAFE(_val, _newval)  ((void)0)
 
-#define ATOMIC_LOAD(_val)  (0)
-#define ATOMIC_STORE(_val, _newval)  ((void)0)
+#define ATOMIC_LOAD(_val, ...)  (0)
+#define ATOMIC_STORE(_val, _newval, ...)  ((void)0)
 
-#define ATOMIC_ADD(T, _val, _incr)  (0)
-#define ATOMIC_SUB(T, _val, _decr)  (0)
+#define ATOMIC_ADD(T, _val, _incr, ...)  (0)
+#define ATOMIC_SUB(T, _val, _decr, ...)  (0)
 
-#define ATOMIC_EXCHANGE(T, _val, _newval)  (0)
-#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) (0)
+#define ATOMIC_EXCHANGE(T, _val, _newval, ...)  (0)
+#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) (0)
 #endif
 
 /* If no weak cmpxchg is provided (not all systems will have one), substitute a
  * strong cmpxchg. */
 #ifndef ATOMIC_COMPARE_EXCHANGE_WEAK
-#define ATOMIC_COMPARE_EXCHANGE_WEAK(a, b, c, d) ATOMIC_COMPARE_EXCHANGE_STRONG(a, b, c, d)
+#define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG
 #endif
 
-/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non-
- * atomic variables. */
-#define COMPARE_EXCHANGE(_val, _oldval, _newval)  ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false))
-
 
 typedef unsigned int uint;
 typedef ATOMIC(uint) RefCount;
@@ -306,6 +304,29 @@ inline uint IncrementRef(RefCount *ptr)
 inline uint DecrementRef(RefCount *ptr)
 { return ATOMIC_SUB(uint, ptr, 1)-1; }
 
+
+/* NOTE: Not atomic! */
+inline int ExchangeInt(volatile int *ptr, int newval)
+{
+    int old = *ptr;
+    *ptr = newval;
+    return old;
+}
+
+typedef void *volatile XchgPtr;
+/* NOTE: Not atomic! */
+inline void *ExchangePtr(XchgPtr *ptr, void *newval)
+{
+    void *old = *ptr;
+    *ptr = newval;
+    return old;
+}
+
+/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non-
+ * atomic variables. */
+#define COMPARE_EXCHANGE(_val, _oldval, _newval)  ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false))
+
+
 #ifdef __cplusplus
 }
 #endif

+ 4 - 0
libs/openal-soft/include/static_assert.h

@@ -10,7 +10,11 @@
 #else
 #define CTASTR2(_pre,_post) _pre##_post
 #define CTASTR(_pre,_post) CTASTR2(_pre,_post)
+#if defined(__COUNTER__)
 #define static_assert(_cond, _msg) typedef struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } CTASTR(static_assertion_,__COUNTER__)
+#else
+#define static_assert(_cond, _msg) struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); }
+#endif
 #endif
 #endif
 

+ 1 - 1
libs/openal-soft/include/threads.h

@@ -234,7 +234,7 @@ void altss_delete(altss_t tss_id);
 
 int altimespec_get(struct timespec *ts, int base);
 
-void al_nssleep(time_t sec, long nsec);
+void al_nssleep(unsigned long nsec);
 
 #ifdef __cplusplus
 }

+ 237 - 70
libs/openal-soft/utils/alsoft-config/mainwindow.cpp

@@ -1,3 +1,6 @@
+
+#include "config.h"
+
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QSettings>
@@ -10,26 +13,92 @@ static const struct {
     char backend_name[16];
     char menu_string[32];
 } backendMenuList[] = {
-#ifdef Q_OS_WIN32
-    { "mmdevapi", "Add MMDevAPI" },
-    { "dsound", "Add DirectSound" },
-    { "winmm", "Add Windows Multimedia" },
-#endif
-#ifdef Q_OS_MAC
-    { "core", "Add CoreAudio" },
+#ifdef HAVE_JACK
+    { "jack", "Add JACK" },
 #endif
+#ifdef HAVE_PULSEAUDIO
     { "pulse", "Add PulseAudio" },
-#ifdef Q_OS_UNIX
+#endif
+#ifdef HAVE_ALSA
     { "alsa", "Add ALSA" },
+#endif
+#ifdef HAVE_COREAUDIO
+    { "core", "Add CoreAudio" },
+#endif
+#ifdef HAVE_OSS
     { "oss", "Add OSS" },
+#endif
+#ifdef HAVE_SOLARIS
     { "solaris", "Add Solaris" },
+#endif
+#ifdef HAVE_SNDIO
     { "sndio", "Add SndIO" },
+#endif
+#ifdef HAVE_QSA
     { "qsa", "Add QSA" },
 #endif
+#ifdef HAVE_MMDEVAPI
+    { "mmdevapi", "Add MMDevAPI" },
+#endif
+#ifdef HAVE_DSOUND
+    { "dsound", "Add DirectSound" },
+#endif
+#ifdef HAVE_WINMM
+    { "winmm", "Add Windows Multimedia" },
+#endif
+#ifdef HAVE_PORTAUDIO
     { "port", "Add PortAudio" },
+#endif
+#ifdef HAVE_OPENSL
     { "opensl", "Add OpenSL" },
+#endif
+
     { "null", "Add Null Output" },
+#ifdef HAVE_WAVE
     { "wave", "Add Wave Writer" },
+#endif
+    { "", "" }
+};
+
+static const struct {
+    const char name[64];
+    const char value[16];
+} speakerModeList[] = {
+    { "Autodetect", "" },
+    { "Mono", "mono" },
+    { "Stereo", "stereo" },
+    { "Quadrophonic", "quad" },
+    { "5.1 Surround (Side)", "surround51" },
+    { "5.1 Surround (Rear)", "surround51rear" },
+    { "6.1 Surround", "surround61" },
+    { "7.1 Surround", "surround71" },
+
+    { "", "" }
+}, sampleTypeList[] = {
+    { "Autodetect", "" },
+    { "8-bit int", "int8" },
+    { "8-bit uint", "uint8" },
+    { "16-bit int", "int16" },
+    { "16-bit uint", "uint16" },
+    { "32-bit int", "int32" },
+    { "32-bit uint", "uint32" },
+    { "32-bit float", "float32" },
+
+    { "", "" }
+}, resamplerList[] = {
+    { "Default", "" },
+    { "Point (low quality, very fast)", "point" },
+    { "Linear (basic quality, fast)", "linear" },
+    { "4-Point Sinc (good quality)", "sinc4" },
+    { "8-Point Sinc (high quality, slow)", "sinc8" },
+    { "Band-limited Sinc (very high quality, very slow)", "bsinc" },
+
+    { "", "" }
+}, stereoModeList[] = {
+    { "Autodetect", "" },
+    { "Speakers", "speakers" },
+    { "Headphones", "headphones" },
+
     { "", "" }
 };
 
@@ -104,11 +173,65 @@ MainWindow::MainWindow(QWidget *parent) :
     mSourceCountValidator(NULL),
     mEffectSlotValidator(NULL),
     mSourceSendValidator(NULL),
-    mSampleRateValidator(NULL),
-    mReverbBoostValidator(NULL)
+    mSampleRateValidator(NULL)
 {
     ui->setupUi(this);
 
+    for(int i = 0;speakerModeList[i].name[0];i++)
+        ui->channelConfigCombo->addItem(speakerModeList[i].name);
+    ui->channelConfigCombo->adjustSize();
+    for(int i = 0;sampleTypeList[i].name[0];i++)
+        ui->sampleFormatCombo->addItem(sampleTypeList[i].name);
+    ui->sampleFormatCombo->adjustSize();
+    for(int i = 0;resamplerList[i].name[0];i++)
+        ui->resamplerComboBox->addItem(resamplerList[i].name);
+    ui->resamplerComboBox->adjustSize();
+    for(int i = 0;stereoModeList[i].name[0];i++)
+        ui->stereoModeCombo->addItem(stereoModeList[i].name);
+    ui->stereoModeCombo->adjustSize();
+
+    ui->hrtfStateComboBox->adjustSize();
+
+#if !defined(HAVE_NEON) && !defined(HAVE_SSE)
+    ui->cpuExtDisabledLabel->move(ui->cpuExtDisabledLabel->x(), ui->cpuExtDisabledLabel->y() - 60);
+#else
+    ui->cpuExtDisabledLabel->setVisible(false);
+#endif
+
+#ifndef HAVE_NEON
+
+#ifndef HAVE_SSE4_1
+#ifndef HAVE_SSE3
+#ifndef HAVE_SSE2
+#ifndef HAVE_SSE
+    ui->enableSSECheckBox->setVisible(false);
+#endif /* !SSE */
+    ui->enableSSE2CheckBox->setVisible(false);
+#endif /* !SSE2 */
+    ui->enableSSE3CheckBox->setVisible(false);
+#endif /* !SSE3 */
+    ui->enableSSE41CheckBox->setVisible(false);
+#endif /* !SSE4.1 */
+    ui->enableNeonCheckBox->setVisible(false);
+
+#else /* !Neon */
+
+#ifndef HAVE_SSE4_1
+#ifndef HAVE_SSE3
+#ifndef HAVE_SSE2
+#ifndef HAVE_SSE
+    ui->enableNeonCheckBox->move(ui->enableNeonCheckBox->x(), ui->enableNeonCheckBox->y() - 30);
+    ui->enableSSECheckBox->setVisible(false);
+#endif /* !SSE */
+    ui->enableSSE2CheckBox->setVisible(false);
+#endif /* !SSE2 */
+    ui->enableSSE3CheckBox->setVisible(false);
+#endif /* !SSE3 */
+    ui->enableSSE41CheckBox->setVisible(false);
+#endif /* !SSE4.1 */
+
+#endif
+
     mPeriodSizeValidator = new QIntValidator(64, 8192, this);
     ui->periodSizeEdit->setValidator(mPeriodSizeValidator);
     mPeriodCountValidator = new QIntValidator(2, 16, this);
@@ -123,9 +246,6 @@ MainWindow::MainWindow(QWidget *parent) :
     mSampleRateValidator = new QIntValidator(8000, 192000, this);
     ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator);
 
-    mReverbBoostValidator = new QDoubleValidator(-12.0, +12.0, 1, this);
-    ui->reverbBoostEdit->setValidator(mReverbBoostValidator);
-
     connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile()));
     connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile()));
 
@@ -146,9 +266,6 @@ MainWindow::MainWindow(QWidget *parent) :
     ui->disabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu);
     connect(ui->disabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDisabledBackendMenu(QPoint)));
 
-    connect(ui->reverbBoostSlider, SIGNAL(valueChanged(int)), this, SLOT(updateReverbBoostEdit(int)));
-    connect(ui->reverbBoostEdit, SIGNAL(textEdited(QString)), this, SLOT(updateReverbBoostSlider(QString)));
-
     loadConfig(getDefaultConfigName());
 }
 
@@ -161,7 +278,6 @@ MainWindow::~MainWindow()
     delete mEffectSlotValidator;
     delete mSourceSendValidator;
     delete mSampleRateValidator;
-    delete mReverbBoostValidator;
 }
 
 void MainWindow::loadConfigFromFile()
@@ -179,12 +295,19 @@ void MainWindow::loadConfig(const QString &fname)
     ui->sampleFormatCombo->setCurrentIndex(0);
     if(sampletype.isEmpty() == false)
     {
-        for(int i = 1;i < ui->sampleFormatCombo->count();i++)
+        for(int i = 0;sampleTypeList[i].name[i];i++)
         {
-            QString item = ui->sampleFormatCombo->itemText(i);
-            if(item.startsWith(sampletype))
+            if(sampletype == sampleTypeList[i].value)
             {
-                ui->sampleFormatCombo->setCurrentIndex(i);
+                for(int j = 1;j < ui->sampleFormatCombo->count();j++)
+                {
+                    QString item = ui->sampleFormatCombo->itemText(j);
+                    if(item == sampleTypeList[i].name)
+                    {
+                        ui->sampleFormatCombo->setCurrentIndex(j);
+                        break;
+                    }
+                }
                 break;
             }
         }
@@ -194,12 +317,19 @@ void MainWindow::loadConfig(const QString &fname)
     ui->channelConfigCombo->setCurrentIndex(0);
     if(channelconfig.isEmpty() == false)
     {
-        for(int i = 1;i < ui->channelConfigCombo->count();i++)
+        for(int i = 0;speakerModeList[i].name[i];i++)
         {
-            QString item = ui->channelConfigCombo->itemText(i);
-            if(item.startsWith(channelconfig))
+            if(channelconfig == speakerModeList[i].value)
             {
-                ui->channelConfigCombo->setCurrentIndex(i);
+                for(int j = 1;j < ui->channelConfigCombo->count();j++)
+                {
+                    QString item = ui->channelConfigCombo->itemText(j);
+                    if(item == speakerModeList[i].name)
+                    {
+                        ui->channelConfigCombo->setCurrentIndex(j);
+                        break;
+                    }
+                }
                 break;
             }
         }
@@ -222,18 +352,49 @@ void MainWindow::loadConfig(const QString &fname)
     ui->srcSendLineEdit->insert(settings.value("sends").toString());
 
     QString resampler = settings.value("resampler").toString().trimmed();
-    if(resampler.isEmpty())
-        ui->resamplerComboBox->setCurrentIndex(0);
-    else
+    ui->resamplerComboBox->setCurrentIndex(0);
+    if(resampler.isEmpty() == false)
+    {
+        /* The "cubic" resampler is no longer supported. It's been replaced by
+         * "sinc4". */
+        if(resampler == "cubic")
+            resampler = "sinc4";
+
+        for(int i = 0;resamplerList[i].name[i];i++)
+        {
+            if(resampler == resamplerList[i].value)
+            {
+                for(int j = 1;j < ui->resamplerComboBox->count();j++)
+                {
+                    QString item = ui->resamplerComboBox->itemText(j);
+                    if(item == resamplerList[i].name)
+                    {
+                        ui->resamplerComboBox->setCurrentIndex(j);
+                        break;
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    QString stereomode = settings.value("stereo-mode").toString().trimmed();
+    ui->stereoModeCombo->setCurrentIndex(0);
+    if(stereomode.isEmpty() == false)
     {
-        for(int i = 1;i < ui->resamplerComboBox->count();i++)
+        for(int i = 0;stereoModeList[i].name[i];i++)
         {
-            QString item = ui->resamplerComboBox->itemText(i);
-            int end = item.indexOf(' ');
-            if(end < 0) end = item.size();
-            if(resampler.size() == end && resampler.compare(item.leftRef(end), Qt::CaseInsensitive) == 0)
+            if(stereomode == stereoModeList[i].value)
             {
-                ui->resamplerComboBox->setCurrentIndex(i);
+                for(int j = 1;j < ui->stereoModeCombo->count();j++)
+                {
+                    QString item = ui->stereoModeCombo->itemText(j);
+                    if(item == stereoModeList[i].name)
+                    {
+                        ui->stereoModeCombo->setCurrentIndex(j);
+                        break;
+                    }
+                }
                 break;
             }
         }
@@ -262,17 +423,18 @@ void MainWindow::loadConfig(const QString &fname)
                    disabledCpuExts.begin(), std::mem_fun_ref(&QString::trimmed));
     ui->enableSSECheckBox->setChecked(!disabledCpuExts.contains("sse", Qt::CaseInsensitive));
     ui->enableSSE2CheckBox->setChecked(!disabledCpuExts.contains("sse2", Qt::CaseInsensitive));
+    ui->enableSSE3CheckBox->setChecked(!disabledCpuExts.contains("sse3", Qt::CaseInsensitive));
     ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive));
     ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive));
 
     if(settings.value("hrtf").toString() == QString())
-        ui->hrtfEnableButton->setChecked(true);
+        ui->hrtfStateComboBox->setCurrentIndex(0);
     else
     {
         if(settings.value("hrtf", true).toBool())
-            ui->hrtfForceButton->setChecked(true);
+            ui->hrtfStateComboBox->setCurrentIndex(1);
         else
-            ui->hrtfDisableButton->setChecked(true);
+            ui->hrtfStateComboBox->setCurrentIndex(2);
     }
 
     QStringList hrtf_tables = settings.value("hrtf_tables").toStringList();
@@ -323,8 +485,6 @@ void MainWindow::loadConfig(const QString &fname)
     }
 
     ui->emulateEaxCheckBox->setChecked(settings.value("reverb/emulate-eax", false).toBool());
-    ui->reverbBoostEdit->clear();
-    ui->reverbBoostEdit->insert(settings.value("reverb/boost").toString());
 
     QStringList excludefx = settings.value("excludefx").toStringList();
     if(excludefx.size() == 1)
@@ -371,15 +531,27 @@ void MainWindow::saveConfig(const QString &fname) const
     }
 
     QString str = ui->sampleFormatCombo->currentText();
-    str.truncate(str.indexOf('-'));
-    settings.setValue("sample-type", str.trimmed());
+    for(int i = 0;sampleTypeList[i].name[0];i++)
+    {
+        if(str == sampleTypeList[i].name)
+        {
+            settings.setValue("sample-type", sampleTypeList[i].value);
+            break;
+        }
+    }
 
     str = ui->channelConfigCombo->currentText();
-    str.truncate(str.indexOf('-'));
-    settings.setValue("channels", str.trimmed());
+    for(int i = 0;speakerModeList[i].name[0];i++)
+    {
+        if(str == speakerModeList[i].name)
+        {
+            settings.setValue("channels", speakerModeList[i].value);
+            break;
+        }
+    }
 
     uint rate = ui->sampleRateCombo->currentText().toUInt();
-    if(rate == 0)
+    if(!(rate > 0))
         settings.setValue("frequency", QString());
     else
         settings.setValue("frequency", rate);
@@ -390,12 +562,24 @@ void MainWindow::saveConfig(const QString &fname) const
     settings.setValue("sources", ui->srcCountLineEdit->text());
     settings.setValue("slots", ui->effectSlotLineEdit->text());
 
-    if(ui->resamplerComboBox->currentIndex() == 0)
-        settings.setValue("resampler", QString());
-    else
+    str = ui->resamplerComboBox->currentText();
+    for(int i = 0;resamplerList[i].name[0];i++)
     {
-        str = ui->resamplerComboBox->currentText();
-        settings.setValue("resampler", str.split(' ').first().toLower());
+        if(str == resamplerList[i].name)
+        {
+            settings.setValue("resampler", resamplerList[i].value);
+            break;
+        }
+    }
+
+    str = ui->stereoModeCombo->currentText();
+    for(int i = 0;stereoModeList[i].name[0];i++)
+    {
+        if(str == stereoModeList[i].name)
+        {
+            settings.setValue("stereo-mode", stereoModeList[i].value);
+            break;
+        }
     }
 
     QStringList strlist;
@@ -403,15 +587,17 @@ void MainWindow::saveConfig(const QString &fname) const
         strlist.append("sse");
     if(!ui->enableSSE2CheckBox->isChecked())
         strlist.append("sse2");
+    if(!ui->enableSSE3CheckBox->isChecked())
+        strlist.append("sse3");
     if(!ui->enableSSE41CheckBox->isChecked())
         strlist.append("sse4.1");
     if(!ui->enableNeonCheckBox->isChecked())
         strlist.append("neon");
     settings.setValue("disable-cpu-exts", strlist.join(QChar(',')));
 
-    if(ui->hrtfForceButton->isChecked())
+    if(ui->hrtfStateComboBox->currentIndex() == 1)
         settings.setValue("hrtf", "true");
-    else if(ui->hrtfDisableButton->isChecked())
+    else if(ui->hrtfStateComboBox->currentIndex() == 2)
         settings.setValue("hrtf", "false");
     else
         settings.setValue("hrtf", QString());
@@ -449,12 +635,6 @@ void MainWindow::saveConfig(const QString &fname) const
     else
         settings.setValue("reverb/emulate-eax", QString()/*"false"*/);
 
-    // TODO: Remove check when we can properly match global values.
-    if(ui->reverbBoostSlider->sliderPosition() == 0)
-        settings.setValue("reverb/boost", QString());
-    else
-        settings.setValue("reverb/boost", ui->reverbBoostEdit->text());
-
     strlist.clear();
     if(!ui->enableEaxReverbCheck->isChecked())
         strlist.append("eaxreverb");
@@ -645,16 +825,3 @@ void MainWindow::showDisabledBackendMenu(QPoint pt)
             ui->disabledBackendList->addItem(iter.value());
     }
 }
-
-void MainWindow::updateReverbBoostEdit(int value)
-{
-    ui->reverbBoostEdit->clear();
-    if(value != 0)
-        ui->reverbBoostEdit->insert(QString::number(value/10.0, 'f', 1));
-}
-
-void MainWindow::updateReverbBoostSlider(QString value)
-{
-    int pos = int(value.toFloat()*10.0f);
-    ui->reverbBoostSlider->setSliderPosition(pos);
-}

+ 0 - 4
libs/openal-soft/utils/alsoft-config/mainwindow.h

@@ -35,9 +35,6 @@ private slots:
     void showEnabledBackendMenu(QPoint pt);
     void showDisabledBackendMenu(QPoint pt);
 
-    void updateReverbBoostEdit(int size);
-    void updateReverbBoostSlider(QString value);
-
 private:
     Ui::MainWindow *ui;
 
@@ -47,7 +44,6 @@ private:
     QValidator *mEffectSlotValidator;
     QValidator *mSourceSendValidator;
     QValidator *mSampleRateValidator;
-    QValidator *mReverbBoostValidator;
 
     void loadConfig(const QString &fname);
     void saveConfig(const QString &fname) const;

+ 138 - 263
libs/openal-soft/utils/alsoft-config/mainwindow.ui

@@ -57,8 +57,8 @@
       <property name="geometry">
        <rect>
         <x>120</x>
-        <y>20</y>
-        <width>188</width>
+        <y>50</y>
+        <width>78</width>
         <height>22</height>
        </rect>
       </property>
@@ -69,52 +69,12 @@ float and converted to the output sample type as needed.</string>
       <property name="sizeAdjustPolicy">
        <enum>QComboBox::AdjustToContents</enum>
       </property>
-      <item>
-       <property name="text">
-        <string>- Autodetect -</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>int8 - signed 8-bit int</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>uint8 - unsigned 8-bit int</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>int16 - signed 16-bit int</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>uint16 - unsigned 16-bit int</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>int32 - signed 32-bit int</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>uint32 - unsigned 32-bit int</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>float32 - 32-bit float</string>
-       </property>
-      </item>
      </widget>
      <widget class="QLabel" name="label_5">
       <property name="geometry">
        <rect>
         <x>10</x>
-        <y>20</y>
+        <y>50</y>
         <width>101</width>
         <height>21</height>
        </rect>
@@ -130,7 +90,7 @@ float and converted to the output sample type as needed.</string>
       <property name="geometry">
        <rect>
         <x>10</x>
-        <y>50</y>
+        <y>20</y>
         <width>101</width>
         <height>21</height>
        </rect>
@@ -146,8 +106,8 @@ float and converted to the output sample type as needed.</string>
       <property name="geometry">
        <rect>
         <x>120</x>
-        <y>50</y>
-        <width>227</width>
+        <y>20</y>
+        <width>78</width>
         <height>22</height>
        </rect>
       </property>
@@ -159,48 +119,13 @@ to stereo output.</string>
       <property name="sizeAdjustPolicy">
        <enum>QComboBox::AdjustToContents</enum>
       </property>
-      <item>
-       <property name="text">
-        <string>- Autodetect -</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>mono - 1-channel Mono</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>stereo - 2-channel Stereo</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>quad - 4-channel Quadraphonic</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>surround51 - 5.1 Surround Sound</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>surround61 - 6.1 Surround Sound</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>surround71 - 7.1 Surround Sound</string>
-       </property>
-      </item>
      </widget>
      <widget class="QComboBox" name="sampleRateCombo">
       <property name="geometry">
        <rect>
-        <x>120</x>
-        <y>80</y>
-        <width>111</width>
+        <x>370</x>
+        <y>20</y>
+        <width>96</width>
         <height>22</height>
        </rect>
       </property>
@@ -218,27 +143,22 @@ to stereo output.</string>
       </property>
       <item>
        <property name="text">
-        <string>- Autodetect -</string>
+        <string>Autodetect</string>
        </property>
       </item>
       <item>
        <property name="text">
-        <string>96000</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>48000</string>
+        <string>8000</string>
        </property>
       </item>
       <item>
        <property name="text">
-        <string>44100</string>
+        <string>11025</string>
        </property>
       </item>
       <item>
        <property name="text">
-        <string>32000</string>
+        <string>16000</string>
        </property>
       </item>
       <item>
@@ -248,26 +168,26 @@ to stereo output.</string>
       </item>
       <item>
        <property name="text">
-        <string>16000</string>
+        <string>32000</string>
        </property>
       </item>
       <item>
        <property name="text">
-        <string>11025</string>
+        <string>44100</string>
        </property>
       </item>
       <item>
        <property name="text">
-        <string>8000</string>
+        <string>48000</string>
        </property>
       </item>
      </widget>
      <widget class="QLabel" name="label_7">
       <property name="geometry">
        <rect>
-        <x>10</x>
-        <y>80</y>
-        <width>101</width>
+        <x>280</x>
+        <y>20</y>
+        <width>81</width>
         <height>21</height>
        </rect>
       </property>
@@ -282,73 +202,20 @@ to stereo output.</string>
       <property name="geometry">
        <rect>
         <x>10</x>
-        <y>200</y>
+        <y>180</y>
         <width>511</width>
-        <height>161</height>
+        <height>191</height>
        </rect>
       </property>
       <property name="title">
        <string>HRTF (Stereo only)</string>
       </property>
-      <widget class="QRadioButton" name="hrtfEnableButton">
-       <property name="geometry">
-        <rect>
-         <x>20</x>
-         <y>30</y>
-         <width>71</width>
-         <height>21</height>
-        </rect>
-       </property>
-       <property name="toolTip">
-        <string>Allows applications to request HRTF mixing.</string>
-       </property>
-       <property name="text">
-        <string>Enable</string>
-       </property>
-       <property name="checked">
-        <bool>true</bool>
-       </property>
-      </widget>
-      <widget class="QRadioButton" name="hrtfDisableButton">
-       <property name="geometry">
-        <rect>
-         <x>20</x>
-         <y>50</y>
-         <width>71</width>
-         <height>21</height>
-        </rect>
-       </property>
-       <property name="toolTip">
-        <string>Does not allow HRTF mixing, even when requested.</string>
-       </property>
-       <property name="text">
-        <string>Disable</string>
-       </property>
-      </widget>
-      <widget class="QRadioButton" name="hrtfForceButton">
-       <property name="geometry">
-        <rect>
-         <x>20</x>
-         <y>70</y>
-         <width>71</width>
-         <height>21</height>
-        </rect>
-       </property>
-       <property name="toolTip">
-        <string>Attempts to force HRTF mixing, even if applications request not
-to do it. This may override the channel configuration and
-sample rate.</string>
-       </property>
-       <property name="text">
-        <string>Force</string>
-       </property>
-      </widget>
       <widget class="QListWidget" name="hrtfFileList">
        <property name="geometry">
         <rect>
-         <x>110</x>
+         <x>20</x>
          <y>30</y>
-         <width>301</width>
+         <width>391</width>
          <height>121</height>
         </rect>
        </property>
@@ -378,7 +245,7 @@ contain these markers, which will be replaced as needed:
       <widget class="QPushButton" name="hrtfAddButton">
        <property name="geometry">
         <rect>
-         <x>419</x>
+         <x>420</x>
          <y>30</y>
          <width>81</width>
          <height>25</height>
@@ -399,7 +266,7 @@ contain these markers, which will be replaced as needed:
       <widget class="QPushButton" name="hrtfRemoveButton">
        <property name="geometry">
         <rect>
-         <x>419</x>
+         <x>420</x>
          <y>60</y>
          <width>81</width>
          <height>25</height>
@@ -414,12 +281,56 @@ contain these markers, which will be replaced as needed:
         </iconset>
        </property>
       </widget>
+      <widget class="QComboBox" name="hrtfStateComboBox">
+       <property name="geometry">
+        <rect>
+         <x>110</x>
+         <y>160</y>
+         <width>161</width>
+         <height>22</height>
+        </rect>
+       </property>
+       <property name="sizeAdjustPolicy">
+        <enum>QComboBox::AdjustToContentsOnFirstShow</enum>
+       </property>
+       <item>
+        <property name="text">
+         <string>Application preference</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Force on</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Force off</string>
+        </property>
+       </item>
+      </widget>
+      <widget class="QLabel" name="label_15">
+       <property name="geometry">
+        <rect>
+         <x>30</x>
+         <y>160</y>
+         <width>71</width>
+         <height>21</height>
+        </rect>
+       </property>
+       <property name="text">
+        <string>HRTF Mode:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
      </widget>
      <widget class="QGroupBox" name="groupBox_3">
       <property name="geometry">
        <rect>
         <x>10</x>
-        <y>110</y>
+        <y>90</y>
         <width>511</width>
         <height>91</height>
        </rect>
@@ -590,6 +501,37 @@ frames needed for each mixing update.</string>
        </widget>
       </widget>
      </widget>
+     <widget class="QLabel" name="label_14">
+      <property name="geometry">
+       <rect>
+        <x>280</x>
+        <y>50</y>
+        <width>81</width>
+        <height>21</height>
+       </rect>
+      </property>
+      <property name="text">
+       <string>Stereo Mode:</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+      </property>
+     </widget>
+     <widget class="QComboBox" name="stereoModeCombo">
+      <property name="geometry">
+       <rect>
+        <x>370</x>
+        <y>50</y>
+        <width>78</width>
+        <height>22</height>
+       </rect>
+      </property>
+      <property name="toolTip">
+       <string>How to treat stereo output. As headphones, HRTF or crossfeed
+filters may be used to improve binaural quality, which may not
+otherwise be suitable for speakers.</string>
+      </property>
+     </widget>
     </widget>
     <widget class="QWidget" name="tab_2">
      <attribute name="title">
@@ -737,7 +679,7 @@ value currently possible is 4.</string>
        <rect>
         <x>110</x>
         <y>120</y>
-        <width>185</width>
+        <width>78</width>
         <height>22</height>
        </rect>
       </property>
@@ -747,34 +689,14 @@ value currently possible is 4.</string>
       <property name="sizeAdjustPolicy">
        <enum>QComboBox::AdjustToContents</enum>
       </property>
-      <item>
-       <property name="text">
-        <string>- Default -</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>Point (low quality, fast)</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>Linear (basic quality, fast)</string>
-       </property>
-      </item>
-      <item>
-       <property name="text">
-        <string>Cubic Spline (good quality)</string>
-       </property>
-      </item>
      </widget>
-     <widget class="QGroupBox" name="groupBox_2">
+     <widget class="QGroupBox" name="cpuExtGroupBox">
       <property name="geometry">
        <rect>
         <x>10</x>
         <y>150</y>
         <width>511</width>
-        <height>91</height>
+        <height>121</height>
        </rect>
       </property>
       <property name="toolTip">
@@ -788,7 +710,7 @@ be useful for preventing those extensions from being used.</string>
       <widget class="QCheckBox" name="enableSSECheckBox">
        <property name="geometry">
         <rect>
-         <x>180</x>
+         <x>100</x>
          <y>20</y>
          <width>71</width>
          <height>31</height>
@@ -805,7 +727,7 @@ be useful for preventing those extensions from being used.</string>
        <property name="geometry">
         <rect>
          <x>180</x>
-         <y>50</y>
+         <y>20</y>
          <width>71</width>
          <height>31</height>
         </rect>
@@ -820,7 +742,7 @@ be useful for preventing those extensions from being used.</string>
       <widget class="QCheckBox" name="enableNeonCheckBox">
        <property name="geometry">
         <rect>
-         <x>260</x>
+         <x>100</x>
          <y>50</y>
          <width>71</width>
          <height>31</height>
@@ -836,7 +758,7 @@ be useful for preventing those extensions from being used.</string>
       <widget class="QCheckBox" name="enableSSE41CheckBox">
        <property name="geometry">
         <rect>
-         <x>260</x>
+         <x>340</x>
          <y>20</y>
          <width>71</width>
          <height>31</height>
@@ -849,6 +771,35 @@ be useful for preventing those extensions from being used.</string>
         <bool>true</bool>
        </property>
       </widget>
+      <widget class="QCheckBox" name="enableSSE3CheckBox">
+       <property name="geometry">
+        <rect>
+         <x>260</x>
+         <y>20</y>
+         <width>71</width>
+         <height>31</height>
+        </rect>
+       </property>
+       <property name="text">
+        <string>SSE3</string>
+       </property>
+       <property name="checked">
+        <bool>true</bool>
+       </property>
+      </widget>
+      <widget class="QLabel" name="cpuExtDisabledLabel">
+       <property name="geometry">
+        <rect>
+         <x>101</x>
+         <y>80</y>
+         <width>311</width>
+         <height>31</height>
+        </rect>
+       </property>
+       <property name="text">
+        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;No support enabled for CPU Extensions&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+       </property>
+      </widget>
      </widget>
     </widget>
     <widget class="QWidget" name="tab">
@@ -956,87 +907,11 @@ some quality.</string>
        <string>Emulate EAX Reverb:</string>
       </property>
      </widget>
-     <widget class="QGroupBox" name="groupBox_4">
-      <property name="geometry">
-       <rect>
-        <x>10</x>
-        <y>100</y>
-        <width>511</width>
-        <height>61</height>
-       </rect>
-      </property>
-      <property name="toolTip">
-       <string>Global amplification for reverb output, expressed in decibels.
-+6 will be a scale of (approximately) 2x, +12 will be a scale of
-4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A
-value of 0 means no change.</string>
-      </property>
-      <property name="title">
-       <string>Reverb Boost</string>
-      </property>
-      <widget class="QSlider" name="reverbBoostSlider">
-       <property name="geometry">
-        <rect>
-         <x>10</x>
-         <y>30</y>
-         <width>391</width>
-         <height>23</height>
-        </rect>
-       </property>
-       <property name="toolTip">
-        <string/>
-       </property>
-       <property name="minimum">
-        <number>-120</number>
-       </property>
-       <property name="maximum">
-        <number>120</number>
-       </property>
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="tickPosition">
-        <enum>QSlider::TicksBelow</enum>
-       </property>
-       <property name="tickInterval">
-        <number>10</number>
-       </property>
-      </widget>
-      <widget class="QLineEdit" name="reverbBoostEdit">
-       <property name="geometry">
-        <rect>
-         <x>410</x>
-         <y>30</y>
-         <width>51</width>
-         <height>22</height>
-        </rect>
-       </property>
-       <property name="alignment">
-        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-       </property>
-       <property name="placeholderText">
-        <string>0.0</string>
-       </property>
-      </widget>
-      <widget class="QLabel" name="label_12">
-       <property name="geometry">
-        <rect>
-         <x>460</x>
-         <y>30</y>
-         <width>31</width>
-         <height>21</height>
-        </rect>
-       </property>
-       <property name="text">
-        <string>dB</string>
-       </property>
-      </widget>
-     </widget>
      <widget class="QGroupBox" name="groupBox_5">
       <property name="geometry">
        <rect>
         <x>10</x>
-        <y>170</y>
+        <y>100</y>
         <width>511</width>
         <height>191</height>
        </rect>

+ 1 - 93
libs/openal-soft/utils/makehrtf.c

@@ -227,8 +227,7 @@ enum HeadModelT {
 // Desired output format from the command line.
 enum OutputFormatT {
   OF_NONE  = 0,
-  OF_MHR      ,   // OpenAL Soft MHR data set file.
-  OF_TABLE        // OpenAL Soft built-in table file (used when compiling).
+  OF_MHR          // OpenAL Soft MHR data set file.
 };
 
 // Unsigned integer type.
@@ -2089,84 +2088,6 @@ static int StoreMhr (const HrirDataT * hData, const char * filename) {
   return (1);
 }
 
-// Store the OpenAL Soft built-in table.
-static int StoreTable (const HrirDataT * hData, const char * filename) {
-  FILE * fp = NULL;
-  uint step, end, n, j, i;
-  int hpHist, v;
-  char text [128 + 1];
-
-  if ((fp = fopen (filename, "wb")) == NULL) {
-     fprintf (stderr, "Error:  Could not open table file '%s'.\n", filename);
-     return (0);
-  }
-  snprintf (text, 128, "/* Elevation metrics */\n"
-                       "static const ALubyte defaultAzCount[%u] = { ", hData -> mEvCount);
-  if (! WriteAscii (text, fp, filename))
-     return (0);
-  for (i = 0; i < hData -> mEvCount; i ++) {
-      snprintf (text, 128, "%u, ", hData -> mAzCount [i]);
-      if (! WriteAscii (text, fp, filename))
-         return (0);
-  }
-  snprintf (text, 128, "};\n"
-                       "static const ALushort defaultEvOffset[%u] = { ", hData -> mEvCount);
-  if (! WriteAscii (text, fp, filename))
-     return (0);
-  for (i = 0; i < hData -> mEvCount; i ++) {
-      snprintf (text, 128, "%u, ", hData -> mEvOffset [i]);
-      if (! WriteAscii (text, fp, filename))
-         return (0);
-  }
-  step = hData -> mIrSize;
-  end = hData -> mIrCount * step;
-  n = hData -> mIrPoints;
-  snprintf (text, 128, "};\n\n"
-                       "/* HRIR Coefficients */\n"
-                       "static const ALshort defaultCoeffs[%u] =\n{\n", hData -> mIrCount * n);
-  if (! WriteAscii (text, fp, filename))
-     return (0);
-  srand (0x31DF840C);
-  for (j = 0; j < end; j += step) {
-      if (! WriteAscii ("   ", fp, filename))
-         return (0);
-      hpHist = 0;
-      for (i = 0; i < n; i ++) {
-          v = HpTpdfDither (32767.0 * hData -> mHrirs [j + i], & hpHist);
-          snprintf (text, 128, " %+d,", v);
-          if (! WriteAscii (text, fp, filename))
-             return (0);
-      }
-      if (! WriteAscii ("\n", fp, filename))
-         return (0);
-  }
-  snprintf (text, 128, "};\n\n"
-                       "/* HRIR Delays */\n"
-                       "static const ALubyte defaultDelays[%u] =\n{\n"
-                       "   ", hData -> mIrCount);
-  if (! WriteAscii (text, fp, filename))
-     return (0);
-  for (j = 0; j < hData -> mIrCount; j ++) {
-      v = (int) fmin (round (hData -> mIrRate * hData -> mHrtds [j]), MAX_HRTD);
-      snprintf (text, 128, " %d,", v);
-      if (! WriteAscii (text, fp, filename))
-         return (0);
-  }
-  if (! WriteAscii ("\n};\n\n"
-                    "/* Default HRTF Definition */\n", fp, filename))
-     return (0);
-  snprintf (text, 128, "static const struct Hrtf DefaultHrtf = {\n"
-                       "    %u, %u, %u, defaultAzCount, defaultEvOffset,\n",
-                       hData -> mIrRate, hData -> mIrPoints, hData -> mEvCount);
-  if (! WriteAscii (text, fp, filename))
-     return (0);
-  if (! WriteAscii ("    defaultCoeffs, defaultDelays, NULL\n"
-                    "};\n", fp, filename))
-     return (0);
-  fclose (fp);
-  return (1);
-}
-
 // Process the data set definition to read and validate the data set metrics.
 static int ProcessMetrics (TokenReaderT * tr, const uint fftSize, const uint truncSize, HrirDataT * hData) {
   char ident [MAX_IDENT_LEN + 1];
@@ -2583,11 +2504,6 @@ static int ProcessDefinition (const char * inName, const uint outRate, const uin
       if (! StoreMhr (& hData, expName))
          return (0);
     break;
-    case OF_TABLE :
-      fprintf (stderr, "Creating OpenAL Soft table file...\n");
-      if (! StoreTable (& hData, expName))
-         return (0);
-    break;
     default :
     break;
   }
@@ -2619,8 +2535,6 @@ int main (const int argc, const char * argv []) {
      fprintf (stdout, "Commands:\n");
      fprintf (stdout, " -m, --make-mhr  Makes an OpenAL Soft compatible HRTF data set.\n");
      fprintf (stdout, "                 Defaults output to: ./oalsoft_hrtf_%%r.mhr\n");
-     fprintf (stdout, " -t, --make-tab  Makes the built-in table used when compiling OpenAL Soft.\n");
-     fprintf (stdout, "                 Defaults output to: ./hrtf_tables.inc\n");
      fprintf (stdout, " -h, --help      Displays this help information.\n\n");
      fprintf (stdout, "Options:\n");
      fprintf (stdout, " -r=<rate>       Change the data set sample rate to the specified value and\n");
@@ -2647,12 +2561,6 @@ int main (const int argc, const char * argv []) {
      else
         outName = "./oalsoft_hrtf_%r.mhr";
      outFormat = OF_MHR;
-  } else if ((strcmp (argv [1], "--make-tab") == 0) || (strcmp (argv [1], "-t") == 0)) {
-     if (argc > 3)
-        outName = argv [3];
-     else
-        outName = "./hrtf_tables.inc";
-     outFormat = OF_TABLE;
   } else {
      fprintf (stderr, "Error:  Invalid command '%s'.\n", argv [1]);
      return (-1);

+ 30 - 0
libs/openal-soft/utils/openal-info.c

@@ -147,6 +147,35 @@ static void printALCInfo(ALCdevice *device)
     }
 }
 
+static void printHRTFInfo(ALCdevice *device)
+{
+    LPALCGETSTRINGISOFT alcGetStringiSOFT;
+    ALCint num_hrtfs;
+
+    if(alcIsExtensionPresent(device, "ALC_SOFT_HRTF") == ALC_FALSE)
+    {
+        printf("HRTF extension not available\n");
+        return;
+    }
+
+    alcGetStringiSOFT = alcGetProcAddress(device, "alcGetStringiSOFT");
+
+    alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtfs);
+    if(!num_hrtfs)
+        printf("No HRTFs found\n");
+    else
+    {
+        ALCint i;
+        printf("Available HRTFs:\n");
+        for(i = 0;i < num_hrtfs;++i)
+        {
+            const ALCchar *name = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
+            printf("    %s\n", name);
+        }
+    }
+    checkALCErrors(device);
+}
+
 static void printALInfo(void)
 {
     printf("OpenAL vendor string: %s\n", alGetString(AL_VENDOR));
@@ -287,6 +316,7 @@ int main(int argc, char *argv[])
         return 1;
     }
     printALCInfo(device);
+    printHRTFInfo(device);
 
     context = alcCreateContext(device, NULL);
     if(!context || alcMakeContextCurrent(context) == ALC_FALSE)

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