Tizen 2.1 base
authorJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:50:17 +0000 (01:50 +0900)
committerJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:50:17 +0000 (01:50 +0900)
64 files changed:
Alc/ALc.c [new file with mode: 0644]
Alc/ALu.c [new file with mode: 0644]
Alc/alcConfig.c [new file with mode: 0644]
Alc/alcEcho.c [new file with mode: 0644]
Alc/alcModulator.c [new file with mode: 0644]
Alc/alcReverb.c [new file with mode: 0644]
Alc/alcRing.c [new file with mode: 0644]
Alc/alcThread.c [new file with mode: 0644]
Alc/alsa.c [new file with mode: 0644]
Alc/avsystem.c [new file with mode: 0644]
Alc/bs2b.c [new file with mode: 0644]
Alc/dsound.c [new file with mode: 0644]
Alc/mixer.c [new file with mode: 0644]
Alc/null.c [new file with mode: 0644]
Alc/oss.c [new file with mode: 0644]
Alc/panning.c [new file with mode: 0644]
Alc/portaudio.c [new file with mode: 0644]
Alc/pulseaudio.c [new file with mode: 0644]
Alc/solaris.c [new file with mode: 0644]
Alc/wave.c [new file with mode: 0644]
Alc/winmm.c [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0755]
COPYING [new file with mode: 0644]
OpenAL32/Include/alAuxEffectSlot.h [new file with mode: 0755]
OpenAL32/Include/alBuffer.h [new file with mode: 0755]
OpenAL32/Include/alDatabuffer.h [new file with mode: 0755]
OpenAL32/Include/alEffect.h [new file with mode: 0755]
OpenAL32/Include/alError.h [new file with mode: 0755]
OpenAL32/Include/alFilter.h [new file with mode: 0755]
OpenAL32/Include/alListener.h [new file with mode: 0755]
OpenAL32/Include/alMain.h [new file with mode: 0755]
OpenAL32/Include/alSource.h [new file with mode: 0755]
OpenAL32/Include/alState.h [new file with mode: 0644]
OpenAL32/Include/alThunk.h [new file with mode: 0755]
OpenAL32/Include/alu.h [new file with mode: 0755]
OpenAL32/Include/bs2b.h [new file with mode: 0755]
OpenAL32/alAuxEffectSlot.c [new file with mode: 0755]
OpenAL32/alBuffer.c [new file with mode: 0755]
OpenAL32/alDatabuffer.c [new file with mode: 0755]
OpenAL32/alEffect.c [new file with mode: 0755]
OpenAL32/alError.c [new file with mode: 0755]
OpenAL32/alExtension.c [new file with mode: 0755]
OpenAL32/alFilter.c [new file with mode: 0755]
OpenAL32/alListener.c [new file with mode: 0755]
OpenAL32/alSource.c [new file with mode: 0755]
OpenAL32/alState.c [new file with mode: 0755]
OpenAL32/alThunk.c [new file with mode: 0644]
README [new file with mode: 0755]
XCompile.txt [new file with mode: 0644]
alsoftrc.sample [new file with mode: 0755]
build/.empty [new file with mode: 0644]
cmake/CheckCCompilerFlag.cmake [new file with mode: 0755]
cmake/CheckSharedFunctionExists.c [new file with mode: 0755]
cmake/CheckSharedLibraryExists.cmake [new file with mode: 0755]
config.h.in [new file with mode: 0755]
include/AL/al.h [new file with mode: 0644]
include/AL/alc.h [new file with mode: 0644]
include/AL/alext.h [new file with mode: 0644]
include/AL/efx-creative.h [new file with mode: 0644]
include/AL/efx.h [new file with mode: 0644]
openal-soft.manifest [new file with mode: 0755]
openal.pc.in [new file with mode: 0755]
packaging/openal-soft.spec [new file with mode: 0755]
utils/openal-info.c [new file with mode: 0644]

diff --git a/Alc/ALc.c b/Alc/ALc.c
new file mode 100644 (file)
index 0000000..42dca54
--- /dev/null
+++ b/Alc/ALc.c
@@ -0,0 +1,2345 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <ctype.h>
+
+#include "alMain.h"
+#include "alSource.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alThunk.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alAuxEffectSlot.h"
+#include "alDatabuffer.h"
+#include "bs2b.h"
+#include "alu.h"
+#if defined(USE_DLOG)
+#include <dlog.h>
+#endif
+
+#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+typedef struct BackendInfo {
+    const char *name;
+    void (*Init)(BackendFuncs*);
+    void (*Deinit)(void);
+    void (*Probe)(int);
+    BackendFuncs Funcs;
+} BackendInfo;
+static BackendInfo BackendList[] = {
+#ifdef HAVE_PULSEAUDIO
+    { "pulse", alc_pulse_init, alc_pulse_deinit, alc_pulse_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_ALSA
+    { "alsa", alc_alsa_init, alc_alsa_deinit, alc_alsa_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_OSS
+    { "oss", alc_oss_init, alc_oss_deinit, alc_oss_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_SOLARIS
+    { "solaris", alc_solaris_init, alc_solaris_deinit, alc_solaris_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_DSOUND
+    { "dsound", alcDSoundInit, alcDSoundDeinit, alcDSoundProbe, EmptyFuncs },
+#endif
+#ifdef HAVE_WINMM
+    { "winmm", alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs },
+#endif
+#ifdef HAVE_PORTAUDIO
+    { "port", alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs },
+#endif
+
+    { "null", alc_null_init, alc_null_deinit, alc_null_probe, EmptyFuncs },
+#ifdef HAVE_WAVE
+    { "wave", alc_wave_init, alc_wave_deinit, alc_wave_probe, EmptyFuncs },
+#endif
+#ifdef HAVE_AVSYSTEM
+   { "avsystem", alc_avsystem_init, alc_avsystem_deinit, alc_avsystem_probe, EmptyFuncs },
+#endif
+
+    { NULL, NULL, NULL, NULL, EmptyFuncs }
+};
+#undef EmptyFuncs
+
+///////////////////////////////////////////////////////
+
+#define ALC_EFX_MAJOR_VERSION                              0x20001
+#define ALC_EFX_MINOR_VERSION                              0x20002
+#define ALC_MAX_AUXILIARY_SENDS                            0x20003
+
+///////////////////////////////////////////////////////
+// STRING and EXTENSIONS
+
+typedef struct ALCfunction {
+    const ALCchar *funcName;
+    ALCvoid *address;
+} ALCfunction;
+
+typedef struct ALCenums {
+    const ALCchar *enumName;
+    ALCenum value;
+} ALCenums;
+
+
+static const ALCfunction alcFunctions[] = {
+    { "alcCreateContext",           (ALCvoid *) alcCreateContext         },
+    { "alcMakeContextCurrent",      (ALCvoid *) alcMakeContextCurrent    },
+    { "alcProcessContext",          (ALCvoid *) alcProcessContext        },
+    { "alcSuspendContext",          (ALCvoid *) alcSuspendContext        },
+    { "alcDestroyContext",          (ALCvoid *) alcDestroyContext        },
+    { "alcGetCurrentContext",       (ALCvoid *) alcGetCurrentContext     },
+    { "alcGetContextsDevice",       (ALCvoid *) alcGetContextsDevice     },
+    { "alcOpenDevice",              (ALCvoid *) alcOpenDevice            },
+    { "alcCloseDevice",             (ALCvoid *) alcCloseDevice           },
+    { "alcGetError",                (ALCvoid *) alcGetError              },
+    { "alcIsExtensionPresent",      (ALCvoid *) alcIsExtensionPresent    },
+    { "alcGetProcAddress",          (ALCvoid *) alcGetProcAddress        },
+    { "alcGetEnumValue",            (ALCvoid *) alcGetEnumValue          },
+    { "alcGetString",               (ALCvoid *) alcGetString             },
+    { "alcGetIntegerv",             (ALCvoid *) alcGetIntegerv           },
+    { "alcCaptureOpenDevice",       (ALCvoid *) alcCaptureOpenDevice     },
+    { "alcCaptureCloseDevice",      (ALCvoid *) alcCaptureCloseDevice    },
+    { "alcCaptureStart",            (ALCvoid *) alcCaptureStart          },
+    { "alcCaptureStop",             (ALCvoid *) alcCaptureStop           },
+    { "alcCaptureSamples",          (ALCvoid *) alcCaptureSamples        },
+
+    { "alcSetThreadContext",        (ALCvoid *) alcSetThreadContext      },
+    { "alcGetThreadContext",        (ALCvoid *) alcGetThreadContext      },
+
+    { "alEnable",                   (ALCvoid *) alEnable                 },
+    { "alDisable",                  (ALCvoid *) alDisable                },
+    { "alIsEnabled",                (ALCvoid *) alIsEnabled              },
+    { "alGetString",                (ALCvoid *) alGetString              },
+    { "alGetBooleanv",              (ALCvoid *) alGetBooleanv            },
+    { "alGetIntegerv",              (ALCvoid *) alGetIntegerv            },
+    { "alGetFloatv",                (ALCvoid *) alGetFloatv              },
+    { "alGetDoublev",               (ALCvoid *) alGetDoublev             },
+    { "alGetBoolean",               (ALCvoid *) alGetBoolean             },
+    { "alGetInteger",               (ALCvoid *) alGetInteger             },
+    { "alGetFloat",                 (ALCvoid *) alGetFloat               },
+    { "alGetDouble",                (ALCvoid *) alGetDouble              },
+    { "alGetError",                 (ALCvoid *) alGetError               },
+    { "alIsExtensionPresent",       (ALCvoid *) alIsExtensionPresent     },
+    { "alGetProcAddress",           (ALCvoid *) alGetProcAddress         },
+    { "alGetEnumValue",             (ALCvoid *) alGetEnumValue           },
+    { "alListenerf",                (ALCvoid *) alListenerf              },
+    { "alListener3f",               (ALCvoid *) alListener3f             },
+    { "alListenerfv",               (ALCvoid *) alListenerfv             },
+    { "alListeneri",                (ALCvoid *) alListeneri              },
+    { "alListener3i",               (ALCvoid *) alListener3i             },
+    { "alListeneriv",               (ALCvoid *) alListeneriv             },
+    { "alGetListenerf",             (ALCvoid *) alGetListenerf           },
+    { "alGetListener3f",            (ALCvoid *) alGetListener3f          },
+    { "alGetListenerfv",            (ALCvoid *) alGetListenerfv          },
+    { "alGetListeneri",             (ALCvoid *) alGetListeneri           },
+    { "alGetListener3i",            (ALCvoid *) alGetListener3i          },
+    { "alGetListeneriv",            (ALCvoid *) alGetListeneriv          },
+    { "alGenSources",               (ALCvoid *) alGenSources             },
+    { "alDeleteSources",            (ALCvoid *) alDeleteSources          },
+    { "alIsSource",                 (ALCvoid *) alIsSource               },
+    { "alSourcef",                  (ALCvoid *) alSourcef                },
+    { "alSource3f",                 (ALCvoid *) alSource3f               },
+    { "alSourcefv",                 (ALCvoid *) alSourcefv               },
+    { "alSourcei",                  (ALCvoid *) alSourcei                },
+    { "alSource3i",                 (ALCvoid *) alSource3i               },
+    { "alSourceiv",                 (ALCvoid *) alSourceiv               },
+    { "alGetSourcef",               (ALCvoid *) alGetSourcef             },
+    { "alGetSource3f",              (ALCvoid *) alGetSource3f            },
+    { "alGetSourcefv",              (ALCvoid *) alGetSourcefv            },
+    { "alGetSourcei",               (ALCvoid *) alGetSourcei             },
+    { "alGetSource3i",              (ALCvoid *) alGetSource3i            },
+    { "alGetSourceiv",              (ALCvoid *) alGetSourceiv            },
+    { "alSourcePlayv",              (ALCvoid *) alSourcePlayv            },
+    { "alSourceStopv",              (ALCvoid *) alSourceStopv            },
+    { "alSourceRewindv",            (ALCvoid *) alSourceRewindv          },
+    { "alSourcePausev",             (ALCvoid *) alSourcePausev           },
+    { "alSourcePlay",               (ALCvoid *) alSourcePlay             },
+    { "alSourceStop",               (ALCvoid *) alSourceStop             },
+    { "alSourceRewind",             (ALCvoid *) alSourceRewind           },
+    { "alSourcePause",              (ALCvoid *) alSourcePause            },
+    { "alSourceQueueBuffers",       (ALCvoid *) alSourceQueueBuffers     },
+    { "alSourceUnqueueBuffers",     (ALCvoid *) alSourceUnqueueBuffers   },
+    { "alGenBuffers",               (ALCvoid *) alGenBuffers             },
+    { "alDeleteBuffers",            (ALCvoid *) alDeleteBuffers          },
+    { "alIsBuffer",                 (ALCvoid *) alIsBuffer               },
+    { "alBufferData",               (ALCvoid *) alBufferData             },
+    { "alBufferf",                  (ALCvoid *) alBufferf                },
+    { "alBuffer3f",                 (ALCvoid *) alBuffer3f               },
+    { "alBufferfv",                 (ALCvoid *) alBufferfv               },
+    { "alBufferi",                  (ALCvoid *) alBufferi                },
+    { "alBuffer3i",                 (ALCvoid *) alBuffer3i               },
+    { "alBufferiv",                 (ALCvoid *) alBufferiv               },
+    { "alGetBufferf",               (ALCvoid *) alGetBufferf             },
+    { "alGetBuffer3f",              (ALCvoid *) alGetBuffer3f            },
+    { "alGetBufferfv",              (ALCvoid *) alGetBufferfv            },
+    { "alGetBufferi",               (ALCvoid *) alGetBufferi             },
+    { "alGetBuffer3i",              (ALCvoid *) alGetBuffer3i            },
+    { "alGetBufferiv",              (ALCvoid *) alGetBufferiv            },
+    { "alDopplerFactor",            (ALCvoid *) alDopplerFactor          },
+    { "alDopplerVelocity",          (ALCvoid *) alDopplerVelocity        },
+    { "alSpeedOfSound",             (ALCvoid *) alSpeedOfSound           },
+    { "alDistanceModel",            (ALCvoid *) alDistanceModel          },
+
+    { "alGenFilters",               (ALCvoid *) alGenFilters             },
+    { "alDeleteFilters",            (ALCvoid *) alDeleteFilters          },
+    { "alIsFilter",                 (ALCvoid *) alIsFilter               },
+    { "alFilteri",                  (ALCvoid *) alFilteri                },
+    { "alFilteriv",                 (ALCvoid *) alFilteriv               },
+    { "alFilterf",                  (ALCvoid *) alFilterf                },
+    { "alFilterfv",                 (ALCvoid *) alFilterfv               },
+    { "alGetFilteri",               (ALCvoid *) alGetFilteri             },
+    { "alGetFilteriv",              (ALCvoid *) alGetFilteriv            },
+    { "alGetFilterf",               (ALCvoid *) alGetFilterf             },
+    { "alGetFilterfv",              (ALCvoid *) alGetFilterfv            },
+
+    { "alGenEffects",               (ALCvoid *) alGenEffects             },
+    { "alDeleteEffects",            (ALCvoid *) alDeleteEffects          },
+    { "alIsEffect",                 (ALCvoid *) alIsEffect               },
+    { "alEffecti",                  (ALCvoid *) alEffecti                },
+    { "alEffectiv",                 (ALCvoid *) alEffectiv               },
+    { "alEffectf",                  (ALCvoid *) alEffectf                },
+    { "alEffectfv",                 (ALCvoid *) alEffectfv               },
+    { "alGetEffecti",               (ALCvoid *) alGetEffecti             },
+    { "alGetEffectiv",              (ALCvoid *) alGetEffectiv            },
+    { "alGetEffectf",               (ALCvoid *) alGetEffectf             },
+    { "alGetEffectfv",              (ALCvoid *) alGetEffectfv            },
+
+    { "alGenAuxiliaryEffectSlots",  (ALCvoid *) alGenAuxiliaryEffectSlots},
+    { "alDeleteAuxiliaryEffectSlots",(ALCvoid *) alDeleteAuxiliaryEffectSlots},
+    { "alIsAuxiliaryEffectSlot",    (ALCvoid *) alIsAuxiliaryEffectSlot  },
+    { "alAuxiliaryEffectSloti",     (ALCvoid *) alAuxiliaryEffectSloti   },
+    { "alAuxiliaryEffectSlotiv",    (ALCvoid *) alAuxiliaryEffectSlotiv  },
+    { "alAuxiliaryEffectSlotf",     (ALCvoid *) alAuxiliaryEffectSlotf   },
+    { "alAuxiliaryEffectSlotfv",    (ALCvoid *) alAuxiliaryEffectSlotfv  },
+    { "alGetAuxiliaryEffectSloti",  (ALCvoid *) alGetAuxiliaryEffectSloti},
+    { "alGetAuxiliaryEffectSlotiv", (ALCvoid *) alGetAuxiliaryEffectSlotiv},
+    { "alGetAuxiliaryEffectSlotf",  (ALCvoid *) alGetAuxiliaryEffectSlotf},
+    { "alGetAuxiliaryEffectSlotfv", (ALCvoid *) alGetAuxiliaryEffectSlotfv},
+
+    { "alBufferSubDataSOFT",        (ALCvoid *) alBufferSubDataSOFT      },
+#if 0
+    { "alGenDatabuffersEXT",        (ALCvoid *) alGenDatabuffersEXT      },
+    { "alDeleteDatabuffersEXT",     (ALCvoid *) alDeleteDatabuffersEXT   },
+    { "alIsDatabufferEXT",          (ALCvoid *) alIsDatabufferEXT        },
+    { "alDatabufferDataEXT",        (ALCvoid *) alDatabufferDataEXT      },
+    { "alDatabufferSubDataEXT",     (ALCvoid *) alDatabufferSubDataEXT   },
+    { "alGetDatabufferSubDataEXT",  (ALCvoid *) alGetDatabufferSubDataEXT},
+    { "alDatabufferfEXT",           (ALCvoid *) alDatabufferfEXT         },
+    { "alDatabufferfvEXT",          (ALCvoid *) alDatabufferfvEXT        },
+    { "alDatabufferiEXT",           (ALCvoid *) alDatabufferiEXT         },
+    { "alDatabufferivEXT",          (ALCvoid *) alDatabufferivEXT        },
+    { "alGetDatabufferfEXT",        (ALCvoid *) alGetDatabufferfEXT      },
+    { "alGetDatabufferfvEXT",       (ALCvoid *) alGetDatabufferfvEXT     },
+    { "alGetDatabufferiEXT",        (ALCvoid *) alGetDatabufferiEXT      },
+    { "alGetDatabufferivEXT",       (ALCvoid *) alGetDatabufferivEXT     },
+    { "alSelectDatabufferEXT",      (ALCvoid *) alSelectDatabufferEXT    },
+    { "alMapDatabufferEXT",         (ALCvoid *) alMapDatabufferEXT       },
+    { "alUnmapDatabufferEXT",       (ALCvoid *) alUnmapDatabufferEXT     },
+#endif
+    { NULL,                         (ALCvoid *) NULL                     }
+};
+
+static const ALCenums enumeration[] = {
+    // Types
+    { "ALC_INVALID",                          ALC_INVALID                         },
+    { "ALC_FALSE",                            ALC_FALSE                           },
+    { "ALC_TRUE",                             ALC_TRUE                            },
+
+    // ALC Properties
+    { "ALC_MAJOR_VERSION",                    ALC_MAJOR_VERSION                   },
+    { "ALC_MINOR_VERSION",                    ALC_MINOR_VERSION                   },
+    { "ALC_ATTRIBUTES_SIZE",                  ALC_ATTRIBUTES_SIZE                 },
+    { "ALC_ALL_ATTRIBUTES",                   ALC_ALL_ATTRIBUTES                  },
+    { "ALC_DEFAULT_DEVICE_SPECIFIER",         ALC_DEFAULT_DEVICE_SPECIFIER        },
+    { "ALC_DEVICE_SPECIFIER",                 ALC_DEVICE_SPECIFIER                },
+    { "ALC_ALL_DEVICES_SPECIFIER",            ALC_ALL_DEVICES_SPECIFIER           },
+    { "ALC_DEFAULT_ALL_DEVICES_SPECIFIER",    ALC_DEFAULT_ALL_DEVICES_SPECIFIER   },
+    { "ALC_EXTENSIONS",                       ALC_EXTENSIONS                      },
+    { "ALC_FREQUENCY",                        ALC_FREQUENCY                       },
+    { "ALC_REFRESH",                          ALC_REFRESH                         },
+    { "ALC_SYNC",                             ALC_SYNC                            },
+    { "ALC_MONO_SOURCES",                     ALC_MONO_SOURCES                    },
+    { "ALC_STEREO_SOURCES",                   ALC_STEREO_SOURCES                  },
+    { "ALC_CAPTURE_DEVICE_SPECIFIER",         ALC_CAPTURE_DEVICE_SPECIFIER        },
+    { "ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER},
+    { "ALC_CAPTURE_SAMPLES",                  ALC_CAPTURE_SAMPLES                 },
+    { "ALC_CONNECTED",                        ALC_CONNECTED                       },
+
+    // EFX Properties
+    { "ALC_EFX_MAJOR_VERSION",                ALC_EFX_MAJOR_VERSION               },
+    { "ALC_EFX_MINOR_VERSION",                ALC_EFX_MINOR_VERSION               },
+    { "ALC_MAX_AUXILIARY_SENDS",              ALC_MAX_AUXILIARY_SENDS             },
+
+    // ALC Error Message
+    { "ALC_NO_ERROR",                         ALC_NO_ERROR                        },
+    { "ALC_INVALID_DEVICE",                   ALC_INVALID_DEVICE                  },
+    { "ALC_INVALID_CONTEXT",                  ALC_INVALID_CONTEXT                 },
+    { "ALC_INVALID_ENUM",                     ALC_INVALID_ENUM                    },
+    { "ALC_INVALID_VALUE",                    ALC_INVALID_VALUE                   },
+    { "ALC_OUT_OF_MEMORY",                    ALC_OUT_OF_MEMORY                   },
+    { NULL,                                   (ALCenum)0 }
+};
+// Error strings
+static const ALCchar alcNoError[] = "No Error";
+static const ALCchar alcErrInvalidDevice[] = "Invalid Device";
+static const ALCchar alcErrInvalidContext[] = "Invalid Context";
+static const ALCchar alcErrInvalidEnum[] = "Invalid Enum";
+static const ALCchar alcErrInvalidValue[] = "Invalid Value";
+static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
+
+/* Device lists. Sizes only include the first ending null character, not the
+ * second */
+static ALCchar *alcDeviceList;
+static size_t alcDeviceListSize;
+static ALCchar *alcAllDeviceList;
+static size_t alcAllDeviceListSize;
+static ALCchar *alcCaptureDeviceList;
+static size_t alcCaptureDeviceListSize;
+// Default is always the first in the list
+static ALCchar *alcDefaultDeviceSpecifier;
+static ALCchar *alcDefaultAllDeviceSpecifier;
+static ALCchar *alcCaptureDefaultDeviceSpecifier;
+
+
+static const ALCchar alcNoDeviceExtList[] =
+    "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
+    "ALC_EXT_thread_local_context";
+static const ALCchar alcExtensionList[] =
+    "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
+    "ALC_EXT_disconnect ALC_EXT_EFX ALC_EXT_thread_local_context";
+static const ALCint alcMajorVersion = 1;
+static const ALCint alcMinorVersion = 1;
+
+static const ALCint alcEFXMajorVersion = 1;
+static const ALCint alcEFXMinorVersion = 0;
+
+///////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////
+// Global Variables
+
+static ALCdevice *g_pDeviceList = NULL;
+static ALCuint    g_ulDeviceCount = 0;
+
+static CRITICAL_SECTION g_csMutex;
+
+// Context List
+static ALCcontext *g_pContextList = NULL;
+static ALCuint     g_ulContextCount = 0;
+
+// Thread-local current context
+static tls_type LocalContext;
+// Process-wide current context
+static ALCcontext *GlobalContext;
+
+// Context Error
+static ALCenum g_eLastNullDeviceError = ALC_NO_ERROR;
+
+// Default context extensions
+static const ALchar alExtList[] =
+    "AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 "
+    "AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW "
+    "AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model "
+    "AL_LOKI_quadriphonic AL_SOFT_buffer_sub_data AL_SOFT_loop_points";
+
+// Mixing Priority Level
+static ALint RTPrioLevel;
+
+// Output Log File
+static FILE *LogFile;
+
+///////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////
+// ALC Related helper functions
+static void ReleaseALC(void);
+
+#ifdef HAVE_GCC_DESTRUCTOR
+static void alc_init(void) __attribute__((constructor));
+static void alc_deinit(void) __attribute__((destructor));
+#else
+#ifdef _WIN32
+static void alc_init(void);
+static void alc_deinit(void);
+
+BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
+{
+    (void)lpReserved;
+
+    // Perform actions based on the reason for calling.
+    switch(ul_reason_for_call)
+    {
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls(hModule);
+            alc_init();
+            break;
+
+        case DLL_PROCESS_DETACH:
+            alc_deinit();
+            break;
+    }
+    return TRUE;
+}
+#endif
+#endif
+
+static void alc_init(void)
+{
+    int i;
+    const char *devs, *str;
+
+    str = getenv("ALSOFT_LOGFILE");
+    if(str && str[0])
+    {
+        LogFile = fopen(str, "w");
+        if(!LogFile)
+            fprintf(stderr, "AL lib: Failed to open log file '%s'\n", str);
+    }
+    if(!LogFile)
+        LogFile = stderr;
+
+    InitializeCriticalSection(&g_csMutex);
+    ALTHUNK_INIT();
+    ReadALConfig();
+
+    tls_create(&LocalContext);
+
+    RTPrioLevel = GetConfigValueInt(NULL, "rt-prio", 0);
+
+    DefaultResampler = GetConfigValueInt(NULL, "resampler", RESAMPLER_DEFAULT);
+    if(DefaultResampler >= RESAMPLER_MAX || DefaultResampler <= RESAMPLER_MIN)
+        DefaultResampler = RESAMPLER_DEFAULT;
+
+    devs = GetConfigValue(NULL, "drivers", "");
+    if(devs[0])
+    {
+        int n;
+        size_t len;
+        const char *next = devs;
+        int endlist, delitem;
+
+        i = 0;
+        do {
+            devs = next;
+            next = strchr(devs, ',');
+
+            delitem = (devs[0] == '-');
+            if(devs[0] == '-') devs++;
+
+            if(!devs[0] || devs[0] == ',')
+            {
+                endlist = 0;
+                continue;
+            }
+            endlist = 1;
+
+            len = (next ? ((size_t)(next-devs)) : strlen(devs));
+            for(n = i;BackendList[n].Init;n++)
+            {
+                if(len == strlen(BackendList[n].name) &&
+                   strncmp(BackendList[n].name, devs, len) == 0)
+                {
+                    if(delitem)
+                    {
+                        do {
+                            BackendList[n] = BackendList[n+1];
+                            ++n;
+                        } while(BackendList[n].Init);
+                    }
+                    else
+                    {
+                        BackendInfo Bkp = BackendList[n];
+                        while(n > i)
+                        {
+                            BackendList[n] = BackendList[n-1];
+                            --n;
+                        }
+                        BackendList[n] = Bkp;
+
+                        i++;
+                    }
+                    break;
+                }
+            }
+        } while(next++);
+
+        if(endlist)
+        {
+            BackendList[i].name = NULL;
+            BackendList[i].Init = NULL;
+            BackendList[i].Deinit = NULL;
+            BackendList[i].Probe = NULL;
+        }
+    }
+
+    for(i = 0;BackendList[i].Init;i++)
+        BackendList[i].Init(&BackendList[i].Funcs);
+
+    str = GetConfigValue(NULL, "excludefx", "");
+    if(str[0])
+    {
+        const struct {
+            const char *name;
+            int type;
+        } EffectList[] = {
+            { "eaxreverb", EAXREVERB },
+            { "reverb", REVERB },
+            { "echo", ECHO },
+            { "modulator", MODULATOR },
+            { NULL, 0 }
+        };
+        int n;
+        size_t len;
+        const char *next = str;
+
+        do {
+            str = next;
+            next = strchr(str, ',');
+
+            if(!str[0] || next == str)
+                continue;
+
+            len = (next ? ((size_t)(next-str)) : strlen(str));
+            for(n = 0;EffectList[n].name;n++)
+            {
+                if(len == strlen(EffectList[n].name) &&
+                   strncmp(EffectList[n].name, str, len) == 0)
+                    DisabledEffects[EffectList[n].type] = AL_TRUE;
+            }
+        } while(next++);
+    }
+}
+
+static void alc_deinit(void)
+{
+    int i;
+
+    ReleaseALC();
+
+    for(i = 0;BackendList[i].Deinit;i++)
+        BackendList[i].Deinit();
+
+    tls_delete(LocalContext);
+
+    FreeALConfig();
+    ALTHUNK_EXIT();
+    DeleteCriticalSection(&g_csMutex);
+
+    if(LogFile != stderr)
+        fclose(LogFile);
+    LogFile = NULL;
+}
+
+
+static void ProbeDeviceList()
+{
+    ALint i;
+
+    free(alcDeviceList); alcDeviceList = NULL;
+    alcDeviceListSize = 0;
+
+    for(i = 0;BackendList[i].Probe;i++)
+        BackendList[i].Probe(DEVICE_PROBE);
+}
+
+static void ProbeAllDeviceList()
+{
+    ALint i;
+
+    free(alcAllDeviceList); alcAllDeviceList = NULL;
+    alcAllDeviceListSize = 0;
+
+    for(i = 0;BackendList[i].Probe;i++)
+        BackendList[i].Probe(ALL_DEVICE_PROBE);
+}
+
+static void ProbeCaptureDeviceList()
+{
+    ALint i;
+
+    free(alcCaptureDeviceList); alcCaptureDeviceList = NULL;
+    alcCaptureDeviceListSize = 0;
+
+    for(i = 0;BackendList[i].Probe;i++)
+        BackendList[i].Probe(CAPTURE_DEVICE_PROBE);
+}
+
+
+static void AppendList(const ALCchar *name, ALCchar **List, size_t *ListSize)
+{
+    size_t len = strlen(name);
+    void *temp;
+
+    if(len == 0)
+        return;
+
+    temp = realloc(*List, (*ListSize) + len + 2);
+    if(!temp)
+    {
+        AL_PRINT("Realloc failed to add %s!\n", name);
+        return;
+    }
+    *List = temp;
+
+    memcpy((*List)+(*ListSize), name, len+1);
+    *ListSize += len+1;
+    (*List)[*ListSize] = 0;
+}
+
+#define DECL_APPEND_LIST_FUNC(type)                                          \
+void Append##type##List(const ALCchar *name)                                 \
+{ AppendList(name, &alc##type##List, &alc##type##ListSize); }
+
+DECL_APPEND_LIST_FUNC(Device)
+DECL_APPEND_LIST_FUNC(AllDevice)
+DECL_APPEND_LIST_FUNC(CaptureDevice)
+
+#undef DECL_APPEND_LIST_FUNC
+
+
+void al_print(const char *fname, unsigned int line, const char *fmt, ...)
+{
+    const char *fn;
+    char str[256];
+    int i;
+
+    fn = strrchr(fname, '/');
+    if(!fn) fn = strrchr(fname, '\\');;
+    if(!fn) fn = fname;
+    else fn += 1;
+
+    i = snprintf(str, sizeof(str), "AL lib: %s:%d: ", fn, line);
+    if(i < (int)sizeof(str) && i > 0)
+    {
+        va_list ap;
+        va_start(ap, fmt);
+        vsnprintf(str+i, sizeof(str)-i, fmt, ap);
+        va_end(ap);
+    }
+    str[sizeof(str)-1] = 0;
+#if defined(USE_DLOG)
+    SLOG(LOG_WARN, "MMFW_OPENAL", "%s", str);
+#else
+    fprintf(LogFile, "%s", str);
+#endif
+    fflush(LogFile);
+}
+
+void SetRTPriority(void)
+{
+    ALboolean failed;
+
+#ifdef _WIN32
+    if(RTPrioLevel > 0)
+        failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+    else
+        failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+#elif defined(HAVE_PTHREAD_SETSCHEDPARAM)
+    struct sched_param param;
+
+    if(RTPrioLevel > 0)
+    {
+        /* Use the minimum real-time priority possible for now (on Linux this
+         * should be 1 for SCHED_RR) */
+        param.sched_priority = sched_get_priority_min(SCHED_RR);
+        failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, &param);
+    }
+    else
+    {
+        param.sched_priority = 0;
+        failed = !!pthread_setschedparam(pthread_self(), SCHED_OTHER, &param);
+    }
+#else
+    /* Real-time priority not available */
+    failed = (RTPrioLevel>0);
+#endif
+    if(failed)
+        AL_PRINT("Failed to set priority level for thread\n");
+}
+
+
+void InitUIntMap(UIntMap *map)
+{
+    map->array = NULL;
+    map->size = 0;
+    map->maxsize = 0;
+}
+
+void ResetUIntMap(UIntMap *map)
+{
+    free(map->array);
+    map->array = NULL;
+    map->size = 0;
+    map->maxsize = 0;
+}
+
+ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value)
+{
+    ALsizei pos = 0;
+
+    if(map->size > 0)
+    {
+        ALsizei low = 0;
+        ALsizei high = map->size - 1;
+        while(low < high)
+        {
+            ALsizei mid = low + (high-low)/2;
+            if(map->array[mid].key < key)
+                low = mid + 1;
+            else
+                high = mid;
+        }
+        if(map->array[low].key < key)
+            low++;
+        pos = low;
+    }
+
+    if(pos == map->size || map->array[pos].key != key)
+    {
+        if(map->size == map->maxsize)
+        {
+            ALvoid *temp;
+            ALsizei newsize;
+
+            newsize = (map->maxsize ? (map->maxsize<<1) : 4);
+            if(newsize < map->maxsize)
+                return AL_OUT_OF_MEMORY;
+
+            temp = realloc(map->array, newsize*sizeof(map->array[0]));
+            if(!temp) return AL_OUT_OF_MEMORY;
+            map->array = temp;
+            map->maxsize = newsize;
+        }
+
+        map->size++;
+        if(pos < map->size-1)
+            memmove(&map->array[pos+1], &map->array[pos],
+                    (map->size-1-pos)*sizeof(map->array[0]));
+    }
+    map->array[pos].key = key;
+    map->array[pos].value = value;
+
+    return AL_NO_ERROR;
+}
+
+void RemoveUIntMapKey(UIntMap *map, ALuint key)
+{
+    if(map->size > 0)
+    {
+        ALsizei low = 0;
+        ALsizei high = map->size - 1;
+        while(low < high)
+        {
+            ALsizei mid = low + (high-low)/2;
+            if(map->array[mid].key < key)
+                low = mid + 1;
+            else
+                high = mid;
+        }
+        if(map->array[low].key == key)
+        {
+            if(low < map->size-1)
+                memmove(&map->array[low], &map->array[low+1],
+                        (map->size-1-low)*sizeof(map->array[0]));
+            map->size--;
+        }
+    }
+}
+
+ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key)
+{
+    if(map->size > 0)
+    {
+        ALsizei low = 0;
+        ALsizei high = map->size - 1;
+        while(low < high)
+        {
+            ALsizei mid = low + (high-low)/2;
+            if(map->array[mid].key < key)
+                low = mid + 1;
+            else
+                high = mid;
+        }
+        if(map->array[low].key == key)
+            return map->array[low].value;
+    }
+    return NULL;
+}
+
+
+ALuint BytesFromDevFmt(enum DevFmtType type)
+{
+    switch(type)
+    {
+    case DevFmtByte: return sizeof(ALbyte);
+    case DevFmtUByte: return sizeof(ALubyte);
+    case DevFmtShort: return sizeof(ALshort);
+    case DevFmtUShort: return sizeof(ALushort);
+    case DevFmtFloat: return sizeof(ALfloat);
+    }
+    return 0;
+}
+ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
+{
+    switch(chans)
+    {
+    case DevFmtMono: return 1;
+    case DevFmtStereo: return 2;
+    case DevFmtQuad: return 4;
+    case DevFmtX51: return 6;
+    case DevFmtX61: return 7;
+    case DevFmtX71: return 8;
+    }
+    return 0;
+}
+ALboolean DecomposeDevFormat(ALenum format, enum DevFmtChannels *chans,
+                             enum DevFmtType *type)
+{
+    switch(format)
+    {
+        case AL_FORMAT_MONO8:
+            *chans = DevFmtMono;
+            *type  = DevFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_MONO16:
+            *chans = DevFmtMono;
+            *type  = DevFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_MONO_FLOAT32:
+            *chans = DevFmtMono;
+            *type  = DevFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO8:
+            *chans = DevFmtStereo;
+            *type  = DevFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO16:
+            *chans = DevFmtStereo;
+            *type  = DevFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO_FLOAT32:
+            *chans = DevFmtStereo;
+            *type  = DevFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD8:
+            *chans = DevFmtQuad;
+            *type  = DevFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD16:
+            *chans = DevFmtQuad;
+            *type  = DevFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD32:
+            *chans = DevFmtQuad;
+            *type  = DevFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN8:
+            *chans = DevFmtX51;
+            *type  = DevFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN16:
+            *chans = DevFmtX51;
+            *type  = DevFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN32:
+            *chans = DevFmtX51;
+            *type  = DevFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN8:
+            *chans = DevFmtX61;
+            *type  = DevFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN16:
+            *chans = DevFmtX61;
+            *type  = DevFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN32:
+            *chans = DevFmtX61;
+            *type  = DevFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN8:
+            *chans = DevFmtX71;
+            *type  = DevFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN16:
+            *chans = DevFmtX71;
+            *type  = DevFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN32:
+            *chans = DevFmtX71;
+            *type  = DevFmtFloat;
+            return AL_TRUE;
+    }
+    return AL_FALSE;
+}
+
+/*
+    IsDevice
+
+    Check pDevice is a valid Device pointer
+*/
+static ALCboolean IsDevice(ALCdevice *pDevice)
+{
+    ALCdevice *pTempDevice;
+
+    SuspendContext(NULL);
+
+    pTempDevice = g_pDeviceList;
+    while(pTempDevice && pTempDevice != pDevice)
+        pTempDevice = pTempDevice->next;
+
+    ProcessContext(NULL);
+
+    return (pTempDevice ? ALC_TRUE : ALC_FALSE);
+}
+
+/*
+    IsContext
+
+    Check pContext is a valid Context pointer
+*/
+static ALCboolean IsContext(ALCcontext *pContext)
+{
+    ALCcontext *pTempContext;
+
+    SuspendContext(NULL);
+
+    pTempContext = g_pContextList;
+    while (pTempContext && pTempContext != pContext)
+        pTempContext = pTempContext->next;
+
+    ProcessContext(NULL);
+
+    return (pTempContext ? ALC_TRUE : ALC_FALSE);
+}
+
+
+/*
+    alcSetError
+
+    Store latest ALC Error
+*/
+ALCvoid alcSetError(ALCdevice *device, ALenum errorCode)
+{
+    if(IsDevice(device))
+        device->LastError = errorCode;
+    else
+        g_eLastNullDeviceError = errorCode;
+}
+
+
+/* UpdateDeviceParams:
+ *
+ * Updates device parameters according to the attribute list.
+ */
+static ALCboolean UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
+{
+    ALCuint freq, numMono, numStereo, numSends;
+    ALboolean running;
+    ALuint oldRate;
+    ALuint attrIdx;
+    ALuint i;
+
+    running = ((device->NumContexts > 0) ? AL_TRUE : AL_FALSE);
+    oldRate = device->Frequency;
+
+    // Check for attributes
+    if(attrList && attrList[0])
+    {
+        // If a context is already running on the device, stop playback so the
+        // device attributes can be updated
+        if(running)
+        {
+            ProcessContext(NULL);
+            ALCdevice_StopPlayback(device);
+            SuspendContext(NULL);
+            running = AL_FALSE;
+        }
+
+        freq = device->Frequency;
+        numMono = device->NumMonoSources;
+        numStereo = device->NumStereoSources;
+        numSends = device->NumAuxSends;
+
+        attrIdx = 0;
+        while(attrList[attrIdx])
+        {
+            if(attrList[attrIdx] == ALC_FREQUENCY &&
+               !ConfigValueExists(NULL, "frequency"))
+            {
+                freq = attrList[attrIdx + 1];
+                if(freq < 8000)
+                    freq = 8000;
+            }
+
+            if(attrList[attrIdx] == ALC_STEREO_SOURCES)
+            {
+                numStereo = attrList[attrIdx + 1];
+                if(numStereo > device->MaxNoOfSources)
+                    numStereo = device->MaxNoOfSources;
+
+                numMono = device->MaxNoOfSources - numStereo;
+            }
+
+            if(attrList[attrIdx] == ALC_MAX_AUXILIARY_SENDS &&
+               !ConfigValueExists(NULL, "sends"))
+            {
+                numSends = attrList[attrIdx + 1];
+                if(numSends > MAX_SENDS)
+                    numSends = MAX_SENDS;
+            }
+
+            attrIdx += 2;
+        }
+
+        device->UpdateSize = (ALuint64)device->UpdateSize * freq /
+                             device->Frequency;
+
+        device->Frequency = freq;
+        device->NumMonoSources = numMono;
+        device->NumStereoSources = numStereo;
+        device->NumAuxSends = numSends;
+    }
+
+    if(running)
+        return ALC_TRUE;
+
+    if(ALCdevice_ResetPlayback(device) == ALC_FALSE)
+        return ALC_FALSE;
+
+    aluInitPanning(device);
+
+    for(i = 0;i < MAXCHANNELS;i++)
+    {
+        device->ClickRemoval[i] = 0.0f;
+        device->PendingClicks[i] = 0.0f;
+    }
+
+    for(i = 0;i < device->NumContexts;i++)
+    {
+        ALCcontext *context = device->Contexts[i];
+        ALsizei pos;
+
+        SuspendContext(context);
+        for(pos = 0;pos < context->EffectSlotMap.size;pos++)
+        {
+            ALeffectslot *slot = context->EffectSlotMap.array[pos].value;
+
+            if(ALEffect_DeviceUpdate(slot->EffectState, device) == AL_FALSE)
+            {
+                ProcessContext(context);
+                return ALC_FALSE;
+            }
+            ALEffect_Update(slot->EffectState, context, &slot->effect);
+        }
+
+        for(pos = 0;pos < context->SourceMap.size;pos++)
+        {
+            ALsource *source = context->SourceMap.array[pos].value;
+            ALuint s = device->NumAuxSends;
+            while(s < MAX_SENDS)
+            {
+                if(source->Send[s].Slot)
+                    source->Send[s].Slot->refcount--;
+                source->Send[s].Slot = NULL;
+                source->Send[s].WetFilter.type = 0;
+                source->Send[s].WetFilter.filter = 0;
+                s++;
+            }
+            source->NeedsUpdate = AL_TRUE;
+        }
+        ProcessContext(context);
+    }
+
+    if(device->Bs2bLevel > 0 && device->Bs2bLevel <= 6)
+    {
+        if(!device->Bs2b)
+        {
+            device->Bs2b = calloc(1, sizeof(*device->Bs2b));
+            bs2b_clear(device->Bs2b);
+        }
+        bs2b_set_srate(device->Bs2b, device->Frequency);
+        bs2b_set_level(device->Bs2b, device->Bs2bLevel);
+    }
+    else
+    {
+        free(device->Bs2b);
+        device->Bs2b = NULL;
+    }
+
+    if(ChannelsFromDevFmt(device->FmtChans) <= 2)
+    {
+        device->HeadDampen = GetConfigValueFloat(NULL, "head_dampen", DEFAULT_HEAD_DAMPEN);
+        device->HeadDampen = __min(device->HeadDampen, 1.0f);
+        device->HeadDampen = __max(device->HeadDampen, 0.0f);
+    }
+    else
+        device->HeadDampen = 0.0f;
+
+    return ALC_TRUE;
+}
+
+
+/*
+    SuspendContext
+
+    Thread-safe entry
+*/
+ALCvoid SuspendContext(ALCcontext *pContext)
+{
+    (void)pContext;
+    EnterCriticalSection(&g_csMutex);
+}
+
+
+/*
+    ProcessContext
+
+    Thread-safe exit
+*/
+ALCvoid ProcessContext(ALCcontext *pContext)
+{
+    (void)pContext;
+    LeaveCriticalSection(&g_csMutex);
+}
+
+
+/*
+    GetContextSuspended
+
+    Returns the currently active Context, in a locked state
+*/
+ALCcontext *GetContextSuspended(void)
+{
+    ALCcontext *pContext = NULL;
+
+    SuspendContext(NULL);
+
+    pContext = tls_get(LocalContext);
+    if(pContext && !IsContext(pContext))
+    {
+        tls_set(LocalContext, NULL);
+        pContext = NULL;
+    }
+    if(!pContext)
+        pContext = GlobalContext;
+
+    if(pContext)
+        SuspendContext(pContext);
+
+    ProcessContext(NULL);
+
+    return pContext;
+}
+
+
+/*
+    InitContext
+
+    Initialize Context variables
+*/
+static ALvoid InitContext(ALCcontext *pContext)
+{
+    //Initialise listener
+    pContext->Listener.Gain = 1.0f;
+    pContext->Listener.MetersPerUnit = 1.0f;
+    pContext->Listener.Position[0] = 0.0f;
+    pContext->Listener.Position[1] = 0.0f;
+    pContext->Listener.Position[2] = 0.0f;
+    pContext->Listener.Velocity[0] = 0.0f;
+    pContext->Listener.Velocity[1] = 0.0f;
+    pContext->Listener.Velocity[2] = 0.0f;
+    pContext->Listener.Forward[0] = 0.0f;
+    pContext->Listener.Forward[1] = 0.0f;
+    pContext->Listener.Forward[2] = -1.0f;
+    pContext->Listener.Up[0] = 0.0f;
+    pContext->Listener.Up[1] = 1.0f;
+    pContext->Listener.Up[2] = 0.0f;
+
+    //Validate pContext
+    pContext->LastError = AL_NO_ERROR;
+    pContext->Suspended = AL_FALSE;
+    pContext->ActiveSourceCount = 0;
+    InitUIntMap(&pContext->SourceMap);
+    InitUIntMap(&pContext->EffectSlotMap);
+
+    //Set globals
+    pContext->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
+    pContext->SourceDistanceModel = AL_FALSE;
+    pContext->DopplerFactor = 1.0f;
+    pContext->DopplerVelocity = 1.0f;
+    pContext->flSpeedOfSound = SPEEDOFSOUNDMETRESPERSEC;
+
+    pContext->ExtensionList = alExtList;
+}
+
+
+/*
+    ExitContext
+
+    Clean up Context, destroy any remaining Sources
+*/
+static ALCvoid ExitContext(ALCcontext *pContext)
+{
+    //Invalidate context
+    pContext->LastError = AL_NO_ERROR;
+}
+
+///////////////////////////////////////////////////////
+
+
+///////////////////////////////////////////////////////
+// ALC Functions calls
+
+
+// This should probably move to another c file but for now ...
+ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
+{
+    ALCboolean DeviceFound = ALC_FALSE;
+    ALCdevice *device = NULL;
+    ALCint i;
+
+    if(SampleSize <= 0)
+    {
+        alcSetError(NULL, ALC_INVALID_VALUE);
+        return NULL;
+    }
+
+    if(deviceName && !deviceName[0])
+        deviceName = NULL;
+
+    device = calloc(1, sizeof(ALCdevice));
+    if(!device)
+    {
+        alcSetError(NULL, ALC_OUT_OF_MEMORY);
+        return NULL;
+    }
+
+    //Validate device
+    device->Connected = ALC_TRUE;
+    device->IsCaptureDevice = AL_TRUE;
+
+    device->szDeviceName = NULL;
+
+    device->Frequency = frequency;
+    if(DecomposeDevFormat(format, &device->FmtChans, &device->FmtType) == AL_FALSE)
+    {
+        free(device);
+        alcSetError(NULL, ALC_INVALID_ENUM);
+        return NULL;
+    }
+
+    device->UpdateSize = SampleSize;
+    device->NumUpdates = 1;
+
+    SuspendContext(NULL);
+    for(i = 0;BackendList[i].Init;i++)
+    {
+        device->Funcs = &BackendList[i].Funcs;
+        if(ALCdevice_OpenCapture(device, deviceName))
+        {
+            device->next = g_pDeviceList;
+            g_pDeviceList = device;
+            g_ulDeviceCount++;
+
+            DeviceFound = ALC_TRUE;
+            break;
+        }
+    }
+    ProcessContext(NULL);
+
+    if(!DeviceFound)
+    {
+        alcSetError(NULL, ALC_INVALID_VALUE);
+        free(device);
+        device = NULL;
+    }
+
+    return device;
+}
+
+ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *pDevice)
+{
+    ALCdevice **list;
+
+    if(!IsDevice(pDevice) || !pDevice->IsCaptureDevice)
+    {
+        alcSetError(pDevice, ALC_INVALID_DEVICE);
+        return ALC_FALSE;
+    }
+
+    SuspendContext(NULL);
+
+    list = &g_pDeviceList;
+    while(*list != pDevice)
+        list = &(*list)->next;
+
+    *list = (*list)->next;
+    g_ulDeviceCount--;
+
+    ProcessContext(NULL);
+
+    ALCdevice_CloseCapture(pDevice);
+
+    free(pDevice->szDeviceName);
+    pDevice->szDeviceName = NULL;
+
+    free(pDevice);
+
+    return ALC_TRUE;
+}
+
+ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
+{
+    SuspendContext(NULL);
+    if(!IsDevice(device) || !device->IsCaptureDevice)
+        alcSetError(device, ALC_INVALID_DEVICE);
+    else if(device->Connected)
+        ALCdevice_StartCapture(device);
+    ProcessContext(NULL);
+}
+
+ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
+{
+    SuspendContext(NULL);
+    if(!IsDevice(device) || !device->IsCaptureDevice)
+        alcSetError(device, ALC_INVALID_DEVICE);
+    else
+        ALCdevice_StopCapture(device);
+    ProcessContext(NULL);
+}
+
+ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
+{
+    SuspendContext(NULL);
+    if(!IsDevice(device) || !device->IsCaptureDevice)
+        alcSetError(device, ALC_INVALID_DEVICE);
+    else
+        ALCdevice_CaptureSamples(device, buffer, samples);
+    ProcessContext(NULL);
+}
+
+/*
+    alcGetError
+
+    Return last ALC generated error code
+*/
+ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
+{
+    ALCenum errorCode;
+
+    if(IsDevice(device))
+    {
+        errorCode = device->LastError;
+        device->LastError = ALC_NO_ERROR;
+    }
+    else
+    {
+        errorCode = g_eLastNullDeviceError;
+        g_eLastNullDeviceError = ALC_NO_ERROR;
+    }
+    return errorCode;
+}
+
+
+/*
+    alcSuspendContext
+
+    Not functional
+*/
+ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *pContext)
+{
+    SuspendContext(NULL);
+    if(IsContext(pContext))
+        pContext->Suspended = AL_TRUE;
+    ProcessContext(NULL);
+}
+
+
+/*
+    alcProcessContext
+
+    Not functional
+*/
+ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *pContext)
+{
+    SuspendContext(NULL);
+    if(IsContext(pContext))
+        pContext->Suspended = AL_FALSE;
+    ProcessContext(NULL);
+}
+
+
+/*
+    alcGetString
+
+    Returns information about the Device, and error strings
+*/
+ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *pDevice,ALCenum param)
+{
+    const ALCchar *value = NULL;
+
+    switch (param)
+    {
+    case ALC_NO_ERROR:
+        value = alcNoError;
+        break;
+
+    case ALC_INVALID_ENUM:
+        value = alcErrInvalidEnum;
+        break;
+
+    case ALC_INVALID_VALUE:
+        value = alcErrInvalidValue;
+        break;
+
+    case ALC_INVALID_DEVICE:
+        value = alcErrInvalidDevice;
+        break;
+
+    case ALC_INVALID_CONTEXT:
+        value = alcErrInvalidContext;
+        break;
+
+    case ALC_OUT_OF_MEMORY:
+        value = alcErrOutOfMemory;
+        break;
+
+    case ALC_DEVICE_SPECIFIER:
+        if(IsDevice(pDevice))
+            value = pDevice->szDeviceName;
+        else
+        {
+            ProbeDeviceList();
+            value = alcDeviceList;
+        }
+        break;
+
+    case ALC_ALL_DEVICES_SPECIFIER:
+        ProbeAllDeviceList();
+        value = alcAllDeviceList;
+        break;
+
+    case ALC_CAPTURE_DEVICE_SPECIFIER:
+        if(IsDevice(pDevice))
+            value = pDevice->szDeviceName;
+        else
+        {
+            ProbeCaptureDeviceList();
+            value = alcCaptureDeviceList;
+        }
+        break;
+
+    /* Default devices are always first in the list */
+    case ALC_DEFAULT_DEVICE_SPECIFIER:
+        if(!alcDeviceList)
+            ProbeDeviceList();
+
+        free(alcDefaultDeviceSpecifier);
+        alcDefaultDeviceSpecifier = strdup(alcDeviceList ? alcDeviceList : "");
+        if(!alcDefaultDeviceSpecifier)
+            alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+        value = alcDefaultDeviceSpecifier;
+        break;
+
+    case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
+        if(!alcAllDeviceList)
+            ProbeAllDeviceList();
+
+        free(alcDefaultAllDeviceSpecifier);
+        alcDefaultAllDeviceSpecifier = strdup(alcAllDeviceList ?
+                                              alcAllDeviceList : "");
+        if(!alcDefaultAllDeviceSpecifier)
+            alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+        value = alcDefaultAllDeviceSpecifier;
+        break;
+
+    case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
+        if(!alcCaptureDeviceList)
+            ProbeCaptureDeviceList();
+
+        free(alcCaptureDefaultDeviceSpecifier);
+        alcCaptureDefaultDeviceSpecifier = strdup(alcCaptureDeviceList ?
+                                                  alcCaptureDeviceList : "");
+        if(!alcCaptureDefaultDeviceSpecifier)
+            alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+        value = alcCaptureDefaultDeviceSpecifier;
+        break;
+
+    case ALC_EXTENSIONS:
+        if(IsDevice(pDevice))
+            value = alcExtensionList;
+        else
+            value = alcNoDeviceExtList;
+        break;
+
+    default:
+        alcSetError(pDevice, ALC_INVALID_ENUM);
+        break;
+    }
+
+    return value;
+}
+
+
+/*
+    alcGetIntegerv
+
+    Returns information about the Device and the version of Open AL
+*/
+ALC_API ALCvoid ALC_APIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsizei size,ALCint *data)
+{
+    if(size == 0 || data == NULL)
+    {
+        alcSetError(device, ALC_INVALID_VALUE);
+        return;
+    }
+
+    if(IsDevice(device) && device->IsCaptureDevice)
+    {
+        SuspendContext(NULL);
+
+        // Capture device
+        switch (param)
+        {
+        case ALC_CAPTURE_SAMPLES:
+            *data = ALCdevice_AvailableSamples(device);
+            break;
+
+        case ALC_CONNECTED:
+            *data = device->Connected;
+            break;
+
+        default:
+            alcSetError(device, ALC_INVALID_ENUM);
+            break;
+        }
+
+        ProcessContext(NULL);
+        return;
+    }
+
+    // Playback Device
+    switch (param)
+    {
+        case ALC_MAJOR_VERSION:
+            *data = alcMajorVersion;
+            break;
+
+        case ALC_MINOR_VERSION:
+            *data = alcMinorVersion;
+            break;
+
+        case ALC_EFX_MAJOR_VERSION:
+            *data = alcEFXMajorVersion;
+            break;
+
+        case ALC_EFX_MINOR_VERSION:
+            *data = alcEFXMinorVersion;
+            break;
+
+        case ALC_MAX_AUXILIARY_SENDS:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else
+                *data = device->NumAuxSends;
+            break;
+
+        case ALC_ATTRIBUTES_SIZE:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else
+                *data = 13;
+            break;
+
+        case ALC_ALL_ATTRIBUTES:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else if (size < 13)
+                alcSetError(device, ALC_INVALID_VALUE);
+            else
+            {
+                int i = 0;
+
+                SuspendContext(NULL);
+                data[i++] = ALC_FREQUENCY;
+                data[i++] = device->Frequency;
+
+                data[i++] = ALC_REFRESH;
+                data[i++] = device->Frequency / device->UpdateSize;
+
+                data[i++] = ALC_SYNC;
+                data[i++] = ALC_FALSE;
+
+                data[i++] = ALC_MONO_SOURCES;
+                data[i++] = device->NumMonoSources;
+
+                data[i++] = ALC_STEREO_SOURCES;
+                data[i++] = device->NumStereoSources;
+
+                data[i++] = ALC_MAX_AUXILIARY_SENDS;
+                data[i++] = device->NumAuxSends;
+
+                data[i++] = 0;
+                ProcessContext(NULL);
+            }
+            break;
+
+        case ALC_FREQUENCY:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else
+                *data = device->Frequency;
+            break;
+
+        case ALC_REFRESH:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else
+                *data = device->Frequency / device->UpdateSize;
+            break;
+
+        case ALC_SYNC:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else
+                *data = ALC_FALSE;
+            break;
+
+        case ALC_MONO_SOURCES:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else
+                *data = device->NumMonoSources;
+            break;
+
+        case ALC_STEREO_SOURCES:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else
+                *data = device->NumStereoSources;
+            break;
+
+        case ALC_CONNECTED:
+            if(!IsDevice(device))
+                alcSetError(device, ALC_INVALID_DEVICE);
+            else
+                *data = device->Connected;
+            break;
+
+        default:
+            alcSetError(device, ALC_INVALID_ENUM);
+            break;
+    }
+}
+
+
+/*
+    alcIsExtensionPresent
+
+    Determines if there is support for a particular extension
+*/
+ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName)
+{
+    ALCboolean bResult = ALC_FALSE;
+    const char *ptr;
+    size_t len;
+
+    if(!extName)
+    {
+        alcSetError(device, ALC_INVALID_VALUE);
+        return ALC_FALSE;
+    }
+
+    len = strlen(extName);
+    ptr = (IsDevice(device) ? alcExtensionList : alcNoDeviceExtList);
+    while(ptr && *ptr)
+    {
+        if(strncasecmp(ptr, extName, len) == 0 &&
+           (ptr[len] == '\0' || isspace(ptr[len])))
+        {
+            bResult = ALC_TRUE;
+            break;
+        }
+        if((ptr=strchr(ptr, ' ')) != NULL)
+        {
+            do {
+                ++ptr;
+            } while(isspace(*ptr));
+        }
+    }
+
+    return bResult;
+}
+
+
+/*
+    alcGetProcAddress
+
+    Retrieves the function address for a particular extension function
+*/
+ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName)
+{
+    ALsizei i = 0;
+
+    if(!funcName)
+    {
+        alcSetError(device, ALC_INVALID_VALUE);
+        return NULL;
+    }
+
+    while(alcFunctions[i].funcName && strcmp(alcFunctions[i].funcName,funcName) != 0)
+        i++;
+    return alcFunctions[i].address;
+}
+
+
+/*
+    alcGetEnumValue
+
+    Get the value for a particular ALC Enumerated Value
+*/
+ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName)
+{
+    ALsizei i = 0;
+
+    if(!enumName)
+    {
+        alcSetError(device, ALC_INVALID_VALUE);
+        return (ALCenum)0;
+    }
+
+    while(enumeration[i].enumName && strcmp(enumeration[i].enumName,enumName) != 0)
+        i++;
+    return enumeration[i].value;
+}
+
+
+/*
+    alcCreateContext
+
+    Create and attach a Context to a particular Device.
+*/
+ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList)
+{
+    ALCcontext *ALContext;
+    void *temp;
+
+    SuspendContext(NULL);
+
+    if(!IsDevice(device) || device->IsCaptureDevice || !device->Connected)
+    {
+        alcSetError(device, ALC_INVALID_DEVICE);
+        ProcessContext(NULL);
+        return NULL;
+    }
+
+    // Reset Context Last Error code
+    device->LastError = ALC_NO_ERROR;
+
+    if(UpdateDeviceParams(device, attrList) == ALC_FALSE)
+    {
+        alcSetError(device, ALC_INVALID_DEVICE);
+        aluHandleDisconnect(device);
+        ProcessContext(NULL);
+        ALCdevice_StopPlayback(device);
+        return NULL;
+    }
+
+    ALContext = NULL;
+    temp = realloc(device->Contexts, (device->NumContexts+1) * sizeof(*device->Contexts));
+    if(temp)
+    {
+        device->Contexts = temp;
+
+        ALContext = calloc(1, sizeof(ALCcontext));
+        if(ALContext)
+        {
+            ALContext->MaxActiveSources = 256;
+            ALContext->ActiveSources = malloc(sizeof(ALContext->ActiveSources[0]) *
+                                              ALContext->MaxActiveSources);
+        }
+    }
+    if(!ALContext || !ALContext->ActiveSources)
+    {
+        free(ALContext);
+        alcSetError(device, ALC_OUT_OF_MEMORY);
+        ProcessContext(NULL);
+        if(device->NumContexts == 0)
+            ALCdevice_StopPlayback(device);
+        return NULL;
+    }
+
+    device->Contexts[device->NumContexts++] = ALContext;
+    ALContext->Device = device;
+
+    InitContext(ALContext);
+
+    ALContext->next = g_pContextList;
+    g_pContextList = ALContext;
+    g_ulContextCount++;
+
+    ProcessContext(NULL);
+
+    return ALContext;
+}
+
+
+/*
+    alcDestroyContext
+
+    Remove a Context
+*/
+ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context)
+{
+    ALCdevice *Device;
+    ALCcontext **list;
+    ALuint i;
+
+    if(!IsContext(context))
+    {
+        alcSetError(NULL, ALC_INVALID_CONTEXT);
+        return;
+    }
+
+    Device = context->Device;
+
+    if(Device->NumContexts == 1)
+        ALCdevice_StopPlayback(Device);
+
+    SuspendContext(NULL);
+
+    if(context == GlobalContext)
+        GlobalContext = NULL;
+
+    for(i = 0;i < Device->NumContexts;i++)
+    {
+        if(Device->Contexts[i] == context)
+        {
+            Device->Contexts[i] = Device->Contexts[Device->NumContexts-1];
+            Device->NumContexts--;
+            break;
+        }
+    }
+
+    // Lock context
+    SuspendContext(context);
+
+    if(context->SourceMap.size > 0)
+    {
+#ifdef _DEBUG
+        AL_PRINT("alcDestroyContext(): deleting %d Source(s)\n", context->SourceMap.size);
+#endif
+        ReleaseALSources(context);
+    }
+    ResetUIntMap(&context->SourceMap);
+
+    if(context->EffectSlotMap.size > 0)
+    {
+#ifdef _DEBUG
+        AL_PRINT("alcDestroyContext(): deleting %d AuxiliaryEffectSlot(s)\n", context->EffectSlotMap.size);
+#endif
+        ReleaseALAuxiliaryEffectSlots(context);
+    }
+    ResetUIntMap(&context->EffectSlotMap);
+
+    free(context->ActiveSources);
+    context->ActiveSources = NULL;
+    context->MaxActiveSources = 0;
+    context->ActiveSourceCount = 0;
+
+    list = &g_pContextList;
+    while(*list != context)
+        list = &(*list)->next;
+
+    *list = (*list)->next;
+    g_ulContextCount--;
+
+    // Unlock context
+    ProcessContext(context);
+    ProcessContext(NULL);
+
+    ExitContext(context);
+
+    // Free memory (MUST do this after ProcessContext)
+    memset(context, 0, sizeof(ALCcontext));
+    free(context);
+}
+
+
+/*
+    alcGetCurrentContext
+
+    Returns the currently active Context
+*/
+ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(ALCvoid)
+{
+    ALCcontext *pContext;
+
+    if((pContext=GetContextSuspended()) != NULL)
+        ProcessContext(pContext);
+
+    return pContext;
+}
+
+/*
+    alcGetThreadContext
+
+    Returns the currently active thread-local Context
+*/
+ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
+{
+    ALCcontext *pContext = NULL;
+
+    SuspendContext(NULL);
+
+    pContext = tls_get(LocalContext);
+    if(pContext && !IsContext(pContext))
+    {
+        tls_set(LocalContext, NULL);
+        pContext = NULL;
+    }
+
+    ProcessContext(NULL);
+
+    return pContext;
+}
+
+
+/*
+    alcGetContextsDevice
+
+    Returns the Device that a particular Context is attached to
+*/
+ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *pContext)
+{
+    ALCdevice *pDevice = NULL;
+
+    SuspendContext(NULL);
+    if(IsContext(pContext))
+        pDevice = pContext->Device;
+    else
+        alcSetError(NULL, ALC_INVALID_CONTEXT);
+    ProcessContext(NULL);
+
+    return pDevice;
+}
+
+
+/*
+    alcMakeContextCurrent
+
+    Makes the given Context the active Context
+*/
+ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
+{
+    ALboolean bReturn = AL_TRUE;
+
+    SuspendContext(NULL);
+
+    // context must be a valid Context or NULL
+    if(context == NULL || IsContext(context))
+    {
+        GlobalContext = context;
+        tls_set(LocalContext, NULL);
+    }
+    else
+    {
+        alcSetError(NULL, ALC_INVALID_CONTEXT);
+        bReturn = AL_FALSE;
+    }
+
+    ProcessContext(NULL);
+
+    return bReturn;
+}
+
+/*
+    alcSetThreadContext
+
+    Makes the given Context the active Context for the current thread
+*/
+ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
+{
+    ALboolean bReturn = AL_TRUE;
+
+    SuspendContext(NULL);
+
+    // context must be a valid Context or NULL
+    if(context == NULL || IsContext(context))
+        tls_set(LocalContext, context);
+    else
+    {
+        alcSetError(NULL, ALC_INVALID_CONTEXT);
+        bReturn = AL_FALSE;
+    }
+
+    ProcessContext(NULL);
+
+    return bReturn;
+}
+
+
+// Sets the default channel order used by most non-WaveFormatEx-based APIs
+void SetDefaultChannelOrder(ALCdevice *device)
+{
+    switch(device->FmtChans)
+    {
+    case DevFmtMono: device->DevChannels[FRONT_CENTER] = 0; break;
+
+    case DevFmtStereo: device->DevChannels[FRONT_LEFT]  = 0;
+                       device->DevChannels[FRONT_RIGHT] = 1; break;
+
+    case DevFmtQuad: device->DevChannels[FRONT_LEFT]  = 0;
+                     device->DevChannels[FRONT_RIGHT] = 1;
+                     device->DevChannels[BACK_LEFT]   = 2;
+                     device->DevChannels[BACK_RIGHT]  = 3; break;
+
+    case DevFmtX51: device->DevChannels[FRONT_LEFT]   = 0;
+                    device->DevChannels[FRONT_RIGHT]  = 1;
+                    device->DevChannels[BACK_LEFT]    = 2;
+                    device->DevChannels[BACK_RIGHT]   = 3;
+                    device->DevChannels[FRONT_CENTER] = 4;
+                    device->DevChannels[LFE]          = 5; break;
+
+    case DevFmtX61: device->DevChannels[FRONT_LEFT]   = 0;
+                    device->DevChannels[FRONT_RIGHT]  = 1;
+                    device->DevChannels[FRONT_CENTER] = 2;
+                    device->DevChannels[LFE]          = 3;
+                    device->DevChannels[BACK_CENTER]  = 4;
+                    device->DevChannels[SIDE_LEFT]    = 5;
+                    device->DevChannels[SIDE_RIGHT]   = 6; break;
+
+    case DevFmtX71: device->DevChannels[FRONT_LEFT]   = 0;
+                    device->DevChannels[FRONT_RIGHT]  = 1;
+                    device->DevChannels[BACK_LEFT]    = 2;
+                    device->DevChannels[BACK_RIGHT]   = 3;
+                    device->DevChannels[FRONT_CENTER] = 4;
+                    device->DevChannels[LFE]          = 5;
+                    device->DevChannels[SIDE_LEFT]    = 6;
+                    device->DevChannels[SIDE_RIGHT]   = 7; break;
+    }
+}
+// Sets the default order used by WaveFormatEx
+void SetDefaultWFXChannelOrder(ALCdevice *device)
+{
+    switch(device->FmtChans)
+    {
+    case DevFmtMono: device->DevChannels[FRONT_CENTER] = 0; break;
+
+    case DevFmtStereo: device->DevChannels[FRONT_LEFT]  = 0;
+                       device->DevChannels[FRONT_RIGHT] = 1; break;
+
+    case DevFmtQuad: device->DevChannels[FRONT_LEFT]  = 0;
+                     device->DevChannels[FRONT_RIGHT] = 1;
+                     device->DevChannels[BACK_LEFT]   = 2;
+                     device->DevChannels[BACK_RIGHT]  = 3; break;
+
+    case DevFmtX51: device->DevChannels[FRONT_LEFT]   = 0;
+                    device->DevChannels[FRONT_RIGHT]  = 1;
+                    device->DevChannels[FRONT_CENTER] = 2;
+                    device->DevChannels[LFE]          = 3;
+                    device->DevChannels[BACK_LEFT]    = 4;
+                    device->DevChannels[BACK_RIGHT]   = 5; break;
+
+    case DevFmtX61: device->DevChannels[FRONT_LEFT]   = 0;
+                    device->DevChannels[FRONT_RIGHT]  = 1;
+                    device->DevChannels[FRONT_CENTER] = 2;
+                    device->DevChannels[LFE]          = 3;
+                    device->DevChannels[BACK_CENTER]  = 4;
+                    device->DevChannels[SIDE_LEFT]    = 5;
+                    device->DevChannels[SIDE_RIGHT]   = 6; break;
+
+    case DevFmtX71: device->DevChannels[FRONT_LEFT]   = 0;
+                    device->DevChannels[FRONT_RIGHT]  = 1;
+                    device->DevChannels[FRONT_CENTER] = 2;
+                    device->DevChannels[LFE]          = 3;
+                    device->DevChannels[BACK_LEFT]    = 4;
+                    device->DevChannels[BACK_RIGHT]   = 5;
+                    device->DevChannels[SIDE_LEFT]    = 6;
+                    device->DevChannels[SIDE_RIGHT]   = 7; break;
+    }
+}
+
+static ALenum GetFormatFromString(const char *str)
+{
+    if(strcasecmp(str, "AL_FORMAT_MONO32") == 0)    return AL_FORMAT_MONO_FLOAT32;
+    if(strcasecmp(str, "AL_FORMAT_STEREO32") == 0)  return AL_FORMAT_STEREO_FLOAT32;
+    if(strcasecmp(str, "AL_FORMAT_QUAD32") == 0)    return AL_FORMAT_QUAD32;
+    if(strcasecmp(str, "AL_FORMAT_51CHN32") == 0)   return AL_FORMAT_51CHN32;
+    if(strcasecmp(str, "AL_FORMAT_61CHN32") == 0)   return AL_FORMAT_61CHN32;
+    if(strcasecmp(str, "AL_FORMAT_71CHN32") == 0)   return AL_FORMAT_71CHN32;
+
+    if(strcasecmp(str, "AL_FORMAT_MONO16") == 0)    return AL_FORMAT_MONO16;
+    if(strcasecmp(str, "AL_FORMAT_STEREO16") == 0)  return AL_FORMAT_STEREO16;
+    if(strcasecmp(str, "AL_FORMAT_QUAD16") == 0)    return AL_FORMAT_QUAD16;
+    if(strcasecmp(str, "AL_FORMAT_51CHN16") == 0)   return AL_FORMAT_51CHN16;
+    if(strcasecmp(str, "AL_FORMAT_61CHN16") == 0)   return AL_FORMAT_61CHN16;
+    if(strcasecmp(str, "AL_FORMAT_71CHN16") == 0)   return AL_FORMAT_71CHN16;
+
+    if(strcasecmp(str, "AL_FORMAT_MONO8") == 0)    return AL_FORMAT_MONO8;
+    if(strcasecmp(str, "AL_FORMAT_STEREO8") == 0)  return AL_FORMAT_STEREO8;
+    if(strcasecmp(str, "AL_FORMAT_QUAD8") == 0)    return AL_FORMAT_QUAD8;
+    if(strcasecmp(str, "AL_FORMAT_51CHN8") == 0)   return AL_FORMAT_51CHN8;
+    if(strcasecmp(str, "AL_FORMAT_61CHN8") == 0)   return AL_FORMAT_61CHN8;
+    if(strcasecmp(str, "AL_FORMAT_71CHN8") == 0)   return AL_FORMAT_71CHN8;
+
+    AL_PRINT("Unknown format: \"%s\"\n", str);
+    return AL_FORMAT_STEREO16;
+}
+
+/*
+    alcOpenDevice
+
+    Open the Device specified.
+*/
+ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName)
+{
+    ALboolean bDeviceFound = AL_FALSE;
+    const ALCchar *fmt;
+    ALCdevice *device;
+    ALint i;
+
+    if(deviceName && !deviceName[0])
+        deviceName = NULL;
+
+    device = calloc(1, sizeof(ALCdevice));
+    if(!device)
+    {
+        alcSetError(NULL, ALC_OUT_OF_MEMORY);
+        return NULL;
+    }
+
+    //Validate device
+    device->Connected = ALC_TRUE;
+    device->IsCaptureDevice = AL_FALSE;
+    device->LastError = ALC_NO_ERROR;
+
+    device->Bs2b = NULL;
+    device->szDeviceName = NULL;
+
+    device->Contexts = NULL;
+    device->NumContexts = 0;
+
+    InitUIntMap(&device->BufferMap);
+    InitUIntMap(&device->EffectMap);
+    InitUIntMap(&device->FilterMap);
+    InitUIntMap(&device->DatabufferMap);
+
+    //Set output format
+    device->Frequency = GetConfigValueInt(NULL, "frequency", SWMIXER_OUTPUT_RATE);
+    if(device->Frequency < 8000)
+        device->Frequency = 8000;
+
+    fmt = GetConfigValue(NULL, "format", "AL_FORMAT_STEREO16");
+    if(DecomposeDevFormat(GetFormatFromString(fmt),
+                          &device->FmtChans, &device->FmtType) == AL_FALSE)
+    {
+        /* Should never happen... */
+        device->FmtChans = DevFmtStereo;
+        device->FmtType = DevFmtShort;
+    }
+
+    device->NumUpdates = GetConfigValueInt(NULL, "periods", 4);
+    if(device->NumUpdates < 2)
+        device->NumUpdates = 4;
+
+    device->UpdateSize = GetConfigValueInt(NULL, "period_size", 1024);
+    if(device->UpdateSize <= 0)
+        device->UpdateSize = 1024;
+
+    device->MaxNoOfSources = GetConfigValueInt(NULL, "sources", 256);
+    if((ALint)device->MaxNoOfSources <= 0)
+        device->MaxNoOfSources = 256;
+
+    device->AuxiliaryEffectSlotMax = GetConfigValueInt(NULL, "slots", 4);
+    if((ALint)device->AuxiliaryEffectSlotMax <= 0)
+        device->AuxiliaryEffectSlotMax = 4;
+
+    device->NumStereoSources = 1;
+    device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources;
+
+    device->NumAuxSends = GetConfigValueInt(NULL, "sends", 1);
+    if(device->NumAuxSends > MAX_SENDS)
+        device->NumAuxSends = MAX_SENDS;
+
+    device->Bs2bLevel = GetConfigValueInt(NULL, "cf_level", 0);
+
+    device->DuplicateStereo = GetConfigValueBool(NULL, "stereodup", 1);
+
+    device->HeadDampen = 0.0f;
+
+    // Find a playback device to open
+    SuspendContext(NULL);
+    for(i = 0;BackendList[i].Init;i++)
+    {
+        device->Funcs = &BackendList[i].Funcs;
+        if(ALCdevice_OpenPlayback(device, deviceName))
+        {
+            device->next = g_pDeviceList;
+            g_pDeviceList = device;
+            g_ulDeviceCount++;
+
+            bDeviceFound = AL_TRUE;
+            break;
+        }
+    }
+    ProcessContext(NULL);
+
+    if(!bDeviceFound)
+    {
+        // No suitable output device found
+        alcSetError(NULL, ALC_INVALID_VALUE);
+        free(device);
+        device = NULL;
+    }
+
+    return device;
+}
+
+
+/*
+    alcCloseDevice
+
+    Close the specified Device
+*/
+ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *pDevice)
+{
+    ALCdevice **list;
+
+    if(!IsDevice(pDevice) || pDevice->IsCaptureDevice)
+    {
+        alcSetError(pDevice, ALC_INVALID_DEVICE);
+        return ALC_FALSE;
+    }
+
+    SuspendContext(NULL);
+
+    list = &g_pDeviceList;
+    while(*list != pDevice)
+        list = &(*list)->next;
+
+    *list = (*list)->next;
+    g_ulDeviceCount--;
+
+    ProcessContext(NULL);
+
+    if(pDevice->NumContexts > 0)
+    {
+#ifdef _DEBUG
+        AL_PRINT("alcCloseDevice(): destroying %u Context(s)\n", pDevice->NumContexts);
+#endif
+        while(pDevice->NumContexts > 0)
+            alcDestroyContext(pDevice->Contexts[0]);
+    }
+    ALCdevice_ClosePlayback(pDevice);
+
+    if(pDevice->BufferMap.size > 0)
+    {
+#ifdef _DEBUG
+        AL_PRINT("alcCloseDevice(): deleting %d Buffer(s)\n", pDevice->BufferMap.size);
+#endif
+        ReleaseALBuffers(pDevice);
+    }
+    ResetUIntMap(&pDevice->BufferMap);
+
+    if(pDevice->EffectMap.size > 0)
+    {
+#ifdef _DEBUG
+        AL_PRINT("alcCloseDevice(): deleting %d Effect(s)\n", pDevice->EffectMap.size);
+#endif
+        ReleaseALEffects(pDevice);
+    }
+    ResetUIntMap(&pDevice->EffectMap);
+
+    if(pDevice->FilterMap.size > 0)
+    {
+#ifdef _DEBUG
+        AL_PRINT("alcCloseDevice(): deleting %d Filter(s)\n", pDevice->FilterMap.size);
+#endif
+        ReleaseALFilters(pDevice);
+    }
+    ResetUIntMap(&pDevice->FilterMap);
+
+    if(pDevice->DatabufferMap.size > 0)
+    {
+#ifdef _DEBUG
+        AL_PRINT("alcCloseDevice(): deleting %d Databuffer(s)\n", pDevice->DatabufferMap.size);
+#endif
+        ReleaseALDatabuffers(pDevice);
+    }
+    ResetUIntMap(&pDevice->DatabufferMap);
+
+    free(pDevice->Bs2b);
+    pDevice->Bs2b = NULL;
+
+    free(pDevice->szDeviceName);
+    pDevice->szDeviceName = NULL;
+
+    free(pDevice->Contexts);
+    pDevice->Contexts = NULL;
+
+    //Release device structure
+    memset(pDevice, 0, sizeof(ALCdevice));
+    free(pDevice);
+
+    return ALC_TRUE;
+}
+
+
+static void ReleaseALC(void)
+{
+    free(alcDeviceList); alcDeviceList = NULL;
+    alcDeviceListSize = 0;
+    free(alcAllDeviceList); alcAllDeviceList = NULL;
+    alcAllDeviceListSize = 0;
+    free(alcCaptureDeviceList); alcCaptureDeviceList = NULL;
+    alcCaptureDeviceListSize = 0;
+
+    free(alcDefaultDeviceSpecifier);
+    alcDefaultDeviceSpecifier = NULL;
+    free(alcDefaultAllDeviceSpecifier);
+    alcDefaultAllDeviceSpecifier = NULL;
+    free(alcCaptureDefaultDeviceSpecifier);
+    alcCaptureDefaultDeviceSpecifier = NULL;
+
+#ifdef _DEBUG
+    if(g_ulDeviceCount > 0)
+        AL_PRINT("exit(): closing %u Device%s\n", g_ulDeviceCount, (g_ulDeviceCount>1)?"s":"");
+#endif
+
+    while(g_pDeviceList)
+    {
+        if(g_pDeviceList->IsCaptureDevice)
+            alcCaptureCloseDevice(g_pDeviceList);
+        else
+            alcCloseDevice(g_pDeviceList);
+    }
+}
+
+///////////////////////////////////////////////////////
diff --git a/Alc/ALu.c b/Alc/ALu.c
new file mode 100644 (file)
index 0000000..d831e9c
--- /dev/null
+++ b/Alc/ALu.c
@@ -0,0 +1,1028 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alListener.h"
+#include "alAuxEffectSlot.h"
+#include "alu.h"
+#include "bs2b.h"
+
+
+static __inline ALvoid aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
+{
+    outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
+    outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
+    outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
+}
+
+static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
+{
+    return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
+           inVector1[2]*inVector2[2];
+}
+
+static __inline ALvoid aluNormalize(ALfloat *inVector)
+{
+    ALfloat length, inverse_length;
+
+    length = aluSqrt(aluDotproduct(inVector, inVector));
+    if(length != 0.0f)
+    {
+        inverse_length = 1.0f/length;
+        inVector[0] *= inverse_length;
+        inVector[1] *= inverse_length;
+        inVector[2] *= inverse_length;
+    }
+}
+
+static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
+{
+    ALfloat temp[4] = {
+        vector[0], vector[1], vector[2], w
+    };
+
+    vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
+    vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
+    vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
+}
+
+
+ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
+{
+    ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
+    ALbufferlistitem *BufferListItem;
+    enum DevFmtChannels DevChans;
+    enum FmtChannels Channels;
+    ALfloat DryGain, DryGainHF;
+    ALfloat WetGain[MAX_SENDS];
+    ALfloat WetGainHF[MAX_SENDS];
+    ALint NumSends, Frequency;
+    ALboolean DupStereo;
+    ALfloat Pitch;
+    ALfloat cw;
+    ALint i;
+
+    /* Get device properties */
+    DevChans  = ALContext->Device->FmtChans;
+    DupStereo = ALContext->Device->DuplicateStereo;
+    NumSends  = ALContext->Device->NumAuxSends;
+    Frequency = ALContext->Device->Frequency;
+
+    /* Get listener properties */
+    ListenerGain = ALContext->Listener.Gain;
+
+    /* Get source properties */
+    SourceVolume = ALSource->flGain;
+    MinVolume    = ALSource->flMinGain;
+    MaxVolume    = ALSource->flMaxGain;
+    Pitch        = ALSource->flPitch;
+
+    /* Calculate the stepping value */
+    Channels = FmtMono;
+    BufferListItem = ALSource->queue;
+    while(BufferListItem != NULL)
+    {
+        ALbuffer *ALBuffer;
+        if((ALBuffer=BufferListItem->buffer) != NULL)
+        {
+            ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
+                                                               ALBuffer->FmtType);
+            maxstep -= ResamplerPadding[ALSource->Resampler] +
+                       ResamplerPrePadding[ALSource->Resampler] + 1;
+            maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
+
+            Pitch = Pitch * ALBuffer->Frequency / Frequency;
+            if(Pitch > (ALfloat)maxstep)
+                ALSource->Params.Step = maxstep<<FRACTIONBITS;
+            else
+            {
+                ALSource->Params.Step = Pitch*FRACTIONONE;
+                if(ALSource->Params.Step == 0)
+                    ALSource->Params.Step = 1;
+            }
+
+            Channels = ALBuffer->FmtChannels;
+            break;
+        }
+        BufferListItem = BufferListItem->next;
+    }
+
+    /* Calculate gains */
+    DryGain = SourceVolume;
+    DryGain = __min(DryGain,MaxVolume);
+    DryGain = __max(DryGain,MinVolume);
+    DryGainHF = 1.0f;
+
+    switch(ALSource->DirectFilter.type)
+    {
+        case AL_FILTER_LOWPASS:
+            DryGain *= ALSource->DirectFilter.Gain;
+            DryGainHF *= ALSource->DirectFilter.GainHF;
+            break;
+    }
+
+    for(i = 0;i < MAXCHANNELS;i++)
+    {
+        ALuint i2;
+        for(i2 = 0;i2 < MAXCHANNELS;i2++)
+            ALSource->Params.DryGains[i][i2] = 0.0f;
+    }
+
+    switch(Channels)
+    {
+    case FmtMono:
+        ALSource->Params.DryGains[0][FRONT_CENTER]  = DryGain * ListenerGain;
+        break;
+    case FmtStereo:
+        if(DupStereo == AL_FALSE)
+        {
+            ALSource->Params.DryGains[0][FRONT_LEFT]  = DryGain * ListenerGain;
+            ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+        }
+        else
+        {
+            switch(DevChans)
+            {
+            case DevFmtMono:
+            case DevFmtStereo:
+                ALSource->Params.DryGains[0][FRONT_LEFT]  = DryGain * ListenerGain;
+                ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+                break;
+
+            case DevFmtQuad:
+            case DevFmtX51:
+                DryGain *= aluSqrt(2.0f/4.0f);
+                ALSource->Params.DryGains[0][FRONT_LEFT]  = DryGain * ListenerGain;
+                ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+                ALSource->Params.DryGains[0][BACK_LEFT]   = DryGain * ListenerGain;
+                ALSource->Params.DryGains[1][BACK_RIGHT]  = DryGain * ListenerGain;
+                break;
+
+            case DevFmtX61:
+                DryGain *= aluSqrt(2.0f/4.0f);
+                ALSource->Params.DryGains[0][FRONT_LEFT]  = DryGain * ListenerGain;
+                ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+                ALSource->Params.DryGains[0][SIDE_LEFT]   = DryGain * ListenerGain;
+                ALSource->Params.DryGains[1][SIDE_RIGHT]  = DryGain * ListenerGain;
+                break;
+
+            case DevFmtX71:
+                DryGain *= aluSqrt(2.0f/6.0f);
+                ALSource->Params.DryGains[0][FRONT_LEFT]  = DryGain * ListenerGain;
+                ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+                ALSource->Params.DryGains[0][BACK_LEFT]   = DryGain * ListenerGain;
+                ALSource->Params.DryGains[1][BACK_RIGHT]  = DryGain * ListenerGain;
+                ALSource->Params.DryGains[0][SIDE_LEFT]   = DryGain * ListenerGain;
+                ALSource->Params.DryGains[1][SIDE_RIGHT]  = DryGain * ListenerGain;
+                break;
+            }
+        }
+        break;
+
+    case FmtRear:
+        ALSource->Params.DryGains[0][BACK_LEFT]  = DryGain * ListenerGain;
+        ALSource->Params.DryGains[1][BACK_RIGHT] = DryGain * ListenerGain;
+        break;
+
+    case FmtQuad:
+        ALSource->Params.DryGains[0][FRONT_LEFT]  = DryGain * ListenerGain;
+        ALSource->Params.DryGains[1][FRONT_RIGHT] = DryGain * ListenerGain;
+        ALSource->Params.DryGains[2][BACK_LEFT]   = DryGain * ListenerGain;
+        ALSource->Params.DryGains[3][BACK_RIGHT]  = DryGain * ListenerGain;
+        break;
+
+    case FmtX51:
+        ALSource->Params.DryGains[0][FRONT_LEFT]   = DryGain * ListenerGain;
+        ALSource->Params.DryGains[1][FRONT_RIGHT]  = DryGain * ListenerGain;
+        ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
+        ALSource->Params.DryGains[3][LFE]          = DryGain * ListenerGain;
+        ALSource->Params.DryGains[4][BACK_LEFT]    = DryGain * ListenerGain;
+        ALSource->Params.DryGains[5][BACK_RIGHT]   = DryGain * ListenerGain;
+        break;
+
+    case FmtX61:
+        ALSource->Params.DryGains[0][FRONT_LEFT]   = DryGain * ListenerGain;
+        ALSource->Params.DryGains[1][FRONT_RIGHT]  = DryGain * ListenerGain;
+        ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
+        ALSource->Params.DryGains[3][LFE]          = DryGain * ListenerGain;
+        ALSource->Params.DryGains[4][BACK_CENTER]  = DryGain * ListenerGain;
+        ALSource->Params.DryGains[5][SIDE_LEFT]    = DryGain * ListenerGain;
+        ALSource->Params.DryGains[6][SIDE_RIGHT]   = DryGain * ListenerGain;
+        break;
+
+    case FmtX71:
+        ALSource->Params.DryGains[0][FRONT_LEFT]   = DryGain * ListenerGain;
+        ALSource->Params.DryGains[1][FRONT_RIGHT]  = DryGain * ListenerGain;
+        ALSource->Params.DryGains[2][FRONT_CENTER] = DryGain * ListenerGain;
+        ALSource->Params.DryGains[3][LFE]          = DryGain * ListenerGain;
+        ALSource->Params.DryGains[4][BACK_LEFT]    = DryGain * ListenerGain;
+        ALSource->Params.DryGains[5][BACK_RIGHT]   = DryGain * ListenerGain;
+        ALSource->Params.DryGains[6][SIDE_LEFT]    = DryGain * ListenerGain;
+        ALSource->Params.DryGains[7][SIDE_RIGHT]   = DryGain * ListenerGain;
+        break;
+    }
+
+    for(i = 0;i < NumSends;i++)
+    {
+        WetGain[i] = SourceVolume;
+        WetGain[i] = __min(WetGain[i],MaxVolume);
+        WetGain[i] = __max(WetGain[i],MinVolume);
+        WetGainHF[i] = 1.0f;
+
+        switch(ALSource->Send[i].WetFilter.type)
+        {
+            case AL_FILTER_LOWPASS:
+                WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
+                WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
+                break;
+        }
+
+        ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
+    }
+
+    /* Update filter coefficients. Calculations based on the I3DL2
+     * spec. */
+    cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
+
+    /* We use two chained one-pole filters, so we need to take the
+     * square root of the squared gain, which is the same as the base
+     * gain. */
+    ALSource->Params.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
+
+    for(i = 0;i < NumSends;i++)
+    {
+        /* We use a one-pole filter, so we need to take the squared gain */
+        ALfloat a = lpCoeffCalc(WetGainHF[i]*WetGainHF[i], cw);
+        ALSource->Params.Send[i].iirFilter.coeff = a;
+    }
+}
+
+ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
+{
+    const ALCdevice *Device = ALContext->Device;
+    ALfloat InnerAngle,OuterAngle,Angle,Distance,OrigDist;
+    ALfloat Direction[3],Position[3],SourceToListener[3];
+    ALfloat Velocity[3],ListenerVel[3];
+    ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff,OuterGainHF;
+    ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
+    ALfloat DopplerFactor, DopplerVelocity, SpeedOfSound;
+    ALfloat AirAbsorptionFactor;
+    ALbufferlistitem *BufferListItem;
+    ALfloat Attenuation, EffectiveDist;
+    ALfloat RoomAttenuation[MAX_SENDS];
+    ALfloat MetersPerUnit;
+    ALfloat RoomRolloff[MAX_SENDS];
+    ALfloat DryGain;
+    ALfloat DryGainHF;
+    ALfloat WetGain[MAX_SENDS];
+    ALfloat WetGainHF[MAX_SENDS];
+    ALfloat DirGain, AmbientGain;
+    const ALfloat *SpeakerGain;
+    ALfloat Pitch;
+    ALfloat length;
+    ALuint Frequency;
+    ALint NumSends;
+    ALint pos, s, i;
+    ALfloat cw;
+
+    DryGainHF = 1.0f;
+    for(i = 0;i < MAX_SENDS;i++)
+        WetGainHF[i] = 1.0f;
+
+    //Get context properties
+    DopplerFactor   = ALContext->DopplerFactor * ALSource->DopplerFactor;
+    DopplerVelocity = ALContext->DopplerVelocity;
+    SpeedOfSound    = ALContext->flSpeedOfSound;
+    NumSends        = Device->NumAuxSends;
+    Frequency       = Device->Frequency;
+
+    //Get listener properties
+    ListenerGain = ALContext->Listener.Gain;
+    MetersPerUnit = ALContext->Listener.MetersPerUnit;
+    memcpy(ListenerVel, ALContext->Listener.Velocity, sizeof(ALContext->Listener.Velocity));
+
+    //Get source properties
+    SourceVolume = ALSource->flGain;
+    memcpy(Position,  ALSource->vPosition,    sizeof(ALSource->vPosition));
+    memcpy(Direction, ALSource->vOrientation, sizeof(ALSource->vOrientation));
+    memcpy(Velocity,  ALSource->vVelocity,    sizeof(ALSource->vVelocity));
+    MinVolume    = ALSource->flMinGain;
+    MaxVolume    = ALSource->flMaxGain;
+    MinDist      = ALSource->flRefDistance;
+    MaxDist      = ALSource->flMaxDistance;
+    Rolloff      = ALSource->flRollOffFactor;
+    InnerAngle   = ALSource->flInnerAngle;
+    OuterAngle   = ALSource->flOuterAngle;
+    OuterGainHF  = ALSource->OuterGainHF;
+    AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
+
+    //1. Translate Listener to origin (convert to head relative)
+    if(ALSource->bHeadRelative == AL_FALSE)
+    {
+        ALfloat U[3],V[3],N[3];
+        ALfloat Matrix[4][4];
+
+        // Build transform matrix
+        memcpy(N, ALContext->Listener.Forward, sizeof(N));  // At-vector
+        aluNormalize(N);  // Normalized At-vector
+        memcpy(V, ALContext->Listener.Up, sizeof(V));  // Up-vector
+        aluNormalize(V);  // Normalized Up-vector
+        aluCrossproduct(N, V, U); // Right-vector
+        aluNormalize(U);  // Normalized Right-vector
+        Matrix[0][0] = U[0]; Matrix[0][1] = V[0]; Matrix[0][2] = -N[0]; Matrix[0][3] = 0.0f;
+        Matrix[1][0] = U[1]; Matrix[1][1] = V[1]; Matrix[1][2] = -N[1]; Matrix[1][3] = 0.0f;
+        Matrix[2][0] = U[2]; Matrix[2][1] = V[2]; Matrix[2][2] = -N[2]; Matrix[2][3] = 0.0f;
+        Matrix[3][0] = 0.0f; Matrix[3][1] = 0.0f; Matrix[3][2] =  0.0f; Matrix[3][3] = 1.0f;
+
+        // Translate position
+        Position[0] -= ALContext->Listener.Position[0];
+        Position[1] -= ALContext->Listener.Position[1];
+        Position[2] -= ALContext->Listener.Position[2];
+
+        // Transform source position and direction into listener space
+        aluMatrixVector(Position, 1.0f, Matrix);
+        aluMatrixVector(Direction, 0.0f, Matrix);
+        // Transform source and listener velocity into listener space
+        aluMatrixVector(Velocity, 0.0f, Matrix);
+        aluMatrixVector(ListenerVel, 0.0f, Matrix);
+    }
+    else
+        ListenerVel[0] = ListenerVel[1] = ListenerVel[2] = 0.0f;
+
+    SourceToListener[0] = -Position[0];
+    SourceToListener[1] = -Position[1];
+    SourceToListener[2] = -Position[2];
+    aluNormalize(SourceToListener);
+    aluNormalize(Direction);
+
+    //2. Calculate distance attenuation
+    Distance = aluSqrt(aluDotproduct(Position, Position));
+    OrigDist = Distance;
+
+    Attenuation = 1.0f;
+    for(i = 0;i < NumSends;i++)
+    {
+        RoomAttenuation[i] = 1.0f;
+
+        RoomRolloff[i] = ALSource->RoomRolloffFactor;
+        if(ALSource->Send[i].Slot &&
+           (ALSource->Send[i].Slot->effect.type == AL_EFFECT_REVERB ||
+            ALSource->Send[i].Slot->effect.type == AL_EFFECT_EAXREVERB))
+            RoomRolloff[i] += ALSource->Send[i].Slot->effect.Reverb.RoomRolloffFactor;
+    }
+
+    switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
+                                            ALContext->DistanceModel)
+    {
+        case AL_INVERSE_DISTANCE_CLAMPED:
+            Distance=__max(Distance,MinDist);
+            Distance=__min(Distance,MaxDist);
+            if(MaxDist < MinDist)
+                break;
+            //fall-through
+        case AL_INVERSE_DISTANCE:
+            if(MinDist > 0.0f)
+            {
+                if((MinDist + (Rolloff * (Distance - MinDist))) > 0.0f)
+                    Attenuation = MinDist / (MinDist + (Rolloff * (Distance - MinDist)));
+                for(i = 0;i < NumSends;i++)
+                {
+                    if((MinDist + (RoomRolloff[i] * (Distance - MinDist))) > 0.0f)
+                        RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (Distance - MinDist)));
+                }
+            }
+            break;
+
+        case AL_LINEAR_DISTANCE_CLAMPED:
+            Distance=__max(Distance,MinDist);
+            Distance=__min(Distance,MaxDist);
+            if(MaxDist < MinDist)
+                break;
+            //fall-through
+        case AL_LINEAR_DISTANCE:
+            if(MaxDist != MinDist)
+            {
+                Attenuation = 1.0f - (Rolloff*(Distance-MinDist)/(MaxDist - MinDist));
+                Attenuation = __max(Attenuation, 0.0f);
+                for(i = 0;i < NumSends;i++)
+                {
+                    RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(Distance-MinDist)/(MaxDist - MinDist));
+                    RoomAttenuation[i] = __max(RoomAttenuation[i], 0.0f);
+                }
+            }
+            break;
+
+        case AL_EXPONENT_DISTANCE_CLAMPED:
+            Distance=__max(Distance,MinDist);
+            Distance=__min(Distance,MaxDist);
+            if(MaxDist < MinDist)
+                break;
+            //fall-through
+        case AL_EXPONENT_DISTANCE:
+            if(Distance > 0.0f && MinDist > 0.0f)
+            {
+                Attenuation = aluPow(Distance/MinDist, -Rolloff);
+                for(i = 0;i < NumSends;i++)
+                    RoomAttenuation[i] = aluPow(Distance/MinDist, -RoomRolloff[i]);
+            }
+            break;
+
+        case AL_NONE:
+            break;
+    }
+
+    // Source Gain + Attenuation
+    DryGain = SourceVolume * Attenuation;
+    for(i = 0;i < NumSends;i++)
+        WetGain[i] = SourceVolume * RoomAttenuation[i];
+
+    EffectiveDist = 0.0f;
+    if(MinDist > 0.0f && Attenuation < 1.0f)
+        EffectiveDist = (MinDist/Attenuation - MinDist)*MetersPerUnit;
+
+    // Distance-based air absorption
+    if(AirAbsorptionFactor > 0.0f && EffectiveDist > 0.0f)
+    {
+        ALfloat absorb;
+
+        // Absorption calculation is done in dB
+        absorb = (AirAbsorptionFactor*AIRABSORBGAINDBHF) *
+                 EffectiveDist;
+        // Convert dB to linear gain before applying
+        absorb = aluPow(10.0f, absorb/20.0f);
+
+        DryGainHF *= absorb;
+    }
+
+    //3. Apply directional soundcones
+    Angle = aluAcos(aluDotproduct(Direction,SourceToListener)) * 180.0f/M_PI;
+    if(Angle >= InnerAngle && Angle <= OuterAngle)
+    {
+        ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
+        ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f)*scale);
+        ConeHF = (1.0f+(OuterGainHF-1.0f)*scale);
+    }
+    else if(Angle > OuterAngle)
+    {
+        ConeVolume = (1.0f+(ALSource->flOuterGain-1.0f));
+        ConeHF = (1.0f+(OuterGainHF-1.0f));
+    }
+    else
+    {
+        ConeVolume = 1.0f;
+        ConeHF = 1.0f;
+    }
+
+    // Apply some high-frequency attenuation for sources behind the listener
+    // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
+    // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
+    // the same as SourceToListener[2]
+    Angle = aluAcos(SourceToListener[2]) * 180.0f/M_PI;
+    // Sources within the minimum distance attenuate less
+    if(OrigDist < MinDist)
+        Angle *= OrigDist/MinDist;
+    if(Angle > 90.0f)
+    {
+        ALfloat scale = (Angle-90.0f) / (180.1f-90.0f); // .1 to account for fp errors
+        ConeHF *= 1.0f - (Device->HeadDampen*scale);
+    }
+
+    DryGain *= ConeVolume;
+    if(ALSource->DryGainHFAuto)
+        DryGainHF *= ConeHF;
+
+    // Clamp to Min/Max Gain
+    DryGain = __min(DryGain,MaxVolume);
+    DryGain = __max(DryGain,MinVolume);
+
+    for(i = 0;i < NumSends;i++)
+    {
+        ALeffectslot *Slot = ALSource->Send[i].Slot;
+
+        if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
+        {
+            ALSource->Params.Send[i].WetGain = 0.0f;
+            WetGainHF[i] = 1.0f;
+            continue;
+        }
+
+        if(Slot->AuxSendAuto)
+        {
+            if(ALSource->WetGainAuto)
+                WetGain[i] *= ConeVolume;
+            if(ALSource->WetGainHFAuto)
+                WetGainHF[i] *= ConeHF;
+
+            // Clamp to Min/Max Gain
+            WetGain[i] = __min(WetGain[i],MaxVolume);
+            WetGain[i] = __max(WetGain[i],MinVolume);
+
+            if(Slot->effect.type == AL_EFFECT_REVERB ||
+               Slot->effect.type == AL_EFFECT_EAXREVERB)
+            {
+                /* Apply a decay-time transformation to the wet path, based on
+                 * the attenuation of the dry path.
+                 *
+                 * Using the approximate (effective) source to listener
+                 * distance, the initial decay of the reverb effect is
+                 * calculated and applied to the wet path.
+                 */
+                WetGain[i] *= aluPow(10.0f, EffectiveDist /
+                                            (SPEEDOFSOUNDMETRESPERSEC *
+                                             Slot->effect.Reverb.DecayTime) *
+                                            -60.0 / 20.0);
+
+                WetGainHF[i] *= aluPow(Slot->effect.Reverb.AirAbsorptionGainHF,
+                                       AirAbsorptionFactor * EffectiveDist);
+            }
+        }
+        else
+        {
+            /* If the slot's auxiliary send auto is off, the data sent to the
+             * effect slot is the same as the dry path, sans filter effects */
+            WetGain[i] = DryGain;
+            WetGainHF[i] = DryGainHF;
+        }
+
+        switch(ALSource->Send[i].WetFilter.type)
+        {
+            case AL_FILTER_LOWPASS:
+                WetGain[i] *= ALSource->Send[i].WetFilter.Gain;
+                WetGainHF[i] *= ALSource->Send[i].WetFilter.GainHF;
+                break;
+        }
+        ALSource->Params.Send[i].WetGain = WetGain[i] * ListenerGain;
+    }
+
+    // Apply filter gains and filters
+    switch(ALSource->DirectFilter.type)
+    {
+        case AL_FILTER_LOWPASS:
+            DryGain *= ALSource->DirectFilter.Gain;
+            DryGainHF *= ALSource->DirectFilter.GainHF;
+            break;
+    }
+    DryGain *= ListenerGain;
+
+    // Calculate Velocity
+    Pitch = ALSource->flPitch;
+    if(DopplerFactor != 0.0f)
+    {
+        ALfloat VSS, VLS;
+        ALfloat MaxVelocity = (SpeedOfSound*DopplerVelocity) /
+                              DopplerFactor;
+
+        VSS = aluDotproduct(Velocity, SourceToListener);
+        if(VSS >= MaxVelocity)
+            VSS = (MaxVelocity - 1.0f);
+        else if(VSS <= -MaxVelocity)
+            VSS = -MaxVelocity + 1.0f;
+
+        VLS = aluDotproduct(ListenerVel, SourceToListener);
+        if(VLS >= MaxVelocity)
+            VLS = (MaxVelocity - 1.0f);
+        else if(VLS <= -MaxVelocity)
+            VLS = -MaxVelocity + 1.0f;
+
+        Pitch *= ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VLS)) /
+                 ((SpeedOfSound*DopplerVelocity) - (DopplerFactor*VSS));
+    }
+
+    BufferListItem = ALSource->queue;
+    while(BufferListItem != NULL)
+    {
+        ALbuffer *ALBuffer;
+        if((ALBuffer=BufferListItem->buffer) != NULL)
+        {
+            ALint maxstep = STACK_DATA_SIZE / FrameSizeFromFmt(ALBuffer->FmtChannels,
+                                                               ALBuffer->FmtType);
+            maxstep -= ResamplerPadding[ALSource->Resampler] +
+                       ResamplerPrePadding[ALSource->Resampler] + 1;
+            maxstep = min(maxstep, INT_MAX>>FRACTIONBITS);
+
+            Pitch = Pitch * ALBuffer->Frequency / Frequency;
+            if(Pitch > (ALfloat)maxstep)
+                ALSource->Params.Step = maxstep<<FRACTIONBITS;
+            else
+            {
+                ALSource->Params.Step = Pitch*FRACTIONONE;
+                if(ALSource->Params.Step == 0)
+                    ALSource->Params.Step = 1;
+            }
+            break;
+        }
+        BufferListItem = BufferListItem->next;
+    }
+
+    // Use energy-preserving panning algorithm for multi-speaker playback
+    length = __max(OrigDist, MinDist);
+    if(length > 0.0f)
+    {
+        ALfloat invlen = 1.0f/length;
+        Position[0] *= invlen;
+        Position[1] *= invlen;
+        Position[2] *= invlen;
+    }
+
+    pos = aluCart2LUTpos(-Position[2], Position[0]);
+    SpeakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
+
+    DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]);
+    // elevation adjustment for directional gain. this sucks, but
+    // has low complexity
+    AmbientGain = aluSqrt(1.0/Device->NumChan);
+    for(s = 0;s < MAXCHANNELS;s++)
+    {
+        ALuint s2;
+        for(s2 = 0;s2 < MAXCHANNELS;s2++)
+            ALSource->Params.DryGains[s][s2] = 0.0f;
+    }
+    for(s = 0;s < (ALsizei)Device->NumChan;s++)
+    {
+        Channel chan = Device->Speaker2Chan[s];
+        ALfloat gain = AmbientGain + (SpeakerGain[chan]-AmbientGain)*DirGain;
+        ALSource->Params.DryGains[0][chan] = DryGain * gain;
+    }
+
+    /* Update filter coefficients. */
+    cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / Frequency);
+
+    /* Spatialized sources use four chained one-pole filters, so we need to
+     * take the fourth root of the squared gain, which is the same as the
+     * square root of the base gain. */
+    ALSource->Params.iirFilter.coeff = lpCoeffCalc(aluSqrt(DryGainHF), cw);
+
+    for(i = 0;i < NumSends;i++)
+    {
+        /* The wet path uses two chained one-pole filters, so take the
+         * base gain (square root of the squared gain) */
+        ALSource->Params.Send[i].iirFilter.coeff = lpCoeffCalc(WetGainHF[i], cw);
+    }
+}
+
+
+static __inline ALfloat aluF2F(ALfloat val)
+{
+    return val;
+}
+static __inline ALushort aluF2US(ALfloat val)
+{
+    if(val > 1.0f) return 65535;
+    if(val < -1.0f) return 0;
+    return (ALint)(val*32767.0f) + 32768;
+}
+static __inline ALshort aluF2S(ALfloat val)
+{
+    if(val > 1.0f) return 32767;
+    if(val < -1.0f) return -32768;
+    return (ALint)(val*32767.0f);
+}
+static __inline ALubyte aluF2UB(ALfloat val)
+{
+    ALushort i = aluF2US(val);
+    return i>>8;
+}
+static __inline ALbyte aluF2B(ALfloat val)
+{
+    ALshort i = aluF2S(val);
+    return i>>8;
+}
+
+static const Channel MonoChans[] = { FRONT_CENTER };
+static const Channel StereoChans[] = { FRONT_LEFT, FRONT_RIGHT };
+static const Channel QuadChans[] = { FRONT_LEFT, FRONT_RIGHT,
+                                     BACK_LEFT, BACK_RIGHT };
+static const Channel X51Chans[] = { FRONT_LEFT, FRONT_RIGHT,
+                                    FRONT_CENTER, LFE,
+                                    BACK_LEFT, BACK_RIGHT };
+static const Channel X61Chans[] = { FRONT_LEFT, FRONT_LEFT,
+                                    FRONT_CENTER, LFE, BACK_CENTER,
+                                    SIDE_LEFT, SIDE_RIGHT };
+static const Channel X71Chans[] = { FRONT_LEFT, FRONT_RIGHT,
+                                    FRONT_CENTER, LFE,
+                                    BACK_LEFT, BACK_RIGHT,
+                                    SIDE_LEFT, SIDE_RIGHT };
+
+#define DECL_TEMPLATE(T, chans,N, func)                                       \
+static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
+{                                                                             \
+    ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer;                    \
+    ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix;                   \
+    const ALuint *ChanMap = device->DevChannels;                              \
+    ALuint i, j, c;                                                           \
+                                                                              \
+    for(i = 0;i < SamplesToDo;i++)                                            \
+    {                                                                         \
+        for(j = 0;j < N;j++)                                                  \
+        {                                                                     \
+            ALfloat samp = 0.0f;                                              \
+            for(c = 0;c < MAXCHANNELS;c++)                                    \
+                samp += DryBuffer[i][c] * Matrix[c][chans[j]];                \
+            ((T*)buffer)[ChanMap[chans[j]]] = func(samp);                     \
+        }                                                                     \
+        buffer = ((T*)buffer) + N;                                            \
+    }                                                                         \
+}
+
+DECL_TEMPLATE(ALfloat, MonoChans,1, aluF2F)
+DECL_TEMPLATE(ALfloat, QuadChans,4, aluF2F)
+DECL_TEMPLATE(ALfloat, X51Chans,6, aluF2F)
+DECL_TEMPLATE(ALfloat, X61Chans,7, aluF2F)
+DECL_TEMPLATE(ALfloat, X71Chans,8, aluF2F)
+
+DECL_TEMPLATE(ALushort, MonoChans,1, aluF2US)
+DECL_TEMPLATE(ALushort, QuadChans,4, aluF2US)
+DECL_TEMPLATE(ALushort, X51Chans,6, aluF2US)
+DECL_TEMPLATE(ALushort, X61Chans,7, aluF2US)
+DECL_TEMPLATE(ALushort, X71Chans,8, aluF2US)
+
+DECL_TEMPLATE(ALshort, MonoChans,1, aluF2S)
+DECL_TEMPLATE(ALshort, QuadChans,4, aluF2S)
+DECL_TEMPLATE(ALshort, X51Chans,6, aluF2S)
+DECL_TEMPLATE(ALshort, X61Chans,7, aluF2S)
+DECL_TEMPLATE(ALshort, X71Chans,8, aluF2S)
+
+DECL_TEMPLATE(ALubyte, MonoChans,1, aluF2UB)
+DECL_TEMPLATE(ALubyte, QuadChans,4, aluF2UB)
+DECL_TEMPLATE(ALubyte, X51Chans,6, aluF2UB)
+DECL_TEMPLATE(ALubyte, X61Chans,7, aluF2UB)
+DECL_TEMPLATE(ALubyte, X71Chans,8, aluF2UB)
+
+DECL_TEMPLATE(ALbyte, MonoChans,1, aluF2B)
+DECL_TEMPLATE(ALbyte, QuadChans,4, aluF2B)
+DECL_TEMPLATE(ALbyte, X51Chans,6, aluF2B)
+DECL_TEMPLATE(ALbyte, X61Chans,7, aluF2B)
+DECL_TEMPLATE(ALbyte, X71Chans,8, aluF2B)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T, chans,N, func)                                       \
+static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
+{                                                                             \
+    ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer;                    \
+    ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix;                   \
+    const ALuint *ChanMap = device->DevChannels;                              \
+    ALuint i, j, c;                                                           \
+                                                                              \
+    if(device->Bs2b)                                                          \
+    {                                                                         \
+        for(i = 0;i < SamplesToDo;i++)                                        \
+        {                                                                     \
+            float samples[2] = { 0.0f, 0.0f };                                \
+            for(c = 0;c < MAXCHANNELS;c++)                                    \
+            {                                                                 \
+                samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT];          \
+                samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT];         \
+            }                                                                 \
+            bs2b_cross_feed(device->Bs2b, samples);                           \
+            ((T*)buffer)[ChanMap[FRONT_LEFT]]  = func(samples[0]);            \
+            ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]);            \
+            buffer = ((T*)buffer) + 2;                                        \
+        }                                                                     \
+    }                                                                         \
+    else                                                                      \
+    {                                                                         \
+        for(i = 0;i < SamplesToDo;i++)                                        \
+        {                                                                     \
+            for(j = 0;j < N;j++)                                              \
+            {                                                                 \
+                ALfloat samp = 0.0f;                                          \
+                for(c = 0;c < MAXCHANNELS;c++)                                \
+                    samp += DryBuffer[i][c] * Matrix[c][chans[j]];            \
+                ((T*)buffer)[ChanMap[chans[j]]] = func(samp);                 \
+            }                                                                 \
+            buffer = ((T*)buffer) + N;                                        \
+        }                                                                     \
+    }                                                                         \
+}
+
+DECL_TEMPLATE(ALfloat, StereoChans,2, aluF2F)
+DECL_TEMPLATE(ALushort, StereoChans,2, aluF2US)
+DECL_TEMPLATE(ALshort, StereoChans,2, aluF2S)
+DECL_TEMPLATE(ALubyte, StereoChans,2, aluF2UB)
+DECL_TEMPLATE(ALbyte, StereoChans,2, aluF2B)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T, func)                                                \
+static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo)       \
+{                                                                             \
+    switch(device->FmtChans)                                                  \
+    {                                                                         \
+        case DevFmtMono:                                                      \
+            Write_##T##_MonoChans(device, buffer, SamplesToDo);               \
+            break;                                                            \
+        case DevFmtStereo:                                                    \
+            Write_##T##_StereoChans(device, buffer, SamplesToDo);             \
+            break;                                                            \
+        case DevFmtQuad:                                                      \
+            Write_##T##_QuadChans(device, buffer, SamplesToDo);               \
+            break;                                                            \
+        case DevFmtX51:                                                       \
+            Write_##T##_X51Chans(device, buffer, SamplesToDo);                \
+            break;                                                            \
+        case DevFmtX61:                                                       \
+            Write_##T##_X61Chans(device, buffer, SamplesToDo);                \
+            break;                                                            \
+        case DevFmtX71:                                                       \
+            Write_##T##_X71Chans(device, buffer, SamplesToDo);                \
+            break;                                                            \
+    }                                                                         \
+}
+
+DECL_TEMPLATE(ALfloat, aluF2F)
+DECL_TEMPLATE(ALushort, aluF2US)
+DECL_TEMPLATE(ALshort, aluF2S)
+DECL_TEMPLATE(ALubyte, aluF2UB)
+DECL_TEMPLATE(ALbyte, aluF2B)
+
+#undef DECL_TEMPLATE
+
+ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
+{
+    ALuint SamplesToDo;
+    ALeffectslot *ALEffectSlot;
+    ALCcontext **ctx, **ctx_end;
+    ALsource **src, **src_end;
+    int fpuState;
+    ALuint i, c;
+    ALsizei e;
+
+#if defined(HAVE_FESETROUND)
+    fpuState = fegetround();
+    fesetround(FE_TOWARDZERO);
+#elif defined(HAVE__CONTROLFP)
+    fpuState = _controlfp(_RC_CHOP, _MCW_RC);
+#else
+    (void)fpuState;
+#endif
+
+    while(size > 0)
+    {
+        /* Setup variables */
+        SamplesToDo = min(size, BUFFERSIZE);
+
+        /* Clear mixing buffer */
+        memset(device->DryBuffer, 0, SamplesToDo*MAXCHANNELS*sizeof(ALfloat));
+
+        SuspendContext(NULL);
+        ctx = device->Contexts;
+        ctx_end = ctx + device->NumContexts;
+        while(ctx != ctx_end)
+        {
+            SuspendContext(*ctx);
+
+            src = (*ctx)->ActiveSources;
+            src_end = src + (*ctx)->ActiveSourceCount;
+            while(src != src_end)
+            {
+                if((*src)->state != AL_PLAYING)
+                {
+                    --((*ctx)->ActiveSourceCount);
+                    *src = *(--src_end);
+                    continue;
+                }
+
+                if((*src)->NeedsUpdate)
+                {
+                    ALsource_Update(*src, *ctx);
+                    (*src)->NeedsUpdate = AL_FALSE;
+                }
+
+                MixSource(*src, device, SamplesToDo);
+                src++;
+            }
+
+            /* effect slot processing */
+            for(e = 0;e < (*ctx)->EffectSlotMap.size;e++)
+            {
+                ALEffectSlot = (*ctx)->EffectSlotMap.array[e].value;
+
+                for(i = 0;i < SamplesToDo;i++)
+                {
+                    ALEffectSlot->ClickRemoval[0] -= ALEffectSlot->ClickRemoval[0] / 256.0f;
+                    ALEffectSlot->WetBuffer[i] += ALEffectSlot->ClickRemoval[0];
+                }
+                for(i = 0;i < 1;i++)
+                {
+                    ALEffectSlot->ClickRemoval[i] += ALEffectSlot->PendingClicks[i];
+                    ALEffectSlot->PendingClicks[i] = 0.0f;
+                }
+
+                ALEffect_Process(ALEffectSlot->EffectState, ALEffectSlot,
+                                 SamplesToDo, ALEffectSlot->WetBuffer,
+                                 device->DryBuffer);
+
+                for(i = 0;i < SamplesToDo;i++)
+                    ALEffectSlot->WetBuffer[i] = 0.0f;
+            }
+
+            ProcessContext(*ctx);
+            ctx++;
+        }
+        ProcessContext(NULL);
+
+        //Post processing loop
+        for(i = 0;i < SamplesToDo;i++)
+        {
+            for(c = 0;c < MAXCHANNELS;c++)
+            {
+                device->ClickRemoval[c] -= device->ClickRemoval[c] / 256.0f;
+                device->DryBuffer[i][c] += device->ClickRemoval[c];
+            }
+        }
+        for(i = 0;i < MAXCHANNELS;i++)
+        {
+            device->ClickRemoval[i] += device->PendingClicks[i];
+            device->PendingClicks[i] = 0.0f;
+        }
+
+        switch(device->FmtType)
+        {
+            case DevFmtByte:
+                Write_ALbyte(device, buffer, SamplesToDo);
+                break;
+            case DevFmtUByte:
+                Write_ALubyte(device, buffer, SamplesToDo);
+                break;
+            case DevFmtShort:
+                Write_ALshort(device, buffer, SamplesToDo);
+                break;
+            case DevFmtUShort:
+                Write_ALushort(device, buffer, SamplesToDo);
+                break;
+            case DevFmtFloat:
+                Write_ALfloat(device, buffer, SamplesToDo);
+                break;
+        }
+
+        size -= SamplesToDo;
+    }
+
+#if defined(HAVE_FESETROUND)
+    fesetround(fpuState);
+#elif defined(HAVE__CONTROLFP)
+    _controlfp(fpuState, _MCW_RC);
+#endif
+}
+
+
+ALvoid aluHandleDisconnect(ALCdevice *device)
+{
+    ALuint i;
+
+    SuspendContext(NULL);
+    for(i = 0;i < device->NumContexts;i++)
+    {
+        ALCcontext *Context = device->Contexts[i];
+        ALsource *source;
+        ALsizei pos;
+
+        SuspendContext(Context);
+
+        for(pos = 0;pos < Context->SourceMap.size;pos++)
+        {
+            source = Context->SourceMap.array[pos].value;
+            if(source->state == AL_PLAYING)
+            {
+                source->state = AL_STOPPED;
+                source->BuffersPlayed = source->BuffersInQueue;
+                source->position = 0;
+                source->position_fraction = 0;
+            }
+        }
+        ProcessContext(Context);
+    }
+
+    device->Connected = ALC_FALSE;
+    ProcessContext(NULL);
+}
diff --git a/Alc/alcConfig.c b/Alc/alcConfig.c
new file mode 100644 (file)
index 0000000..847e5d1
--- /dev/null
@@ -0,0 +1,338 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifdef _WIN32
+#ifdef __MINGW64__
+#define _WIN32_IE 0x501
+#else
+#define _WIN32_IE 0x400
+#endif
+#endif
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "alMain.h"
+
+#ifdef _WIN32_IE
+#include <shlobj.h>
+#endif
+
+typedef struct ConfigEntry {
+    char *key;
+    char *value;
+} ConfigEntry;
+
+typedef struct ConfigBlock {
+    char *name;
+    ConfigEntry *entries;
+    size_t entryCount;
+} ConfigBlock;
+
+static ConfigBlock *cfgBlocks;
+static size_t cfgCount;
+
+static char buffer[1024];
+
+static void LoadConfigFromFile(FILE *f)
+{
+    ConfigBlock *curBlock = cfgBlocks;
+    ConfigEntry *ent;
+
+    while(fgets(buffer, sizeof(buffer), f))
+    {
+        size_t i = 0;
+
+        while(isspace(buffer[i]))
+            i++;
+        if(!buffer[i] || buffer[i] == '#')
+            continue;
+
+        memmove(buffer, buffer+i, strlen(buffer+i)+1);
+
+        if(buffer[0] == '[')
+        {
+            ConfigBlock *nextBlock;
+
+            i = 1;
+            while(buffer[i] && buffer[i] != ']')
+                i++;
+
+            if(!buffer[i])
+            {
+                 AL_PRINT("config parse error: bad line \"%s\"\n", buffer);
+                 continue;
+            }
+            buffer[i] = 0;
+
+            do {
+                i++;
+                if(buffer[i] && !isspace(buffer[i]))
+                {
+                    if(buffer[i] != '#')
+                        AL_PRINT("config warning: extra data after block: \"%s\"\n", buffer+i);
+                    break;
+                }
+            } while(buffer[i]);
+
+            nextBlock = NULL;
+            for(i = 0;i < cfgCount;i++)
+            {
+                if(strcasecmp(cfgBlocks[i].name, buffer+1) == 0)
+                {
+                    nextBlock = cfgBlocks+i;
+//                    AL_PRINT("found block '%s'\n", nextBlock->name);
+                    break;
+                }
+            }
+
+            if(!nextBlock)
+            {
+                nextBlock = realloc(cfgBlocks, (cfgCount+1)*sizeof(ConfigBlock));
+                if(!nextBlock)
+                {
+                     AL_PRINT("config parse error: error reallocating config blocks\n");
+                     continue;
+                }
+                cfgBlocks = nextBlock;
+                nextBlock = cfgBlocks+cfgCount;
+                cfgCount++;
+
+                nextBlock->name = strdup(buffer+1);
+                nextBlock->entries = NULL;
+                nextBlock->entryCount = 0;
+
+//                AL_PRINT("found new block '%s'\n", nextBlock->name);
+            }
+            curBlock = nextBlock;
+            continue;
+        }
+
+        /* Look for the option name */
+        i = 0;
+        while(buffer[i] && buffer[i] != '#' && buffer[i] != '=' &&
+              !isspace(buffer[i]))
+            i++;
+
+        if(!buffer[i] || buffer[i] == '#' || i == 0)
+        {
+            AL_PRINT("config parse error: malformed option line: \"%s\"\n", buffer);
+            continue;
+        }
+
+        /* Seperate the option */
+        if(buffer[i] != '=')
+        {
+            buffer[i++] = 0;
+
+            while(isspace(buffer[i]))
+                i++;
+            if(buffer[i] != '=')
+            {
+                AL_PRINT("config parse error: option without a value: \"%s\"\n", buffer);
+                continue;
+            }
+        }
+        /* Find the start of the value */
+        buffer[i++] = 0;
+        while(isspace(buffer[i]))
+            i++;
+
+        /* Check if we already have this option set */
+        ent = curBlock->entries;
+        while((size_t)(ent-curBlock->entries) < curBlock->entryCount)
+        {
+            if(strcasecmp(ent->key, buffer) == 0)
+                break;
+            ent++;
+        }
+
+        if((size_t)(ent-curBlock->entries) >= curBlock->entryCount)
+        {
+            /* Allocate a new option entry */
+            ent = realloc(curBlock->entries, (curBlock->entryCount+1)*sizeof(ConfigEntry));
+            if(!ent)
+            {
+                 AL_PRINT("config parse error: error reallocating config entries\n");
+                 continue;
+            }
+            curBlock->entries = ent;
+            ent = curBlock->entries + curBlock->entryCount;
+            curBlock->entryCount++;
+
+            ent->key = strdup(buffer);
+            ent->value = NULL;
+        }
+
+        /* Look for the end of the line (Null term, new-line, or #-symbol) and
+           eat up the trailing whitespace */
+        memmove(buffer, buffer+i, strlen(buffer+i)+1);
+
+        i = 0;
+        while(buffer[i] && buffer[i] != '#' && buffer[i] != '\n')
+            i++;
+        do {
+            i--;
+        } while(isspace(buffer[i]));
+        buffer[++i] = 0;
+
+        free(ent->value);
+        ent->value = strdup(buffer);
+
+//        AL_PRINT("found '%s' = '%s'\n", ent->key, ent->value);
+    }
+}
+
+void ReadALConfig(void)
+{
+    FILE *f;
+
+    cfgBlocks = calloc(1, sizeof(ConfigBlock));
+    cfgBlocks->name = strdup("general");
+    cfgCount = 1;
+
+#ifdef _WIN32
+    if(SHGetSpecialFolderPathA(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE)
+    {
+        size_t p = strlen(buffer);
+        snprintf(buffer+p, sizeof(buffer)-p, "\\alsoft.ini");
+        f = fopen(buffer, "rt");
+        if(f)
+        {
+            LoadConfigFromFile(f);
+            fclose(f);
+        }
+    }
+#else
+    f = fopen("/etc/openal/alsoft.conf", "r");
+    if(f)
+    {
+        LoadConfigFromFile(f);
+        fclose(f);
+    }
+    if(getenv("HOME") && *(getenv("HOME")))
+    {
+        snprintf(buffer, sizeof(buffer), "%s/.alsoftrc", getenv("HOME"));
+        f = fopen(buffer, "r");
+        if(f)
+        {
+            LoadConfigFromFile(f);
+            fclose(f);
+        }
+    }
+#endif
+    if(getenv("ALSOFT_CONF"))
+    {
+        f = fopen(getenv("ALSOFT_CONF"), "r");
+        if(f)
+        {
+            LoadConfigFromFile(f);
+            fclose(f);
+        }
+    }
+}
+
+void FreeALConfig(void)
+{
+    size_t i;
+
+    for(i = 0;i < cfgCount;i++)
+    {
+        size_t j;
+        for(j = 0;j < cfgBlocks[i].entryCount;j++)
+        {
+           free(cfgBlocks[i].entries[j].key);
+           free(cfgBlocks[i].entries[j].value);
+        }
+        free(cfgBlocks[i].entries);
+        free(cfgBlocks[i].name);
+    }
+    free(cfgBlocks);
+    cfgBlocks = NULL;
+    cfgCount = 0;
+}
+
+const char *GetConfigValue(const char *blockName, const char *keyName, const char *def)
+{
+    size_t i, j;
+
+    if(!keyName)
+        return def;
+
+    if(!blockName)
+        blockName = "general";
+
+    for(i = 0;i < cfgCount;i++)
+    {
+        if(strcasecmp(cfgBlocks[i].name, blockName) != 0)
+            continue;
+
+        for(j = 0;j < cfgBlocks[i].entryCount;j++)
+        {
+            if(strcasecmp(cfgBlocks[i].entries[j].key, keyName) == 0)
+            {
+                if(cfgBlocks[i].entries[j].value[0])
+                    return cfgBlocks[i].entries[j].value;
+                return def;
+            }
+        }
+    }
+
+    return def;
+}
+
+int ConfigValueExists(const char *blockName, const char *keyName)
+{
+    const char *val = GetConfigValue(blockName, keyName, "");
+    return !!val[0];
+}
+
+int GetConfigValueInt(const char *blockName, const char *keyName, int def)
+{
+    const char *val = GetConfigValue(blockName, keyName, "");
+
+    if(!val[0]) return def;
+    return strtol(val, NULL, 0);
+}
+
+float GetConfigValueFloat(const char *blockName, const char *keyName, float def)
+{
+    const char *val = GetConfigValue(blockName, keyName, "");
+
+    if(!val[0]) return def;
+#ifdef HAVE_STRTOF
+    return strtof(val, NULL);
+#else
+    return (float)strtod(val, NULL);
+#endif
+}
+
+int GetConfigValueBool(const char *blockName, const char *keyName, int def)
+{
+    const char *val = GetConfigValue(blockName, keyName, "");
+
+    if(!val[0]) return !!def;
+    return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 ||
+            strcasecmp(val, "on") == 0 || atoi(val) != 0);
+}
diff --git a/Alc/alcEcho.c b/Alc/alcEcho.c
new file mode 100644 (file)
index 0000000..68549fd
--- /dev/null
@@ -0,0 +1,196 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Chris Robinson.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALechoState {
+    // Must be first in all effects!
+    ALeffectState state;
+
+    ALfloat *SampleBuffer;
+    ALuint BufferLength;
+
+    // The echo is two tap. The delay is the number of samples from before the
+    // current offset
+    struct {
+        ALuint delay;
+    } Tap[2];
+    ALuint Offset;
+    // The LR gains for the first tap. The second tap uses the reverse
+    ALfloat GainL;
+    ALfloat GainR;
+
+    ALfloat FeedGain;
+
+    ALfloat Gain[MAXCHANNELS];
+
+    FILTER iirFilter;
+    ALfloat history[2];
+} ALechoState;
+
+static ALvoid EchoDestroy(ALeffectState *effect)
+{
+    ALechoState *state = (ALechoState*)effect;
+    if(state)
+    {
+        free(state->SampleBuffer);
+        state->SampleBuffer = NULL;
+        free(state);
+    }
+}
+
+static ALboolean EchoDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+{
+    ALechoState *state = (ALechoState*)effect;
+    ALuint maxlen, i;
+
+    // Use the next power of 2 for the buffer length, so the tap offsets can be
+    // wrapped using a mask instead of a modulo
+    maxlen  = (ALuint)(AL_ECHO_MAX_DELAY * Device->Frequency) + 1;
+    maxlen += (ALuint)(AL_ECHO_MAX_LRDELAY * Device->Frequency) + 1;
+    maxlen  = NextPowerOf2(maxlen);
+
+    if(maxlen != state->BufferLength)
+    {
+        void *temp;
+
+        temp = realloc(state->SampleBuffer, maxlen * sizeof(ALfloat));
+        if(!temp)
+            return AL_FALSE;
+        state->SampleBuffer = temp;
+        state->BufferLength = maxlen;
+    }
+    for(i = 0;i < state->BufferLength;i++)
+        state->SampleBuffer[i] = 0.0f;
+
+    for(i = 0;i < MAXCHANNELS;i++)
+        state->Gain[i] = 0.0f;
+    for(i = 0;i < Device->NumChan;i++)
+    {
+        Channel chan = Device->Speaker2Chan[i];
+        state->Gain[chan] = 1.0f;
+    }
+
+    return AL_TRUE;
+}
+
+static ALvoid EchoUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+    ALechoState *state = (ALechoState*)effect;
+    ALuint frequency = Context->Device->Frequency;
+    ALfloat lrpan, cw, a, g;
+
+    state->Tap[0].delay = (ALuint)(Effect->Echo.Delay * frequency) + 1;
+    state->Tap[1].delay = (ALuint)(Effect->Echo.LRDelay * frequency);
+    state->Tap[1].delay += state->Tap[0].delay;
+
+    lrpan = Effect->Echo.Spread*0.5f + 0.5f;
+    state->GainL = aluSqrt(     lrpan);
+    state->GainR = aluSqrt(1.0f-lrpan);
+
+    state->FeedGain = Effect->Echo.Feedback;
+
+    cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / frequency);
+    g = 1.0f - Effect->Echo.Damping;
+    a = 0.0f;
+    if(g < 0.9999f) // 1-epsilon
+        a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g);
+    state->iirFilter.coeff = a;
+}
+
+static ALvoid EchoProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+    ALechoState *state = (ALechoState*)effect;
+    const ALuint mask = state->BufferLength-1;
+    const ALuint tap1 = state->Tap[0].delay;
+    const ALuint tap2 = state->Tap[1].delay;
+    ALuint offset = state->Offset;
+    const ALfloat gain = Slot->Gain;
+    ALfloat samp[2], smp;
+    ALuint i;
+
+    for(i = 0;i < SamplesToDo;i++,offset++)
+    {
+        // Sample first tap
+        smp = state->SampleBuffer[(offset-tap1) & mask];
+        samp[0] = smp * state->GainL;
+        samp[1] = smp * state->GainR;
+        // Sample second tap. Reverse LR panning
+        smp = state->SampleBuffer[(offset-tap2) & mask];
+        samp[0] += smp * state->GainR;
+        samp[1] += smp * state->GainL;
+
+        // Apply damping and feedback gain to the second tap, and mix in the
+        // new sample
+        smp = lpFilter2P(&state->iirFilter, 0, smp+SamplesIn[i]);
+        state->SampleBuffer[offset&mask] = smp * state->FeedGain;
+
+        // Apply slot gain
+        samp[0] *= gain;
+        samp[1] *= gain;
+
+        SamplesOut[i][FRONT_LEFT]  += state->Gain[FRONT_LEFT]  * samp[0];
+        SamplesOut[i][FRONT_RIGHT] += state->Gain[FRONT_RIGHT] * samp[1];
+        SamplesOut[i][SIDE_LEFT]   += state->Gain[SIDE_LEFT]   * samp[0];
+        SamplesOut[i][SIDE_RIGHT]  += state->Gain[SIDE_RIGHT]  * samp[1];
+        SamplesOut[i][BACK_LEFT]   += state->Gain[BACK_LEFT]   * samp[0];
+        SamplesOut[i][BACK_RIGHT]  += state->Gain[BACK_RIGHT]  * samp[1];
+    }
+    state->Offset = offset;
+}
+
+ALeffectState *EchoCreate(void)
+{
+    ALechoState *state;
+
+    state = malloc(sizeof(*state));
+    if(!state)
+        return NULL;
+
+    state->state.Destroy = EchoDestroy;
+    state->state.DeviceUpdate = EchoDeviceUpdate;
+    state->state.Update = EchoUpdate;
+    state->state.Process = EchoProcess;
+
+    state->BufferLength = 0;
+    state->SampleBuffer = NULL;
+
+    state->Tap[0].delay = 0;
+    state->Tap[1].delay = 0;
+    state->Offset = 0;
+    state->GainL = 0.0f;
+    state->GainR = 0.0f;
+
+    state->iirFilter.coeff = 0.0f;
+    state->iirFilter.history[0] = 0.0f;
+    state->iirFilter.history[1] = 0.0f;
+
+    return &state->state;
+}
diff --git a/Alc/alcModulator.c b/Alc/alcModulator.c
new file mode 100644 (file)
index 0000000..11bb7d4
--- /dev/null
@@ -0,0 +1,205 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Chris Robinson.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alFilter.h"
+#include "alAuxEffectSlot.h"
+#include "alError.h"
+#include "alu.h"
+
+
+typedef struct ALmodulatorState {
+    // Must be first in all effects!
+    ALeffectState state;
+
+    enum {
+        SINUSOID,
+        SAWTOOTH,
+        SQUARE
+    } Waveform;
+
+    ALuint index;
+    ALuint step;
+
+    ALfloat Gain[MAXCHANNELS];
+
+    FILTER iirFilter;
+    ALfloat history[1];
+} ALmodulatorState;
+
+#define WAVEFORM_FRACBITS  16
+#define WAVEFORM_FRACMASK  ((1<<WAVEFORM_FRACBITS)-1)
+
+static __inline ALfloat sin_func(ALuint index)
+{
+    return sin(index / (double)(1<<WAVEFORM_FRACBITS) * M_PI * 2.0f);
+}
+
+static __inline ALfloat saw_func(ALuint index)
+{
+    return index*2.0f/(1<<WAVEFORM_FRACBITS) - 1.0f;
+}
+
+static __inline ALfloat square_func(ALuint index)
+{
+    return ((index>>(WAVEFORM_FRACBITS-1))&1) ? -1.0f : 1.0f;
+}
+
+
+static __inline ALfloat hpFilter1P(FILTER *iir, ALuint offset, ALfloat input)
+{
+    ALfloat *history = &iir->history[offset];
+    ALfloat a = iir->coeff;
+    ALfloat output = input;
+
+    output = output + (history[0]-output)*a;
+    history[0] = output;
+
+    return input - output;
+}
+
+
+static ALvoid ModulatorDestroy(ALeffectState *effect)
+{
+    ALmodulatorState *state = (ALmodulatorState*)effect;
+    free(state);
+}
+
+static ALboolean ModulatorDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+{
+    ALmodulatorState *state = (ALmodulatorState*)effect;
+    ALuint index;
+
+    for(index = 0;index < MAXCHANNELS;index++)
+        state->Gain[index] = 0.0f;
+    for(index = 0;index < Device->NumChan;index++)
+    {
+        Channel chan = Device->Speaker2Chan[index];
+        state->Gain[chan] = 1.0f;
+    }
+
+    return AL_TRUE;
+}
+
+static ALvoid ModulatorUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+    ALmodulatorState *state = (ALmodulatorState*)effect;
+    ALfloat cw, a = 0.0f;
+
+    if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SINUSOID)
+        state->Waveform = SINUSOID;
+    else if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SAWTOOTH)
+        state->Waveform = SAWTOOTH;
+    else if(Effect->Modulator.Waveform == AL_RING_MODULATOR_SQUARE)
+        state->Waveform = SQUARE;
+
+    state->step = Effect->Modulator.Frequency*(1<<WAVEFORM_FRACBITS) /
+                  Context->Device->Frequency;
+    if(!state->step)
+        state->step = 1;
+
+    cw = cos(2.0*M_PI * Effect->Modulator.HighPassCutoff / Context->Device->Frequency);
+    a = (2.0f-cw) - aluSqrt(aluPow(2.0f-cw, 2.0f) - 1.0f);
+    state->iirFilter.coeff = a;
+}
+
+static ALvoid ModulatorProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+    ALmodulatorState *state = (ALmodulatorState*)effect;
+    const ALfloat gain = Slot->Gain;
+    const ALuint step = state->step;
+    ALuint index = state->index;
+    ALfloat samp;
+    ALuint i;
+
+    switch(state->Waveform)
+    {
+    case SINUSOID:
+        for(i = 0;i < SamplesToDo;i++)
+        {
+#define FILTER_OUT(func) do {                                                 \
+    samp = SamplesIn[i];                                                      \
+                                                                              \
+    index += step;                                                            \
+    index &= WAVEFORM_FRACMASK;                                               \
+    samp *= func(index);                                                      \
+                                                                              \
+    samp = hpFilter1P(&state->iirFilter, 0, samp);                            \
+                                                                              \
+    /* Apply slot gain */                                                     \
+    samp *= gain;                                                             \
+                                                                              \
+    SamplesOut[i][FRONT_LEFT]   += state->Gain[FRONT_LEFT]   * samp;          \
+    SamplesOut[i][FRONT_RIGHT]  += state->Gain[FRONT_RIGHT]  * samp;          \
+    SamplesOut[i][FRONT_CENTER] += state->Gain[FRONT_CENTER] * samp;          \
+    SamplesOut[i][SIDE_LEFT]    += state->Gain[SIDE_LEFT]    * samp;          \
+    SamplesOut[i][SIDE_RIGHT]   += state->Gain[SIDE_RIGHT]   * samp;          \
+    SamplesOut[i][BACK_LEFT]    += state->Gain[BACK_LEFT]    * samp;          \
+    SamplesOut[i][BACK_RIGHT]   += state->Gain[BACK_RIGHT]   * samp;          \
+    SamplesOut[i][BACK_CENTER]  += state->Gain[BACK_CENTER]  * samp;          \
+} while(0)
+            FILTER_OUT(sin_func);
+        }
+        break;
+
+    case SAWTOOTH:
+        for(i = 0;i < SamplesToDo;i++)
+        {
+            FILTER_OUT(saw_func);
+        }
+        break;
+
+    case SQUARE:
+        for(i = 0;i < SamplesToDo;i++)
+        {
+            FILTER_OUT(square_func);
+#undef FILTER_OUT
+        }
+        break;
+    }
+    state->index = index;
+}
+
+ALeffectState *ModulatorCreate(void)
+{
+    ALmodulatorState *state;
+
+    state = malloc(sizeof(*state));
+    if(!state)
+        return NULL;
+
+    state->state.Destroy = ModulatorDestroy;
+    state->state.DeviceUpdate = ModulatorDeviceUpdate;
+    state->state.Update = ModulatorUpdate;
+    state->state.Process = ModulatorProcess;
+
+    state->index = 0.0f;
+    state->step = 1.0f;
+
+    state->iirFilter.coeff = 0.0f;
+    state->iirFilter.history[0] = 0.0f;
+
+    return &state->state;
+}
diff --git a/Alc/alcReverb.c b/Alc/alcReverb.c
new file mode 100644 (file)
index 0000000..e48b3b9
--- /dev/null
@@ -0,0 +1,1348 @@
+/**
+ * Reverb for the OpenAL cross platform audio library
+ * Copyright (C) 2008-2009 by Christopher Fitzgerald.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alAuxEffectSlot.h"
+#include "alEffect.h"
+#include "alError.h"
+#include "alu.h"
+
+typedef struct DelayLine
+{
+    // The delay lines use sample lengths that are powers of 2 to allow the
+    // use of bit-masking instead of a modulus for wrapping.
+    ALuint   Mask;
+    ALfloat *Line;
+} DelayLine;
+
+typedef struct ALverbState {
+    // Must be first in all effects!
+    ALeffectState state;
+
+    // All delay lines are allocated as a single buffer to reduce memory
+    // fragmentation and management code.
+    ALfloat  *SampleBuffer;
+    ALuint    TotalSamples;
+    // Master effect low-pass filter (2 chained 1-pole filters).
+    FILTER    LpFilter;
+    ALfloat   LpHistory[2];
+    struct {
+        // Modulator delay line.
+        DelayLine Delay;
+        // The vibrato time is tracked with an index over a modulus-wrapped
+        // range (in samples).
+        ALuint    Index;
+        ALuint    Range;
+        // The depth of frequency change (also in samples) and its filter.
+        ALfloat   Depth;
+        ALfloat   Coeff;
+        ALfloat   Filter;
+    } Mod;
+    // Initial effect delay.
+    DelayLine Delay;
+    // The tap points for the initial delay.  First tap goes to early
+    // reflections, the last to late reverb.
+    ALuint    DelayTap[2];
+    struct {
+        // Output gain for early reflections.
+        ALfloat   Gain;
+        // Early reflections are done with 4 delay lines.
+        ALfloat   Coeff[4];
+        DelayLine Delay[4];
+        ALuint    Offset[4];
+        // The gain for each output channel based on 3D panning (only for the
+        // EAX path).
+        ALfloat   PanGain[MAXCHANNELS];
+    } Early;
+    // Decorrelator delay line.
+    DelayLine Decorrelator;
+    // There are actually 4 decorrelator taps, but the first occurs at the
+    // initial sample.
+    ALuint    DecoTap[3];
+    struct {
+        // Output gain for late reverb.
+        ALfloat   Gain;
+        // Attenuation to compensate for the modal density and decay rate of
+        // the late lines.
+        ALfloat   DensityGain;
+        // The feed-back and feed-forward all-pass coefficient.
+        ALfloat   ApFeedCoeff;
+        // Mixing matrix coefficient.
+        ALfloat   MixCoeff;
+        // Late reverb has 4 parallel all-pass filters.
+        ALfloat   ApCoeff[4];
+        DelayLine ApDelay[4];
+        ALuint    ApOffset[4];
+        // In addition to 4 cyclical delay lines.
+        ALfloat   Coeff[4];
+        DelayLine Delay[4];
+        ALuint    Offset[4];
+        // The cyclical delay lines are 1-pole low-pass filtered.
+        ALfloat   LpCoeff[4];
+        ALfloat   LpSample[4];
+        // The gain for each output channel based on 3D panning (only for the
+        // EAX path).
+        ALfloat   PanGain[MAXCHANNELS];
+    } Late;
+    struct {
+        // Attenuation to compensate for the modal density and decay rate of
+        // the echo line.
+        ALfloat   DensityGain;
+        // Echo delay and all-pass lines.
+        DelayLine Delay;
+        DelayLine ApDelay;
+        ALfloat   Coeff;
+        ALfloat   ApFeedCoeff;
+        ALfloat   ApCoeff;
+        ALuint    Offset;
+        ALuint    ApOffset;
+        // The echo line is 1-pole low-pass filtered.
+        ALfloat   LpCoeff;
+        ALfloat   LpSample;
+        // Echo mixing coefficients.
+        ALfloat   MixCoeff[2];
+    } Echo;
+    // The current read offset for all delay lines.
+    ALuint Offset;
+
+    // The gain for each output channel (non-EAX path only; aliased from
+    // Late.PanGain)
+    ALfloat *Gain;
+} ALverbState;
+
+/* This coefficient is used to define the maximum frequency range controlled
+ * by the modulation depth.  The current value of 0.1 will allow it to swing
+ * from 0.9x to 1.1x.  This value must be below 1.  At 1 it will cause the
+ * sampler to stall on the downswing, and above 1 it will cause it to sample
+ * backwards.
+ */
+static const ALfloat MODULATION_DEPTH_COEFF = 0.1f;
+
+/* A filter is used to avoid the terrible distortion caused by changing
+ * modulation time and/or depth.  To be consistent across different sample
+ * rates, the coefficient must be raised to a constant divided by the sample
+ * rate:  coeff^(constant / rate).
+ */
+static const ALfloat MODULATION_FILTER_COEFF = 0.048f;
+static const ALfloat MODULATION_FILTER_CONST = 100000.0f;
+
+// When diffusion is above 0, an all-pass filter is used to take the edge off
+// the echo effect.  It uses the following line length (in seconds).
+static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f;
+
+// Input into the late reverb is decorrelated between four channels.  Their
+// timings are dependent on a fraction and multiplier.  See the
+// UpdateDecorrelator() routine for the calculations involved.
+static const ALfloat DECO_FRACTION = 0.15f;
+static const ALfloat DECO_MULTIPLIER = 2.0f;
+
+// All delay line lengths are specified in seconds.
+
+// The lengths of the early delay lines.
+static const ALfloat EARLY_LINE_LENGTH[4] =
+{
+    0.0015f, 0.0045f, 0.0135f, 0.0405f
+};
+
+// The lengths of the late all-pass delay lines.
+static const ALfloat ALLPASS_LINE_LENGTH[4] =
+{
+    0.0151f, 0.0167f, 0.0183f, 0.0200f,
+};
+
+// The lengths of the late cyclical delay lines.
+static const ALfloat LATE_LINE_LENGTH[4] =
+{
+    0.0211f, 0.0311f, 0.0461f, 0.0680f
+};
+
+// The late cyclical delay lines have a variable length dependent on the
+// effect's density parameter (inverted for some reason) and this multiplier.
+static const ALfloat LATE_LINE_MULTIPLIER = 4.0f;
+
+// Calculate the length of a delay line and store its mask and offset.
+static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay)
+{
+    ALuint samples;
+
+    // All line lengths are powers of 2, calculated from their lengths, with
+    // an additional sample in case of rounding errors.
+    samples = NextPowerOf2((ALuint)(length * frequency) + 1);
+    // All lines share a single sample buffer.
+    Delay->Mask = samples - 1;
+    Delay->Line = (ALfloat*)offset;
+    // Return the sample count for accumulation.
+    return samples;
+}
+
+// Given the allocated sample buffer, this function updates each delay line
+// offset.
+static __inline ALvoid RealizeLineOffset(ALfloat * sampleBuffer, DelayLine *Delay)
+{
+    Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line];
+}
+
+/* Calculates the delay line metrics and allocates the shared sample buffer
+ * for all lines given a flag indicating whether or not to allocate the EAX-
+ * related delays (eaxFlag) and the sample rate (frequency).  If an
+ * allocation failure occurs, it returns AL_FALSE.
+ */
+static ALboolean AllocLines(ALboolean eaxFlag, ALuint frequency, ALverbState *State)
+{
+    ALuint totalSamples, index;
+    ALfloat length;
+    ALfloat *newBuffer = NULL;
+
+    // All delay line lengths are calculated to accomodate the full range of
+    // lengths given their respective paramters.
+    totalSamples = 0;
+    if(eaxFlag)
+    {
+        /* The modulator's line length is calculated from the maximum
+         * modulation time and depth coefficient, and halfed for the low-to-
+         * high frequency swing.  An additional sample is added to keep it
+         * stable when there is no modulation.
+         */
+        length = (AL_EAXREVERB_MAX_MODULATION_TIME * MODULATION_DEPTH_COEFF /
+                  2.0f) + (1.0f / frequency);
+        totalSamples += CalcLineLength(length, totalSamples, frequency,
+                                       &State->Mod.Delay);
+    }
+
+    // The initial delay is the sum of the reflections and late reverb
+    // delays.
+    if(eaxFlag)
+        length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY +
+                 AL_EAXREVERB_MAX_LATE_REVERB_DELAY;
+    else
+        length = AL_REVERB_MAX_REFLECTIONS_DELAY +
+                 AL_REVERB_MAX_LATE_REVERB_DELAY;
+    totalSamples += CalcLineLength(length, totalSamples, frequency,
+                                   &State->Delay);
+
+    // The early reflection lines.
+    for(index = 0;index < 4;index++)
+        totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples,
+                                       frequency, &State->Early.Delay[index]);
+
+    // The decorrelator line is calculated from the lowest reverb density (a
+    // parameter value of 1).
+    length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) *
+             LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER);
+    totalSamples += CalcLineLength(length, totalSamples, frequency,
+                                   &State->Decorrelator);
+
+    // The late all-pass lines.
+    for(index = 0;index < 4;index++)
+        totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples,
+                                       frequency, &State->Late.ApDelay[index]);
+
+    // The late delay lines are calculated from the lowest reverb density.
+    for(index = 0;index < 4;index++)
+    {
+        length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER);
+        totalSamples += CalcLineLength(length, totalSamples, frequency,
+                                       &State->Late.Delay[index]);
+    }
+
+    if(eaxFlag)
+    {
+        // The echo all-pass and delay lines.
+        totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples,
+                                       frequency, &State->Echo.ApDelay);
+        totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples,
+                                       frequency, &State->Echo.Delay);
+    }
+
+    if(totalSamples != State->TotalSamples)
+    {
+        newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples);
+        if(newBuffer == NULL)
+            return AL_FALSE;
+        State->SampleBuffer = newBuffer;
+        State->TotalSamples = totalSamples;
+    }
+
+    // Update all delays to reflect the new sample buffer.
+    RealizeLineOffset(State->SampleBuffer, &State->Delay);
+    RealizeLineOffset(State->SampleBuffer, &State->Decorrelator);
+    for(index = 0;index < 4;index++)
+    {
+        RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]);
+        RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]);
+        RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]);
+    }
+    if(eaxFlag)
+    {
+        RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay);
+        RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay);
+        RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay);
+    }
+
+    // Clear the sample buffer.
+    for(index = 0;index < State->TotalSamples;index++)
+        State->SampleBuffer[index] = 0.0f;
+
+    return AL_TRUE;
+}
+
+// Calculate a decay coefficient given the length of each cycle and the time
+// until the decay reaches -60 dB.
+static __inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime)
+{
+    return aluPow(10.0f, length / decayTime * -60.0f / 20.0f);
+}
+
+// Calculate a decay length from a coefficient and the time until the decay
+// reaches -60 dB.
+static __inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime)
+{
+    return log10(coeff) / -60.0 * 20.0f * decayTime;
+}
+
+// Calculate the high frequency parameter for the I3DL2 coefficient
+// calculation.
+static __inline ALfloat CalcI3DL2HFreq(ALfloat hfRef, ALuint frequency)
+{
+    return cos(2.0f * M_PI * hfRef / frequency);
+}
+
+// Calculate an attenuation to be applied to the input of any echo models to
+// compensate for modal density and decay time.
+static __inline ALfloat CalcDensityGain(ALfloat a)
+{
+    /* The energy of a signal can be obtained by finding the area under the
+     * squared signal.  This takes the form of Sum(x_n^2), where x is the
+     * amplitude for the sample n.
+     *
+     * Decaying feedback matches exponential decay of the form Sum(a^n),
+     * where a is the attenuation coefficient, and n is the sample.  The area
+     * under this decay curve can be calculated as:  1 / (1 - a).
+     *
+     * Modifying the above equation to find the squared area under the curve
+     * (for energy) yields:  1 / (1 - a^2).  Input attenuation can then be
+     * calculated by inverting the square root of this approximation,
+     * yielding:  1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2).
+     */
+    return aluSqrt(1.0f - (a * a));
+}
+
+// Calculate the mixing matrix coefficients given a diffusion factor.
+static __inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y)
+{
+    ALfloat n, t;
+
+    // The matrix is of order 4, so n is sqrt (4 - 1).
+    n = aluSqrt(3.0f);
+    t = diffusion * atan(n);
+
+    // Calculate the first mixing matrix coefficient.
+    *x = cos(t);
+    // Calculate the second mixing matrix coefficient.
+    *y = sin(t) / n;
+}
+
+// Calculate the limited HF ratio for use with the late reverb low-pass
+// filters.
+static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime)
+{
+    ALfloat limitRatio;
+
+    /* Find the attenuation due to air absorption in dB (converting delay
+     * time to meters using the speed of sound).  Then reversing the decay
+     * equation, solve for HF ratio.  The delay length is cancelled out of
+     * the equation, so it can be calculated once for all lines.
+     */
+    limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) *
+                         SPEEDOFSOUNDMETRESPERSEC);
+    // Need to limit the result to a minimum of 0.1, just like the HF ratio
+    // parameter.
+    limitRatio = __max(limitRatio, 0.1f);
+
+    // Using the limit calculated above, apply the upper bound to the HF
+    // ratio.
+    return __min(hfRatio, limitRatio);
+}
+
+// Calculate the coefficient for a HF (and eventually LF) decay damping
+// filter.
+static __inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw)
+{
+    ALfloat coeff, g;
+
+    // Eventually this should boost the high frequencies when the ratio
+    // exceeds 1.
+    coeff = 0.0f;
+    if (hfRatio < 1.0f)
+    {
+        // Calculate the low-pass coefficient by dividing the HF decay
+        // coefficient by the full decay coefficient.
+        g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff;
+
+        // Damping is done with a 1-pole filter, so g needs to be squared.
+        g *= g;
+        coeff = lpCoeffCalc(g, cw);
+
+        // Very low decay times will produce minimal output, so apply an
+        // upper bound to the coefficient.
+        coeff = __min(coeff, 0.98f);
+    }
+    return coeff;
+}
+
+// Update the EAX modulation index, range, and depth.  Keep in mind that this
+// kind of vibrato is additive and not multiplicative as one may expect.  The
+// downswing will sound stronger than the upswing.
+static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALverbState *State)
+{
+    ALfloat length;
+
+    /* Modulation is calculated in two parts.
+     *
+     * The modulation time effects the sinus applied to the change in
+     * frequency.  An index out of the current time range (both in samples)
+     * is incremented each sample.  The range is bound to a reasonable
+     * minimum (1 sample) and when the timing changes, the index is rescaled
+     * to the new range (to keep the sinus consistent).
+     */
+    length = modTime * frequency;
+    if (length >= 1.0f) {
+       State->Mod.Index = (ALuint)(State->Mod.Index * length /
+                                   State->Mod.Range);
+       State->Mod.Range = (ALuint)length;
+    } else {
+       State->Mod.Index = 0;
+       State->Mod.Range = 1;
+    }
+
+    /* The modulation depth effects the amount of frequency change over the
+     * range of the sinus.  It needs to be scaled by the modulation time so
+     * that a given depth produces a consistent change in frequency over all
+     * ranges of time.  Since the depth is applied to a sinus value, it needs
+     * to be halfed once for the sinus range and again for the sinus swing
+     * in time (half of it is spent decreasing the frequency, half is spent
+     * increasing it).
+     */
+    State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f /
+                       2.0f * frequency;
+}
+
+// Update the offsets for the initial effect delay line.
+static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALverbState *State)
+{
+    // Calculate the initial delay taps.
+    State->DelayTap[0] = (ALuint)(earlyDelay * frequency);
+    State->DelayTap[1] = (ALuint)((earlyDelay + lateDelay) * frequency);
+}
+
+// Update the early reflections gain and line coefficients.
+static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALverbState *State)
+{
+    ALuint index;
+
+    // Calculate the early reflections gain (from the master effect gain, and
+    // reflections gain parameters) with a constant attenuation of 0.5.
+    State->Early.Gain = 0.5f * reverbGain * earlyGain;
+
+    // Calculate the gain (coefficient) for each early delay line using the
+    // late delay time.  This expands the early reflections to the start of
+    // the late reverb.
+    for(index = 0;index < 4;index++)
+        State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index],
+                                                   lateDelay);
+}
+
+// Update the offsets for the decorrelator line.
+static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALverbState *State)
+{
+    ALuint index;
+    ALfloat length;
+
+    /* The late reverb inputs are decorrelated to smooth the reverb tail and
+     * reduce harsh echos.  The first tap occurs immediately, while the
+     * remaining taps are delayed by multiples of a fraction of the smallest
+     * cyclical delay time.
+     *
+     * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay
+     */
+    for(index = 0;index < 3;index++)
+    {
+        length = (DECO_FRACTION * aluPow(DECO_MULTIPLIER, (ALfloat)index)) *
+                 LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER));
+        State->DecoTap[index] = (ALuint)(length * frequency);
+    }
+}
+
+// Update the late reverb gains, line lengths, and line coefficients.
+static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
+{
+    ALfloat length;
+    ALuint index;
+
+    /* Calculate the late reverb gain (from the master effect gain, and late
+     * reverb gain parameters).  Since the output is tapped prior to the
+     * application of the next delay line coefficients, this gain needs to be
+     * attenuated by the 'x' mixing matrix coefficient as well.
+     */
+    State->Late.Gain = reverbGain * lateGain * xMix;
+
+    /* To compensate for changes in modal density and decay time of the late
+     * reverb signal, the input is attenuated based on the maximal energy of
+     * the outgoing signal.  This approximation is used to keep the apparent
+     * energy of the signal equal for all ranges of density and decay time.
+     *
+     * The average length of the cyclcical delay lines is used to calculate
+     * the attenuation coefficient.
+     */
+    length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] +
+              LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f;
+    length *= 1.0f + (density * LATE_LINE_MULTIPLIER);
+    State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length,
+                                                             decayTime));
+
+    // Calculate the all-pass feed-back and feed-forward coefficient.
+    State->Late.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
+
+    for(index = 0;index < 4;index++)
+    {
+        // Calculate the gain (coefficient) for each all-pass line.
+        State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index],
+                                                    decayTime);
+
+        // Calculate the length (in seconds) of each cyclical delay line.
+        length = LATE_LINE_LENGTH[index] * (1.0f + (density *
+                                                    LATE_LINE_MULTIPLIER));
+
+        // Calculate the delay offset for each cyclical delay line.
+        State->Late.Offset[index] = (ALuint)(length * frequency);
+
+        // Calculate the gain (coefficient) for each cyclical line.
+        State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime);
+
+        // Calculate the damping coefficient for each low-pass filter.
+        State->Late.LpCoeff[index] =
+            CalcDampingCoeff(hfRatio, length, decayTime,
+                             State->Late.Coeff[index], cw);
+
+        // Attenuate the cyclical line coefficients by the mixing coefficient
+        // (x).
+        State->Late.Coeff[index] *= xMix;
+    }
+}
+
+// Update the echo gain, line offset, line coefficients, and mixing
+// coefficients.
+static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALverbState *State)
+{
+    // Update the offset and coefficient for the echo delay line.
+    State->Echo.Offset = (ALuint)(echoTime * frequency);
+
+    // Calculate the decay coefficient for the echo line.
+    State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime);
+
+    // Calculate the energy-based attenuation coefficient for the echo delay
+    // line.
+    State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff);
+
+    // Calculate the echo all-pass feed coefficient.
+    State->Echo.ApFeedCoeff = 0.5f * aluPow(diffusion, 2.0f);
+
+    // Calculate the echo all-pass attenuation coefficient.
+    State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime);
+
+    // Calculate the damping coefficient for each low-pass filter.
+    State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime,
+                                           State->Echo.Coeff, cw);
+
+    /* Calculate the echo mixing coefficients.  The first is applied to the
+     * echo itself.  The second is used to attenuate the late reverb when
+     * echo depth is high and diffusion is low, so the echo is slightly
+     * stronger than the decorrelated echos in the reverb tail.
+     */
+    State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth;
+    State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion));
+}
+
+// Update the early and late 3D panning gains.
+static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALverbState *State)
+{
+    ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1],
+                            ReflectionsPan[2] };
+    ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1],
+                           LateReverbPan[2] };
+    const ALfloat *speakerGain;
+    ALfloat dirGain;
+    ALfloat length;
+    ALuint index;
+    ALint pos;
+
+    // Calculate the 3D-panning gains for the early reflections and late
+    // reverb.
+    length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2];
+    if(length > 1.0f)
+    {
+        length = 1.0f / aluSqrt(length);
+        earlyPan[0] *= length;
+        earlyPan[1] *= length;
+        earlyPan[2] *= length;
+    }
+    length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2];
+    if(length > 1.0f)
+    {
+        length = 1.0f / aluSqrt(length);
+        latePan[0] *= length;
+        latePan[1] *= length;
+        latePan[2] *= length;
+    }
+
+    /* This code applies directional reverb just like the mixer applies
+     * directional sources.  It diffuses the sound toward all speakers as the
+     * magnitude of the panning vector drops, which is only a rough
+     * approximation of the expansion of sound across the speakers from the
+     * panning direction.
+     */
+    pos = aluCart2LUTpos(earlyPan[2], earlyPan[0]);
+    speakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
+    dirGain = aluSqrt((earlyPan[0] * earlyPan[0]) + (earlyPan[2] * earlyPan[2]));
+
+    for(index = 0;index < MAXCHANNELS;index++)
+        State->Early.PanGain[index] = 0.0f;
+    for(index = 0;index < Device->NumChan;index++)
+    {
+        Channel chan = Device->Speaker2Chan[index];
+        State->Early.PanGain[chan] = 1.0 + (speakerGain[chan]-1.0)*dirGain;
+    }
+
+
+    pos = aluCart2LUTpos(latePan[2], latePan[0]);
+    speakerGain = &Device->PanningLUT[MAXCHANNELS * pos];
+    dirGain = aluSqrt((latePan[0] * latePan[0]) + (latePan[2] * latePan[2]));
+
+    for(index = 0;index < MAXCHANNELS;index++)
+         State->Late.PanGain[index] = 0.0f;
+    for(index = 0;index < Device->NumChan;index++)
+    {
+        Channel chan = Device->Speaker2Chan[index];
+        State->Late.PanGain[chan] = 1.0 + (speakerGain[chan]-1.0)*dirGain;
+    }
+}
+
+// Basic delay line input/output routines.
+static __inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset)
+{
+    return Delay->Line[offset&Delay->Mask];
+}
+
+static __inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in)
+{
+    Delay->Line[offset&Delay->Mask] = in;
+}
+
+// Attenuated delay line output routine.
+static __inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff)
+{
+    return coeff * Delay->Line[offset&Delay->Mask];
+}
+
+// Basic attenuated all-pass input/output routine.
+static __inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff)
+{
+    ALfloat out, feed;
+
+    out = DelayLineOut(Delay, outOffset);
+    feed = feedCoeff * in;
+    DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in);
+
+    // The time-based attenuation is only applied to the delay output to
+    // keep it from affecting the feed-back path (which is already controlled
+    // by the all-pass feed coefficient).
+    return (coeff * out) - feed;
+}
+
+// Given an input sample, this function produces modulation for the late
+// reverb.
+static __inline ALfloat EAXModulation(ALverbState *State, ALfloat in)
+{
+    ALfloat sinus, frac;
+    ALuint offset;
+    ALfloat out0, out1;
+
+    // Calculate the sinus rythm (dependent on modulation time and the
+    // sampling rate).  The center of the sinus is moved to reduce the delay
+    // of the effect when the time or depth are low.
+    sinus = 1.0f - cos(2.0f * M_PI * State->Mod.Index / State->Mod.Range);
+
+    // The depth determines the range over which to read the input samples
+    // from, so it must be filtered to reduce the distortion caused by even
+    // small parameter changes.
+    State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth,
+                             State->Mod.Coeff);
+
+    // Calculate the read offset and fraction between it and the next sample.
+    frac   = (1.0f + (State->Mod.Filter * sinus));
+    offset = (ALuint)frac;
+    frac  -= offset;
+
+    // Get the two samples crossed by the offset, and feed the delay line
+    // with the next input sample.
+    out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset);
+    out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1);
+    DelayLineIn(&State->Mod.Delay, State->Offset, in);
+
+    // Step the modulation index forward, keeping it bound to its range.
+    State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range;
+
+    // The output is obtained by linearly interpolating the two samples that
+    // were acquired above.
+    return lerp(out0, out1, frac);
+}
+
+// Delay line output routine for early reflections.
+static __inline ALfloat EarlyDelayLineOut(ALverbState *State, ALuint index)
+{
+    return AttenuatedDelayLineOut(&State->Early.Delay[index],
+                                  State->Offset - State->Early.Offset[index],
+                                  State->Early.Coeff[index]);
+}
+
+// Given an input sample, this function produces four-channel output for the
+// early reflections.
+static __inline ALvoid EarlyReflection(ALverbState *State, ALfloat in, ALfloat *out)
+{
+    ALfloat d[4], v, f[4];
+
+    // Obtain the decayed results of each early delay line.
+    d[0] = EarlyDelayLineOut(State, 0);
+    d[1] = EarlyDelayLineOut(State, 1);
+    d[2] = EarlyDelayLineOut(State, 2);
+    d[3] = EarlyDelayLineOut(State, 3);
+
+    /* The following uses a lossless scattering junction from waveguide
+     * theory.  It actually amounts to a householder mixing matrix, which
+     * will produce a maximally diffuse response, and means this can probably
+     * be considered a simple feed-back delay network (FDN).
+     *          N
+     *         ---
+     *         \
+     * v = 2/N /   d_i
+     *         ---
+     *         i=1
+     */
+    v = (d[0] + d[1] + d[2] + d[3]) * 0.5f;
+    // The junction is loaded with the input here.
+    v += in;
+
+    // Calculate the feed values for the delay lines.
+    f[0] = v - d[0];
+    f[1] = v - d[1];
+    f[2] = v - d[2];
+    f[3] = v - d[3];
+
+    // Re-feed the delay lines.
+    DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]);
+    DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]);
+    DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]);
+    DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]);
+
+    // Output the results of the junction for all four channels.
+    out[0] = State->Early.Gain * f[0];
+    out[1] = State->Early.Gain * f[1];
+    out[2] = State->Early.Gain * f[2];
+    out[3] = State->Early.Gain * f[3];
+}
+
+// All-pass input/output routine for late reverb.
+static __inline ALfloat LateAllPassInOut(ALverbState *State, ALuint index, ALfloat in)
+{
+    return AllpassInOut(&State->Late.ApDelay[index],
+                        State->Offset - State->Late.ApOffset[index],
+                        State->Offset, in, State->Late.ApFeedCoeff,
+                        State->Late.ApCoeff[index]);
+}
+
+// Delay line output routine for late reverb.
+static __inline ALfloat LateDelayLineOut(ALverbState *State, ALuint index)
+{
+    return AttenuatedDelayLineOut(&State->Late.Delay[index],
+                                  State->Offset - State->Late.Offset[index],
+                                  State->Late.Coeff[index]);
+}
+
+// Low-pass filter input/output routine for late reverb.
+static __inline ALfloat LateLowPassInOut(ALverbState *State, ALuint index, ALfloat in)
+{
+    in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]);
+    State->Late.LpSample[index] = in;
+    return in;
+}
+
+// Given four decorrelated input samples, this function produces four-channel
+// output for the late reverb.
+static __inline ALvoid LateReverb(ALverbState *State, ALfloat *in, ALfloat *out)
+{
+    ALfloat d[4], f[4];
+
+    // Obtain the decayed results of the cyclical delay lines, and add the
+    // corresponding input channels.  Then pass the results through the
+    // low-pass filters.
+
+    // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back
+    // to 0.
+    d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2));
+    d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0));
+    d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3));
+    d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1));
+
+    // To help increase diffusion, run each line through an all-pass filter.
+    // When there is no diffusion, the shortest all-pass filter will feed the
+    // shortest delay line.
+    d[0] = LateAllPassInOut(State, 0, d[0]);
+    d[1] = LateAllPassInOut(State, 1, d[1]);
+    d[2] = LateAllPassInOut(State, 2, d[2]);
+    d[3] = LateAllPassInOut(State, 3, d[3]);
+
+    /* Late reverb is done with a modified feed-back delay network (FDN)
+     * topology.  Four input lines are each fed through their own all-pass
+     * filter and then into the mixing matrix.  The four outputs of the
+     * mixing matrix are then cycled back to the inputs.  Each output feeds
+     * a different input to form a circlular feed cycle.
+     *
+     * The mixing matrix used is a 4D skew-symmetric rotation matrix derived
+     * using a single unitary rotational parameter:
+     *
+     *  [  d,  a,  b,  c ]          1 = a^2 + b^2 + c^2 + d^2
+     *  [ -a,  d,  c, -b ]
+     *  [ -b, -c,  d,  a ]
+     *  [ -c,  b, -a,  d ]
+     *
+     * The rotation is constructed from the effect's diffusion parameter,
+     * yielding:  1 = x^2 + 3 y^2; where a, b, and c are the coefficient y
+     * with differing signs, and d is the coefficient x.  The matrix is thus:
+     *
+     *  [  x,  y, -y,  y ]          n = sqrt(matrix_order - 1)
+     *  [ -y,  x,  y,  y ]          t = diffusion_parameter * atan(n)
+     *  [  y, -y,  x,  y ]          x = cos(t)
+     *  [ -y, -y, -y,  x ]          y = sin(t) / n
+     *
+     * To reduce the number of multiplies, the x coefficient is applied with
+     * the cyclical delay line coefficients.  Thus only the y coefficient is
+     * applied when mixing, and is modified to be:  y / x.
+     */
+    f[0] = d[0] + (State->Late.MixCoeff * (         d[1] + -d[2] + d[3]));
+    f[1] = d[1] + (State->Late.MixCoeff * (-d[0]         +  d[2] + d[3]));
+    f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1]         + d[3]));
+    f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2]       ));
+
+    // Output the results of the matrix for all four channels, attenuated by
+    // the late reverb gain (which is attenuated by the 'x' mix coefficient).
+    out[0] = State->Late.Gain * f[0];
+    out[1] = State->Late.Gain * f[1];
+    out[2] = State->Late.Gain * f[2];
+    out[3] = State->Late.Gain * f[3];
+
+    // Re-feed the cyclical delay lines.
+    DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]);
+    DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]);
+    DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]);
+    DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]);
+}
+
+// Given an input sample, this function mixes echo into the four-channel late
+// reverb.
+static __inline ALvoid EAXEcho(ALverbState *State, ALfloat in, ALfloat *late)
+{
+    ALfloat out, feed;
+
+    // Get the latest attenuated echo sample for output.
+    feed = AttenuatedDelayLineOut(&State->Echo.Delay,
+                                  State->Offset - State->Echo.Offset,
+                                  State->Echo.Coeff);
+
+    // Mix the output into the late reverb channels.
+    out = State->Echo.MixCoeff[0] * feed;
+    late[0] = (State->Echo.MixCoeff[1] * late[0]) + out;
+    late[1] = (State->Echo.MixCoeff[1] * late[1]) + out;
+    late[2] = (State->Echo.MixCoeff[1] * late[2]) + out;
+    late[3] = (State->Echo.MixCoeff[1] * late[3]) + out;
+
+    // Mix the energy-attenuated input with the output and pass it through
+    // the echo low-pass filter.
+    feed += State->Echo.DensityGain * in;
+    feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff);
+    State->Echo.LpSample = feed;
+
+    // Then the echo all-pass filter.
+    feed = AllpassInOut(&State->Echo.ApDelay,
+                        State->Offset - State->Echo.ApOffset,
+                        State->Offset, feed, State->Echo.ApFeedCoeff,
+                        State->Echo.ApCoeff);
+
+    // Feed the delay with the mixed and filtered sample.
+    DelayLineIn(&State->Echo.Delay, State->Offset, feed);
+}
+
+// Perform the non-EAX reverb pass on a given input sample, resulting in
+// four-channel output.
+static __inline ALvoid VerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
+{
+    ALfloat feed, taps[4];
+
+    // Low-pass filter the incoming sample.
+    in = lpFilter2P(&State->LpFilter, 0, in);
+
+    // Feed the initial delay line.
+    DelayLineIn(&State->Delay, State->Offset, in);
+
+    // Calculate the early reflection from the first delay tap.
+    in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
+    EarlyReflection(State, in, early);
+
+    // Feed the decorrelator from the energy-attenuated output of the second
+    // delay tap.
+    in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
+    feed = in * State->Late.DensityGain;
+    DelayLineIn(&State->Decorrelator, State->Offset, feed);
+
+    // Calculate the late reverb from the decorrelator taps.
+    taps[0] = feed;
+    taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
+    taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
+    taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
+    LateReverb(State, taps, late);
+
+    // Step all delays forward one sample.
+    State->Offset++;
+}
+
+// Perform the EAX reverb pass on a given input sample, resulting in four-
+// channel output.
+static __inline ALvoid EAXVerbPass(ALverbState *State, ALfloat in, ALfloat *early, ALfloat *late)
+{
+    ALfloat feed, taps[4];
+
+    // Low-pass filter the incoming sample.
+    in = lpFilter2P(&State->LpFilter, 0, in);
+
+    // Perform any modulation on the input.
+    in = EAXModulation(State, in);
+
+    // Feed the initial delay line.
+    DelayLineIn(&State->Delay, State->Offset, in);
+
+    // Calculate the early reflection from the first delay tap.
+    in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]);
+    EarlyReflection(State, in, early);
+
+    // Feed the decorrelator from the energy-attenuated output of the second
+    // delay tap.
+    in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]);
+    feed = in * State->Late.DensityGain;
+    DelayLineIn(&State->Decorrelator, State->Offset, feed);
+
+    // Calculate the late reverb from the decorrelator taps.
+    taps[0] = feed;
+    taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]);
+    taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]);
+    taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]);
+    LateReverb(State, taps, late);
+
+    // Calculate and mix in any echo.
+    EAXEcho(State, in, late);
+
+    // Step all delays forward one sample.
+    State->Offset++;
+}
+
+// This destroys the reverb state.  It should be called only when the effect
+// slot has a different (or no) effect loaded over the reverb effect.
+static ALvoid VerbDestroy(ALeffectState *effect)
+{
+    ALverbState *State = (ALverbState*)effect;
+    if(State)
+    {
+        free(State->SampleBuffer);
+        State->SampleBuffer = NULL;
+        free(State);
+    }
+}
+
+// This updates the device-dependant reverb state.  This is called on
+// initialization and any time the device parameters (eg. playback frequency,
+// or format) have been changed.
+static ALboolean VerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+{
+    ALverbState *State = (ALverbState*)effect;
+    ALuint frequency = Device->Frequency;
+    ALuint index;
+
+    // Allocate the delay lines.
+    if(!AllocLines(AL_FALSE, frequency, State))
+        return AL_FALSE;
+
+    // The early reflection and late all-pass filter line lengths are static,
+    // so their offsets only need to be calculated once.
+    for(index = 0;index < 4;index++)
+    {
+        State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
+                                              frequency);
+        State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
+                                               frequency);
+    }
+
+    for(index = 0;index < MAXCHANNELS;index++)
+         State->Gain[index] = 0.0f;
+    for(index = 0;index < Device->NumChan;index++)
+    {
+        Channel chan = Device->Speaker2Chan[index];
+        State->Gain[chan] = 1.0f;
+    }
+
+    return AL_TRUE;
+}
+
+// This updates the device-dependant EAX reverb state.  This is called on
+// initialization and any time the device parameters (eg. playback frequency,
+// format) have been changed.
+static ALboolean EAXVerbDeviceUpdate(ALeffectState *effect, ALCdevice *Device)
+{
+    ALverbState *State = (ALverbState*)effect;
+    ALuint frequency = Device->Frequency, index;
+
+    // Allocate the delay lines.
+    if(!AllocLines(AL_TRUE, frequency, State))
+        return AL_FALSE;
+
+    // Calculate the modulation filter coefficient.  Notice that the exponent
+    // is calculated given the current sample rate.  This ensures that the
+    // resulting filter response over time is consistent across all sample
+    // rates.
+    State->Mod.Coeff = aluPow(MODULATION_FILTER_COEFF,
+                              MODULATION_FILTER_CONST / frequency);
+
+    // The early reflection and late all-pass filter line lengths are static,
+    // so their offsets only need to be calculated once.
+    for(index = 0;index < 4;index++)
+    {
+        State->Early.Offset[index] = (ALuint)(EARLY_LINE_LENGTH[index] *
+                                              frequency);
+        State->Late.ApOffset[index] = (ALuint)(ALLPASS_LINE_LENGTH[index] *
+                                               frequency);
+    }
+
+    // The echo all-pass filter line length is static, so its offset only
+    // needs to be calculated once.
+    State->Echo.ApOffset = (ALuint)(ECHO_ALLPASS_LENGTH * frequency);
+
+    return AL_TRUE;
+}
+
+// This updates the reverb state.  This is called any time the reverb effect
+// is loaded into a slot.
+static ALvoid VerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+    ALverbState *State = (ALverbState*)effect;
+    ALuint frequency = Context->Device->Frequency;
+    ALfloat cw, x, y, hfRatio;
+
+    // Calculate the master low-pass filter (from the master effect HF gain).
+    cw = CalcI3DL2HFreq(Effect->Reverb.HFReference, frequency);
+    // This is done with 2 chained 1-pole filters, so no need to square g.
+    State->LpFilter.coeff = lpCoeffCalc(Effect->Reverb.GainHF, cw);
+
+    // Update the initial effect delay.
+    UpdateDelayLine(Effect->Reverb.ReflectionsDelay,
+                    Effect->Reverb.LateReverbDelay, frequency, State);
+
+    // Update the early lines.
+    UpdateEarlyLines(Effect->Reverb.Gain, Effect->Reverb.ReflectionsGain,
+                     Effect->Reverb.LateReverbDelay, State);
+
+    // Update the decorrelator.
+    UpdateDecorrelator(Effect->Reverb.Density, frequency, State);
+
+    // Get the mixing matrix coefficients (x and y).
+    CalcMatrixCoeffs(Effect->Reverb.Diffusion, &x, &y);
+    // Then divide x into y to simplify the matrix calculation.
+    State->Late.MixCoeff = y / x;
+
+    // If the HF limit parameter is flagged, calculate an appropriate limit
+    // based on the air absorption parameter.
+    hfRatio = Effect->Reverb.DecayHFRatio;
+    if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f)
+        hfRatio = CalcLimitedHfRatio(hfRatio, Effect->Reverb.AirAbsorptionGainHF,
+                                     Effect->Reverb.DecayTime);
+
+    // Update the late lines.
+    UpdateLateLines(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain,
+                    x, Effect->Reverb.Density, Effect->Reverb.DecayTime,
+                    Effect->Reverb.Diffusion, hfRatio, cw, frequency, State);
+}
+
+// This updates the EAX reverb state.  This is called any time the EAX reverb
+// effect is loaded into a slot.
+static ALvoid EAXVerbUpdate(ALeffectState *effect, ALCcontext *Context, const ALeffect *Effect)
+{
+    ALverbState *State = (ALverbState*)effect;
+    ALuint frequency = Context->Device->Frequency;
+    ALfloat cw, x, y, hfRatio;
+
+    // Calculate the master low-pass filter (from the master effect HF gain).
+    cw = CalcI3DL2HFreq(Effect->Reverb.HFReference, frequency);
+    // This is done with 2 chained 1-pole filters, so no need to square g.
+    State->LpFilter.coeff = lpCoeffCalc(Effect->Reverb.GainHF, cw);
+
+    // Update the modulator line.
+    UpdateModulator(Effect->Reverb.ModulationTime,
+                    Effect->Reverb.ModulationDepth, frequency, State);
+
+    // Update the initial effect delay.
+    UpdateDelayLine(Effect->Reverb.ReflectionsDelay,
+                    Effect->Reverb.LateReverbDelay, frequency, State);
+
+    // Update the early lines.
+    UpdateEarlyLines(Effect->Reverb.Gain, Effect->Reverb.ReflectionsGain,
+                     Effect->Reverb.LateReverbDelay, State);
+
+    // Update the decorrelator.
+    UpdateDecorrelator(Effect->Reverb.Density, frequency, State);
+
+    // Get the mixing matrix coefficients (x and y).
+    CalcMatrixCoeffs(Effect->Reverb.Diffusion, &x, &y);
+    // Then divide x into y to simplify the matrix calculation.
+    State->Late.MixCoeff = y / x;
+
+    // If the HF limit parameter is flagged, calculate an appropriate limit
+    // based on the air absorption parameter.
+    hfRatio = Effect->Reverb.DecayHFRatio;
+    if(Effect->Reverb.DecayHFLimit && Effect->Reverb.AirAbsorptionGainHF < 1.0f)
+        hfRatio = CalcLimitedHfRatio(hfRatio, Effect->Reverb.AirAbsorptionGainHF,
+                                     Effect->Reverb.DecayTime);
+
+    // Update the late lines.
+    UpdateLateLines(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain,
+                    x, Effect->Reverb.Density, Effect->Reverb.DecayTime,
+                    Effect->Reverb.Diffusion, hfRatio, cw, frequency, State);
+
+    // Update the echo line.
+    UpdateEchoLine(Effect->Reverb.Gain, Effect->Reverb.LateReverbGain,
+                   Effect->Reverb.EchoTime, Effect->Reverb.DecayTime,
+                   Effect->Reverb.Diffusion, Effect->Reverb.EchoDepth,
+                   hfRatio, cw, frequency, State);
+
+    // Update early and late 3D panning.
+    Update3DPanning(Context->Device, Effect->Reverb.ReflectionsPan,
+                    Effect->Reverb.LateReverbPan, State);
+}
+
+// This processes the reverb state, given the input samples and an output
+// buffer.
+static ALvoid VerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+    ALverbState *State = (ALverbState*)effect;
+    ALuint index;
+    ALfloat early[4], late[4], out[4];
+    ALfloat gain = Slot->Gain;
+    const ALfloat *panGain = State->Gain;
+
+    for(index = 0;index < SamplesToDo;index++)
+    {
+        // Process reverb for this sample.
+        VerbPass(State, SamplesIn[index], early, late);
+
+        // Mix early reflections and late reverb.
+        out[0] = (early[0] + late[0]) * gain;
+        out[1] = (early[1] + late[1]) * gain;
+        out[2] = (early[2] + late[2]) * gain;
+        out[3] = (early[3] + late[3]) * gain;
+
+        // Output the results.
+        SamplesOut[index][FRONT_LEFT]   += panGain[FRONT_LEFT]   * out[0];
+        SamplesOut[index][FRONT_RIGHT]  += panGain[FRONT_RIGHT]  * out[1];
+        SamplesOut[index][FRONT_CENTER] += panGain[FRONT_CENTER] * out[3];
+        SamplesOut[index][SIDE_LEFT]    += panGain[SIDE_LEFT]    * out[0];
+        SamplesOut[index][SIDE_RIGHT]   += panGain[SIDE_RIGHT]   * out[1];
+        SamplesOut[index][BACK_LEFT]    += panGain[BACK_LEFT]    * out[0];
+        SamplesOut[index][BACK_RIGHT]   += panGain[BACK_RIGHT]   * out[1];
+        SamplesOut[index][BACK_CENTER]  += panGain[BACK_CENTER]  * out[2];
+    }
+}
+
+// This processes the EAX reverb state, given the input samples and an output
+// buffer.
+static ALvoid EAXVerbProcess(ALeffectState *effect, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+    ALverbState *State = (ALverbState*)effect;
+    ALuint index;
+    ALfloat early[4], late[4];
+    ALfloat gain = Slot->Gain;
+
+    for(index = 0;index < SamplesToDo;index++)
+    {
+        // Process reverb for this sample.
+        EAXVerbPass(State, SamplesIn[index], early, late);
+
+        // Unfortunately, while the number and configuration of gains for
+        // panning adjust according to MAXCHANNELS, the output from the
+        // reverb engine is not so scalable.
+        SamplesOut[index][FRONT_LEFT] +=
+           (State->Early.PanGain[FRONT_LEFT]*early[0] +
+            State->Late.PanGain[FRONT_LEFT]*late[0]) * gain;
+        SamplesOut[index][FRONT_RIGHT] +=
+           (State->Early.PanGain[FRONT_RIGHT]*early[1] +
+            State->Late.PanGain[FRONT_RIGHT]*late[1]) * gain;
+        SamplesOut[index][FRONT_CENTER] +=
+           (State->Early.PanGain[FRONT_CENTER]*early[3] +
+            State->Late.PanGain[FRONT_CENTER]*late[3]) * gain;
+        SamplesOut[index][SIDE_LEFT] +=
+           (State->Early.PanGain[SIDE_LEFT]*early[0] +
+            State->Late.PanGain[SIDE_LEFT]*late[0]) * gain;
+        SamplesOut[index][SIDE_RIGHT] +=
+           (State->Early.PanGain[SIDE_RIGHT]*early[1] +
+            State->Late.PanGain[SIDE_RIGHT]*late[1]) * gain;
+        SamplesOut[index][BACK_LEFT] +=
+           (State->Early.PanGain[BACK_LEFT]*early[0] +
+            State->Late.PanGain[BACK_LEFT]*late[0]) * gain;
+        SamplesOut[index][BACK_RIGHT] +=
+           (State->Early.PanGain[BACK_RIGHT]*early[1] +
+            State->Late.PanGain[BACK_RIGHT]*late[1]) * gain;
+        SamplesOut[index][BACK_CENTER] +=
+           (State->Early.PanGain[BACK_CENTER]*early[2] +
+            State->Late.PanGain[BACK_CENTER]*late[2]) * gain;
+    }
+}
+
+// This creates the reverb state.  It should be called only when the reverb
+// effect is loaded into a slot that doesn't already have a reverb effect.
+ALeffectState *VerbCreate(void)
+{
+    ALverbState *State = NULL;
+    ALuint index;
+
+    State = malloc(sizeof(ALverbState));
+    if(!State)
+        return NULL;
+
+    State->state.Destroy = VerbDestroy;
+    State->state.DeviceUpdate = VerbDeviceUpdate;
+    State->state.Update = VerbUpdate;
+    State->state.Process = VerbProcess;
+
+    State->TotalSamples = 0;
+    State->SampleBuffer = NULL;
+
+    State->LpFilter.coeff = 0.0f;
+    State->LpFilter.history[0] = 0.0f;
+    State->LpFilter.history[1] = 0.0f;
+
+    State->Mod.Delay.Mask = 0;
+    State->Mod.Delay.Line = NULL;
+    State->Mod.Index = 0;
+    State->Mod.Range = 1;
+    State->Mod.Depth = 0.0f;
+    State->Mod.Coeff = 0.0f;
+    State->Mod.Filter = 0.0f;
+
+    State->Delay.Mask = 0;
+    State->Delay.Line = NULL;
+    State->DelayTap[0] = 0;
+    State->DelayTap[1] = 0;
+
+    State->Early.Gain = 0.0f;
+    for(index = 0;index < 4;index++)
+    {
+        State->Early.Coeff[index] = 0.0f;
+        State->Early.Delay[index].Mask = 0;
+        State->Early.Delay[index].Line = NULL;
+        State->Early.Offset[index] = 0;
+    }
+
+    State->Decorrelator.Mask = 0;
+    State->Decorrelator.Line = NULL;
+    State->DecoTap[0] = 0;
+    State->DecoTap[1] = 0;
+    State->DecoTap[2] = 0;
+
+    State->Late.Gain = 0.0f;
+    State->Late.DensityGain = 0.0f;
+    State->Late.ApFeedCoeff = 0.0f;
+    State->Late.MixCoeff = 0.0f;
+    for(index = 0;index < 4;index++)
+    {
+        State->Late.ApCoeff[index] = 0.0f;
+        State->Late.ApDelay[index].Mask = 0;
+        State->Late.ApDelay[index].Line = NULL;
+        State->Late.ApOffset[index] = 0;
+
+        State->Late.Coeff[index] = 0.0f;
+        State->Late.Delay[index].Mask = 0;
+        State->Late.Delay[index].Line = NULL;
+        State->Late.Offset[index] = 0;
+
+        State->Late.LpCoeff[index] = 0.0f;
+        State->Late.LpSample[index] = 0.0f;
+    }
+
+    for(index = 0;index < MAXCHANNELS;index++)
+    {
+        State->Early.PanGain[index] = 0.0f;
+        State->Late.PanGain[index] = 0.0f;
+    }
+
+    State->Echo.DensityGain = 0.0f;
+    State->Echo.Delay.Mask = 0;
+    State->Echo.Delay.Line = NULL;
+    State->Echo.ApDelay.Mask = 0;
+    State->Echo.ApDelay.Line = NULL;
+    State->Echo.Coeff = 0.0f;
+    State->Echo.ApFeedCoeff = 0.0f;
+    State->Echo.ApCoeff = 0.0f;
+    State->Echo.Offset = 0;
+    State->Echo.ApOffset = 0;
+    State->Echo.LpCoeff = 0.0f;
+    State->Echo.LpSample = 0.0f;
+    State->Echo.MixCoeff[0] = 0.0f;
+    State->Echo.MixCoeff[1] = 0.0f;
+
+    State->Offset = 0;
+
+    State->Gain = State->Late.PanGain;
+
+    return &State->state;
+}
+
+ALeffectState *EAXVerbCreate(void)
+{
+    ALeffectState *State = VerbCreate();
+    if(State)
+    {
+        State->DeviceUpdate = EAXVerbDeviceUpdate;
+        State->Update = EAXVerbUpdate;
+        State->Process = EAXVerbProcess;
+    }
+    return State;
+}
diff --git a/Alc/alcRing.c b/Alc/alcRing.c
new file mode 100644 (file)
index 0000000..3361eb6
--- /dev/null
@@ -0,0 +1,131 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "alMain.h"
+
+
+struct RingBuffer {
+    ALubyte *mem;
+
+    ALsizei frame_size;
+    ALsizei length;
+    ALint read_pos;
+    ALint write_pos;
+
+    CRITICAL_SECTION cs;
+};
+
+
+RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length)
+{
+    RingBuffer *ring = calloc(1, sizeof(*ring));
+    if(ring)
+    {
+        ring->frame_size = frame_size;
+        ring->length = length+1;
+        ring->write_pos = 1;
+        ring->mem = malloc(ring->length * ring->frame_size);
+        if(!ring->mem)
+        {
+            free(ring);
+            ring = NULL;
+        }
+
+        InitializeCriticalSection(&ring->cs);
+    }
+    return ring;
+}
+
+void DestroyRingBuffer(RingBuffer *ring)
+{
+    if(ring)
+    {
+        DeleteCriticalSection(&ring->cs);
+        free(ring->mem);
+        free(ring);
+    }
+}
+
+ALsizei RingBufferSize(RingBuffer *ring)
+{
+    ALsizei s;
+
+    EnterCriticalSection(&ring->cs);
+    s = (ring->write_pos-ring->read_pos-1+ring->length) % ring->length;
+    LeaveCriticalSection(&ring->cs);
+
+    return s;
+}
+
+void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
+{
+    int remain;
+
+    EnterCriticalSection(&ring->cs);
+
+    remain = (ring->read_pos-ring->write_pos+ring->length) % ring->length;
+    if(remain < len) len = remain;
+
+    if(len > 0)
+    {
+        remain = ring->length - ring->write_pos;
+        if(remain < len)
+        {
+            memcpy(ring->mem+(ring->write_pos*ring->frame_size), data,
+                   remain*ring->frame_size);
+            memcpy(ring->mem, data+(remain*ring->frame_size),
+                   (len-remain)*ring->frame_size);
+        }
+        else
+            memcpy(ring->mem+(ring->write_pos*ring->frame_size), data,
+                   len*ring->frame_size);
+
+        ring->write_pos += len;
+        ring->write_pos %= ring->length;
+    }
+
+    LeaveCriticalSection(&ring->cs);
+}
+
+void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
+{
+    int remain;
+
+    EnterCriticalSection(&ring->cs);
+
+    remain = ring->length - ring->read_pos;
+    if(remain < len)
+    {
+        memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), remain*ring->frame_size);
+        memcpy(data+(remain*ring->frame_size), ring->mem, (len-remain)*ring->frame_size);
+    }
+    else
+        memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), len*ring->frame_size);
+
+    ring->read_pos += len;
+    ring->read_pos %= ring->length;
+
+    LeaveCriticalSection(&ring->cs);
+}
diff --git a/Alc/alcThread.c b/Alc/alcThread.c
new file mode 100644 (file)
index 0000000..582dfd8
--- /dev/null
@@ -0,0 +1,128 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alThunk.h"
+
+
+#ifdef _WIN32
+
+typedef struct {
+    ALuint (*func)(ALvoid*);
+    ALvoid *ptr;
+    HANDLE thread;
+} ThreadInfo;
+
+static DWORD CALLBACK StarterFunc(void *ptr)
+{
+    ThreadInfo *inf = (ThreadInfo*)ptr;
+    ALint ret;
+
+    ret = inf->func(inf->ptr);
+    ExitThread((DWORD)ret);
+
+    return (DWORD)ret;
+}
+
+ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
+{
+    DWORD dummy;
+    ThreadInfo *inf = malloc(sizeof(ThreadInfo));
+    if(!inf) return 0;
+
+    inf->func = func;
+    inf->ptr = ptr;
+
+    inf->thread = CreateThread(NULL, 0, StarterFunc, inf, 0, &dummy);
+    if(!inf->thread)
+    {
+        free(inf);
+        return NULL;
+    }
+
+    return inf;
+}
+
+ALuint StopThread(ALvoid *thread)
+{
+    ThreadInfo *inf = thread;
+    DWORD ret = 0;
+
+    WaitForSingleObject(inf->thread, INFINITE);
+    GetExitCodeThread(inf->thread, &ret);
+    CloseHandle(inf->thread);
+
+    free(inf);
+
+    return (ALuint)ret;
+}
+
+#else
+
+#include <pthread.h>
+
+typedef struct {
+    ALuint (*func)(ALvoid*);
+    ALvoid *ptr;
+    ALuint ret;
+    pthread_t thread;
+} ThreadInfo;
+
+static void *StarterFunc(void *ptr)
+{
+    ThreadInfo *inf = (ThreadInfo*)ptr;
+    inf->ret = inf->func(inf->ptr);
+    return NULL;
+}
+
+ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr)
+{
+    ThreadInfo *inf = malloc(sizeof(ThreadInfo));
+    if(!inf) return NULL;
+
+    inf->func = func;
+    inf->ptr = ptr;
+    if(pthread_create(&inf->thread, NULL, StarterFunc, inf) != 0)
+    {
+        free(inf);
+        return NULL;
+    }
+
+    return inf;
+}
+
+ALuint StopThread(ALvoid *thread)
+{
+    ThreadInfo *inf = thread;
+    ALuint ret;
+
+    pthread_join(inf->thread, NULL);
+    ret = inf->ret;
+
+    free(inf);
+
+    return ret;
+}
+
+#endif
diff --git a/Alc/alsa.c b/Alc/alsa.c
new file mode 100644 (file)
index 0000000..a7e8758
--- /dev/null
@@ -0,0 +1,1048 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include <alsa/asoundlib.h>
+
+
+typedef struct {
+    snd_pcm_t *pcmHandle;
+
+    ALvoid *buffer;
+    ALsizei size;
+
+    ALboolean doCapture;
+    RingBuffer *ring;
+
+    volatile int killNow;
+    ALvoid *thread;
+} alsa_data;
+
+typedef struct {
+    ALCchar *name;
+    int card, dev;
+} DevMap;
+
+static void *alsa_handle;
+#define MAKE_FUNC(f) static typeof(f) * p##f
+MAKE_FUNC(snd_strerror);
+MAKE_FUNC(snd_pcm_open);
+MAKE_FUNC(snd_pcm_close);
+MAKE_FUNC(snd_pcm_nonblock);
+MAKE_FUNC(snd_pcm_frames_to_bytes);
+MAKE_FUNC(snd_pcm_bytes_to_frames);
+MAKE_FUNC(snd_pcm_hw_params_malloc);
+MAKE_FUNC(snd_pcm_hw_params_free);
+MAKE_FUNC(snd_pcm_hw_params_any);
+MAKE_FUNC(snd_pcm_hw_params_set_access);
+MAKE_FUNC(snd_pcm_hw_params_set_format);
+MAKE_FUNC(snd_pcm_hw_params_set_channels);
+MAKE_FUNC(snd_pcm_hw_params_set_periods_near);
+MAKE_FUNC(snd_pcm_hw_params_set_rate_near);
+MAKE_FUNC(snd_pcm_hw_params_set_rate);
+MAKE_FUNC(snd_pcm_hw_params_set_rate_resample);
+MAKE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
+MAKE_FUNC(snd_pcm_hw_params_set_period_time_near);
+MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_near);
+MAKE_FUNC(snd_pcm_hw_params_set_period_size_near);
+MAKE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
+MAKE_FUNC(snd_pcm_hw_params_get_buffer_size);
+MAKE_FUNC(snd_pcm_hw_params_get_period_size);
+MAKE_FUNC(snd_pcm_hw_params_get_access);
+MAKE_FUNC(snd_pcm_hw_params_get_periods);
+MAKE_FUNC(snd_pcm_hw_params);
+MAKE_FUNC(snd_pcm_sw_params_malloc);
+MAKE_FUNC(snd_pcm_sw_params_current);
+MAKE_FUNC(snd_pcm_sw_params_set_avail_min);
+MAKE_FUNC(snd_pcm_sw_params);
+MAKE_FUNC(snd_pcm_sw_params_free);
+MAKE_FUNC(snd_pcm_prepare);
+MAKE_FUNC(snd_pcm_start);
+MAKE_FUNC(snd_pcm_resume);
+MAKE_FUNC(snd_pcm_wait);
+MAKE_FUNC(snd_pcm_state);
+MAKE_FUNC(snd_pcm_avail_update);
+MAKE_FUNC(snd_pcm_areas_silence);
+MAKE_FUNC(snd_pcm_mmap_begin);
+MAKE_FUNC(snd_pcm_mmap_commit);
+MAKE_FUNC(snd_pcm_readi);
+MAKE_FUNC(snd_pcm_writei);
+MAKE_FUNC(snd_pcm_drain);
+MAKE_FUNC(snd_pcm_recover);
+MAKE_FUNC(snd_pcm_info_malloc);
+MAKE_FUNC(snd_pcm_info_free);
+MAKE_FUNC(snd_pcm_info_set_device);
+MAKE_FUNC(snd_pcm_info_set_subdevice);
+MAKE_FUNC(snd_pcm_info_set_stream);
+MAKE_FUNC(snd_pcm_info_get_name);
+MAKE_FUNC(snd_ctl_pcm_next_device);
+MAKE_FUNC(snd_ctl_pcm_info);
+MAKE_FUNC(snd_ctl_open);
+MAKE_FUNC(snd_ctl_close);
+MAKE_FUNC(snd_ctl_card_info_malloc);
+MAKE_FUNC(snd_ctl_card_info_free);
+MAKE_FUNC(snd_ctl_card_info);
+MAKE_FUNC(snd_ctl_card_info_get_name);
+MAKE_FUNC(snd_card_next);
+#undef MAKE_FUNC
+
+
+static const ALCchar alsaDevice[] = "ALSA Default";
+static DevMap *allDevNameMap;
+static ALuint numDevNames;
+static DevMap *allCaptureDevNameMap;
+static ALuint numCaptureDevNames;
+
+
+void *alsa_load(void)
+{
+    if(!alsa_handle)
+    {
+        char *str;
+
+#ifdef HAVE_DLFCN_H
+        alsa_handle = dlopen("libasound.so.2", RTLD_NOW);
+        if(!alsa_handle)
+            return NULL;
+        dlerror();
+
+#define LOAD_FUNC(f) do { \
+    p##f = dlsym(alsa_handle, #f); \
+    if((str=dlerror()) != NULL) \
+    { \
+        dlclose(alsa_handle); \
+        alsa_handle = NULL; \
+        AL_PRINT("Could not load %s from libasound.so.2: %s\n", #f, str); \
+        return NULL; \
+    } \
+} while(0)
+#else
+        str = NULL;
+        alsa_handle = (void*)0xDEADBEEF;
+#define LOAD_FUNC(f) p##f = f
+#endif
+
+LOAD_FUNC(snd_strerror);
+LOAD_FUNC(snd_pcm_open);
+LOAD_FUNC(snd_pcm_close);
+LOAD_FUNC(snd_pcm_nonblock);
+LOAD_FUNC(snd_pcm_frames_to_bytes);
+LOAD_FUNC(snd_pcm_bytes_to_frames);
+LOAD_FUNC(snd_pcm_hw_params_malloc);
+LOAD_FUNC(snd_pcm_hw_params_free);
+LOAD_FUNC(snd_pcm_hw_params_any);
+LOAD_FUNC(snd_pcm_hw_params_set_access);
+LOAD_FUNC(snd_pcm_hw_params_set_format);
+LOAD_FUNC(snd_pcm_hw_params_set_channels);
+LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
+LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
+LOAD_FUNC(snd_pcm_hw_params_set_rate);
+LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
+LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
+LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
+LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
+LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
+LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
+LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
+LOAD_FUNC(snd_pcm_hw_params_get_period_size);
+LOAD_FUNC(snd_pcm_hw_params_get_access);
+LOAD_FUNC(snd_pcm_hw_params_get_periods);
+LOAD_FUNC(snd_pcm_hw_params);
+LOAD_FUNC(snd_pcm_sw_params_malloc);
+LOAD_FUNC(snd_pcm_sw_params_current);
+LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
+LOAD_FUNC(snd_pcm_sw_params);
+LOAD_FUNC(snd_pcm_sw_params_free);
+LOAD_FUNC(snd_pcm_prepare);
+LOAD_FUNC(snd_pcm_start);
+LOAD_FUNC(snd_pcm_resume);
+LOAD_FUNC(snd_pcm_wait);
+LOAD_FUNC(snd_pcm_state);
+LOAD_FUNC(snd_pcm_avail_update);
+LOAD_FUNC(snd_pcm_areas_silence);
+LOAD_FUNC(snd_pcm_mmap_begin);
+LOAD_FUNC(snd_pcm_mmap_commit);
+LOAD_FUNC(snd_pcm_readi);
+LOAD_FUNC(snd_pcm_writei);
+LOAD_FUNC(snd_pcm_drain);
+LOAD_FUNC(snd_pcm_recover);
+
+LOAD_FUNC(snd_pcm_info_malloc);
+LOAD_FUNC(snd_pcm_info_free);
+LOAD_FUNC(snd_pcm_info_set_device);
+LOAD_FUNC(snd_pcm_info_set_subdevice);
+LOAD_FUNC(snd_pcm_info_set_stream);
+LOAD_FUNC(snd_pcm_info_get_name);
+LOAD_FUNC(snd_ctl_pcm_next_device);
+LOAD_FUNC(snd_ctl_pcm_info);
+LOAD_FUNC(snd_ctl_open);
+LOAD_FUNC(snd_ctl_close);
+LOAD_FUNC(snd_ctl_card_info_malloc);
+LOAD_FUNC(snd_ctl_card_info_free);
+LOAD_FUNC(snd_ctl_card_info);
+LOAD_FUNC(snd_ctl_card_info_get_name);
+LOAD_FUNC(snd_card_next);
+
+#undef LOAD_FUNC
+    }
+    return alsa_handle;
+}
+
+static DevMap *probe_devices(snd_pcm_stream_t stream, ALuint *count)
+{
+    snd_ctl_t *handle;
+    int card, err, dev, idx;
+    snd_ctl_card_info_t *info;
+    snd_pcm_info_t *pcminfo;
+    DevMap *DevList;
+    char name[1024];
+
+    psnd_ctl_card_info_malloc(&info);
+    psnd_pcm_info_malloc(&pcminfo);
+
+    card = -1;
+    if((err=psnd_card_next(&card)) < 0)
+        AL_PRINT("Failed to find a card: %s\n", psnd_strerror(err));
+
+    DevList = malloc(sizeof(DevMap) * 1);
+    DevList[0].name = strdup("ALSA Default");
+    idx = 1;
+    while(card >= 0)
+    {
+        sprintf(name, "hw:%d", card);
+        if((err = psnd_ctl_open(&handle, name, 0)) < 0)
+        {
+            AL_PRINT("control open (%i): %s\n", card, psnd_strerror(err));
+            goto next_card;
+        }
+        if((err = psnd_ctl_card_info(handle, info)) < 0)
+        {
+            AL_PRINT("control hardware info (%i): %s\n", card, psnd_strerror(err));
+            psnd_ctl_close(handle);
+            goto next_card;
+        }
+
+        dev = -1;
+        while(1)
+        {
+            const char *cname, *dname;
+            void *temp;
+
+            if(psnd_ctl_pcm_next_device(handle, &dev) < 0)
+                AL_PRINT("snd_ctl_pcm_next_device failed\n");
+            if(dev < 0)
+                break;
+
+            psnd_pcm_info_set_device(pcminfo, dev);
+            psnd_pcm_info_set_subdevice(pcminfo, 0);
+            psnd_pcm_info_set_stream(pcminfo, stream);
+            if((err = psnd_ctl_pcm_info(handle, pcminfo)) < 0) {
+                if(err != -ENOENT)
+                    AL_PRINT("control digital audio info (%i): %s\n", card, psnd_strerror(err));
+                continue;
+            }
+
+            temp = realloc(DevList, sizeof(DevMap) * (idx+1));
+            if(temp)
+            {
+                DevList = temp;
+                cname = psnd_ctl_card_info_get_name(info);
+                dname = psnd_pcm_info_get_name(pcminfo);
+                snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d) via ALSA",
+                         cname, dname, card, dev);
+                DevList[idx].name = strdup(name);
+                DevList[idx].card = card;
+                DevList[idx].dev = dev;
+                idx++;
+            }
+        }
+        psnd_ctl_close(handle);
+    next_card:
+        if(psnd_card_next(&card) < 0) {
+            AL_PRINT("snd_card_next failed\n");
+            break;
+        }
+    }
+
+    psnd_pcm_info_free(pcminfo);
+    psnd_ctl_card_info_free(info);
+
+    *count = idx;
+    return DevList;
+}
+
+
+static int xrun_recovery(snd_pcm_t *handle, int err)
+{
+    err = psnd_pcm_recover(handle, err, 1);
+    if(err < 0)
+        AL_PRINT("recover failed: %s\n", psnd_strerror(err));
+    return err;
+}
+
+static int verify_state(snd_pcm_t *handle)
+{
+    snd_pcm_state_t state = psnd_pcm_state(handle);
+    if(state == SND_PCM_STATE_DISCONNECTED)
+        return -ENODEV;
+    if(state == SND_PCM_STATE_XRUN)
+    {
+        int err = xrun_recovery(handle, -EPIPE);
+        if(err < 0) return err;
+    }
+    else if(state == SND_PCM_STATE_SUSPENDED)
+    {
+        int err = xrun_recovery(handle, -ESTRPIPE);
+        if(err < 0) return err;
+    }
+
+    return state;
+}
+
+
+static ALuint ALSAProc(ALvoid *ptr)
+{
+    ALCdevice *pDevice = (ALCdevice*)ptr;
+    alsa_data *data = (alsa_data*)pDevice->ExtraData;
+    const snd_pcm_channel_area_t *areas = NULL;
+    snd_pcm_sframes_t avail, commitres;
+    snd_pcm_uframes_t offset, frames;
+    char *WritePtr;
+    int err;
+
+    SetRTPriority();
+
+    while(!data->killNow)
+    {
+        int state = verify_state(data->pcmHandle);
+        if(state < 0)
+        {
+            AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
+            aluHandleDisconnect(pDevice);
+            break;
+        }
+
+        avail = psnd_pcm_avail_update(data->pcmHandle);
+        if(avail < 0)
+        {
+            AL_PRINT("available update failed: %s\n", psnd_strerror(avail));
+            continue;
+        }
+
+        // make sure there's frames to process
+        if((snd_pcm_uframes_t)avail < pDevice->UpdateSize)
+        {
+            if(state != SND_PCM_STATE_RUNNING)
+            {
+                err = psnd_pcm_start(data->pcmHandle);
+                if(err < 0)
+                {
+                    AL_PRINT("start failed: %s\n", psnd_strerror(err));
+                    continue;
+                }
+            }
+            if(psnd_pcm_wait(data->pcmHandle, 1000) == 0)
+                AL_PRINT("Wait timeout... buffer size too low?\n");
+            continue;
+        }
+        avail -= avail%pDevice->UpdateSize;
+
+        // it is possible that contiguous areas are smaller, thus we use a loop
+        while(avail > 0)
+        {
+            frames = avail;
+
+            err = psnd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
+            if(err < 0)
+            {
+                AL_PRINT("mmap begin error: %s\n", psnd_strerror(err));
+                break;
+            }
+
+            WritePtr = (char*)areas->addr + (offset * areas->step / 8);
+            aluMixData(pDevice, WritePtr, frames);
+
+            commitres = psnd_pcm_mmap_commit(data->pcmHandle, offset, frames);
+            if(commitres < 0 || (commitres-frames) != 0)
+            {
+                AL_PRINT("mmap commit error: %s\n",
+                         psnd_strerror(commitres >= 0 ? -EPIPE : commitres));
+                break;
+            }
+
+            avail -= frames;
+        }
+    }
+
+    return 0;
+}
+
+static ALuint ALSANoMMapProc(ALvoid *ptr)
+{
+    ALCdevice *pDevice = (ALCdevice*)ptr;
+    alsa_data *data = (alsa_data*)pDevice->ExtraData;
+    snd_pcm_sframes_t avail;
+    char *WritePtr;
+
+    SetRTPriority();
+
+    while(!data->killNow)
+    {
+        int state = verify_state(data->pcmHandle);
+        if(state < 0)
+        {
+            AL_PRINT("Invalid state detected: %s\n", psnd_strerror(state));
+            aluHandleDisconnect(pDevice);
+            break;
+        }
+
+        WritePtr = data->buffer;
+        avail = data->size / psnd_pcm_frames_to_bytes(data->pcmHandle, 1);
+        aluMixData(pDevice, WritePtr, avail);
+
+        while(avail > 0)
+        {
+            int ret = psnd_pcm_writei(data->pcmHandle, WritePtr, avail);
+            switch (ret)
+            {
+            case -EAGAIN:
+                continue;
+            case -ESTRPIPE:
+            case -EPIPE:
+            case -EINTR:
+                ret = psnd_pcm_recover(data->pcmHandle, ret, 1);
+                if(ret < 0)
+                    avail = 0;
+                break;
+            default:
+                if (ret >= 0)
+                {
+                    WritePtr += psnd_pcm_frames_to_bytes(data->pcmHandle, ret);
+                    avail -= ret;
+                }
+                break;
+            }
+            if (ret < 0)
+            {
+                ret = psnd_pcm_prepare(data->pcmHandle);
+                if(ret < 0)
+                    break;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+    alsa_data *data;
+    char driver[64];
+    int i;
+
+    if(!alsa_load())
+        return ALC_FALSE;
+
+    strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1);
+    driver[sizeof(driver)-1] = 0;
+
+    if(!deviceName)
+        deviceName = alsaDevice;
+    else if(strcmp(deviceName, alsaDevice) != 0)
+    {
+        size_t idx;
+
+        if(!allDevNameMap)
+            allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
+
+        for(idx = 0;idx < numDevNames;idx++)
+        {
+            if(allDevNameMap[idx].name &&
+               strcmp(deviceName, allDevNameMap[idx].name) == 0)
+            {
+                if(idx > 0)
+                    sprintf(driver, "hw:%d,%d", allDevNameMap[idx].card, allDevNameMap[idx].dev);
+                break;
+            }
+        }
+        if(idx == numDevNames)
+            return ALC_FALSE;
+    }
+
+    data = (alsa_data*)calloc(1, sizeof(alsa_data));
+
+    i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+    if(i >= 0)
+    {
+        i = psnd_pcm_nonblock(data->pcmHandle, 0);
+        if(i < 0)
+            psnd_pcm_close(data->pcmHandle);
+    }
+    if(i < 0)
+    {
+        free(data);
+        AL_PRINT("Could not open playback device '%s': %s\n", driver, psnd_strerror(i));
+        return ALC_FALSE;
+    }
+
+    device->szDeviceName = strdup(deviceName);
+    device->ExtraData = data;
+    return ALC_TRUE;
+}
+
+static void alsa_close_playback(ALCdevice *device)
+{
+    alsa_data *data = (alsa_data*)device->ExtraData;
+
+    psnd_pcm_close(data->pcmHandle);
+    free(data);
+    device->ExtraData = NULL;
+}
+
+static ALCboolean alsa_reset_playback(ALCdevice *device)
+{
+    alsa_data *data = (alsa_data*)device->ExtraData;
+    snd_pcm_uframes_t periodSizeInFrames;
+    unsigned int periodLen, bufferLen;
+    snd_pcm_sw_params_t *sp = NULL;
+    snd_pcm_hw_params_t *p = NULL;
+    snd_pcm_access_t access;
+    snd_pcm_format_t format;
+    unsigned int periods;
+    unsigned int rate;
+    int allowmmap;
+    char *err;
+    int i;
+
+
+    format = -1;
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            format = SND_PCM_FORMAT_S8;
+            break;
+        case DevFmtUByte:
+            format = SND_PCM_FORMAT_U8;
+            break;
+        case DevFmtShort:
+            format = SND_PCM_FORMAT_S16;
+            break;
+        case DevFmtUShort:
+            format = SND_PCM_FORMAT_U16;
+            break;
+        case DevFmtFloat:
+            format = SND_PCM_FORMAT_FLOAT;
+            break;
+    }
+
+    allowmmap = GetConfigValueBool("alsa", "mmap", 1);
+    periods = device->NumUpdates;
+    periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency;
+    bufferLen = periodLen * periods;
+    rate = device->Frequency;
+
+    err = NULL;
+    psnd_pcm_hw_params_malloc(&p);
+
+    if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
+        err = "any";
+    /* set interleaved access */
+    if(i >= 0 && (!allowmmap || (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0))
+    {
+        if(periods > 2)
+        {
+            periods--;
+            bufferLen = periodLen * periods;
+        }
+        if((i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+            err = "set access";
+    }
+    /* set format (implicitly sets sample bits) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
+    {
+        device->FmtType = DevFmtFloat;
+        if(format == SND_PCM_FORMAT_FLOAT ||
+           (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_FLOAT)) < 0)
+        {
+            device->FmtType = DevFmtShort;
+            if(format == SND_PCM_FORMAT_S16 ||
+               (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_S16)) < 0)
+            {
+                device->FmtType = DevFmtUByte;
+                if(format == SND_PCM_FORMAT_U8 ||
+                   (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, SND_PCM_FORMAT_U8)) < 0)
+                    err = "set format";
+            }
+        }
+    }
+    /* set channels (implicitly sets frame bits) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(device->FmtChans))) < 0)
+    {
+        device->FmtChans = DevFmtStereo;
+        if((i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, 2)) < 0)
+        {
+            device->FmtChans = DevFmtMono;
+            if((i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, 1)) < 0)
+                err = "set channels";
+        }
+    }
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_rate_resample(data->pcmHandle, p, 0)) < 0)
+    {
+        AL_PRINT("Failed to disable ALSA resampler\n");
+        i = 0;
+    }
+    /* set rate (implicitly constrains period/buffer parameters) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_rate_near(data->pcmHandle, p, &rate, NULL)) < 0)
+        err = "set rate near";
+    /* set buffer time (implicitly constrains period/buffer parameters) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_buffer_time_near(data->pcmHandle, p, &bufferLen, NULL)) < 0)
+        err = "set buffer time near";
+    /* set period time in frame units (implicitly sets buffer size/bytes/time and period size/bytes) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_period_time_near(data->pcmHandle, p, &periodLen, NULL)) < 0)
+        err = "set period time near";
+    /* install and prepare hardware configuration */
+    if(i >= 0 && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
+        err = "set params";
+    if(i >= 0 && (i=psnd_pcm_hw_params_get_access(p, &access)) < 0)
+        err = "get access";
+    if(i >= 0 && (i=psnd_pcm_hw_params_get_period_size(p, &periodSizeInFrames, NULL)) < 0)
+        err = "get period size";
+    if(i >= 0 && (i=psnd_pcm_hw_params_get_periods(p, &periods, NULL)) < 0)
+        err = "get periods";
+    if(i < 0)
+    {
+        AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
+        psnd_pcm_hw_params_free(p);
+        return ALC_FALSE;
+    }
+
+    psnd_pcm_hw_params_free(p);
+
+    err = NULL;
+    psnd_pcm_sw_params_malloc(&sp);
+
+    if((i=psnd_pcm_sw_params_current(data->pcmHandle, sp)) != 0)
+        err = "sw current";
+    if(i == 0 && (i=psnd_pcm_sw_params_set_avail_min(data->pcmHandle, sp, periodSizeInFrames)) != 0)
+        err = "sw set avail min";
+    if(i == 0 && (i=psnd_pcm_sw_params(data->pcmHandle, sp)) != 0)
+        err = "sw set params";
+    if(i != 0)
+    {
+        AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
+        psnd_pcm_sw_params_free(sp);
+        return ALC_FALSE;
+    }
+
+    psnd_pcm_sw_params_free(sp);
+
+    device->Frequency = rate;
+
+    SetDefaultChannelOrder(device);
+
+    data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, periodSizeInFrames);
+    if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
+    {
+        /* Increase periods by one, since the temp buffer counts as an extra
+         * period */
+        periods++;
+        data->buffer = malloc(data->size);
+        if(!data->buffer)
+        {
+            AL_PRINT("buffer malloc failed\n");
+            return ALC_FALSE;
+        }
+        device->UpdateSize = periodSizeInFrames;
+        device->NumUpdates = periods;
+        data->thread = StartThread(ALSANoMMapProc, device);
+    }
+    else
+    {
+        i = psnd_pcm_prepare(data->pcmHandle);
+        if(i < 0)
+        {
+            AL_PRINT("prepare error: %s\n", psnd_strerror(i));
+            return ALC_FALSE;
+        }
+        device->UpdateSize = periodSizeInFrames;
+        device->NumUpdates = periods;
+        data->thread = StartThread(ALSAProc, device);
+    }
+    if(data->thread == NULL)
+    {
+        AL_PRINT("Could not create playback thread\n");
+        free(data->buffer);
+        data->buffer = NULL;
+        return ALC_FALSE;
+    }
+
+    return ALC_TRUE;
+}
+
+static void alsa_stop_playback(ALCdevice *device)
+{
+    alsa_data *data = (alsa_data*)device->ExtraData;
+
+    if(data->thread)
+    {
+        data->killNow = 1;
+        StopThread(data->thread);
+        data->thread = NULL;
+    }
+    data->killNow = 0;
+    free(data->buffer);
+    data->buffer = NULL;
+}
+
+
+static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+    snd_pcm_hw_params_t *p;
+    snd_pcm_uframes_t bufferSizeInFrames;
+    snd_pcm_format_t format;
+    ALuint frameSize;
+    alsa_data *data;
+    char driver[64];
+    char *err;
+    int i;
+
+    if(!alsa_load())
+        return ALC_FALSE;
+
+    strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1);
+    driver[sizeof(driver)-1] = 0;
+
+    if(!allCaptureDevNameMap)
+        allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
+
+    if(!deviceName)
+        deviceName = allCaptureDevNameMap[0].name;
+    else
+    {
+        size_t idx;
+
+        for(idx = 0;idx < numCaptureDevNames;idx++)
+        {
+            if(allCaptureDevNameMap[idx].name &&
+               strcmp(deviceName, allCaptureDevNameMap[idx].name) == 0)
+            {
+                if(idx > 0)
+                    sprintf(driver, "plughw:%d,%d", allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev);
+                break;
+            }
+        }
+        if(idx == numCaptureDevNames)
+            return ALC_FALSE;
+    }
+
+    data = (alsa_data*)calloc(1, sizeof(alsa_data));
+
+    i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+    if(i < 0)
+    {
+        AL_PRINT("Could not open capture device '%s': %s\n", driver, psnd_strerror(i));
+        free(data);
+        return ALC_FALSE;
+    }
+
+    format = -1;
+    switch(pDevice->FmtType)
+    {
+        case DevFmtByte:
+            format = SND_PCM_FORMAT_S8;
+            break;
+        case DevFmtUByte:
+            format = SND_PCM_FORMAT_U8;
+            break;
+        case DevFmtShort:
+            format = SND_PCM_FORMAT_S16;
+            break;
+        case DevFmtUShort:
+            format = SND_PCM_FORMAT_U16;
+            break;
+        case DevFmtFloat:
+            format = SND_PCM_FORMAT_FLOAT;
+            break;
+    }
+
+    err = NULL;
+    bufferSizeInFrames = pDevice->UpdateSize * pDevice->NumUpdates;
+    psnd_pcm_hw_params_malloc(&p);
+
+    if((i=psnd_pcm_hw_params_any(data->pcmHandle, p)) < 0)
+        err = "any";
+    /* set interleaved access */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+        err = "set access";
+    /* set format (implicitly sets sample bits) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_format(data->pcmHandle, p, format)) < 0)
+        err = "set format";
+    /* set channels (implicitly sets frame bits) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_channels(data->pcmHandle, p, ChannelsFromDevFmt(pDevice->FmtChans))) < 0)
+        err = "set channels";
+    /* set rate (implicitly constrains period/buffer parameters) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_rate(data->pcmHandle, p, pDevice->Frequency, 0)) < 0)
+        err = "set rate near";
+    /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
+    if(i >= 0 && (i=psnd_pcm_hw_params_set_buffer_size_near(data->pcmHandle, p, &bufferSizeInFrames)) < 0)
+        err = "set buffer size near";
+    /* install and prepare hardware configuration */
+    if(i >= 0 && (i=psnd_pcm_hw_params(data->pcmHandle, p)) < 0)
+        err = "set params";
+    if(i < 0)
+    {
+        AL_PRINT("%s failed: %s\n", err, psnd_strerror(i));
+        psnd_pcm_hw_params_free(p);
+        goto error;
+    }
+
+    if((i=psnd_pcm_hw_params_get_period_size(p, &bufferSizeInFrames, NULL)) < 0)
+    {
+        AL_PRINT("get size failed: %s\n", psnd_strerror(i));
+        psnd_pcm_hw_params_free(p);
+        goto error;
+    }
+
+    psnd_pcm_hw_params_free(p);
+
+    frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+    data->ring = CreateRingBuffer(frameSize, pDevice->UpdateSize*pDevice->NumUpdates);
+    if(!data->ring)
+    {
+        AL_PRINT("ring buffer create failed\n");
+        goto error;
+    }
+
+    data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames);
+    data->buffer = malloc(data->size);
+    if(!data->buffer)
+    {
+        AL_PRINT("buffer malloc failed\n");
+        goto error;
+    }
+
+    pDevice->szDeviceName = strdup(deviceName);
+
+    pDevice->ExtraData = data;
+    return ALC_TRUE;
+
+error:
+    free(data->buffer);
+    DestroyRingBuffer(data->ring);
+    psnd_pcm_close(data->pcmHandle);
+    free(data);
+
+    pDevice->ExtraData = NULL;
+    return ALC_FALSE;
+}
+
+static void alsa_close_capture(ALCdevice *pDevice)
+{
+    alsa_data *data = (alsa_data*)pDevice->ExtraData;
+
+    psnd_pcm_close(data->pcmHandle);
+    DestroyRingBuffer(data->ring);
+
+    free(data->buffer);
+    free(data);
+    pDevice->ExtraData = NULL;
+}
+
+static void alsa_start_capture(ALCdevice *Device)
+{
+    alsa_data *data = (alsa_data*)Device->ExtraData;
+    int err;
+
+    err = psnd_pcm_start(data->pcmHandle);
+    if(err < 0)
+    {
+        AL_PRINT("start failed: %s\n", psnd_strerror(err));
+        aluHandleDisconnect(Device);
+    }
+    else
+        data->doCapture = AL_TRUE;
+}
+
+static void alsa_stop_capture(ALCdevice *Device)
+{
+    alsa_data *data = (alsa_data*)Device->ExtraData;
+    psnd_pcm_drain(data->pcmHandle);
+    data->doCapture = AL_FALSE;
+}
+
+static ALCuint alsa_available_samples(ALCdevice *Device)
+{
+    alsa_data *data = (alsa_data*)Device->ExtraData;
+    snd_pcm_sframes_t avail;
+
+    avail = (Device->Connected ? psnd_pcm_avail_update(data->pcmHandle) : 0);
+    if(avail < 0)
+    {
+        AL_PRINT("avail update failed: %s\n", psnd_strerror(avail));
+
+        if((avail=psnd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
+        {
+            if(data->doCapture)
+                avail = psnd_pcm_start(data->pcmHandle);
+            if(avail >= 0)
+                avail = psnd_pcm_avail_update(data->pcmHandle);
+        }
+        if(avail < 0)
+        {
+            AL_PRINT("restore error: %s\n", psnd_strerror(avail));
+            aluHandleDisconnect(Device);
+        }
+    }
+    while(avail > 0)
+    {
+        snd_pcm_sframes_t amt;
+
+        amt = psnd_pcm_bytes_to_frames(data->pcmHandle, data->size);
+        if(avail < amt) amt = avail;
+
+        amt = psnd_pcm_readi(data->pcmHandle, data->buffer, amt);
+        if(amt < 0)
+        {
+            AL_PRINT("read error: %s\n", psnd_strerror(amt));
+
+            if(amt == -EAGAIN)
+                continue;
+            if((amt=psnd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
+            {
+                if(data->doCapture)
+                    amt = psnd_pcm_start(data->pcmHandle);
+                if(amt >= 0)
+                    amt = psnd_pcm_avail_update(data->pcmHandle);
+            }
+            if(amt < 0)
+            {
+                AL_PRINT("restore error: %s\n", psnd_strerror(amt));
+                aluHandleDisconnect(Device);
+                break;
+            }
+            avail = amt;
+            continue;
+        }
+
+        WriteRingBuffer(data->ring, data->buffer, amt);
+        avail -= amt;
+    }
+
+    return RingBufferSize(data->ring);
+}
+
+static void alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
+{
+    alsa_data *data = (alsa_data*)Device->ExtraData;
+
+    if(Samples <= alsa_available_samples(Device))
+        ReadRingBuffer(data->ring, Buffer, Samples);
+    else
+        alcSetError(Device, ALC_INVALID_VALUE);
+}
+
+
+BackendFuncs alsa_funcs = {
+    alsa_open_playback,
+    alsa_close_playback,
+    alsa_reset_playback,
+    alsa_stop_playback,
+    alsa_open_capture,
+    alsa_close_capture,
+    alsa_start_capture,
+    alsa_stop_capture,
+    alsa_capture_samples,
+    alsa_available_samples
+};
+
+void alc_alsa_init(BackendFuncs *func_list)
+{
+    *func_list = alsa_funcs;
+}
+
+void alc_alsa_deinit(void)
+{
+    ALuint i;
+
+    for(i = 0;i < numDevNames;++i)
+        free(allDevNameMap[i].name);
+    free(allDevNameMap);
+    allDevNameMap = NULL;
+    numDevNames = 0;
+
+    for(i = 0;i < numCaptureDevNames;++i)
+        free(allCaptureDevNameMap[i].name);
+    free(allCaptureDevNameMap);
+    allCaptureDevNameMap = NULL;
+    numCaptureDevNames = 0;
+
+    if(alsa_handle)
+    {
+#ifdef HAVE_DLFCN_H
+        dlclose(alsa_handle);
+#endif
+        alsa_handle = NULL;
+    }
+}
+
+void alc_alsa_probe(int type)
+{
+    ALuint i;
+
+    if(!alsa_load())
+        return;
+
+    if(type == DEVICE_PROBE)
+        AppendDeviceList(alsaDevice);
+    else if(type == ALL_DEVICE_PROBE)
+    {
+        for(i = 0;i < numDevNames;++i)
+            free(allDevNameMap[i].name);
+
+        free(allDevNameMap);
+        allDevNameMap = probe_devices(SND_PCM_STREAM_PLAYBACK, &numDevNames);
+
+        for(i = 0;i < numDevNames;++i)
+            AppendAllDeviceList(allDevNameMap[i].name);
+    }
+    else if(type == CAPTURE_DEVICE_PROBE)
+    {
+        for(i = 0;i < numCaptureDevNames;++i)
+            free(allCaptureDevNameMap[i].name);
+
+        free(allCaptureDevNameMap);
+        allCaptureDevNameMap = probe_devices(SND_PCM_STREAM_CAPTURE, &numCaptureDevNames);
+
+        for(i = 0;i < numCaptureDevNames;++i)
+            AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
+    }
+}
diff --git a/Alc/avsystem.c b/Alc/avsystem.c
new file mode 100644 (file)
index 0000000..303324b
--- /dev/null
@@ -0,0 +1,464 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include <avsystem.h>
+#include <avsys-audio.h>
+#include <audio-session-manager.h>
+#include <mm_session.h>
+#include <mm_session_private.h>
+
+#ifndef SOUND_MIXER_READ
+#define SOUND_MIXER_READ MIXER_READ
+#endif
+#ifndef SOUND_MIXER_WRITE
+#define SOUND_MIXER_WRITE MIXER_WRITE
+#endif
+
+//for debug
+#define LOG_LEVEL_2
+#if defined(LOG_LEVEL_0)
+#define func_in()
+#define func_out()
+#elif defined(LOG_LEVEL_1)
+#define func_in()                              fprintf(stderr,"<< %s\n", __FUNCTION__)
+#define func_out()                             fprintf(stderr, ">> %s\n", __FUNCTION__)
+#elif defined(LOG_LEVEL_2)
+#include <dlog.h>
+#define LOG_TAG        "MMFW_OPENAL"
+#define func_in() SLOG(LOG_VERBOSE, LOG_TAG, "<< %s\n", __FUNCTION__)
+#define func_out() SLOG(LOG_VERBOSE, LOG_TAG, ">> %s\n", __FUNCTION__)
+#endif
+
+static const ALCchar avsystem_Device[] = "avsystem";
+
+typedef struct {
+       avsys_audio_param_t             param;
+       avsys_handle_t                  handle;
+       int                                             data_size;
+       ALubyte                                 *mix_data;
+       volatile int                    killNow;
+       ALboolean                               doCapture;
+       ALvoid                                  *thread;
+       int                                             asm_handle;
+       ASM_sound_events_t              asm_event;
+} avsys_data;
+
+
+ASM_cb_result_t
+asm_callback(int handle, ASM_event_sources_t event_src, ASM_sound_commands_t command, unsigned int sound_status, void* cb_data)
+{
+       avsys_data              *data = (avsys_data*) cb_data;
+       ASM_cb_result_t cb_res = ASM_CB_RES_IGNORE;
+       if(!data)
+       {
+               AL_PRINT("asm_callback data is null\n");
+               return cb_res;
+       }
+
+       switch(command)
+       {
+       case ASM_COMMAND_STOP:
+       case ASM_COMMAND_PAUSE:
+               if(AVSYS_FAIL(avsys_audio_set_mute(data->handle, AVSYS_AUDIO_MUTE)))
+               {
+                       AL_PRINT("set handle mute failed\n");
+               }
+               cb_res = ASM_CB_RES_PAUSE;
+               break;
+       case ASM_COMMAND_PLAY:
+       case ASM_COMMAND_RESUME:
+               if(AVSYS_FAIL(avsys_audio_set_mute(data->handle, AVSYS_AUDIO_UNMUTE)))
+               {
+                       AL_PRINT("set handle unmute failed\n");
+               }
+               cb_res = ASM_CB_RES_PLAYING;
+               break;
+       }
+       return cb_res;
+}
+
+static ALuint AvsysProc(ALvoid *ptr)
+{
+       ALCdevice *pDevice = (ALCdevice*)ptr;
+       avsys_data *data;
+       ALint remaining = 0;
+       ALint wrote;
+       ALint lenByte, lenSample;
+
+       ALvoid* WritePtr = NULL;
+
+       func_in();
+       if (ptr == NULL)
+       {
+               AL_PRINT("__thread_input_parameter_is_null\n");
+               return 1;
+       }
+
+       data = (avsys_data*)pDevice->ExtraData;
+       if (data == NULL)
+       {
+               AL_PRINT("__thread_input_parameter_is_null\n");
+               return 1;
+       }
+       if (data->mix_data == NULL)
+       {
+               AL_PRINT("____mix_data is null\n");
+               return 1;
+       }
+
+       while(!data->killNow && pDevice->Connected)
+       {
+               lenByte = data->data_size;
+               lenSample = lenByte / FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+               WritePtr = data->mix_data;
+
+               aluMixData(pDevice, data->mix_data, lenSample);
+
+               while(lenByte > 0 && !data->killNow)
+               {
+                       wrote = avsys_audio_write(data->handle, WritePtr, lenByte);
+                       if(wrote < 0)
+                       {
+                               lenByte =0;
+                               aluHandleDisconnect(pDevice);
+                       }
+                       lenByte -= wrote;
+                       WritePtr += wrote;
+               }
+       }
+
+       func_out();
+       return 0;
+}
+
+static ALuint AvsysCaptureProc(ALvoid *ptr)
+{
+    (void)ptr;
+    return 0;
+}
+
+static ALCboolean avsystem_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+       avsys_data                              *data = NULL;
+       int                                             BufferSize =0;
+       int                                             result = ALC_TRUE;
+
+       func_in();
+
+    if(deviceName)
+    {
+        if(strcmp(deviceName, avsystem_Device) != 0)
+            return ALC_FALSE;
+        device->szDeviceName = strdup(avsystem_Device);
+    }
+    else
+        device->szDeviceName = strdup(avsystem_Device);
+
+
+    data = (avsys_data*)calloc(1, sizeof(avsys_data));
+    if(data == NULL)
+       goto error;
+
+    data->param.mode = AVSYS_AUDIO_MODE_OUTPUT_LOW_LATENCY;
+    data->param.priority = AVSYS_AUDIO_PRIORITY_0;
+    data->param.channels = ChannelsFromDevFmt(device->FmtChans);;
+    data->param.samplerate = device->Frequency;
+    data->param.handle_route = 0;
+    data->param.vol_type = AVSYS_AUDIO_VOLUME_TYPE_MEDIA;
+
+    switch(device->FmtType)
+    {
+       case DevFmtByte:
+       case DevFmtUByte:
+               data->param.format = AVSYS_AUDIO_FORMAT_8BIT;
+               break;
+       case DevFmtUShort:
+               device->FmtType = DevFmtShort;
+               /* fall-through */
+       case DevFmtShort:
+               data->param.format = AVSYS_AUDIO_FORMAT_16BIT;
+               break;
+#if defined(FORMAT_32)
+       case DevFmtFloat:
+               data->param.format = AVSYS_AUDIO_FORMAT_32BIT;
+               break;
+#endif
+       default :
+               AL_PRINT("Not supported format\n");
+               break;
+       }
+
+    if(AVSYS_STATE_SUCCESS !=
+                                       avsys_audio_open(&data->param, &data->handle, &BufferSize))
+    {
+       AL_PRINT("avsys_audio_open() failed\n");
+       goto error;
+    }
+    data->data_size = BufferSize;
+    device->ExtraData = data;
+
+    func_out();
+    return ALC_TRUE;
+
+error:
+       if(data != NULL)
+       {
+               if(data->handle)
+               {
+                       avsys_audio_close(data->handle);
+               }
+               free(data);
+               data = NULL;
+       }
+
+       return ALC_FALSE;
+
+}
+
+static ALCboolean avsystem_reset_playback(ALCdevice *device)
+{
+       avsys_data                              *data = NULL;
+       avsys_audio_volume_t            avsys_volume;
+       int                                             loaded_volume = 9;
+       int                                             sessionType = MM_SESSION_TYPE_SHARE;
+       ASM_sound_events_t              asm_event = ASM_EVENT_NONE;
+       int                                             errorcode = 0;
+       func_in();
+       if(device == NULL)
+       {
+               AL_PRINT("input parameter is null [%d][%s]\n", __LINE__,__func__);
+               return ALC_FALSE;
+       }
+       if(device->ExtraData == NULL)
+       {
+               AL_PRINT("input parameter is null [%d][%s]\n", __LINE__,__func__);
+               return ALC_FALSE;
+       }
+       data = (avsys_data*)device->ExtraData;
+
+       // read session type
+       if(_mm_session_util_read_type(-1, &sessionType) < 0)
+       {
+               AL_PRINT("Read Session Type failed. Set default \"Share\" type\n");
+               sessionType = MM_SESSION_TYPE_SHARE;
+               if(mm_session_init(sessionType) < 0)
+               {
+                       AL_PRINT("mm_session_init() failed\n");
+                       return ALC_FALSE;
+               }
+       }
+
+       // convert MM_SESSION_TYPE to ASM_EVENT_TYPE
+       if(sessionType != MM_SESSION_TYPE_CALL)
+       {
+               switch(sessionType)
+               {
+               case MM_SESSION_TYPE_SHARE:
+                       asm_event = ASM_EVENT_SHARE_OPENAL;
+                       break;
+               case MM_SESSION_TYPE_EXCLUSIVE:
+                       asm_event = ASM_EVENT_EXCLUSIVE_OPENAL;
+                       break;
+               case MM_SESSION_TYPE_NOTIFY:
+                       asm_event = ASM_EVENT_NOTIFY;
+                       break;
+               case MM_SESSION_TYPE_ALARM:
+                       asm_event = ASM_EVENT_ALARM;
+                       break;
+               default:
+                       AL_PRINT("Unexpected %d\n", sessionType);
+                       return ALC_FALSE;
+               }
+       }
+
+       data->asm_event = asm_event;
+
+
+    data->mix_data = calloc(1, data->data_size);
+    if(data->mix_data == NULL)
+    {
+       AL_PRINT("Memory Allocation failed\n");
+       return ALC_FALSE;
+    }
+    device->UpdateSize = data->data_size /FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    SetDefaultChannelOrder(device);
+
+               // register asm handle
+    if(!ASM_register_sound(-1, &data->asm_handle, asm_event, ASM_STATE_PLAYING, asm_callback, data, ASM_RESOURCE_NONE, &errorcode))
+    {
+       AL_PRINT("ASM_register_sound() failed 0x%x\n", errorcode);
+       return ALC_FALSE;
+    }
+
+    data->thread = StartThread(AvsysProc, device);
+    if(data->thread == NULL)
+    {
+       AL_PRINT("Could not create playback thread\n");
+       if(!ASM_unregister_sound(data->asm_handle, asm_event, &errorcode))
+       {
+               AL_PRINT("ASM_unregister_sound() failed 0x%x\n", errorcode);
+               return ALC_FALSE;
+       }
+       return ALC_FALSE;
+    }
+    func_out();
+    return ALC_TRUE;
+}
+
+static void avsystem_stop_playback(ALCdevice *device)
+{
+       int errorcode = 0;
+       avsys_data *data = (avsys_data*)device->ExtraData;
+       func_in();
+    if(data->thread)
+    {
+        data->killNow = 1;
+        StopThread(data->thread);
+        AL_PRINT("Thread Stopped\n");
+        data->thread = NULL;
+    }
+
+    free(data->mix_data);
+    data->mix_data = NULL;
+
+    if(data->asm_event != ASM_EVENT_CALL)
+    {
+       if(!ASM_unregister_sound(data->asm_handle, data->asm_event, &errorcode))
+       {
+               AL_PRINT("ASM_unregister failed in avsystem_stop_playback with 0x%x\n", errorcode);
+       }
+    }
+
+    func_out();
+}
+
+static void avsystem_close_playback(ALCdevice *device)
+{
+       avsys_data *data = (avsys_data*)device->ExtraData;
+
+       func_in();
+
+       avsys_audio_close(data->handle);
+
+       free(data);
+       device->ExtraData = NULL;
+
+    func_out();
+}
+
+static ALCboolean avsystem_open_capture(ALCdevice *device, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
+{
+    func_in();
+    (void)device;
+    (void)deviceName;
+    func_out();
+    return ALC_FALSE;
+}
+
+static void avsystem_close_capture(ALCdevice *device)
+{
+    func_in();
+    (void)device;
+    func_out();
+}
+
+static void avsystem_start_capture(ALCdevice *pDevice)
+{
+    func_in();
+    (void)pDevice;
+    func_out();
+}
+
+static void avsystem_stop_capture(ALCdevice *pDevice)
+{
+    func_in();
+    (void)pDevice;
+    func_out();
+}
+
+static void avsystem_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+    func_in();
+    (void)pDevice;
+    (void)pBuffer;
+    (void)lSamples;
+    func_out();
+}
+
+static ALCuint avsystem_available_samples(ALCdevice *pDevice)
+{
+    func_in();
+    (void)pDevice;
+    return 0;
+    func_out();
+}
+
+BackendFuncs avsys_funcs = {
+    avsystem_open_playback,
+    avsystem_close_playback,
+    avsystem_reset_playback,
+    avsystem_stop_playback,
+    avsystem_open_capture,
+    avsystem_close_capture,
+    avsystem_start_capture,
+    avsystem_stop_capture,
+    avsystem_capture_samples,
+    avsystem_available_samples,
+};
+
+void alc_avsystem_init(BackendFuncs *func_list)
+{
+       func_in();
+    *func_list = avsys_funcs;
+    func_out();
+}
+
+void alc_avsystem_deinit(void)
+{
+       func_in();
+    func_out();
+}
+
+void alc_avsystem_probe(int type)
+{
+    if(type == DEVICE_PROBE)
+               AppendDeviceList(avsystem_Device);
+    else if(type == ALL_DEVICE_PROBE)
+        AppendAllDeviceList(avsystem_Device);
+    else if(type == CAPTURE_DEVICE_PROBE)
+        AppendCaptureDeviceList(avsystem_Device);
+
+}
diff --git a/Alc/bs2b.c b/Alc/bs2b.c
new file mode 100644 (file)
index 0000000..9930e11
--- /dev/null
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 2005 Boris Mikhaylov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <math.h>
+
+#include "bs2b.h"
+
+#ifndef M_PI
+#define M_PI  3.14159265358979323846
+#endif
+
+/* Single pole IIR filter.
+ * O[n] = a0*I[n] + a1*I[n-1] + b1*O[n-1]
+ */
+
+/* Lowpass filter */
+#define lo_filter(in, out_1) (bs2b->a0_lo*(in) + bs2b->b1_lo*(out_1))
+
+/* Highboost filter */
+#define hi_filter(in, in_1, out_1) (bs2b->a0_hi*(in) + bs2b->a1_hi*(in_1) + bs2b->b1_hi*(out_1))
+
+/* Set up all data. */
+static void init(struct bs2b *bs2b)
+{
+    double Fc_lo, Fc_hi;
+    double G_lo,  G_hi;
+    double x;
+
+    if ((bs2b->srate > 192000) || (bs2b->srate < 2000))
+        bs2b->srate = BS2B_DEFAULT_SRATE;
+
+    switch(bs2b->level)
+    {
+    case BS2B_LOW_CLEVEL: /* Low crossfeed level */
+        Fc_lo = 360.0;
+        Fc_hi = 501.0;
+        G_lo  = 0.398107170553497;
+        G_hi  = 0.205671765275719;
+        break;
+
+    case BS2B_MIDDLE_CLEVEL: /* Middle crossfeed level */
+        Fc_lo = 500.0;
+        Fc_hi = 711.0;
+        G_lo  = 0.459726988530872;
+        G_hi  = 0.228208484414988;
+        break;
+
+    case BS2B_HIGH_CLEVEL: /* High crossfeed level (virtual speakers are closer to itself) */
+        Fc_lo = 700.0;
+        Fc_hi = 1021.0;
+        G_lo  = 0.530884444230988;
+        G_hi  = 0.250105790667544;
+        break;
+
+    case BS2B_LOW_ECLEVEL: /* Low easy crossfeed level */
+        Fc_lo = 360.0;
+        Fc_hi = 494.0;
+        G_lo  = 0.316227766016838;
+        G_hi  = 0.168236228897329;
+        break;
+
+    case BS2B_MIDDLE_ECLEVEL: /* Middle easy crossfeed level */
+        Fc_lo = 500.0;
+        Fc_hi = 689.0;
+        G_lo  = 0.354813389233575;
+        G_hi  = 0.187169483835901;
+        break;
+
+    default: /* High easy crossfeed level */
+        bs2b->level = BS2B_HIGH_ECLEVEL;
+
+        Fc_lo = 700.0;
+        Fc_hi = 975.0;
+        G_lo  = 0.398107170553497;
+        G_hi  = 0.205671765275719;
+        break;
+    } /* switch */
+
+    /* $fc = $Fc / $s;
+     * $d  = 1 / 2 / pi / $fc;
+     * $x  = exp(-1 / $d);
+     */
+
+    x           = exp(-2.0 * M_PI * Fc_lo / bs2b->srate);
+    bs2b->b1_lo = x;
+    bs2b->a0_lo = G_lo * (1.0 - x);
+
+    x           = exp(-2.0 * M_PI * Fc_hi / bs2b->srate);
+    bs2b->b1_hi = x;
+    bs2b->a0_hi = 1.0 - G_hi * (1.0 - x);
+    bs2b->a1_hi = -x;
+
+    bs2b->gain  = 1.0 / (1.0 - G_hi + G_lo);
+} /* init */
+
+/* Exported functions.
+ * See descriptions in "bs2b.h"
+ */
+
+void bs2b_set_level(struct bs2b *bs2b, int level)
+{
+    if(level == bs2b->level)
+        return;
+    bs2b->level = level;
+    init(bs2b);
+} /* bs2b_set_level */
+
+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;
+} /* bs2b_get_srate */
+
+void bs2b_clear(struct bs2b *bs2b)
+{
+    int loopv = sizeof(bs2b->last_sample);
+
+    while (loopv)
+    {
+        ((char *)&bs2b->last_sample)[--loopv] = 0;
+    }
+} /* bs2b_clear */
+
+int bs2b_is_clear(struct bs2b *bs2b)
+{
+    int loopv = sizeof(bs2b->last_sample);
+
+    while (loopv)
+    {
+        if (((char *)&bs2b->last_sample)[--loopv] != 0)
+            return 0;
+    }
+    return 1;
+} /* bs2b_is_clear */
+
+void bs2b_cross_feed(struct bs2b *bs2b, float *sample)
+{
+    /* Lowpass filter */
+    bs2b->last_sample.lo[0] = lo_filter(sample[0], bs2b->last_sample.lo[0]);
+    bs2b->last_sample.lo[1] = lo_filter(sample[1], bs2b->last_sample.lo[1]);
+
+    /* Highboost filter */
+    bs2b->last_sample.hi[0] = hi_filter(sample[0], bs2b->last_sample.asis[0], bs2b->last_sample.hi[0]);
+    bs2b->last_sample.hi[1] = hi_filter(sample[1], bs2b->last_sample.asis[1], bs2b->last_sample.hi[1]);
+    bs2b->last_sample.asis[0] = sample[0];
+    bs2b->last_sample.asis[1] = sample[1];
+
+    /* Crossfeed */
+    sample[0] = bs2b->last_sample.hi[0] + bs2b->last_sample.lo[1];
+    sample[1] = bs2b->last_sample.hi[1] + bs2b->last_sample.lo[0];
+
+    /* Bass boost cause allpass attenuation */
+    sample[0] *= bs2b->gain;
+    sample[1] *= bs2b->gain;
+
+    /* Clipping of overloaded samples */
+#if 0
+    if (sample[0] > 1.0)
+        sample[0] = 1.0;
+    if (sample[0] < -1.0)
+        sample[0] = -1.0;
+    if (sample[1] > 1.0)
+        sample[1] = 1.0;
+    if (sample[1] < -1.0)
+        sample[1] = -1.0;
+#endif
+} /* bs2b_cross_feed */
diff --git a/Alc/dsound.c b/Alc/dsound.c
new file mode 100644 (file)
index 0000000..26e6d46
--- /dev/null
@@ -0,0 +1,612 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#define _WIN32_WINNT 0x0500
+#define INITGUID
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+
+#include <dsound.h>
+#include <cguid.h>
+#include <mmreg.h>
+#ifndef _WAVEFORMATEXTENSIBLE_
+#include <ks.h>
+#include <ksmedia.h>
+#endif
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#ifndef DSSPEAKER_5POINT1
+#define DSSPEAKER_5POINT1       6
+#endif
+#ifndef DSSPEAKER_7POINT1
+#define DSSPEAKER_7POINT1       7
+#endif
+
+DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
+DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
+
+static void *ds_handle;
+static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);
+static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
+
+
+typedef struct {
+    // DirectSound Playback Device
+    LPDIRECTSOUND          lpDS;
+    LPDIRECTSOUNDBUFFER    DSpbuffer;
+    LPDIRECTSOUNDBUFFER    DSsbuffer;
+
+    volatile int killNow;
+    ALvoid *thread;
+} DSoundData;
+
+
+typedef struct {
+    ALCchar *name;
+    GUID guid;
+} DevMap;
+
+static const ALCchar dsDevice[] = "DirectSound Default";
+static DevMap *DeviceList;
+static ALuint NumDevices;
+
+
+void *DSoundLoad(void)
+{
+    if(!ds_handle)
+    {
+#ifdef _WIN32
+        ds_handle = LoadLibraryA("dsound.dll");
+        if(ds_handle == NULL)
+        {
+            AL_PRINT("Failed to load dsound.dll\n");
+            return NULL;
+        }
+
+#define LOAD_FUNC(f) do { \
+    p##f = (void*)GetProcAddress((HMODULE)ds_handle, #f); \
+    if(p##f == NULL) \
+    { \
+        FreeLibrary(ds_handle); \
+        ds_handle = NULL; \
+        AL_PRINT("Could not load %s from dsound.dll\n", #f); \
+        return NULL; \
+    } \
+} while(0)
+#else
+        ds_handle = (void*)0xDEADBEEF;
+#define LOAD_FUNC(f) p##f = f
+#endif
+
+LOAD_FUNC(DirectSoundCreate);
+LOAD_FUNC(DirectSoundEnumerateA);
+#undef LOAD_FUNC
+    }
+    return ds_handle;
+}
+
+
+static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
+{
+    char str[1024];
+    void *temp;
+    int count;
+    ALuint i;
+
+    (void)data;
+    (void)drvname;
+
+    if(NumDevices == 0)
+    {
+        temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1));
+        if(temp)
+        {
+            DeviceList = temp;
+            DeviceList[NumDevices].name = strdup(dsDevice);
+            DeviceList[NumDevices].guid = GUID_NULL;
+            NumDevices++;
+        }
+    }
+
+    if(!guid)
+        return TRUE;
+
+    count = 0;
+    do {
+        if(count == 0)
+            snprintf(str, sizeof(str), "%s via DirectSound", desc);
+        else
+            snprintf(str, sizeof(str), "%s #%d via DirectSound", desc, count+1);
+        count++;
+
+        for(i = 0;i < NumDevices;i++)
+        {
+            if(strcmp(str, DeviceList[i].name) == 0)
+                break;
+        }
+    } while(i != NumDevices);
+
+    temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1));
+    if(temp)
+    {
+        DeviceList = temp;
+        DeviceList[NumDevices].name = strdup(str);
+        DeviceList[NumDevices].guid = *guid;
+        NumDevices++;
+    }
+
+    return TRUE;
+}
+
+
+static ALuint DSoundProc(ALvoid *ptr)
+{
+    ALCdevice *pDevice = (ALCdevice*)ptr;
+    DSoundData *pData = (DSoundData*)pDevice->ExtraData;
+    DSBCAPS DSBCaps;
+    DWORD LastCursor = 0;
+    DWORD PlayCursor;
+    VOID *WritePtr1, *WritePtr2;
+    DWORD WriteCnt1,  WriteCnt2;
+    BOOL Playing = FALSE;
+    DWORD FrameSize;
+    DWORD FragSize;
+    DWORD avail;
+    HRESULT err;
+
+    SetRTPriority();
+
+    memset(&DSBCaps, 0, sizeof(DSBCaps));
+    DSBCaps.dwSize = sizeof(DSBCaps);
+    err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
+    if(FAILED(err))
+    {
+        AL_PRINT("Failed to get buffer caps: 0x%lx\n", err);
+        aluHandleDisconnect(pDevice);
+        return 1;
+    }
+
+    FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+    FragSize = pDevice->UpdateSize * FrameSize;
+
+    IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL);
+    while(!pData->killNow)
+    {
+        // Get current play and write cursors
+        IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
+        avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
+
+        if(avail < FragSize)
+        {
+            if(!Playing)
+            {
+                err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
+                if(FAILED(err))
+                {
+                    AL_PRINT("Failed to play buffer: 0x%lx\n", err);
+                    aluHandleDisconnect(pDevice);
+                    return 1;
+                }
+                Playing = TRUE;
+            }
+            Sleep(1);
+            continue;
+        }
+        avail -= avail%FragSize;
+
+        // Lock output buffer
+        WriteCnt1 = 0;
+        WriteCnt2 = 0;
+        err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
+
+        // If the buffer is lost, restore it and lock
+        if(err == DSERR_BUFFERLOST)
+        {
+            err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
+            if(SUCCEEDED(err))
+            {
+                Playing = FALSE;
+                LastCursor = 0;
+                err = IDirectSoundBuffer_Lock(pData->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
+            }
+        }
+
+        // Successfully locked the output buffer
+        if(SUCCEEDED(err))
+        {
+            // If we have an active context, mix data directly into output buffer otherwise fill with silence
+            aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize);
+            aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize);
+
+            // Unlock output buffer only when successfully locked
+            IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
+        }
+        else
+        {
+            AL_PRINT("Buffer lock error: %#lx\n", err);
+            aluHandleDisconnect(pDevice);
+            return 1;
+        }
+
+        // Update old write cursor location
+        LastCursor += WriteCnt1+WriteCnt2;
+        LastCursor %= DSBCaps.dwBufferBytes;
+    }
+
+    return 0;
+}
+
+static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
+{
+    DSoundData *pData = NULL;
+    LPGUID guid = NULL;
+    HRESULT hr;
+
+    if(!DSoundLoad())
+        return ALC_FALSE;
+
+    if(!deviceName)
+        deviceName = dsDevice;
+    else if(strcmp(deviceName, dsDevice) != 0)
+    {
+        ALuint i;
+
+        if(!DeviceList)
+        {
+            hr = pDirectSoundEnumerateA(DSoundEnumDevices, NULL);
+            if(FAILED(hr))
+                AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
+        }
+
+        for(i = 0;i < NumDevices;i++)
+        {
+            if(strcmp(deviceName, DeviceList[i].name) == 0)
+            {
+                if(i > 0)
+                    guid = &DeviceList[i].guid;
+                break;
+            }
+        }
+        if(i == NumDevices)
+            return ALC_FALSE;
+    }
+
+    //Initialise requested device
+    pData = calloc(1, sizeof(DSoundData));
+    if(!pData)
+    {
+        alcSetError(device, ALC_OUT_OF_MEMORY);
+        return ALC_FALSE;
+    }
+
+    //DirectSound Init code
+    hr = pDirectSoundCreate(guid, &pData->lpDS, NULL);
+    if(SUCCEEDED(hr))
+        hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
+    if(FAILED(hr))
+    {
+        if(pData->lpDS)
+            IDirectSound_Release(pData->lpDS);
+        free(pData);
+        AL_PRINT("Device init failed: 0x%08lx\n", hr);
+        return ALC_FALSE;
+    }
+
+    device->szDeviceName = strdup(deviceName);
+    device->ExtraData = pData;
+    return ALC_TRUE;
+}
+
+static void DSoundClosePlayback(ALCdevice *device)
+{
+    DSoundData *pData = device->ExtraData;
+
+    IDirectSound_Release(pData->lpDS);
+    free(pData);
+    device->ExtraData = NULL;
+}
+
+static ALCboolean DSoundResetPlayback(ALCdevice *device)
+{
+    DSoundData *pData = (DSoundData*)device->ExtraData;
+    DSBUFFERDESC DSBDescription;
+    WAVEFORMATEXTENSIBLE OutputType;
+    DWORD speakers;
+    HRESULT hr;
+
+    memset(&OutputType, 0, sizeof(OutputType));
+
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            device->FmtType = DevFmtUByte;
+            break;
+        case DevFmtUShort:
+            device->FmtType = DevFmtShort;
+            break;
+        case DevFmtUByte:
+        case DevFmtShort:
+        case DevFmtFloat:
+            break;
+    }
+
+    hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
+    if(SUCCEEDED(hr) && ConfigValueExists(NULL, "format"))
+    {
+        switch(device->FmtChans)
+        {
+            case DevFmtMono:
+                speakers = DSSPEAKER_COMBINED(DSSPEAKER_MONO, 0);
+                break;
+            case DevFmtStereo:
+                speakers = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, 0);
+                break;
+            case DevFmtQuad:
+                speakers = DSSPEAKER_COMBINED(DSSPEAKER_QUAD, 0);
+                break;
+            case DevFmtX51:
+                speakers = DSSPEAKER_COMBINED(DSSPEAKER_5POINT1, 0);
+                break;
+            case DevFmtX61:
+                /* ??? */;
+                break;
+            case DevFmtX71:
+                speakers = DSSPEAKER_COMBINED(DSSPEAKER_7POINT1, 0);
+                break;
+        }
+    }
+    if(SUCCEEDED(hr))
+    {
+        speakers = DSSPEAKER_CONFIG(speakers);
+        if(speakers == DSSPEAKER_MONO)
+        {
+            device->FmtChans = DevFmtMono;
+            OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
+        }
+        else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
+        {
+            device->FmtChans = DevFmtStereo;
+            OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                       SPEAKER_FRONT_RIGHT;
+        }
+        else if(speakers == DSSPEAKER_QUAD)
+        {
+            device->FmtChans = DevFmtQuad;
+            OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                       SPEAKER_FRONT_RIGHT |
+                                       SPEAKER_BACK_LEFT |
+                                       SPEAKER_BACK_RIGHT;
+        }
+        else if(speakers == DSSPEAKER_5POINT1)
+        {
+            device->FmtChans = DevFmtX51;
+            OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                       SPEAKER_FRONT_RIGHT |
+                                       SPEAKER_FRONT_CENTER |
+                                       SPEAKER_LOW_FREQUENCY |
+                                       SPEAKER_BACK_LEFT |
+                                       SPEAKER_BACK_RIGHT;
+        }
+        else if(speakers == DSSPEAKER_7POINT1)
+        {
+            device->FmtChans = DevFmtX71;
+            OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
+                                       SPEAKER_FRONT_RIGHT |
+                                       SPEAKER_FRONT_CENTER |
+                                       SPEAKER_LOW_FREQUENCY |
+                                       SPEAKER_BACK_LEFT |
+                                       SPEAKER_BACK_RIGHT |
+                                       SPEAKER_SIDE_LEFT |
+                                       SPEAKER_SIDE_RIGHT;
+        }
+
+        OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
+        OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
+        OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
+        OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
+        OutputType.Format.nSamplesPerSec = device->Frequency;
+        OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
+        OutputType.Format.cbSize = 0;
+    }
+
+    if(OutputType.Format.nChannels > 2 || OutputType.Format.wBitsPerSample > 16)
+    {
+        OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+        OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
+        OutputType.Format.cbSize = 22;
+        if(OutputType.Format.wBitsPerSample == 32)
+            OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
+        else
+            OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+    }
+    else
+    {
+        if(SUCCEEDED(hr))
+        {
+            memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
+            DSBDescription.dwSize=sizeof(DSBUFFERDESC);
+            DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
+            hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
+        }
+        if(SUCCEEDED(hr))
+            hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
+    }
+
+    if(SUCCEEDED(hr))
+    {
+        memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
+        DSBDescription.dwSize=sizeof(DSBUFFERDESC);
+        DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
+        DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
+                                     OutputType.Format.nBlockAlign;
+        DSBDescription.lpwfxFormat=&OutputType.Format;
+        hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
+    }
+
+    if(SUCCEEDED(hr))
+    {
+        SetDefaultWFXChannelOrder(device);
+        pData->thread = StartThread(DSoundProc, device);
+        if(!pData->thread)
+            hr = E_FAIL;
+    }
+
+    if(FAILED(hr))
+    {
+        if (pData->DSsbuffer)
+            IDirectSoundBuffer_Release(pData->DSsbuffer);
+        pData->DSsbuffer = NULL;
+        if (pData->DSpbuffer)
+            IDirectSoundBuffer_Release(pData->DSpbuffer);
+        pData->DSpbuffer = NULL;
+        return ALC_FALSE;
+    }
+
+    return ALC_TRUE;
+}
+
+static void DSoundStopPlayback(ALCdevice *device)
+{
+    DSoundData *pData = device->ExtraData;
+
+    if(!pData->thread)
+        return;
+
+    pData->killNow = 1;
+    StopThread(pData->thread);
+    pData->thread = NULL;
+
+    pData->killNow = 0;
+
+    IDirectSoundBuffer_Release(pData->DSsbuffer);
+    pData->DSsbuffer = NULL;
+    if (pData->DSpbuffer)
+        IDirectSoundBuffer_Release(pData->DSpbuffer);
+    pData->DSpbuffer = NULL;
+}
+
+
+static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+    (void)pDevice;
+    (void)deviceName;
+    return ALC_FALSE;
+}
+
+static void DSoundCloseCapture(ALCdevice *pDevice)
+{
+    (void)pDevice;
+}
+
+static void DSoundStartCapture(ALCdevice *pDevice)
+{
+    (void)pDevice;
+}
+
+static void DSoundStopCapture(ALCdevice *pDevice)
+{
+    (void)pDevice;
+}
+
+static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+    (void)pDevice;
+    (void)pBuffer;
+    (void)lSamples;
+}
+
+static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
+{
+    (void)pDevice;
+    return 0;
+}
+
+
+BackendFuncs DSoundFuncs = {
+    DSoundOpenPlayback,
+    DSoundClosePlayback,
+    DSoundResetPlayback,
+    DSoundStopPlayback,
+    DSoundOpenCapture,
+    DSoundCloseCapture,
+    DSoundStartCapture,
+    DSoundStopCapture,
+    DSoundCaptureSamples,
+    DSoundAvailableSamples
+};
+
+
+void alcDSoundInit(BackendFuncs *FuncList)
+{
+    *FuncList = DSoundFuncs;
+}
+
+void alcDSoundDeinit(void)
+{
+    ALuint i;
+
+    for(i = 0;i < NumDevices;++i)
+        free(DeviceList[i].name);
+    free(DeviceList);
+    DeviceList = NULL;
+    NumDevices = 0;
+
+    if(ds_handle)
+    {
+#ifdef _WIN32
+        FreeLibrary(ds_handle);
+#endif
+        ds_handle = NULL;
+    }
+}
+
+void alcDSoundProbe(int type)
+{
+    if(!DSoundLoad()) return;
+
+    if(type == DEVICE_PROBE)
+        AppendDeviceList(dsDevice);
+    else if(type == ALL_DEVICE_PROBE)
+    {
+        HRESULT hr;
+        ALuint i;
+
+        for(i = 0;i < NumDevices;++i)
+            free(DeviceList[i].name);
+        free(DeviceList);
+        DeviceList = NULL;
+        NumDevices = 0;
+
+        hr = pDirectSoundEnumerateA(DSoundEnumDevices, NULL);
+        if(FAILED(hr))
+            AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
+        else
+        {
+            for(i = 0;i < NumDevices;i++)
+                AppendAllDeviceList(DeviceList[i].name);
+        }
+    }
+}
diff --git a/Alc/mixer.c b/Alc/mixer.c
new file mode 100644 (file)
index 0000000..3a92c85
--- /dev/null
@@ -0,0 +1,1420 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alListener.h"
+#include "alAuxEffectSlot.h"
+#include "alu.h"
+#include "bs2b.h"
+
+
+static __inline ALdouble point32(const ALfloat *vals, ALint step, ALint frac)
+{ return vals[0]; (void)step; (void)frac; }
+static __inline ALdouble lerp32(const ALfloat *vals, ALint step, ALint frac)
+{ return lerp(vals[0], vals[step], frac * (1.0/FRACTIONONE)); }
+static __inline ALdouble cubic32(const ALfloat *vals, ALint step, ALint frac)
+{ return cubic(vals[-step], vals[0], vals[step], vals[step+step],
+               frac * (1.0/FRACTIONONE)); }
+
+static __inline ALdouble point16(const ALshort *vals, ALint step, ALint frac)
+{ return vals[0] * (1.0/32767.0); (void)step; (void)frac; }
+static __inline ALdouble lerp16(const ALshort *vals, ALint step, ALint frac)
+{ return lerp(vals[0], vals[step], frac * (1.0/FRACTIONONE)) * (1.0/32767.0); }
+static __inline ALdouble cubic16(const ALshort *vals, ALint step, ALint frac)
+{ return cubic(vals[-step], vals[0], vals[step], vals[step+step],
+               frac * (1.0/FRACTIONONE)) * (1.0/32767.0); }
+
+static __inline ALdouble point8(const ALubyte *vals, ALint step, ALint frac)
+{ return (vals[0]-128.0) * (1.0/127.0); (void)step; (void)frac; }
+static __inline ALdouble lerp8(const ALubyte *vals, ALint step, ALint frac)
+{ return (lerp(vals[0], vals[step],
+               frac * (1.0/FRACTIONONE))-128.0) * (1.0/127.0); }
+static __inline ALdouble cubic8(const ALubyte *vals, ALint step, ALint frac)
+{ return (cubic(vals[-step], vals[0], vals[step], vals[step+step],
+                frac * (1.0/FRACTIONONE))-128.0) * (1.0/127.0); }
+
+//#define MEASURE_OPENAL_MIXING_PERFORMANCE
+#ifdef MEASURE_OPENAL_MIXING_PERFORMANCE
+
+#include <sys/time.h>
+
+unsigned long int OpenALGetSysElapsedTime(void)
+{
+       static struct timeval init_time = { 0 , 0 };
+       static int bFirst = 0;
+       struct timeval current_time;
+
+       if ( bFirst == 0 )
+       {
+               bFirst = 1;
+               gettimeofday(&init_time, NULL);
+       }
+       
+       gettimeofday(&current_time, NULL);
+       return  ((current_time.tv_sec * 1000000 + current_time.tv_usec) - (init_time.tv_sec * 1000000 + init_time.tv_usec));///1000;    
+}
+
+
+#define OPENAL_PERFORMANCE_LOG(msg...) \
+do{\
+       printf("\n[%s %s %d %lu] ", __FILE__, __func__, __LINE__,OpenALGetSysElapsedTime());\
+       printf(msg);\
+}while(0)
+
+#define OPENAL_PERFORMANCE_LOG_CNT_START(count, msg...)\
+static unsigned int counter = count;\
+static unsigned int counter_at_start = count;\
+static unsigned long int time = 0;\
+static unsigned int fail_cases = 0;\
+unsigned long int time_start = 0;\
+unsigned long int time_stop = 0;\
+time_start = OpenALGetSysElapsedTime()
+
+
+#define OPENAL_PERFORMANCE_LOG_CNT_FAIL(msg...)\
+time_stop = OpenALGetSysElapsedTime();\
+counter--;\
+time += time_stop-time_start;\
+fail_cases++;\
+if (counter == 0)\
+{\
+       printf("\n[%s %d %lu] time = %lu count = %u fail=%u ", __func__, __LINE__,OpenALGetSysElapsedTime()/1000,time/1000, counter_at_start, fail_cases);\
+       printf(msg);\
+       counter = counter_at_start;\
+       time = 0;\
+       fail_cases = 0;\
+}
+
+#define OPENAL_PERFORMANCE_LOG_CNT_STOP(msg...)\
+time_stop = OpenALGetSysElapsedTime();\
+counter--;\
+time += time_stop-time_start;\
+if (counter == 0)\
+{\
+       /*printf("\n[%s %d %lu] time = %lu count = %u fail=%u ",  __func__, __LINE__,OpenALGetSysElapsedTime()/1000,time/1000, counter_at_start, fail_cases);*/\
+       printf("\n[%d %lu] time = %lu count = %u fail=%u ", __LINE__,OpenALGetSysElapsedTime()/1000,time/1000, counter_at_start, fail_cases);\
+       printf(msg);\
+       counter = counter_at_start;\
+       time = 0;\
+       fail_cases = 0;\
+}
+#else
+#define OPENAL_PERFORMANCE_LOG(msg...)
+#define OPENAL_PERFORMANCE_LOG_CNT_START(count, msg...)
+#define OPENAL_PERFORMANCE_LOG_CNT_FAIL(msg...)
+#define OPENAL_PERFORMANCE_LOG_CNT_STOP(msg...)
+#endif
+
+//#define CODE_REARRANGE_APPROACH
+#if defined(ARM_ARCH)
+//#define NEON_ASSEMBLY_APPROACH
+//#define TEST_NEON
+#elif defined(I386_ARCH)
+#endif
+
+#if (defined(CODE_REARRANGE_APPROACH) && defined(NEON_ASSEMBLY_APPROACH))
+#error "YOU CANNOT DEFINE BOTH FLAGS CODE_REARRANGE_APPROACH and NEON_ASSEMBLY_APPROACH. ENABLE ONE OR NONE"
+#endif
+
+#if defined NEON_ASSEMBLY_APPROACH
+#define DECL_TEMPLATE(T, sampler)                                             \
+static void Mix_##T##_1_##sampler(ALsource *Source, ALCdevice *Device,        \
+  const T *data, ALuint *DataPosInt, ALuint *DataPosFrac,                     \
+  ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)                       \
+{                                                                             \
+       OPENAL_PERFORMANCE_LOG_CNT_START(100);\
+       static ALint cumm_BufferSize = 0;\
+       static ALint cumm_SamplesToDo = 0;\
+       cumm_SamplesToDo+=SamplesToDo;\
+       cumm_BufferSize+=BufferSize;\
+       \
+    ALfloat (*DryBuffer)[MAXCHANNELS];                                        \
+    ALfloat *ClickRemoval, *PendingClicks;                                    \
+    ALuint pos, frac;                                                         \
+    ALfloat DrySend[MAXCHANNELS];                                             \
+    FILTER *DryFilter;                                                        \
+    ALuint BufferIdx;                                                         \
+    ALuint increment;                                                         \
+    ALuint out, c;                                                            \
+    ALfloat value;                                                            \
+       ALfloat* DryBufferIn;     \
+                                                                              \
+    increment = Source->Params.Step;                                          \
+                                                                              \
+    DryBuffer = Device->DryBuffer;                                            \
+    ClickRemoval = Device->ClickRemoval;                                      \
+    PendingClicks = Device->PendingClicks;                                    \
+    DryFilter = &Source->Params.iirFilter;                                    \
+    for(c = 0;c < MAXCHANNELS;c++)                                            \
+        DrySend[c] = Source->Params.DryGains[0][c];                           \
+                                                                              \
+    pos = 0;                                                                  \
+    frac = *DataPosFrac;                                                      \
+                                                                              \
+    if(OutPos == 0)                                                           \
+    {                                                                         \
+        value = sampler(data+pos, 1, frac);                                   \
+                                                                              \
+        value = lpFilter4PC(DryFilter, 0, value);                             \
+        for(c = 0;c < MAXCHANNELS;c++)                                        \
+            ClickRemoval[c] -= value*DrySend[c];                              \
+    }                                                                         \
+    for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                     \
+    {                                                                         \
+               DryBufferIn=DryBuffer[OutPos];\
+        /* First order interpolator */                                        \
+        value = sampler(data+pos, 1, frac);                                   \
+                                                                              \
+        /* Direct path final mix buffer and panning */                        \
+        value = lpFilter4P(DryFilter, 0, value);                              \
+       /* for(c = 0;c < MAXCHANNELS;c++)             */                           \
+       /*     DryBuffer[OutPos][c] += value*DrySend[c];  */                       \
+                                  __asm__ volatile (\
+                          "mov r0,#-32 \n\t"\
+                          "vld1.32   {d0,d1,d2,d3}, [%0]!                         \n\t"\
+                          "vld1.32   {d8,d9,d10,d11}, [%2]!                       \n\t"\
+                          "vld1.32 d4,[%0]                                                        \n\t"\
+                          "vld1.32 d5,[%2],r0                                                     \n\t"\
+                          "vdup.f32  q6, %1                                                       \n\t"\
+                          "vmla.f32    q0, q4, q6                                                         \n\t"\
+                          "vmla.f32    q1, q5, q6                                                         \n\t"\
+                          "vmla.f32    s8, s10, s24                                               \n\t"\
+                          "vst1.32    {d4}, [%0],r0                               \n\t"\
+                          "vst1.32    {d0,d1,d2,d3}, [%0]                                         \n\t"\
+                                 ::"r"(DryBufferIn),"r"(value), "r"(DrySend):"r0", "q0", "q1", "q2", "q3", "q4", "q5", "q6");\
+                                                                              \
+        frac += increment;                                                    \
+        pos  += frac>>FRACTIONBITS;                                           \
+        frac &= FRACTIONMASK;                                                 \
+        OutPos++;                                                             \
+    }                                                                         \
+    if(OutPos == SamplesToDo)                                                 \
+    {                                                                         \
+        value = sampler(data+pos, 1, frac);                                   \
+                                                                              \
+        value = lpFilter4PC(DryFilter, 0, value);                             \
+        for(c = 0;c < MAXCHANNELS;c++)                                        \
+            PendingClicks[c] += value*DrySend[c];                             \
+    }                                                                         \
+                                                                              \
+    for(out = 0;out < Device->NumAuxSends;out++)                              \
+    {                                                                         \
+        ALfloat  WetSend;                                                     \
+        ALfloat *WetBuffer;                                                   \
+        ALfloat *WetClickRemoval;                                             \
+        ALfloat *WetPendingClicks;                                            \
+        FILTER  *WetFilter;                                                   \
+                                                                              \
+        if(!Source->Send[out].Slot ||                                         \
+           Source->Send[out].Slot->effect.type == AL_EFFECT_NULL)             \
+            continue;                                                         \
+                                                                              \
+        WetBuffer = Source->Send[out].Slot->WetBuffer;                        \
+        WetClickRemoval = Source->Send[out].Slot->ClickRemoval;               \
+        WetPendingClicks = Source->Send[out].Slot->PendingClicks;             \
+        WetFilter = &Source->Params.Send[out].iirFilter;                      \
+        WetSend = Source->Params.Send[out].WetGain;                           \
+                                                                              \
+        pos = 0;                                                              \
+        frac = *DataPosFrac;                                                  \
+        OutPos -= BufferSize;                                                 \
+                                                                              \
+        if(OutPos == 0)                                                       \
+        {                                                                     \
+            value = sampler(data+pos, 1, frac);                               \
+                                                                              \
+            value = lpFilter2PC(WetFilter, 0, value);                         \
+            WetClickRemoval[0] -= value*WetSend;                              \
+        }                                                                     \
+        for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                 \
+        {                                                                     \
+            /* First order interpolator */                                    \
+            value = sampler(data+pos, 1, frac);                               \
+                                                                              \
+            /* Room path final mix buffer and panning */                      \
+            value = lpFilter2P(WetFilter, 0, value);                          \
+            WetBuffer[OutPos] += value*WetSend;                               \
+                                                                              \
+            frac += increment;                                                \
+            pos  += frac>>FRACTIONBITS;                                       \
+            frac &= FRACTIONMASK;                                             \
+            OutPos++;                                                         \
+        }                                                                     \
+        if(OutPos == SamplesToDo)                                             \
+        {                                                                     \
+            value = sampler(data+pos, 1, frac);                               \
+                                                                              \
+            value = lpFilter2PC(WetFilter, 0, value);                         \
+            WetPendingClicks[0] += value*WetSend;                             \
+        }                                                                     \
+    }                                                                         \
+    *DataPosInt += pos;                                                       \
+    *DataPosFrac = frac;                                                      \
+                       OPENAL_PERFORMANCE_LOG_CNT_STOP("Neon Chan=1 T_SamplesToDo=%d", cumm_SamplesToDo);\
+}
+#else
+#define DECL_TEMPLATE(T, sampler)                                             \
+static void Mix_##T##_1_##sampler(ALsource *Source, ALCdevice *Device,        \
+  const T *data, ALuint *DataPosInt, ALuint *DataPosFrac,                     \
+  ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)                       \
+{                                                                             \
+       OPENAL_PERFORMANCE_LOG_CNT_START(100);\
+       static ALint cumm_BufferSize = 0;\
+       static ALint cumm_SamplesToDo = 0;\
+       cumm_SamplesToDo+=SamplesToDo;\
+       cumm_BufferSize+=BufferSize;\
+       \
+    ALfloat (*DryBuffer)[MAXCHANNELS];                                        \
+    ALfloat *ClickRemoval, *PendingClicks;                                    \
+    ALuint pos, frac;                                                         \
+    ALfloat DrySend[MAXCHANNELS];                                             \
+    FILTER *DryFilter;                                                        \
+    ALuint BufferIdx;                                                         \
+    ALuint increment;                                                         \
+    ALuint out, c;                                                            \
+    ALfloat value;                                                            \
+                                                                              \
+    increment = Source->Params.Step;                                          \
+                                                                              \
+    DryBuffer = Device->DryBuffer;                                            \
+    ClickRemoval = Device->ClickRemoval;                                      \
+    PendingClicks = Device->PendingClicks;                                    \
+    DryFilter = &Source->Params.iirFilter;                                    \
+    for(c = 0;c < MAXCHANNELS;c++)                                            \
+        DrySend[c] = Source->Params.DryGains[0][c];                           \
+                                                                              \
+    pos = 0;                                                                  \
+    frac = *DataPosFrac;                                                      \
+                                                                              \
+    if(OutPos == 0)                                                           \
+    {                                                                         \
+        value = sampler(data+pos, 1, frac);                                   \
+                                                                              \
+        value = lpFilter4PC(DryFilter, 0, value);                             \
+        for(c = 0;c < MAXCHANNELS;c++)                                        \
+            ClickRemoval[c] -= value*DrySend[c];                              \
+    }                                                                         \
+    for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                     \
+    {                                                                         \
+        /* First order interpolator */                                        \
+        value = sampler(data+pos, 1, frac);                                   \
+                                                                              \
+        /* Direct path final mix buffer and panning */                        \
+        value = lpFilter4P(DryFilter, 0, value);                              \
+        for(c = 0;c < MAXCHANNELS;c++)                                        \
+            DryBuffer[OutPos][c] += value*DrySend[c];                         \
+                                                                              \
+        frac += increment;                                                    \
+        pos  += frac>>FRACTIONBITS;                                           \
+        frac &= FRACTIONMASK;                                                 \
+        OutPos++;                                                             \
+    }                                                                         \
+    if(OutPos == SamplesToDo)                                                 \
+    {                                                                         \
+        value = sampler(data+pos, 1, frac);                                   \
+                                                                              \
+        value = lpFilter4PC(DryFilter, 0, value);                             \
+        for(c = 0;c < MAXCHANNELS;c++)                                        \
+            PendingClicks[c] += value*DrySend[c];                             \
+    }                                                                         \
+                                                                              \
+    for(out = 0;out < Device->NumAuxSends;out++)                              \
+    {                                                                         \
+        ALfloat  WetSend;                                                     \
+        ALfloat *WetBuffer;                                                   \
+        ALfloat *WetClickRemoval;                                             \
+        ALfloat *WetPendingClicks;                                            \
+        FILTER  *WetFilter;                                                   \
+                                                                              \
+        if(!Source->Send[out].Slot ||                                         \
+           Source->Send[out].Slot->effect.type == AL_EFFECT_NULL)             \
+            continue;                                                         \
+                                                                              \
+        WetBuffer = Source->Send[out].Slot->WetBuffer;                        \
+        WetClickRemoval = Source->Send[out].Slot->ClickRemoval;               \
+        WetPendingClicks = Source->Send[out].Slot->PendingClicks;             \
+        WetFilter = &Source->Params.Send[out].iirFilter;                      \
+        WetSend = Source->Params.Send[out].WetGain;                           \
+                                                                              \
+        pos = 0;                                                              \
+        frac = *DataPosFrac;                                                  \
+        OutPos -= BufferSize;                                                 \
+                                                                              \
+        if(OutPos == 0)                                                       \
+        {                                                                     \
+            value = sampler(data+pos, 1, frac);                               \
+                                                                              \
+            value = lpFilter2PC(WetFilter, 0, value);                         \
+            WetClickRemoval[0] -= value*WetSend;                              \
+        }                                                                     \
+        for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                 \
+        {                                                                     \
+            /* First order interpolator */                                    \
+            value = sampler(data+pos, 1, frac);                               \
+                                                                              \
+            /* Room path final mix buffer and panning */                      \
+            value = lpFilter2P(WetFilter, 0, value);                          \
+            WetBuffer[OutPos] += value*WetSend;                               \
+                                                                              \
+            frac += increment;                                                \
+            pos  += frac>>FRACTIONBITS;                                       \
+            frac &= FRACTIONMASK;                                             \
+            OutPos++;                                                         \
+        }                                                                     \
+        if(OutPos == SamplesToDo)                                             \
+        {                                                                     \
+            value = sampler(data+pos, 1, frac);                               \
+                                                                              \
+            value = lpFilter2PC(WetFilter, 0, value);                         \
+            WetPendingClicks[0] += value*WetSend;                             \
+        }                                                                     \
+    }                                                                         \
+    *DataPosInt += pos;                                                       \
+    *DataPosFrac = frac;                                                      \
+                       OPENAL_PERFORMANCE_LOG_CNT_STOP("Orig Chan=1 T_SamplesToDo=%d", cumm_SamplesToDo);\
+}
+#endif
+
+DECL_TEMPLATE(ALfloat, point32)
+DECL_TEMPLATE(ALfloat, lerp32)
+DECL_TEMPLATE(ALfloat, cubic32)
+
+DECL_TEMPLATE(ALshort, point16)
+DECL_TEMPLATE(ALshort, lerp16)
+DECL_TEMPLATE(ALshort, cubic16)
+
+DECL_TEMPLATE(ALubyte, point8)
+DECL_TEMPLATE(ALubyte, lerp8)
+DECL_TEMPLATE(ALubyte, cubic8)
+
+#undef DECL_TEMPLATE
+
+
+
+#define DECL_TEMPLATE(T, chnct, sampler)                                      \
+static void Mix_##T##_##chnct##_##sampler(ALsource *Source, ALCdevice *Device,\
+  const T *data, ALuint *DataPosInt, ALuint *DataPosFrac,                     \
+  ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)                       \
+{                                                                             \
+       OPENAL_PERFORMANCE_LOG_CNT_START(100);\
+       static ALint cumm_BufferSize = 0;\
+       static ALint cumm_SamplesToDo = 0;\
+       cumm_SamplesToDo+=SamplesToDo;\
+       cumm_BufferSize+=BufferSize;\
+       \
+    const ALuint Channels = chnct;                                            \
+    const ALfloat scaler = 1.0f/chnct;                                        \
+    ALfloat (*DryBuffer)[MAXCHANNELS];                                        \
+    ALfloat *ClickRemoval, *PendingClicks;                                    \
+    ALuint pos, frac;                                                         \
+    ALfloat DrySend[chnct][MAXCHANNELS];                                      \
+    FILTER *DryFilter;                                                        \
+    ALuint BufferIdx;                                                         \
+    ALuint increment;                                                         \
+    ALuint i, out, c;                                                         \
+    ALfloat value;                                                            \
+                                                                              \
+    increment = Source->Params.Step;                                          \
+                                                                              \
+    DryBuffer = Device->DryBuffer;                                            \
+    ClickRemoval = Device->ClickRemoval;                                      \
+    PendingClicks = Device->PendingClicks;                                    \
+    DryFilter = &Source->Params.iirFilter;                                    \
+    for(i = 0;i < Channels;i++)                                               \
+    {                                                                         \
+        for(c = 0;c < MAXCHANNELS;c++)                                        \
+            DrySend[i][c] = Source->Params.DryGains[i][c];                    \
+    }                                                                         \
+                                                                              \
+    pos = 0;                                                                  \
+    frac = *DataPosFrac;                                                      \
+                                                                              \
+    if(OutPos == 0)                                                           \
+    {                                                                         \
+        for(i = 0;i < Channels;i++)                                           \
+        {                                                                     \
+            value = sampler(data + pos*Channels + i, Channels, frac);         \
+                                                                              \
+            value = lpFilter2PC(DryFilter, i*2, value);                       \
+            for(c = 0;c < MAXCHANNELS;c++)                                    \
+                ClickRemoval[c] -= value*DrySend[i][c];                       \
+        }                                                                     \
+    }                                                                         \
+    for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                     \
+    {                                                                         \
+        for(i = 0;i < Channels;i++)                                           \
+        {                                                                     \
+            value = sampler(data + pos*Channels + i, Channels, frac);         \
+                                                                              \
+            value = lpFilter2P(DryFilter, i*2, value);                        \
+            for(c = 0;c < MAXCHANNELS;c++)                                    \
+                DryBuffer[OutPos][c] += value*DrySend[i][c];                  \
+        }                                                                     \
+                                                                              \
+        frac += increment;                                                    \
+        pos  += frac>>FRACTIONBITS;                                           \
+        frac &= FRACTIONMASK;                                                 \
+        OutPos++;                                                             \
+    }                                                                         \
+    if(OutPos == SamplesToDo)                                                 \
+    {                                                                         \
+        for(i = 0;i < Channels;i++)                                           \
+        {                                                                     \
+            value = sampler(data + pos*Channels + i, Channels, frac);         \
+                                                                              \
+            value = lpFilter2PC(DryFilter, i*2, value);                       \
+            for(c = 0;c < MAXCHANNELS;c++)                                    \
+                PendingClicks[c] += value*DrySend[i][c];                      \
+        }                                                                     \
+    }                                                                         \
+                                                                              \
+    for(out = 0;out < Device->NumAuxSends;out++)                              \
+    {                                                                         \
+        ALfloat  WetSend;                                                     \
+        ALfloat *WetBuffer;                                                   \
+        ALfloat *WetClickRemoval;                                             \
+        ALfloat *WetPendingClicks;                                            \
+        FILTER  *WetFilter;                                                   \
+                                                                              \
+        if(!Source->Send[out].Slot ||                                         \
+           Source->Send[out].Slot->effect.type == AL_EFFECT_NULL)             \
+            continue;                                                         \
+                                                                              \
+        WetBuffer = Source->Send[out].Slot->WetBuffer;                        \
+        WetClickRemoval = Source->Send[out].Slot->ClickRemoval;               \
+        WetPendingClicks = Source->Send[out].Slot->PendingClicks;             \
+        WetFilter = &Source->Params.Send[out].iirFilter;                      \
+        WetSend = Source->Params.Send[out].WetGain;                           \
+                                                                              \
+        pos = 0;                                                              \
+        frac = *DataPosFrac;                                                  \
+        OutPos -= BufferSize;                                                 \
+                                                                              \
+        if(OutPos == 0)                                                       \
+        {                                                                     \
+            for(i = 0;i < Channels;i++)                                       \
+            {                                                                 \
+                value = sampler(data + pos*Channels + i, Channels, frac);     \
+                                                                              \
+                value = lpFilter1PC(WetFilter, i, value);                     \
+                WetClickRemoval[0] -= value*WetSend * scaler;                 \
+            }                                                                 \
+        }                                                                     \
+        for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                 \
+        {                                                                     \
+            for(i = 0;i < Channels;i++)                                       \
+            {                                                                 \
+                value = sampler(data + pos*Channels + i, Channels, frac);     \
+                                                                              \
+                value = lpFilter1P(WetFilter, i, value);                      \
+                WetBuffer[OutPos] += value*WetSend * scaler;                  \
+            }                                                                 \
+                                                                              \
+            frac += increment;                                                \
+            pos  += frac>>FRACTIONBITS;                                       \
+            frac &= FRACTIONMASK;                                             \
+            OutPos++;                                                         \
+        }                                                                     \
+        if(OutPos == SamplesToDo)                                             \
+        {                                                                     \
+            for(i = 0;i < Channels;i++)                                       \
+            {                                                                 \
+                value = sampler(data + pos*Channels + i, Channels, frac);     \
+                                                                              \
+                value = lpFilter1PC(WetFilter, i, value);                     \
+                WetPendingClicks[0] += value*WetSend * scaler;                \
+            }                                                                 \
+        }                                                                     \
+    }                                                                         \
+    *DataPosInt += pos;                                                       \
+    *DataPosFrac = frac;                                                      \
+       OPENAL_PERFORMANCE_LOG_CNT_STOP("Orig T_SamplesToDo=%d ", cumm_SamplesToDo);\
+}
+
+DECL_TEMPLATE(ALfloat, 2, point32)
+DECL_TEMPLATE(ALfloat, 2, lerp32)
+DECL_TEMPLATE(ALfloat, 2, cubic32)
+
+
+#if defined (NEON_ASSEMBLY_APPROACH)
+static void Mix_ALshort_2_point16(ALsource *Source, ALCdevice *Device,
+  const ALshort *data, ALuint *DataPosInt, ALuint *DataPosFrac,                     
+  ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)                       
+{                                                                             
+       OPENAL_PERFORMANCE_LOG_CNT_START(100);
+       static ALint cumm_BufferSize = 0;
+       static ALint cumm_SamplesToDo = 0;
+       cumm_SamplesToDo+=SamplesToDo;
+       cumm_BufferSize+=BufferSize;
+#define chnct 2
+#define sampler point16
+       
+    const ALuint Channels = chnct;                                            
+    const ALfloat scaler = 1.0f/chnct;                                        
+    ALfloat (*DryBuffer)[MAXCHANNELS];                                        
+    ALfloat *ClickRemoval, *PendingClicks;                                    
+    ALuint pos, frac;                                                         
+    ALfloat DrySend[chnct][MAXCHANNELS];                                      
+    FILTER *DryFilter;                                                        
+    ALuint BufferIdx;                                                         
+    ALuint increment;                                                         
+    ALuint i, out, c;                                                         
+    ALfloat value;                                                            
+    ALfloat dryValue0;                                                            
+    ALfloat dryValue1;                                                            
+        ALfloat* DryBufferIn;     
+        ALfloat* DrySendIn0;
+        ALfloat* DrySendIn1;
+    increment = Source->Params.Step;                                          
+       DrySendIn0=DrySend[0];
+       DrySendIn1=DrySend[1];
+                                                                              
+    DryBuffer = Device->DryBuffer;                                            
+    ClickRemoval = Device->ClickRemoval;                                      
+    PendingClicks = Device->PendingClicks;                                    
+    DryFilter = &Source->Params.iirFilter;                                    
+//             DrySendIn0=DrySend[0];
+//             DrySendIn1=DrySend[1];
+               
+    for(i = 0;i < Channels;i++)                                               
+    {                                                                         
+        for(c = 0;c < MAXCHANNELS;c++)                                        
+            DrySend[i][c] = Source->Params.DryGains[i][c];                    
+    }                                                                         
+                                                                              
+    pos = 0;                                                                  
+    frac = *DataPosFrac;                                                      
+                                                                              
+    if(OutPos == 0)                                                           
+    {                                                                         
+      //  for(i = 0;i < Channels;i++)                                           
+        //{                                                                     
+            dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);         
+            dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);         
+                                                                              
+            dryValue0 = lpFilter2PC(DryFilter, 0*2, dryValue0);                       
+            dryValue1 = lpFilter2PC(DryFilter, 1*2, dryValue1);                       
+            for(c = 0;c < MAXCHANNELS;c++)                                    
+           {     
+               ClickRemoval[c] -= dryValue0*DrySend[0][c];                       
+               ClickRemoval[c] -= dryValue1*DrySend[1][c];     
+            }
+       // }                                                                     
+    }                                                                         
+    for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                     
+    {                                                                         
+        //for(i = 0;i < Channels;i++)                                           
+       // {                                                                     
+               DryBufferIn=DryBuffer[OutPos];
+            dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);         
+            dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);         
+                                                                              
+            dryValue0 = lpFilter2P(DryFilter, 0*2, dryValue0);                                         
+            dryValue1 = lpFilter2P(DryFilter, 1*2, dryValue1);
+
+#if defined(TEST_NEON)
+                ALfloat TestDryBufferIn[MAXCHANNELS];
+                memcpy(TestDryBufferIn, DryBufferIn,MAXCHANNELS*sizeof(ALfloat) );
+                for(i = 0;i < MAXCHANNELS;i++)                                                                                   
+                {                                                                                                                                        
+                        TestDryBufferIn[i] += dryValue0*DrySend[0][i];                            
+                        TestDryBufferIn[i] += dryValue1*DrySend[1][i];                            
+                }
+#endif          
+                __asm__ volatile (
+                        "mov r0,#-32 \n\t"
+                        "vld1.32       {d0,d1,d2,d3}, [%0]!     \n\t"
+                        "vld1.32       {d12,d13,d14,d15}, [%3]!                                         \n\t"
+                        "vld1.32       {d16,d17,d18,d19}, [%4]!                                         \n\t"
+                        "vld1.32 d4,[%0]                                                                       \n\t"
+                        "vld1.32 d5,[%3],r0                                                                    \n\t"
+                        "vld1.32 d6,[%4],r0                                                                    \n\t"
+                        "vdup.f32      q4, %1                                   \n\t"
+                        "vdup.f32      q5, %2                                   \n\t"
+                        "vmla.f32        q0, q4, q6                                                     \n\t"
+                        "vmla.f32        q0, q5, q8                                                     \n\t"
+                        "vmla.f32        q1, q4, q7                                                     \n\t"
+                        "vmla.f32        q1, q5, q9                                                     \n\t"
+                        "vmla.f32        s8, s16, s10                                                   \n\t"
+                        "vmla.f32        s8, s20, s12                                                   \n\t"
+                        "vst1.32        {d4}, [%0],r0                                   \n\t"
+                        "vst1.32        {d0,d1,d2,d3}, [%0]                                     \n\t"
+                               ::"r"(DryBufferIn),"r"(dryValue0), "r"(dryValue1), "r"(DrySendIn0), "r"(DrySendIn1):"r0", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9");
+                
+#if defined(TEST_NEON)
+                for(i = 0;i < (MAXCHANNELS-1);i++)                                                                               
+                {              
+                       if (DryBufferIn[i] !=TestDryBufferIn[i])
+                               printf("\n%d not same %f %f %f %f %f %f", i,DryBufferIn[i],TestDryBufferIn[i], dryValue0,DrySend[0][i],dryValue1,DrySend[1][i]);
+               }
+#endif          
+
+        frac += increment;                                                    
+        pos  += frac>>FRACTIONBITS;                                           
+        frac &= FRACTIONMASK;                                                 
+        OutPos++;                                                             
+    }                                                                         
+    if(OutPos == SamplesToDo)                                                 
+    {                                                                         
+        //for(i = 0;i < Channels;i++)                                           
+        //{                                                                     
+               dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);             
+               dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);             
+                                                                              
+               dryValue0 = lpFilter2PC(DryFilter, 0*2, dryValue0);                                             
+              dryValue1 = lpFilter2PC(DryFilter, 1*2, dryValue1);                                              
+            for(c = 0;c < MAXCHANNELS;c++)                                    
+            {
+               PendingClicks[c] += dryValue0*DrySend[0][c];                                      
+               PendingClicks[c] += dryValue1*DrySend[1][c];                                      
+            }
+       // }                                                                     
+    }                                                                         
+                                                                              
+    for(out = 0;out < Device->NumAuxSends;out++)                              
+    {                                                                         
+        ALfloat  WetSend;                                                     
+        ALfloat *WetBuffer;                                                   
+        ALfloat *WetClickRemoval;                                             
+        ALfloat *WetPendingClicks;                                            
+        FILTER  *WetFilter;                                                   
+                                                                              
+        if(!Source->Send[out].Slot ||                                        
+           Source->Send[out].Slot->effect.type == AL_EFFECT_NULL)             
+       {
+       /*
+               printf("\nslot=%d type=%d"\
+                       ,Source->Send[out].Slot \
+                       ,Source->Send[out].Slot ? Source->Send[out].Slot->effect.type:0);
+                       */
+               continue;                                                         
+        }
+                                                                              
+       /*OPENAL_PERFORMANCE_LOG_CNT_START(100);*/
+        WetBuffer = Source->Send[out].Slot->WetBuffer;                        
+        WetClickRemoval = Source->Send[out].Slot->ClickRemoval;               
+        WetPendingClicks = Source->Send[out].Slot->PendingClicks;             
+        WetFilter = &Source->Params.Send[out].iirFilter;                      
+        WetSend = Source->Params.Send[out].WetGain;                           
+                                                                              
+        pos = 0;                                                              
+        frac = *DataPosFrac;                                                  
+        OutPos -= BufferSize;                                                 
+                                                                              
+        if(OutPos == 0)                                                       
+        {                                                                     
+            for(i = 0;i < Channels;i++)                                       
+            {                                                                 
+                value = sampler(data + pos*Channels + i, Channels, frac);     
+                                                                              
+                value = lpFilter1PC(WetFilter, i, value);                     
+                WetClickRemoval[0] -= value*WetSend * scaler;                 
+            }                                                                 
+        }                                                                     
+        for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                 
+        {                                                                     
+            for(i = 0;i < Channels;i++)                                       
+            {                                                                 
+                value = sampler(data + pos*Channels + i, Channels, frac);     
+                                                                              
+                value = lpFilter1P(WetFilter, i, value);                      
+                WetBuffer[OutPos] += value*WetSend * scaler;                  
+            }                                                                 
+                                                                              
+            frac += increment;                                                
+            pos  += frac>>FRACTIONBITS;                                       
+            frac &= FRACTIONMASK;                                             
+            OutPos++;                                                         
+        }                                                                     
+        if(OutPos == SamplesToDo)                                             
+        {                                                                     
+            for(i = 0;i < Channels;i++)                                       
+            {                                                                 
+                value = sampler(data + pos*Channels + i, Channels, frac);     
+                                                                              
+                value = lpFilter1PC(WetFilter, i, value);                     
+                WetPendingClicks[0] += value*WetSend * scaler;                
+            }                                                                 
+        }                                                                     
+/*OPENAL_PERFORMANCE_LOG_CNT_STOP("WetBuffer is calculated");*/
+       }                                                                         
+    *DataPosInt += pos;                                                       
+    *DataPosFrac = frac;      
+       #undef chnct
+       #undef sampler
+       OPENAL_PERFORMANCE_LOG_CNT_STOP("App1+Neon T_SamplesToDo=%d ", cumm_SamplesToDo);
+}
+
+#elif defined (CODE_REARRANGE_APPROACH)
+/*static*/ void Mix_ALshort_2_point16(ALsource *Source, ALCdevice *Device,
+  const ALshort *data, ALuint *DataPosInt, ALuint *DataPosFrac,                     
+  ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)                       
+{                                                                             
+       OPENAL_PERFORMANCE_LOG_CNT_START(100);
+       static ALint cumm_BufferSize = 0;
+       static ALint cumm_SamplesToDo = 0;
+       cumm_SamplesToDo+=SamplesToDo;
+       cumm_BufferSize+=BufferSize;
+#define chnct 2
+#define sampler point16
+       
+    const ALuint Channels = chnct;                                            
+    const ALfloat scaler = 1.0f/chnct;                                        
+    ALfloat (*DryBuffer)[MAXCHANNELS];                                        
+    ALfloat *ClickRemoval, *PendingClicks;                                    
+    ALuint pos, frac;                                                         
+    ALfloat DrySend[chnct][MAXCHANNELS];                                      
+    FILTER *DryFilter;                                                        
+    ALuint BufferIdx;                                                         
+    ALuint increment;                                                         
+    ALuint i, out, c;                                                         
+    ALfloat value;                                                            
+    ALfloat dryValue0;                                                            
+    ALfloat dryValue1;                                                            
+    ALfloat wetValue0;                                                            
+    ALfloat wetValue1;                                                            
+                                                                              
+    increment = Source->Params.Step;                                          
+                                                                              
+    DryBuffer = Device->DryBuffer;                                            
+    ClickRemoval = Device->ClickRemoval;                                      
+    PendingClicks = Device->PendingClicks;                                    
+    DryFilter = &Source->Params.iirFilter;                                    
+    for(i = 0;i < Channels;i++)                                               
+    {                                                                         
+        for(c = 0;c < MAXCHANNELS;c++)                                        
+            DrySend[i][c] = Source->Params.DryGains[i][c];                    
+    }                                                                         
+                                                                              
+    pos = 0;                                                                  
+    frac = *DataPosFrac;                                                      
+                                                                              
+    if(OutPos == 0)                                                           
+    {                                                                         
+      //  for(i = 0;i < Channels;i++)                                           
+        //{                                                                     
+            dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);         
+            dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);         
+                                                                              
+            dryValue0 = lpFilter2PC(DryFilter, 0*2, dryValue0);                       
+            dryValue1 = lpFilter2PC(DryFilter, 1*2, dryValue1);                       
+            for(c = 0;c < MAXCHANNELS;c++)                                    
+           {     
+               ClickRemoval[c] -= dryValue0*DrySend[0][c];                       
+               ClickRemoval[c] -= dryValue1*DrySend[1][c];     
+            }
+       // }                                                                     
+    }                                                                         
+    for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                     
+    {                                                                         
+        //for(i = 0;i < Channels;i++)                                           
+       // {                                                                     
+            dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);         
+            dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);         
+                                                                              
+            dryValue0 = lpFilter2P(DryFilter, 0*2, dryValue0);                                         
+            dryValue1 = lpFilter2P(DryFilter, 1*2, dryValue1);                                         
+            for(c = 0;c < MAXCHANNELS;c++)                                    
+            {
+               DryBuffer[OutPos][c] += dryValue0*DrySend[0][c];                  
+               DryBuffer[OutPos][c] += dryValue1*DrySend[1][c];                  
+            }
+       // }                                                                     
+                                                                              
+        frac += increment;                                                    
+        pos  += frac>>FRACTIONBITS;                                           
+        frac &= FRACTIONMASK;                                                 
+        OutPos++;                                                             
+    }                                                                         
+    if(OutPos == SamplesToDo)                                                 
+    {                                                                         
+        //for(i = 0;i < Channels;i++)                                           
+        //{                                                                     
+               dryValue0 = sampler(data + pos*Channels + 0, Channels, frac);             
+               dryValue1 = sampler(data + pos*Channels + 1, Channels, frac);             
+                                                                              
+               dryValue0 = lpFilter2PC(DryFilter, 0*2, dryValue0);                                             
+              dryValue1 = lpFilter2PC(DryFilter, 1*2, dryValue1);                                              
+            for(c = 0;c < MAXCHANNELS;c++)                                    
+            {
+               PendingClicks[c] += dryValue0*DrySend[0][c];                                      
+               PendingClicks[c] += dryValue1*DrySend[1][c];                                      
+            }
+       // }                                                                     
+    }                                                                         
+                                                                              
+    for(out = 0;out < Device->NumAuxSends;out++)                              
+    {                                                                         
+        ALfloat  WetSend;                                                     
+        ALfloat *WetBuffer;                                                   
+        ALfloat *WetClickRemoval;                                             
+        ALfloat *WetPendingClicks;                                            
+        FILTER  *WetFilter;                                                   
+                                                                              
+        if(!Source->Send[out].Slot ||                                        
+           Source->Send[out].Slot->effect.type == AL_EFFECT_NULL)             
+            continue;                                                         
+                                                                              
+       /*OPENAL_PERFORMANCE_LOG_CNT_START(100);*/
+        WetBuffer = Source->Send[out].Slot->WetBuffer;                        
+        WetClickRemoval = Source->Send[out].Slot->ClickRemoval;               
+        WetPendingClicks = Source->Send[out].Slot->PendingClicks;             
+        WetFilter = &Source->Params.Send[out].iirFilter;                      
+        WetSend = Source->Params.Send[out].WetGain;                           
+                                                                              
+        pos = 0;                                                              
+        frac = *DataPosFrac;                                                  
+        OutPos -= BufferSize;                                                 
+                                                                              
+        if(OutPos == 0)                                                       
+        {                                                                     
+            for(i = 0;i < Channels;i++)                                       
+            {                                                                 
+                value = sampler(data + pos*Channels + i, Channels, frac);     
+                                                                              
+                value = lpFilter1PC(WetFilter, i, value);                     
+                WetClickRemoval[0] -= value*WetSend * scaler;                 
+            }                                                                 
+        }                                                                     
+        for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++)                 
+        {                                                                     
+            for(i = 0;i < Channels;i++)                                       
+            {                                                                 
+                value = sampler(data + pos*Channels + i, Channels, frac);     
+                                                                              
+                value = lpFilter1P(WetFilter, i, value);                      
+                WetBuffer[OutPos] += value*WetSend * scaler;                  
+            }                                                                 
+                                                                              
+            frac += increment;                                                
+            pos  += frac>>FRACTIONBITS;                                       
+            frac &= FRACTIONMASK;                                             
+            OutPos++;                                                         
+        }                                                                     
+        if(OutPos == SamplesToDo)                                             
+        {                                                                     
+            for(i = 0;i < Channels;i++)                                       
+            {                                                                 
+                value = sampler(data + pos*Channels + i, Channels, frac);     
+                                                                              
+                value = lpFilter1PC(WetFilter, i, value);                     
+                WetPendingClicks[0] += value*WetSend * scaler;                
+            }                                                                 
+        }                                                                     
+/*OPENAL_PERFORMANCE_LOG_CNT_STOP("WetBuffer is calculated");*/
+       }                                                                         
+    *DataPosInt += pos;                                                       
+    *DataPosFrac = frac;      
+       #undef chnct
+       #undef sampler
+       OPENAL_PERFORMANCE_LOG_CNT_STOP("App1 T_SamplesToDo=%d T_BufferSize=%u NumAuxSends=%u", cumm_SamplesToDo, cumm_BufferSize,Device->NumAuxSends);
+}
+
+#else
+DECL_TEMPLATE(ALshort, 2, point16)
+#endif
+DECL_TEMPLATE(ALshort, 2, lerp16)
+DECL_TEMPLATE(ALshort, 2, cubic16)
+
+DECL_TEMPLATE(ALubyte, 2, point8)
+DECL_TEMPLATE(ALubyte, 2, lerp8)
+DECL_TEMPLATE(ALubyte, 2, cubic8)
+
+
+DECL_TEMPLATE(ALfloat, 4, point32)
+DECL_TEMPLATE(ALfloat, 4, lerp32)
+DECL_TEMPLATE(ALfloat, 4, cubic32)
+
+DECL_TEMPLATE(ALshort, 4, point16)
+DECL_TEMPLATE(ALshort, 4, lerp16)
+DECL_TEMPLATE(ALshort, 4, cubic16)
+
+DECL_TEMPLATE(ALubyte, 4, point8)
+DECL_TEMPLATE(ALubyte, 4, lerp8)
+DECL_TEMPLATE(ALubyte, 4, cubic8)
+
+
+DECL_TEMPLATE(ALfloat, 6, point32)
+DECL_TEMPLATE(ALfloat, 6, lerp32)
+DECL_TEMPLATE(ALfloat, 6, cubic32)
+
+DECL_TEMPLATE(ALshort, 6, point16)
+DECL_TEMPLATE(ALshort, 6, lerp16)
+DECL_TEMPLATE(ALshort, 6, cubic16)
+
+DECL_TEMPLATE(ALubyte, 6, point8)
+DECL_TEMPLATE(ALubyte, 6, lerp8)
+DECL_TEMPLATE(ALubyte, 6, cubic8)
+
+
+DECL_TEMPLATE(ALfloat, 7, point32)
+DECL_TEMPLATE(ALfloat, 7, lerp32)
+DECL_TEMPLATE(ALfloat, 7, cubic32)
+
+DECL_TEMPLATE(ALshort, 7, point16)
+DECL_TEMPLATE(ALshort, 7, lerp16)
+DECL_TEMPLATE(ALshort, 7, cubic16)
+
+DECL_TEMPLATE(ALubyte, 7, point8)
+DECL_TEMPLATE(ALubyte, 7, lerp8)
+DECL_TEMPLATE(ALubyte, 7, cubic8)
+
+
+DECL_TEMPLATE(ALfloat, 8, point32)
+DECL_TEMPLATE(ALfloat, 8, lerp32)
+DECL_TEMPLATE(ALfloat, 8, cubic32)
+
+DECL_TEMPLATE(ALshort, 8, point16)
+DECL_TEMPLATE(ALshort, 8, lerp16)
+DECL_TEMPLATE(ALshort, 8, cubic16)
+
+DECL_TEMPLATE(ALubyte, 8, point8)
+DECL_TEMPLATE(ALubyte, 8, lerp8)
+DECL_TEMPLATE(ALubyte, 8, cubic8)
+
+#undef DECL_TEMPLATE
+
+
+#define DECL_TEMPLATE(T, sampler)                                             \
+static void Mix_##T##_##sampler(ALsource *Source, ALCdevice *Device,          \
+  enum FmtChannels FmtChannels,                                               \
+  const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac,                \
+  ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)                       \
+{                                                                             \
+    switch(FmtChannels)                                                       \
+    {                                                                         \
+    case FmtMono:                                                             \
+        Mix_##T##_1_##sampler(Source, Device, Data, DataPosInt, DataPosFrac,  \
+                              OutPos, SamplesToDo, BufferSize);               \
+        break;                                                                \
+    case FmtStereo:                                                           \
+    case FmtRear:                                                             \
+        Mix_##T##_2_##sampler(Source, Device, Data, DataPosInt, DataPosFrac,  \
+                              OutPos, SamplesToDo, BufferSize);               \
+        break;                                                                \
+    case FmtQuad:                                                             \
+        Mix_##T##_4_##sampler(Source, Device, Data, DataPosInt, DataPosFrac,  \
+                              OutPos, SamplesToDo, BufferSize);               \
+        break;                                                                \
+    case FmtX51:                                                              \
+        Mix_##T##_6_##sampler(Source, Device, Data, DataPosInt, DataPosFrac,  \
+                              OutPos, SamplesToDo, BufferSize);               \
+        break;                                                                \
+    case FmtX61:                                                              \
+        Mix_##T##_7_##sampler(Source, Device, Data, DataPosInt, DataPosFrac,  \
+                              OutPos, SamplesToDo, BufferSize);               \
+        break;                                                                \
+    case FmtX71:                                                              \
+        Mix_##T##_8_##sampler(Source, Device, Data, DataPosInt, DataPosFrac,  \
+                              OutPos, SamplesToDo, BufferSize);               \
+        break;                                                                \
+    }                                                                         \
+}
+
+DECL_TEMPLATE(ALfloat, point32)
+DECL_TEMPLATE(ALfloat, lerp32)
+DECL_TEMPLATE(ALfloat, cubic32)
+
+DECL_TEMPLATE(ALshort, point16)
+DECL_TEMPLATE(ALshort, lerp16)
+DECL_TEMPLATE(ALshort, cubic16)
+
+DECL_TEMPLATE(ALubyte, point8)
+DECL_TEMPLATE(ALubyte, lerp8)
+DECL_TEMPLATE(ALubyte, cubic8)
+
+#undef DECL_TEMPLATE
+
+
+#define DECL_TEMPLATE(sampler)                                                \
+static void Mix_##sampler(ALsource *Source, ALCdevice *Device,                \
+  enum FmtChannels FmtChannels, enum FmtType FmtType,                         \
+  const ALvoid *Data, ALuint *DataPosInt, ALuint *DataPosFrac,                \
+  ALuint OutPos, ALuint SamplesToDo, ALuint BufferSize)                       \
+{                                                                             \
+    switch(FmtType)                                                           \
+    {                                                                         \
+    case FmtUByte:                                                            \
+        Mix_ALubyte_##sampler##8(Source, Device, FmtChannels,                 \
+                                 Data, DataPosInt, DataPosFrac,               \
+                                 OutPos, SamplesToDo, BufferSize);            \
+        break;                                                                \
+                                                                              \
+    case FmtShort:                                                            \
+        Mix_ALshort_##sampler##16(Source, Device, FmtChannels,                \
+                                  Data, DataPosInt, DataPosFrac,              \
+                                  OutPos, SamplesToDo, BufferSize);           \
+        break;                                                                \
+                                                                              \
+    case FmtFloat:                                                            \
+        Mix_ALfloat_##sampler##32(Source, Device, FmtChannels,                \
+                                  Data, DataPosInt, DataPosFrac,              \
+                                  OutPos, SamplesToDo, BufferSize);           \
+        break;                                                                \
+    }                                                                         \
+}
+
+DECL_TEMPLATE(point)
+DECL_TEMPLATE(lerp)
+DECL_TEMPLATE(cubic)
+
+#undef DECL_TEMPLATE
+
+
+ALvoid MixSource(ALsource *Source, ALCdevice *Device, ALuint SamplesToDo)
+{
+    ALbufferlistitem *BufferListItem;
+    ALuint DataPosInt, DataPosFrac;
+    enum FmtChannels FmtChannels;
+    enum FmtType FmtType;
+    ALuint BuffersPlayed;
+    ALboolean Looping;
+    ALuint increment;
+    resampler_t Resampler;
+    ALenum State;
+    ALuint OutPos;
+    ALuint FrameSize;
+    ALint64 DataSize64;
+    ALuint i;
+
+    /* Get source info */
+    State         = Source->state;
+    BuffersPlayed = Source->BuffersPlayed;
+    DataPosInt    = Source->position;
+    DataPosFrac   = Source->position_fraction;
+    Looping       = Source->bLooping;
+    increment     = Source->Params.Step;
+    Resampler     = (increment == FRACTIONONE) ? POINT_RESAMPLER :
+                                                 Source->Resampler;
+
+    /* Get buffer info */
+    FrameSize = 0;
+    FmtChannels = FmtMono;
+    FmtType = FmtUByte;
+    BufferListItem = Source->queue;
+    for(i = 0;i < Source->BuffersInQueue;i++)
+    {
+        const ALbuffer *ALBuffer;
+        if((ALBuffer=BufferListItem->buffer) != NULL)
+        {
+            FmtChannels = ALBuffer->FmtChannels;
+            FmtType = ALBuffer->FmtType;
+            FrameSize = FrameSizeFromFmt(FmtChannels, FmtType);
+            break;
+        }
+        BufferListItem = BufferListItem->next;
+    }
+
+    /* Get current buffer queue item */
+    BufferListItem = Source->queue;
+    for(i = 0;i < BuffersPlayed;i++)
+        BufferListItem = BufferListItem->next;
+
+    OutPos = 0;
+    do {
+        const ALuint BufferPrePadding = ResamplerPrePadding[Resampler];
+        const ALuint BufferPadding = ResamplerPadding[Resampler];
+        ALubyte StackData[STACK_DATA_SIZE];
+        ALubyte *SrcData = StackData;
+        ALuint SrcDataSize = 0;
+        ALuint BufferSize;
+
+        /* Figure out how many buffer bytes will be needed */
+        DataSize64  = SamplesToDo-OutPos+1;
+        DataSize64 *= increment;
+        DataSize64 += DataPosFrac+FRACTIONMASK;
+        DataSize64 >>= FRACTIONBITS;
+        DataSize64 += BufferPadding+BufferPrePadding;
+        DataSize64 *= FrameSize;
+
+        BufferSize = min(DataSize64, STACK_DATA_SIZE);
+        BufferSize -= BufferSize%FrameSize;
+
+        if(Source->lSourceType == AL_STATIC)
+        {
+            const ALbuffer *ALBuffer = Source->Buffer;
+            const ALubyte *Data = ALBuffer->data;
+            ALuint DataSize;
+            ALuint pos;
+
+            /* 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)*FrameSize;
+                else
+                {
+                    DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
+                    DataSize = min(BufferSize, DataSize);
+
+                    memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
+                    SrcDataSize += DataSize;
+                    BufferSize -= DataSize;
+
+                    pos = 0;
+                }
+
+                /* Copy what's left to play in the source buffer, and clear the
+                 * rest of the temp buffer */
+                DataSize = ALBuffer->size - pos;
+                DataSize = min(BufferSize, DataSize);
+
+                memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
+                SrcDataSize += DataSize;
+                BufferSize -= DataSize;
+
+                memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize);
+                SrcDataSize += BufferSize;
+                BufferSize -= BufferSize;
+            }
+            else
+            {
+                ALuint LoopStart = ALBuffer->LoopStart;
+                ALuint LoopEnd   = ALBuffer->LoopEnd;
+
+                if(DataPosInt >= LoopStart)
+                {
+                    pos = DataPosInt-LoopStart;
+                    while(pos < BufferPrePadding)
+                        pos += LoopEnd-LoopStart;
+                    pos -= BufferPrePadding;
+                    pos += LoopStart;
+                    pos *= FrameSize;
+                }
+                else if(DataPosInt >= BufferPrePadding)
+                    pos = (DataPosInt-BufferPrePadding)*FrameSize;
+                else
+                {
+                    DataSize = (BufferPrePadding-DataPosInt)*FrameSize;
+                    DataSize = min(BufferSize, DataSize);
+
+                    memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
+                    SrcDataSize += DataSize;
+                    BufferSize -= DataSize;
+
+                    pos = 0;
+                }
+
+                /* Copy what's left of this loop iteration, then copy repeats
+                 * of the loop section */
+                DataSize = LoopEnd*FrameSize - pos;
+                DataSize = min(BufferSize, DataSize);
+
+                memcpy(&SrcData[SrcDataSize], &Data[pos], DataSize);
+                SrcDataSize += DataSize;
+                BufferSize -= DataSize;
+
+                DataSize = (LoopEnd-LoopStart) * FrameSize;
+                while(BufferSize > 0)
+                {
+                    DataSize = min(BufferSize, DataSize);
+
+                    memcpy(&SrcData[SrcDataSize], &Data[LoopStart*FrameSize], DataSize);
+                    SrcDataSize += DataSize;
+                    BufferSize -= DataSize;
+                }
+            }
+        }
+        else
+        {
+            /* Crawl the buffer queue to fill in the temp buffer */
+            ALbufferlistitem *BufferListIter = BufferListItem;
+            ALuint pos;
+
+            if(DataPosInt >= BufferPrePadding)
+                pos = (DataPosInt-BufferPrePadding)*FrameSize;
+            else
+            {
+                pos = (BufferPrePadding-DataPosInt)*FrameSize;
+                while(pos > 0)
+                {
+                    if(!BufferListIter->prev && !Looping)
+                    {
+                        ALuint DataSize = min(BufferSize, pos);
+
+                        memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, DataSize);
+                        SrcDataSize += DataSize;
+                        BufferSize -= DataSize;
+
+                        pos = 0;
+                        break;
+                    }
+
+                    if(BufferListIter->prev)
+                        BufferListIter = BufferListIter->prev;
+                    else
+                    {
+                        while(BufferListIter->next)
+                            BufferListIter = BufferListIter->next;
+                    }
+
+                    if(BufferListIter->buffer)
+                    {
+                        if((ALuint)BufferListIter->buffer->size > pos)
+                        {
+                            pos = BufferListIter->buffer->size - pos;
+                            break;
+                        }
+                        pos -= BufferListIter->buffer->size;
+                    }
+                }
+            }
+
+            while(BufferListIter && BufferSize > 0)
+            {
+                const ALbuffer *ALBuffer;
+                if((ALBuffer=BufferListIter->buffer) != NULL)
+                {
+                    const ALubyte *Data = ALBuffer->data;
+                    ALuint DataSize = ALBuffer->size;
+
+                    /* Skip the data already played */
+                    if(DataSize <= pos)
+                        pos -= DataSize;
+                    else
+                    {
+                        Data += pos;
+                        DataSize -= pos;
+                        pos -= pos;
+
+                        DataSize = min(BufferSize, DataSize);
+                        memcpy(&SrcData[SrcDataSize], Data, DataSize);
+                        SrcDataSize += DataSize;
+                        BufferSize -= DataSize;
+                    }
+                }
+                BufferListIter = BufferListIter->next;
+                if(!BufferListIter && Looping)
+                    BufferListIter = Source->queue;
+                else if(!BufferListIter)
+                {
+                    memset(&SrcData[SrcDataSize], (FmtType==FmtUByte)?0x80:0, BufferSize);
+                    SrcDataSize += BufferSize;
+                    BufferSize -= BufferSize;
+                }
+            }
+        }
+
+        /* Figure out how many samples we can mix. */
+        DataSize64  = SrcDataSize / FrameSize;
+        DataSize64 -= BufferPadding+BufferPrePadding;
+        DataSize64 <<= FRACTIONBITS;
+        DataSize64 -= increment;
+        DataSize64 -= DataPosFrac;
+
+        BufferSize = (ALuint)((DataSize64+(increment-1)) / increment);
+        BufferSize = min(BufferSize, (SamplesToDo-OutPos));
+
+        SrcData += BufferPrePadding*FrameSize;
+        switch(Resampler)
+        {
+            case POINT_RESAMPLER:
+                Mix_point(Source, Device, FmtChannels, FmtType,
+                          SrcData, &DataPosInt, &DataPosFrac,
+                          OutPos, SamplesToDo, BufferSize);
+                break;
+            case LINEAR_RESAMPLER:
+                Mix_lerp(Source, Device, FmtChannels, FmtType,
+                         SrcData, &DataPosInt, &DataPosFrac,
+                         OutPos, SamplesToDo, BufferSize);
+                break;
+            case CUBIC_RESAMPLER:
+                Mix_cubic(Source, Device, FmtChannels, FmtType,
+                          SrcData, &DataPosInt, &DataPosFrac,
+                          OutPos, SamplesToDo, BufferSize);
+                break;
+            case RESAMPLER_MIN:
+            case RESAMPLER_MAX:
+            break;
+        }
+        OutPos += BufferSize;
+
+        /* Handle looping sources */
+        while(1)
+        {
+            const ALbuffer *ALBuffer;
+            ALuint DataSize = 0;
+            ALuint LoopStart = 0;
+            ALuint LoopEnd = 0;
+
+            if((ALBuffer=BufferListItem->buffer) != NULL)
+            {
+                DataSize = ALBuffer->size / FrameSize;
+                LoopStart = ALBuffer->LoopStart;
+                LoopEnd = ALBuffer->LoopEnd;
+                if(LoopEnd > DataPosInt)
+                    break;
+            }
+
+            if(Looping && Source->lSourceType == AL_STATIC)
+            {
+                BufferListItem = Source->queue;
+                DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart;
+                break;
+            }
+
+            if(DataSize > DataPosInt)
+                break;
+
+            if(BufferListItem->next)
+            {
+                BufferListItem = BufferListItem->next;
+                BuffersPlayed++;
+            }
+            else if(Looping)
+            {
+                BufferListItem = Source->queue;
+                BuffersPlayed = 0;
+            }
+            else
+            {
+                State = AL_STOPPED;
+                BufferListItem = Source->queue;
+                BuffersPlayed = Source->BuffersInQueue;
+                DataPosInt = 0;
+                DataPosFrac = 0;
+                break;
+            }
+
+            DataPosInt -= DataSize;
+        }
+    } while(State == AL_PLAYING && OutPos < SamplesToDo);
+
+    /* Update source info */
+    Source->state             = State;
+    Source->BuffersPlayed     = BuffersPlayed;
+    Source->position          = DataPosInt;
+    Source->position_fraction = DataPosFrac;
+    Source->Buffer            = BufferListItem->buffer;
+}
diff --git a/Alc/null.c b/Alc/null.c
new file mode 100644 (file)
index 0000000..15efee1
--- /dev/null
@@ -0,0 +1,182 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2010 by Chris Robinson
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+
+typedef struct {
+    ALvoid *buffer;
+    ALuint size;
+
+    volatile int killNow;
+    ALvoid *thread;
+} null_data;
+
+
+static const ALCchar nullDevice[] = "No Output";
+
+static ALuint NullProc(ALvoid *ptr)
+{
+    ALCdevice *Device = (ALCdevice*)ptr;
+    null_data *data = (null_data*)Device->ExtraData;
+    ALuint now, start;
+    ALuint64 avail, done;
+    const ALuint restTime = (ALuint64)Device->UpdateSize * 1000 /
+                            Device->Frequency / 2;
+
+    done = 0;
+    start = timeGetTime();
+    while(!data->killNow && Device->Connected)
+    {
+        now = timeGetTime();
+
+        avail = (ALuint64)(now-start) * Device->Frequency / 1000;
+        if(avail < done)
+        {
+            /* Timer wrapped. Add the remainder of the cycle to the available
+             * count and reset the number of samples done */
+            avail += (ALuint64)0xFFFFFFFFu*Device->Frequency/1000 - done;
+            done = 0;
+        }
+        if(avail-done < Device->UpdateSize)
+        {
+            Sleep(restTime);
+            continue;
+        }
+
+        while(avail-done >= Device->UpdateSize)
+        {
+            aluMixData(Device, data->buffer, Device->UpdateSize);
+            done += Device->UpdateSize;
+        }
+    }
+
+    return 0;
+}
+
+static ALCboolean null_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+    null_data *data;
+
+    if(!deviceName)
+        deviceName = nullDevice;
+    else if(strcmp(deviceName, nullDevice) != 0)
+        return ALC_FALSE;
+
+    data = (null_data*)calloc(1, sizeof(*data));
+
+    device->szDeviceName = strdup(deviceName);
+    device->ExtraData = data;
+    return ALC_TRUE;
+}
+
+static void null_close_playback(ALCdevice *device)
+{
+    null_data *data = (null_data*)device->ExtraData;
+
+    free(data);
+    device->ExtraData = NULL;
+}
+
+static ALCboolean null_reset_playback(ALCdevice *device)
+{
+    null_data *data = (null_data*)device->ExtraData;
+
+    data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans,
+                                                          device->FmtType);
+    data->buffer = malloc(data->size);
+    if(!data->buffer)
+    {
+        AL_PRINT("buffer malloc failed\n");
+        return ALC_FALSE;
+    }
+    SetDefaultWFXChannelOrder(device);
+
+    data->thread = StartThread(NullProc, device);
+    if(data->thread == NULL)
+    {
+        free(data->buffer);
+        data->buffer = NULL;
+        return ALC_FALSE;
+    }
+
+    return ALC_TRUE;
+}
+
+static void null_stop_playback(ALCdevice *device)
+{
+    null_data *data = (null_data*)device->ExtraData;
+
+    if(!data->thread)
+        return;
+
+    data->killNow = 1;
+    StopThread(data->thread);
+    data->thread = NULL;
+
+    data->killNow = 0;
+
+    free(data->buffer);
+    data->buffer = NULL;
+}
+
+
+static ALCboolean null_open_capture(ALCdevice *device, const ALCchar *deviceName)
+{
+    (void)device;
+    (void)deviceName;
+    return ALC_FALSE;
+}
+
+
+BackendFuncs null_funcs = {
+    null_open_playback,
+    null_close_playback,
+    null_reset_playback,
+    null_stop_playback,
+    null_open_capture,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+void alc_null_init(BackendFuncs *func_list)
+{
+    *func_list = null_funcs;
+}
+
+void alc_null_deinit(void)
+{
+}
+
+void alc_null_probe(int type)
+{
+    if(type == DEVICE_PROBE)
+        AppendDeviceList(nullDevice);
+    else if(type == ALL_DEVICE_PROBE)
+        AppendAllDeviceList(nullDevice);
+}
diff --git a/Alc/oss.c b/Alc/oss.c
new file mode 100644 (file)
index 0000000..ea18689
--- /dev/null
+++ b/Alc/oss.c
@@ -0,0 +1,521 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include <sys/soundcard.h>
+
+/*
+ * The OSS documentation talks about SOUND_MIXER_READ, but the header
+ * only contains MIXER_READ. Play safe. Same for WRITE.
+ */
+#ifndef SOUND_MIXER_READ
+#define SOUND_MIXER_READ MIXER_READ
+#endif
+#ifndef SOUND_MIXER_WRITE
+#define SOUND_MIXER_WRITE MIXER_WRITE
+#endif
+
+static const ALCchar oss_device[] = "OSS Default";
+
+typedef struct {
+    int fd;
+    volatile int killNow;
+    ALvoid *thread;
+
+    ALubyte *mix_data;
+    int data_size;
+
+    RingBuffer *ring;
+    int doCapture;
+} oss_data;
+
+
+static int log2i(ALCuint x)
+{
+    int y = 0;
+    while (x > 1)
+    {
+        x >>= 1;
+        y++;
+    }
+    return y;
+}
+
+
+static ALuint OSSProc(ALvoid *ptr)
+{
+    ALCdevice *pDevice = (ALCdevice*)ptr;
+    oss_data *data = (oss_data*)pDevice->ExtraData;
+    ALint frameSize;
+    ssize_t wrote;
+
+    SetRTPriority();
+
+    frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+    while(!data->killNow && pDevice->Connected)
+    {
+        ALint len = data->data_size;
+        ALubyte *WritePtr = data->mix_data;
+
+        aluMixData(pDevice, WritePtr, len/frameSize);
+        while(len > 0 && !data->killNow)
+        {
+            wrote = write(data->fd, WritePtr, len);
+            if(wrote < 0)
+            {
+                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
+                {
+                    AL_PRINT("write failed: %s\n", strerror(errno));
+                    aluHandleDisconnect(pDevice);
+                    break;
+                }
+
+                Sleep(1);
+                continue;
+            }
+
+            len -= wrote;
+            WritePtr += wrote;
+        }
+    }
+
+    return 0;
+}
+
+static ALuint OSSCaptureProc(ALvoid *ptr)
+{
+    ALCdevice *pDevice = (ALCdevice*)ptr;
+    oss_data *data = (oss_data*)pDevice->ExtraData;
+    int frameSize;
+    int amt;
+
+    SetRTPriority();
+
+    frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+    while(!data->killNow)
+    {
+        amt = read(data->fd, data->mix_data, data->data_size);
+        if(amt < 0)
+        {
+            AL_PRINT("read failed: %s\n", strerror(errno));
+            aluHandleDisconnect(pDevice);
+            break;
+        }
+        if(amt == 0)
+        {
+            Sleep(1);
+            continue;
+        }
+        if(data->doCapture)
+            WriteRingBuffer(data->ring, data->mix_data, amt/frameSize);
+    }
+
+    return 0;
+}
+
+static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+    char driver[64];
+    oss_data *data;
+
+    strncpy(driver, GetConfigValue("oss", "device", "/dev/dsp"), sizeof(driver)-1);
+    driver[sizeof(driver)-1] = 0;
+    if(!deviceName)
+        deviceName = oss_device;
+    else if(strcmp(deviceName, oss_device) != 0)
+        return ALC_FALSE;
+
+    data = (oss_data*)calloc(1, sizeof(oss_data));
+    data->killNow = 0;
+
+    data->fd = open(driver, O_WRONLY);
+    if(data->fd == -1)
+    {
+        free(data);
+        AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
+        return ALC_FALSE;
+    }
+
+    device->szDeviceName = strdup(deviceName);
+    device->ExtraData = data;
+    return ALC_TRUE;
+}
+
+static void oss_close_playback(ALCdevice *device)
+{
+    oss_data *data = (oss_data*)device->ExtraData;
+
+    close(data->fd);
+    free(data);
+    device->ExtraData = NULL;
+}
+
+static ALCboolean oss_reset_playback(ALCdevice *device)
+{
+    oss_data *data = (oss_data*)device->ExtraData;
+    int numFragmentsLogSize;
+    int log2FragmentSize;
+    unsigned int periods;
+    audio_buf_info info;
+    ALuint frameSize;
+    int numChannels;
+    int ossFormat;
+    int ossSpeed;
+    char *err;
+
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            ossFormat = AFMT_S8;
+            break;
+        case DevFmtUByte:
+            ossFormat = AFMT_U8;
+            break;
+        case DevFmtUShort:
+        case DevFmtFloat:
+            device->FmtType = DevFmtShort;
+            /* fall-through */
+        case DevFmtShort:
+            ossFormat = AFMT_S16_NE;
+            break;
+    }
+
+    periods = device->NumUpdates;
+    numChannels = ChannelsFromDevFmt(device->FmtChans);
+    frameSize = numChannels * BytesFromDevFmt(device->FmtType);
+
+    ossSpeed = device->Frequency;
+    log2FragmentSize = log2i(device->UpdateSize * frameSize);
+
+    /* according to the OSS spec, 16 bytes are the minimum */
+    if (log2FragmentSize < 4)
+        log2FragmentSize = 4;
+    /* Subtract one period since the temp mixing buffer counts as one. Still
+     * need at least two on the card, though. */
+    if(periods > 2) periods--;
+    numFragmentsLogSize = (periods << 16) | log2FragmentSize;
+
+#define CHECKERR(func) if((func) < 0) {                                       \
+    err = #func;                                                              \
+    goto err;                                                                 \
+}
+    /* Don't fail if SETFRAGMENT fails. We can handle just about anything
+     * that's reported back via GETOSPACE */
+    ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize);
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETOSPACE, &info));
+    if(0)
+    {
+    err:
+        AL_PRINT("%s failed: %s\n", err, strerror(errno));
+        return ALC_FALSE;
+    }
+#undef CHECKERR
+
+    if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
+    {
+        AL_PRINT("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), numChannels);
+        return ALC_FALSE;
+    }
+
+    if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
+         (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
+         (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
+    {
+        AL_PRINT("Could not set %#x format type, got OSS format %#x\n", device->FmtType, ossFormat);
+        return ALC_FALSE;
+    }
+
+    device->Frequency = ossSpeed;
+    device->UpdateSize = info.fragsize / frameSize;
+    device->NumUpdates = info.fragments + 1;
+
+    data->data_size = device->UpdateSize * frameSize;
+    data->mix_data = calloc(1, data->data_size);
+
+    SetDefaultChannelOrder(device);
+
+    data->thread = StartThread(OSSProc, device);
+    if(data->thread == NULL)
+    {
+        free(data->mix_data);
+        data->mix_data = NULL;
+        return ALC_FALSE;
+    }
+
+    return ALC_TRUE;
+}
+
+static void oss_stop_playback(ALCdevice *device)
+{
+    oss_data *data = (oss_data*)device->ExtraData;
+
+    if(!data->thread)
+        return;
+
+    data->killNow = 1;
+    StopThread(data->thread);
+    data->thread = NULL;
+
+    data->killNow = 0;
+    if(ioctl(data->fd, SNDCTL_DSP_RESET) != 0)
+        AL_PRINT("Error resetting device: %s\n", strerror(errno));
+
+    free(data->mix_data);
+    data->mix_data = NULL;
+}
+
+
+static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName)
+{
+    int numFragmentsLogSize;
+    int log2FragmentSize;
+    unsigned int periods;
+    audio_buf_info info;
+    ALuint frameSize;
+    int numChannels;
+    char driver[64];
+    oss_data *data;
+    int ossFormat;
+    int ossSpeed;
+    char *err;
+
+    strncpy(driver, GetConfigValue("oss", "capture", "/dev/dsp"), sizeof(driver)-1);
+    driver[sizeof(driver)-1] = 0;
+    if(!deviceName)
+        deviceName = oss_device;
+    else if(strcmp(deviceName, oss_device) != 0)
+        return ALC_FALSE;
+
+    data = (oss_data*)calloc(1, sizeof(oss_data));
+    data->killNow = 0;
+
+    data->fd = open(driver, O_RDONLY);
+    if(data->fd == -1)
+    {
+        free(data);
+        AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
+        return ALC_FALSE;
+    }
+
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            ossFormat = AFMT_S8;
+            break;
+        case DevFmtUByte:
+            ossFormat = AFMT_U8;
+            break;
+        case DevFmtShort:
+            ossFormat = AFMT_S16_NE;
+            break;
+        case DevFmtUShort:
+        case DevFmtFloat:
+            free(data);
+            AL_PRINT("Format type %#x capture not supported on OSS\n", device->FmtType);
+            return ALC_FALSE;
+    }
+
+    periods = 4;
+    numChannels = ChannelsFromDevFmt(device->FmtChans);
+    frameSize = numChannels * BytesFromDevFmt(device->FmtType);
+    ossSpeed = device->Frequency;
+    log2FragmentSize = log2i(device->UpdateSize * device->NumUpdates *
+                             frameSize / periods);
+
+    /* according to the OSS spec, 16 bytes are the minimum */
+    if (log2FragmentSize < 4)
+        log2FragmentSize = 4;
+    numFragmentsLogSize = (periods << 16) | log2FragmentSize;
+
+#define CHECKERR(func) if((func) < 0) {                                       \
+    err = #func;                                                              \
+    goto err;                                                                 \
+}
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFRAGMENT, &numFragmentsLogSize));
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SETFMT, &ossFormat));
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_CHANNELS, &numChannels));
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_SPEED, &ossSpeed));
+    CHECKERR(ioctl(data->fd, SNDCTL_DSP_GETISPACE, &info));
+    if(0)
+    {
+    err:
+        AL_PRINT("%s failed: %s\n", err, strerror(errno));
+        close(data->fd);
+        free(data);
+        return ALC_FALSE;
+    }
+#undef CHECKERR
+
+    if((int)ChannelsFromDevFmt(device->FmtChans) != numChannels)
+    {
+        AL_PRINT("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), numChannels);
+        close(data->fd);
+        free(data);
+        return ALC_FALSE;
+    }
+
+    if(!((ossFormat == AFMT_S8 && device->FmtType == DevFmtByte) ||
+         (ossFormat == AFMT_U8 && device->FmtType == DevFmtUByte) ||
+         (ossFormat == AFMT_S16_NE && device->FmtType == DevFmtShort)))
+    {
+        AL_PRINT("Could not set %#x format type, got OSS format %#x\n", device->FmtType, ossFormat);
+        close(data->fd);
+        free(data);
+        return ALC_FALSE;
+    }
+
+    data->ring = CreateRingBuffer(frameSize, device->UpdateSize * device->NumUpdates);
+    if(!data->ring)
+    {
+        AL_PRINT("ring buffer create failed\n");
+        close(data->fd);
+        free(data);
+        return ALC_FALSE;
+    }
+
+    data->data_size = info.fragsize;
+    data->mix_data = calloc(1, data->data_size);
+
+    device->ExtraData = data;
+    data->thread = StartThread(OSSCaptureProc, device);
+    if(data->thread == NULL)
+    {
+        device->ExtraData = NULL;
+        free(data->mix_data);
+        free(data);
+        return ALC_FALSE;
+    }
+
+    device->szDeviceName = strdup(deviceName);
+    return ALC_TRUE;
+}
+
+static void oss_close_capture(ALCdevice *device)
+{
+    oss_data *data = (oss_data*)device->ExtraData;
+    data->killNow = 1;
+    StopThread(data->thread);
+
+    close(data->fd);
+
+    DestroyRingBuffer(data->ring);
+
+    free(data->mix_data);
+    free(data);
+    device->ExtraData = NULL;
+}
+
+static void oss_start_capture(ALCdevice *pDevice)
+{
+    oss_data *data = (oss_data*)pDevice->ExtraData;
+    data->doCapture = 1;
+}
+
+static void oss_stop_capture(ALCdevice *pDevice)
+{
+    oss_data *data = (oss_data*)pDevice->ExtraData;
+    data->doCapture = 0;
+}
+
+static void oss_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+    oss_data *data = (oss_data*)pDevice->ExtraData;
+    if(lSamples <= (ALCuint)RingBufferSize(data->ring))
+        ReadRingBuffer(data->ring, pBuffer, lSamples);
+    else
+        alcSetError(pDevice, ALC_INVALID_VALUE);
+}
+
+static ALCuint oss_available_samples(ALCdevice *pDevice)
+{
+    oss_data *data = (oss_data*)pDevice->ExtraData;
+    return RingBufferSize(data->ring);
+}
+
+
+BackendFuncs oss_funcs = {
+    oss_open_playback,
+    oss_close_playback,
+    oss_reset_playback,
+    oss_stop_playback,
+    oss_open_capture,
+    oss_close_capture,
+    oss_start_capture,
+    oss_stop_capture,
+    oss_capture_samples,
+    oss_available_samples
+};
+
+void alc_oss_init(BackendFuncs *func_list)
+{
+    *func_list = oss_funcs;
+}
+
+void alc_oss_deinit(void)
+{
+}
+
+void alc_oss_probe(int type)
+{
+    if(type == DEVICE_PROBE)
+    {
+#ifdef HAVE_STAT
+        struct stat buf;
+        if(stat(GetConfigValue("oss", "device", "/dev/dsp"), &buf) == 0)
+#endif
+            AppendDeviceList(oss_device);
+    }
+    else if(type == ALL_DEVICE_PROBE)
+    {
+#ifdef HAVE_STAT
+        struct stat buf;
+        if(stat(GetConfigValue("oss", "device", "/dev/dsp"), &buf) == 0)
+#endif
+            AppendAllDeviceList(oss_device);
+    }
+    else if(type == CAPTURE_DEVICE_PROBE)
+    {
+#ifdef HAVE_STAT
+        struct stat buf;
+        if(stat(GetConfigValue("oss", "capture", "/dev/dsp"), &buf) == 0)
+#endif
+            AppendCaptureDeviceList(oss_device);
+    }
+}
diff --git a/Alc/panning.c b/Alc/panning.c
new file mode 100644 (file)
index 0000000..dec2a36
--- /dev/null
@@ -0,0 +1,361 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2010 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alu.h"
+
+static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MAXCHANNELS],
+                                  Channel Speaker2Chan[MAXCHANNELS], ALint chans)
+{
+    char layout_str[256];
+    char *confkey, *next;
+    char *sep, *end;
+    Channel val;
+    int i;
+
+    if(!ConfigValueExists(NULL, name))
+        name = "layout";
+
+    strncpy(layout_str, GetConfigValue(NULL, name, ""), sizeof(layout_str));
+    layout_str[sizeof(layout_str)-1] = 0;
+
+    if(!layout_str[0])
+        return;
+
+    next = confkey = layout_str;
+    while(next && *next)
+    {
+        confkey = next;
+        next = strchr(confkey, ',');
+        if(next)
+        {
+            *next = 0;
+            do {
+                next++;
+            } while(isspace(*next) || *next == ',');
+        }
+
+        sep = strchr(confkey, '=');
+        if(!sep || confkey == sep)
+            continue;
+
+        end = sep - 1;
+        while(isspace(*end) && end != confkey)
+            end--;
+        *(++end) = 0;
+
+        if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0)
+            val = FRONT_LEFT;
+        else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0)
+            val = FRONT_RIGHT;
+        else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0)
+            val = FRONT_CENTER;
+        else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0)
+            val = BACK_LEFT;
+        else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0)
+            val = BACK_RIGHT;
+        else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0)
+            val = BACK_CENTER;
+        else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0)
+            val = SIDE_LEFT;
+        else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0)
+            val = SIDE_RIGHT;
+        else
+        {
+            AL_PRINT("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] = angle * M_PI/180.0f;
+                else
+                    AL_PRINT("Invalid angle for speaker \"%s\": %ld\n", confkey, angle);
+                break;
+            }
+        }
+    }
+
+    for(i = 0;i < chans;i++)
+    {
+        int min = i;
+        int i2;
+
+        for(i2 = i+1;i2 < chans;i2++)
+        {
+            if(SpeakerAngle[i2] < SpeakerAngle[min])
+                min = i2;
+        }
+
+        if(min != i)
+        {
+            ALfloat tmpf;
+            Channel tmpc;
+
+            tmpf = SpeakerAngle[i];
+            SpeakerAngle[i] = SpeakerAngle[min];
+            SpeakerAngle[min] = tmpf;
+
+            tmpc = Speaker2Chan[i];
+            Speaker2Chan[i] = Speaker2Chan[min];
+            Speaker2Chan[min] = tmpc;
+        }
+    }
+}
+
+static ALfloat aluLUTpos2Angle(ALint pos)
+{
+    if(pos < QUADRANT_NUM)
+        return aluAtan((ALfloat)pos / (ALfloat)(QUADRANT_NUM - pos));
+    if(pos < 2 * QUADRANT_NUM)
+        return M_PI_2 + aluAtan((ALfloat)(pos - QUADRANT_NUM) / (ALfloat)(2 * QUADRANT_NUM - pos));
+    if(pos < 3 * QUADRANT_NUM)
+        return aluAtan((ALfloat)(pos - 2 * QUADRANT_NUM) / (ALfloat)(3 * QUADRANT_NUM - pos)) - M_PI;
+    return aluAtan((ALfloat)(pos - 3 * QUADRANT_NUM) / (ALfloat)(4 * QUADRANT_NUM - pos)) - M_PI_2;
+}
+
+ALint aluCart2LUTpos(ALfloat re, ALfloat im)
+{
+    ALint pos = 0;
+    ALfloat denom = aluFabs(re) + aluFabs(im);
+    if(denom > 0.0f)
+        pos = (ALint)(QUADRANT_NUM*aluFabs(im) / denom + 0.5);
+
+    if(re < 0.0)
+        pos = 2 * QUADRANT_NUM - pos;
+    if(im < 0.0)
+        pos = LUT_NUM - pos;
+    return pos%LUT_NUM;
+}
+
+ALvoid aluInitPanning(ALCdevice *Device)
+{
+    ALfloat SpeakerAngle[MAXCHANNELS];
+    ALfloat (*Matrix)[MAXCHANNELS];
+    Channel *Speaker2Chan;
+    ALfloat Alpha, Theta;
+    ALfloat *PanningLUT;
+    ALint pos, offset;
+    ALuint s, s2;
+
+    for(s = 0;s < MAXCHANNELS;s++)
+    {
+        for(s2 = 0;s2 < MAXCHANNELS;s2++)
+            Device->ChannelMatrix[s][s2] = ((s==s2) ? 1.0f : 0.0f);
+    }
+
+    Speaker2Chan = Device->Speaker2Chan;
+    Matrix = Device->ChannelMatrix;
+    switch(Device->FmtChans)
+    {
+        case DevFmtMono:
+            Matrix[FRONT_LEFT][FRONT_CENTER]  = aluSqrt(0.5);
+            Matrix[FRONT_RIGHT][FRONT_CENTER] = aluSqrt(0.5);
+            Matrix[SIDE_LEFT][FRONT_CENTER]   = aluSqrt(0.5);
+            Matrix[SIDE_RIGHT][FRONT_CENTER]  = aluSqrt(0.5);
+            Matrix[BACK_LEFT][FRONT_CENTER]   = aluSqrt(0.5);
+            Matrix[BACK_RIGHT][FRONT_CENTER]  = aluSqrt(0.5);
+            Matrix[BACK_CENTER][FRONT_CENTER] = 1.0f;
+            Device->NumChan = 1;
+            Speaker2Chan[0] = FRONT_CENTER;
+            SpeakerAngle[0] = 0.0f * M_PI/180.0f;
+            break;
+
+        case DevFmtStereo:
+            Matrix[FRONT_CENTER][FRONT_LEFT]  = aluSqrt(0.5);
+            Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
+            Matrix[SIDE_LEFT][FRONT_LEFT]     = 1.0f;
+            Matrix[SIDE_RIGHT][FRONT_RIGHT]   = 1.0f;
+            Matrix[BACK_LEFT][FRONT_LEFT]     = 1.0f;
+            Matrix[BACK_RIGHT][FRONT_RIGHT]   = 1.0f;
+            Matrix[BACK_CENTER][FRONT_LEFT]   = aluSqrt(0.5);
+            Matrix[BACK_CENTER][FRONT_RIGHT]  = aluSqrt(0.5);
+            Device->NumChan = 2;
+            Speaker2Chan[0] = FRONT_LEFT;
+            Speaker2Chan[1] = FRONT_RIGHT;
+            SpeakerAngle[0] = -90.0f * M_PI/180.0f;
+            SpeakerAngle[1] =  90.0f * M_PI/180.0f;
+            SetSpeakerArrangement("layout_STEREO", SpeakerAngle, Speaker2Chan, Device->NumChan);
+            break;
+
+        case DevFmtQuad:
+            Matrix[FRONT_CENTER][FRONT_LEFT]  = aluSqrt(0.5);
+            Matrix[FRONT_CENTER][FRONT_RIGHT] = aluSqrt(0.5);
+            Matrix[SIDE_LEFT][FRONT_LEFT]     = aluSqrt(0.5);
+            Matrix[SIDE_LEFT][BACK_LEFT]      = aluSqrt(0.5);
+            Matrix[SIDE_RIGHT][FRONT_RIGHT]   = aluSqrt(0.5);
+            Matrix[SIDE_RIGHT][BACK_RIGHT]    = aluSqrt(0.5);
+            Matrix[BACK_CENTER][BACK_LEFT]    = aluSqrt(0.5);
+            Matrix[BACK_CENTER][BACK_RIGHT]   = aluSqrt(0.5);
+            Device->NumChan = 4;
+            Speaker2Chan[0] = BACK_LEFT;
+            Speaker2Chan[1] = FRONT_LEFT;
+            Speaker2Chan[2] = FRONT_RIGHT;
+            Speaker2Chan[3] = BACK_RIGHT;
+            SpeakerAngle[0] = -135.0f * M_PI/180.0f;
+            SpeakerAngle[1] =  -45.0f * M_PI/180.0f;
+            SpeakerAngle[2] =   45.0f * M_PI/180.0f;
+            SpeakerAngle[3] =  135.0f * M_PI/180.0f;
+            SetSpeakerArrangement("layout_QUAD", SpeakerAngle, Speaker2Chan, Device->NumChan);
+            break;
+
+        case DevFmtX51:
+            Matrix[SIDE_LEFT][FRONT_LEFT]   = aluSqrt(0.5);
+            Matrix[SIDE_LEFT][BACK_LEFT]    = aluSqrt(0.5);
+            Matrix[SIDE_RIGHT][FRONT_RIGHT] = aluSqrt(0.5);
+            Matrix[SIDE_RIGHT][BACK_RIGHT]  = aluSqrt(0.5);
+            Matrix[BACK_CENTER][BACK_LEFT]  = aluSqrt(0.5);
+            Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
+            Device->NumChan = 5;
+            Speaker2Chan[0] = BACK_LEFT;
+            Speaker2Chan[1] = FRONT_LEFT;
+            Speaker2Chan[2] = FRONT_CENTER;
+            Speaker2Chan[3] = FRONT_RIGHT;
+            Speaker2Chan[4] = BACK_RIGHT;
+            SpeakerAngle[0] = -110.0f * M_PI/180.0f;
+            SpeakerAngle[1] =  -30.0f * M_PI/180.0f;
+            SpeakerAngle[2] =    0.0f * M_PI/180.0f;
+            SpeakerAngle[3] =   30.0f * M_PI/180.0f;
+            SpeakerAngle[4] =  110.0f * M_PI/180.0f;
+            SetSpeakerArrangement("layout_51CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+            break;
+
+        case DevFmtX61:
+            Matrix[BACK_LEFT][BACK_CENTER]  = aluSqrt(0.5);
+            Matrix[BACK_LEFT][SIDE_LEFT]    = aluSqrt(0.5);
+            Matrix[BACK_RIGHT][BACK_CENTER] = aluSqrt(0.5);
+            Matrix[BACK_RIGHT][SIDE_RIGHT]  = aluSqrt(0.5);
+            Device->NumChan = 6;
+            Speaker2Chan[0] = SIDE_LEFT;
+            Speaker2Chan[1] = FRONT_LEFT;
+            Speaker2Chan[2] = FRONT_CENTER;
+            Speaker2Chan[3] = FRONT_RIGHT;
+            Speaker2Chan[4] = SIDE_RIGHT;
+            Speaker2Chan[5] = BACK_CENTER;
+            SpeakerAngle[0] = -90.0f * M_PI/180.0f;
+            SpeakerAngle[1] = -30.0f * M_PI/180.0f;
+            SpeakerAngle[2] =   0.0f * M_PI/180.0f;
+            SpeakerAngle[3] =  30.0f * M_PI/180.0f;
+            SpeakerAngle[4] =  90.0f * M_PI/180.0f;
+            SpeakerAngle[5] = 180.0f * M_PI/180.0f;
+            SetSpeakerArrangement("layout_61CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+            break;
+
+        case DevFmtX71:
+            Matrix[BACK_CENTER][BACK_LEFT]  = aluSqrt(0.5);
+            Matrix[BACK_CENTER][BACK_RIGHT] = aluSqrt(0.5);
+            Device->NumChan = 7;
+            Speaker2Chan[0] = BACK_LEFT;
+            Speaker2Chan[1] = SIDE_LEFT;
+            Speaker2Chan[2] = FRONT_LEFT;
+            Speaker2Chan[3] = FRONT_CENTER;
+            Speaker2Chan[4] = FRONT_RIGHT;
+            Speaker2Chan[5] = SIDE_RIGHT;
+            Speaker2Chan[6] = BACK_RIGHT;
+            SpeakerAngle[0] = -150.0f * M_PI/180.0f;
+            SpeakerAngle[1] =  -90.0f * M_PI/180.0f;
+            SpeakerAngle[2] =  -30.0f * M_PI/180.0f;
+            SpeakerAngle[3] =    0.0f * M_PI/180.0f;
+            SpeakerAngle[4] =   30.0f * M_PI/180.0f;
+            SpeakerAngle[5] =   90.0f * M_PI/180.0f;
+            SpeakerAngle[6] =  150.0f * M_PI/180.0f;
+            SetSpeakerArrangement("layout_71CHN", SpeakerAngle, Speaker2Chan, Device->NumChan);
+            break;
+    }
+
+    if(GetConfigValueBool(NULL, "scalemix", 0))
+    {
+        ALfloat maxout = 1.0f;
+        for(s = 0;s < MAXCHANNELS;s++)
+        {
+            ALfloat out = 0.0f;
+            for(s2 = 0;s2 < MAXCHANNELS;s2++)
+                out += Device->ChannelMatrix[s2][s];
+            maxout = __max(maxout, out);
+        }
+
+        maxout = 1.0f/maxout;
+        for(s = 0;s < MAXCHANNELS;s++)
+        {
+            for(s2 = 0;s2 < MAXCHANNELS;s2++)
+                Device->ChannelMatrix[s2][s] *= maxout;
+        }
+    }
+
+    PanningLUT = Device->PanningLUT;
+    for(pos = 0; pos < LUT_NUM; pos++)
+    {
+        /* clear all values */
+        offset = MAXCHANNELS * pos;
+        for(s = 0; s < MAXCHANNELS; s++)
+            PanningLUT[offset+s] = 0.0f;
+
+        if(Device->NumChan == 1)
+        {
+            PanningLUT[offset + Speaker2Chan[0]] = 1.0f;
+            continue;
+        }
+
+        /* source angle */
+        Theta = aluLUTpos2Angle(pos);
+
+        /* set panning values */
+        for(s = 0; s < Device->NumChan - 1; s++)
+        {
+            if(Theta >= SpeakerAngle[s] && Theta < SpeakerAngle[s+1])
+            {
+                /* source between speaker s and speaker s+1 */
+                Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
+                                 (SpeakerAngle[s+1]-SpeakerAngle[s]);
+                PanningLUT[offset + Speaker2Chan[s]]   = cos(Alpha);
+                PanningLUT[offset + Speaker2Chan[s+1]] = sin(Alpha);
+                break;
+            }
+        }
+        if(s == Device->NumChan - 1)
+        {
+            /* source between last and first speaker */
+            if(Theta < SpeakerAngle[0])
+                Theta += 2.0f * M_PI;
+            Alpha = M_PI_2 * (Theta-SpeakerAngle[s]) /
+                             (2.0f * M_PI + SpeakerAngle[0]-SpeakerAngle[s]);
+            PanningLUT[offset + Speaker2Chan[s]] = cos(Alpha);
+            PanningLUT[offset + Speaker2Chan[0]] = sin(Alpha);
+        }
+    }
+}
diff --git a/Alc/portaudio.c b/Alc/portaudio.c
new file mode 100644 (file)
index 0000000..77c7236
--- /dev/null
@@ -0,0 +1,442 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <portaudio.h>
+
+static void *pa_handle;
+#define MAKE_FUNC(x) static typeof(x) * p##x
+MAKE_FUNC(Pa_Initialize);
+MAKE_FUNC(Pa_Terminate);
+MAKE_FUNC(Pa_GetErrorText);
+MAKE_FUNC(Pa_StartStream);
+MAKE_FUNC(Pa_StopStream);
+MAKE_FUNC(Pa_OpenStream);
+MAKE_FUNC(Pa_CloseStream);
+MAKE_FUNC(Pa_GetDefaultOutputDevice);
+MAKE_FUNC(Pa_GetStreamInfo);
+#undef MAKE_FUNC
+
+
+static const ALCchar pa_device[] = "PortAudio Default";
+
+
+void *pa_load(void)
+{
+    if(!pa_handle)
+    {
+        PaError err;
+
+#ifdef _WIN32
+        pa_handle = LoadLibrary("portaudio.dll");
+#define LOAD_FUNC(x) do { \
+    p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
+    if(!(p##x)) { \
+        AL_PRINT("Could not load %s from portaudio.dll\n", #x); \
+        FreeLibrary(pa_handle); \
+        pa_handle = NULL; \
+        return NULL; \
+    } \
+} while(0)
+
+#elif defined(HAVE_DLFCN_H)
+
+    const char *str;
+#if defined(__APPLE__) && defined(__MACH__)
+# define PALIB "libportaudio.2.dylib"
+#else
+# define PALIB "libportaudio.so.2"
+#endif
+        pa_handle = dlopen(PALIB, RTLD_NOW);
+        dlerror();
+
+#define LOAD_FUNC(f) do { \
+    p##f = (typeof(f)*)dlsym(pa_handle, #f); \
+    if((str=dlerror()) != NULL) \
+    { \
+        dlclose(pa_handle); \
+        pa_handle = NULL; \
+        AL_PRINT("Could not load %s from "PALIB": %s\n", #f, str); \
+        return NULL; \
+    } \
+} while(0)
+
+#else
+        pa_handle = (void*)0xDEADBEEF;
+#define LOAD_FUNC(f) p##f = f
+#endif
+
+        if(!pa_handle)
+            return NULL;
+
+LOAD_FUNC(Pa_Initialize);
+LOAD_FUNC(Pa_Terminate);
+LOAD_FUNC(Pa_GetErrorText);
+LOAD_FUNC(Pa_StartStream);
+LOAD_FUNC(Pa_StopStream);
+LOAD_FUNC(Pa_OpenStream);
+LOAD_FUNC(Pa_CloseStream);
+LOAD_FUNC(Pa_GetDefaultOutputDevice);
+LOAD_FUNC(Pa_GetStreamInfo);
+
+#undef LOAD_FUNC
+
+        if((err=pPa_Initialize()) != paNoError)
+        {
+            AL_PRINT("Pa_Initialize() returned an error: %s\n", pPa_GetErrorText(err));
+#ifdef _WIN32
+            FreeLibrary(pa_handle);
+#elif defined(HAVE_DLFCN_H)
+            dlclose(pa_handle);
+#endif
+            pa_handle = NULL;
+            return NULL;
+        }
+    }
+    return pa_handle;
+}
+
+
+typedef struct {
+    PaStream *stream;
+    ALuint update_size;
+
+    RingBuffer *ring;
+} pa_data;
+
+
+static int pa_callback(const void *inputBuffer, void *outputBuffer,
+                       unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+                       const PaStreamCallbackFlags statusFlags, void *userData)
+{
+    ALCdevice *device = (ALCdevice*)userData;
+
+    (void)inputBuffer;
+    (void)timeInfo;
+    (void)statusFlags;
+
+    aluMixData(device, outputBuffer, framesPerBuffer);
+    return 0;
+}
+
+static int pa_capture_cb(const void *inputBuffer, void *outputBuffer,
+                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
+                         const PaStreamCallbackFlags statusFlags, void *userData)
+{
+    ALCdevice *device = (ALCdevice*)userData;
+    pa_data *data = (pa_data*)device->ExtraData;
+
+    (void)outputBuffer;
+    (void)timeInfo;
+    (void)statusFlags;
+
+    WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer);
+    return 0;
+}
+
+
+static ALCboolean pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+    const PaStreamInfo *streamInfo;
+    PaStreamParameters outParams;
+    pa_data *data;
+    PaError err;
+
+    if(!deviceName)
+        deviceName = pa_device;
+    else if(strcmp(deviceName, pa_device) != 0)
+        return ALC_FALSE;
+
+    if(!pa_load())
+        return ALC_FALSE;
+
+    data = (pa_data*)calloc(1, sizeof(pa_data));
+    data->update_size = device->UpdateSize;
+
+    device->ExtraData = data;
+
+    outParams.device = GetConfigValueInt("port", "device", -1);
+    if(outParams.device < 0)
+        outParams.device = pPa_GetDefaultOutputDevice();
+    outParams.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
+                                 (float)device->Frequency;
+    outParams.hostApiSpecificStreamInfo = NULL;
+
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            outParams.sampleFormat = paInt8;
+            break;
+        case DevFmtUByte:
+            outParams.sampleFormat = paUInt8;
+            break;
+        case DevFmtUShort:
+            device->FmtType = DevFmtShort;
+            /* fall-through */
+        case DevFmtShort:
+            outParams.sampleFormat = paInt16;
+            break;
+        case DevFmtFloat:
+            outParams.sampleFormat = paFloat32;
+            break;
+    }
+    outParams.channelCount = ChannelsFromDevFmt(device->FmtChans);
+
+    SetDefaultChannelOrder(device);
+
+    err = pPa_OpenStream(&data->stream, NULL, &outParams, device->Frequency,
+                         device->UpdateSize, paNoFlag, pa_callback, device);
+    if(err != paNoError)
+    {
+        AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err));
+        device->ExtraData = NULL;
+        free(data);
+        return ALC_FALSE;
+    }
+    streamInfo = pPa_GetStreamInfo(data->stream);
+
+    device->szDeviceName = strdup(deviceName);
+    device->Frequency = streamInfo->sampleRate;
+
+    return ALC_TRUE;
+}
+
+static void pa_close_playback(ALCdevice *device)
+{
+    pa_data *data = (pa_data*)device->ExtraData;
+    PaError err;
+
+    err = pPa_CloseStream(data->stream);
+    if(err != paNoError)
+        AL_PRINT("Error closing stream: %s\n", pPa_GetErrorText(err));
+
+    free(data);
+    device->ExtraData = NULL;
+}
+
+static ALCboolean pa_reset_playback(ALCdevice *device)
+{
+    pa_data *data = (pa_data*)device->ExtraData;
+    const PaStreamInfo *streamInfo;
+    PaError err;
+
+    streamInfo = pPa_GetStreamInfo(data->stream);
+    device->Frequency = streamInfo->sampleRate;
+    device->UpdateSize = data->update_size;
+
+    err = pPa_StartStream(data->stream);
+    if(err != paNoError)
+    {
+        AL_PRINT("Pa_StartStream() returned an error: %s\n", pPa_GetErrorText(err));
+        return ALC_FALSE;
+    }
+
+    return ALC_TRUE;
+}
+
+static void pa_stop_playback(ALCdevice *device)
+{
+    pa_data *data = (pa_data*)device->ExtraData;
+    PaError err;
+
+    err = pPa_StopStream(data->stream);
+    if(err != paNoError)
+        AL_PRINT("Error stopping stream: %s\n", pPa_GetErrorText(err));
+}
+
+
+static ALCboolean pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
+{
+    PaStreamParameters inParams;
+    ALuint frame_size;
+    pa_data *data;
+    PaError err;
+
+    if(!deviceName)
+        deviceName = pa_device;
+    else if(strcmp(deviceName, pa_device) != 0)
+        return ALC_FALSE;
+
+    if(!pa_load())
+        return ALC_FALSE;
+
+    data = (pa_data*)calloc(1, sizeof(pa_data));
+    if(data == NULL)
+    {
+        alcSetError(device, ALC_OUT_OF_MEMORY);
+        return ALC_FALSE;
+    }
+
+    frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates);
+    if(data->ring == NULL)
+    {
+        alcSetError(device, ALC_OUT_OF_MEMORY);
+        goto error;
+    }
+
+    inParams.device = GetConfigValueInt("port", "capture", -1);
+    if(inParams.device < 0)
+        inParams.device = pPa_GetDefaultOutputDevice();
+    inParams.suggestedLatency = 0.0f;
+    inParams.hostApiSpecificStreamInfo = NULL;
+
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            inParams.sampleFormat = paInt8;
+            break;
+        case DevFmtUByte:
+            inParams.sampleFormat = paUInt8;
+            break;
+        case DevFmtShort:
+            inParams.sampleFormat = paInt16;
+            break;
+        case DevFmtFloat:
+            inParams.sampleFormat = paFloat32;
+            break;
+        case DevFmtUShort:
+            AL_PRINT("Unsigned short not supported\n");
+            goto error;
+    }
+    inParams.channelCount = ChannelsFromDevFmt(device->FmtChans);
+
+    err = pPa_OpenStream(&data->stream, &inParams, NULL, device->Frequency,
+                         paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device);
+    if(err != paNoError)
+    {
+        AL_PRINT("Pa_OpenStream() returned an error: %s\n", pPa_GetErrorText(err));
+        goto error;
+    }
+
+    device->szDeviceName = strdup(deviceName);
+
+    device->ExtraData = data;
+    return ALC_TRUE;
+
+error:
+    DestroyRingBuffer(data->ring);
+    free(data);
+    return ALC_FALSE;
+}
+
+static void pa_close_capture(ALCdevice *device)
+{
+    pa_data *data = (pa_data*)device->ExtraData;
+    PaError err;
+
+    err = pPa_CloseStream(data->stream);
+    if(err != paNoError)
+        AL_PRINT("Error closing stream: %s\n", pPa_GetErrorText(err));
+
+    free(data);
+    device->ExtraData = NULL;
+}
+
+static void pa_start_capture(ALCdevice *device)
+{
+    pa_data *data = device->ExtraData;
+    PaError err;
+
+    err = pPa_StartStream(data->stream);
+    if(err != paNoError)
+        AL_PRINT("Error starting stream: %s\n", pPa_GetErrorText(err));
+}
+
+static void pa_stop_capture(ALCdevice *device)
+{
+    pa_data *data = (pa_data*)device->ExtraData;
+    PaError err;
+
+    err = pPa_StopStream(data->stream);
+    if(err != paNoError)
+        AL_PRINT("Error stopping stream: %s\n", pPa_GetErrorText(err));
+}
+
+static void pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
+{
+    pa_data *data = device->ExtraData;
+    if(samples <= (ALCuint)RingBufferSize(data->ring))
+        ReadRingBuffer(data->ring, buffer, samples);
+    else
+        alcSetError(device, ALC_INVALID_VALUE);
+}
+
+static ALCuint pa_available_samples(ALCdevice *device)
+{
+    pa_data *data = device->ExtraData;
+    return RingBufferSize(data->ring);
+}
+
+
+static const BackendFuncs pa_funcs = {
+    pa_open_playback,
+    pa_close_playback,
+    pa_reset_playback,
+    pa_stop_playback,
+    pa_open_capture,
+    pa_close_capture,
+    pa_start_capture,
+    pa_stop_capture,
+    pa_capture_samples,
+    pa_available_samples
+};
+
+void alc_pa_init(BackendFuncs *func_list)
+{
+    *func_list = pa_funcs;
+}
+
+void alc_pa_deinit(void)
+{
+    if(pa_handle)
+    {
+        pPa_Terminate();
+#ifdef _WIN32
+        FreeLibrary(pa_handle);
+#elif defined(HAVE_DLFCN_H)
+        dlclose(pa_handle);
+#endif
+        pa_handle = NULL;
+    }
+}
+
+void alc_pa_probe(int type)
+{
+    if(!pa_load()) return;
+
+    if(type == DEVICE_PROBE)
+        AppendDeviceList(pa_device);
+    else if(type == ALL_DEVICE_PROBE)
+        AppendAllDeviceList(pa_device);
+    else if(type == CAPTURE_DEVICE_PROBE)
+        AppendCaptureDeviceList(pa_device);
+}
diff --git a/Alc/pulseaudio.c b/Alc/pulseaudio.c
new file mode 100644 (file)
index 0000000..348f2d5
--- /dev/null
@@ -0,0 +1,1358 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2009 by Konstantinos Natsakis <konstantinos.natsakis@gmail.com>
+ * Copyright (C) 2010 by Chris Robinson <chris.kcat@gmail.com>
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include "alMain.h"
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <pulse/pulseaudio.h>
+
+#if PA_API_VERSION == 11
+#define PA_STREAM_ADJUST_LATENCY 0x2000U
+#define PA_STREAM_EARLY_REQUESTS 0x4000U
+static __inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
+{
+    return (x == PA_STREAM_CREATING || x == PA_STREAM_READY);
+}
+static __inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
+{
+    return (x == PA_CONTEXT_CONNECTING || x == PA_CONTEXT_AUTHORIZING ||
+            x == PA_CONTEXT_SETTING_NAME || x == PA_CONTEXT_READY);
+}
+#define PA_STREAM_IS_GOOD PA_STREAM_IS_GOOD
+#define PA_CONTEXT_IS_GOOD PA_CONTEXT_IS_GOOD
+#elif PA_API_VERSION != 12
+#error Invalid PulseAudio API version
+#endif
+
+#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
+
+static void *pa_handle;
+#define MAKE_FUNC(x) static typeof(x) * p##x
+MAKE_FUNC(pa_context_unref);
+MAKE_FUNC(pa_sample_spec_valid);
+MAKE_FUNC(pa_stream_drop);
+MAKE_FUNC(pa_strerror);
+MAKE_FUNC(pa_context_get_state);
+MAKE_FUNC(pa_stream_get_state);
+MAKE_FUNC(pa_threaded_mainloop_signal);
+MAKE_FUNC(pa_stream_peek);
+MAKE_FUNC(pa_threaded_mainloop_wait);
+MAKE_FUNC(pa_threaded_mainloop_unlock);
+MAKE_FUNC(pa_threaded_mainloop_in_thread);
+MAKE_FUNC(pa_context_new);
+MAKE_FUNC(pa_threaded_mainloop_stop);
+MAKE_FUNC(pa_context_disconnect);
+MAKE_FUNC(pa_threaded_mainloop_start);
+MAKE_FUNC(pa_threaded_mainloop_get_api);
+MAKE_FUNC(pa_context_set_state_callback);
+MAKE_FUNC(pa_stream_write);
+MAKE_FUNC(pa_xfree);
+MAKE_FUNC(pa_stream_connect_record);
+MAKE_FUNC(pa_stream_connect_playback);
+MAKE_FUNC(pa_stream_readable_size);
+MAKE_FUNC(pa_stream_writable_size);
+MAKE_FUNC(pa_stream_cork);
+MAKE_FUNC(pa_stream_is_suspended);
+MAKE_FUNC(pa_stream_get_device_name);
+MAKE_FUNC(pa_path_get_filename);
+MAKE_FUNC(pa_get_binary_name);
+MAKE_FUNC(pa_threaded_mainloop_free);
+MAKE_FUNC(pa_context_errno);
+MAKE_FUNC(pa_xmalloc);
+MAKE_FUNC(pa_stream_unref);
+MAKE_FUNC(pa_threaded_mainloop_accept);
+MAKE_FUNC(pa_stream_set_write_callback);
+MAKE_FUNC(pa_threaded_mainloop_new);
+MAKE_FUNC(pa_context_connect);
+MAKE_FUNC(pa_stream_set_buffer_attr);
+MAKE_FUNC(pa_stream_get_buffer_attr);
+MAKE_FUNC(pa_stream_get_sample_spec);
+MAKE_FUNC(pa_stream_get_time);
+MAKE_FUNC(pa_stream_set_read_callback);
+MAKE_FUNC(pa_stream_set_state_callback);
+MAKE_FUNC(pa_stream_set_moved_callback);
+MAKE_FUNC(pa_stream_set_underflow_callback);
+MAKE_FUNC(pa_stream_new);
+MAKE_FUNC(pa_stream_disconnect);
+MAKE_FUNC(pa_threaded_mainloop_lock);
+MAKE_FUNC(pa_channel_map_init_auto);
+MAKE_FUNC(pa_channel_map_parse);
+MAKE_FUNC(pa_channel_map_snprint);
+MAKE_FUNC(pa_channel_map_equal);
+MAKE_FUNC(pa_context_get_server_info);
+MAKE_FUNC(pa_context_get_sink_info_by_name);
+MAKE_FUNC(pa_context_get_sink_info_list);
+MAKE_FUNC(pa_context_get_source_info_list);
+MAKE_FUNC(pa_operation_get_state);
+MAKE_FUNC(pa_operation_unref);
+#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
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+typedef struct {
+    char *device_name;
+
+    ALCuint samples;
+    ALCuint frame_size;
+
+    RingBuffer *ring;
+
+    pa_buffer_attr attr;
+    pa_sample_spec spec;
+
+    pa_threaded_mainloop *loop;
+
+    ALvoid *thread;
+    volatile ALboolean killNow;
+
+    pa_stream *stream;
+    pa_context *context;
+} pulse_data;
+
+typedef struct {
+    char *name;
+    char *device_name;
+} DevMap;
+
+
+static const ALCchar pulse_device[] = "PulseAudio Default";
+static DevMap *allDevNameMap;
+static ALuint numDevNames;
+static DevMap *allCaptureDevNameMap;
+static ALuint numCaptureDevNames;
+static pa_context_flags_t pulse_ctx_flags;
+
+
+void *pulse_load(void) //{{{
+{
+    if(!pa_handle)
+    {
+#ifdef _WIN32
+        pa_handle = LoadLibrary("libpulse-0.dll");
+#define LOAD_FUNC(x) do { \
+    p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
+    if(!(p##x)) { \
+        AL_PRINT("Could not load %s from libpulse-0.dll\n", #x); \
+        FreeLibrary(pa_handle); \
+        pa_handle = NULL; \
+        return NULL; \
+    } \
+} while(0)
+#define LOAD_OPTIONAL_FUNC(x) do { \
+    p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
+} while(0)
+
+#elif defined (HAVE_DLFCN_H)
+
+        const char *err;
+#if defined(__APPLE__) && defined(__MACH__)
+        pa_handle = dlopen("libpulse.0.dylib", RTLD_NOW);
+#else
+        pa_handle = dlopen("libpulse.so.0", RTLD_NOW);
+#endif
+        dlerror();
+
+#define LOAD_FUNC(x) do { \
+    p##x = dlsym(pa_handle, #x); \
+    if((err=dlerror()) != NULL) { \
+        AL_PRINT("Could not load %s from libpulse: %s\n", #x, err); \
+        dlclose(pa_handle); \
+        pa_handle = NULL; \
+        return NULL; \
+    } \
+} while(0)
+#define LOAD_OPTIONAL_FUNC(x) do { \
+    p##x = dlsym(pa_handle, #x); \
+    if((err=dlerror()) != NULL) { \
+        p##x = NULL; \
+    } \
+} while(0)
+
+#else
+
+        pa_handle = (void*)0xDEADBEEF;
+#define LOAD_FUNC(x) p##x = (x)
+#define LOAD_OPTIONAL_FUNC(x) p##x = (x)
+
+#endif
+        if(!pa_handle)
+            return NULL;
+
+LOAD_FUNC(pa_context_unref);
+LOAD_FUNC(pa_sample_spec_valid);
+LOAD_FUNC(pa_stream_drop);
+LOAD_FUNC(pa_strerror);
+LOAD_FUNC(pa_context_get_state);
+LOAD_FUNC(pa_stream_get_state);
+LOAD_FUNC(pa_threaded_mainloop_signal);
+LOAD_FUNC(pa_stream_peek);
+LOAD_FUNC(pa_threaded_mainloop_wait);
+LOAD_FUNC(pa_threaded_mainloop_unlock);
+LOAD_FUNC(pa_threaded_mainloop_in_thread);
+LOAD_FUNC(pa_context_new);
+LOAD_FUNC(pa_threaded_mainloop_stop);
+LOAD_FUNC(pa_context_disconnect);
+LOAD_FUNC(pa_threaded_mainloop_start);
+LOAD_FUNC(pa_threaded_mainloop_get_api);
+LOAD_FUNC(pa_context_set_state_callback);
+LOAD_FUNC(pa_stream_write);
+LOAD_FUNC(pa_xfree);
+LOAD_FUNC(pa_stream_connect_record);
+LOAD_FUNC(pa_stream_connect_playback);
+LOAD_FUNC(pa_stream_readable_size);
+LOAD_FUNC(pa_stream_writable_size);
+LOAD_FUNC(pa_stream_cork);
+LOAD_FUNC(pa_stream_is_suspended);
+LOAD_FUNC(pa_stream_get_device_name);
+LOAD_FUNC(pa_path_get_filename);
+LOAD_FUNC(pa_get_binary_name);
+LOAD_FUNC(pa_threaded_mainloop_free);
+LOAD_FUNC(pa_context_errno);
+LOAD_FUNC(pa_xmalloc);
+LOAD_FUNC(pa_stream_unref);
+LOAD_FUNC(pa_threaded_mainloop_accept);
+LOAD_FUNC(pa_stream_set_write_callback);
+LOAD_FUNC(pa_threaded_mainloop_new);
+LOAD_FUNC(pa_context_connect);
+LOAD_FUNC(pa_stream_set_buffer_attr);
+LOAD_FUNC(pa_stream_get_buffer_attr);
+LOAD_FUNC(pa_stream_get_sample_spec);
+LOAD_FUNC(pa_stream_get_time);
+LOAD_FUNC(pa_stream_set_read_callback);
+LOAD_FUNC(pa_stream_set_state_callback);
+LOAD_FUNC(pa_stream_set_moved_callback);
+LOAD_FUNC(pa_stream_set_underflow_callback);
+LOAD_FUNC(pa_stream_new);
+LOAD_FUNC(pa_stream_disconnect);
+LOAD_FUNC(pa_threaded_mainloop_lock);
+LOAD_FUNC(pa_channel_map_init_auto);
+LOAD_FUNC(pa_channel_map_parse);
+LOAD_FUNC(pa_channel_map_snprint);
+LOAD_FUNC(pa_channel_map_equal);
+LOAD_FUNC(pa_context_get_server_info);
+LOAD_FUNC(pa_context_get_sink_info_by_name);
+LOAD_FUNC(pa_context_get_sink_info_list);
+LOAD_FUNC(pa_context_get_source_info_list);
+LOAD_FUNC(pa_operation_get_state);
+LOAD_FUNC(pa_operation_unref);
+#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
+#undef LOAD_FUNC
+    }
+    return pa_handle;
+} //}}}
+
+// PulseAudio Event Callbacks //{{{
+static void context_state_callback(pa_context *context, void *pdata) //{{{
+{
+    pa_threaded_mainloop *loop = pdata;
+    pa_context_state_t state;
+
+    state = ppa_context_get_state(context);
+    if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state))
+        ppa_threaded_mainloop_signal(loop, 0);
+}//}}}
+
+static void stream_state_callback(pa_stream *stream, void *pdata) //{{{
+{
+    pa_threaded_mainloop *loop = pdata;
+    pa_stream_state_t state;
+
+    state = ppa_stream_get_state(stream);
+    if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state))
+        ppa_threaded_mainloop_signal(loop, 0);
+}//}}}
+
+static void stream_signal_callback(pa_stream *stream, void *pdata) //{{{
+{
+    ALCdevice *Device = pdata;
+    pulse_data *data = Device->ExtraData;
+    (void)stream;
+
+    ppa_threaded_mainloop_signal(data->loop, 0);
+}//}}}
+
+static void stream_buffer_attr_callback(pa_stream *stream, void *pdata) //{{{
+{
+    ALCdevice *Device = pdata;
+    pulse_data *data = Device->ExtraData;
+
+    SuspendContext(NULL);
+
+    data->attr = *(ppa_stream_get_buffer_attr(stream));
+    Device->UpdateSize = data->attr.minreq / data->frame_size;
+    Device->NumUpdates = (data->attr.tlength/data->frame_size) / Device->UpdateSize;
+    if(Device->NumUpdates <= 1)
+    {
+        Device->NumUpdates = 1;
+        AL_PRINT("PulseAudio returned minreq > tlength/2; expect break up\n");
+    }
+
+    ProcessContext(NULL);
+}//}}}
+
+static void stream_device_callback(pa_stream *stream, void *pdata) //{{{
+{
+    ALCdevice *Device = pdata;
+    pulse_data *data = Device->ExtraData;
+
+    free(data->device_name);
+    data->device_name = strdup(ppa_stream_get_device_name(stream));
+}//}}}
+
+static void context_state_callback2(pa_context *context, void *pdata) //{{{
+{
+    ALCdevice *Device = pdata;
+    pulse_data *data = Device->ExtraData;
+
+    if(ppa_context_get_state(context) == PA_CONTEXT_FAILED)
+    {
+        AL_PRINT("Received context failure!\n");
+        aluHandleDisconnect(Device);
+    }
+    ppa_threaded_mainloop_signal(data->loop, 0);
+}//}}}
+
+static void stream_state_callback2(pa_stream *stream, void *pdata) //{{{
+{
+    ALCdevice *Device = pdata;
+    pulse_data *data = Device->ExtraData;
+
+    if(ppa_stream_get_state(stream) == PA_STREAM_FAILED)
+    {
+        AL_PRINT("Received stream failure!\n");
+        aluHandleDisconnect(Device);
+    }
+    ppa_threaded_mainloop_signal(data->loop, 0);
+}//}}}
+
+static void stream_success_callback(pa_stream *stream, int success, void *pdata) //{{{
+{
+    ALCdevice *Device = pdata;
+    pulse_data *data = Device->ExtraData;
+    (void)stream;
+    (void)success;
+
+    ppa_threaded_mainloop_signal(data->loop, 0);
+}//}}}
+
+static void sink_info_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) //{{{
+{
+    ALCdevice *device = pdata;
+    pulse_data *data = device->ExtraData;
+    char chanmap_str[256] = "";
+    const struct {
+        const char *str;
+        enum DevFmtChannels chans;
+    } 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,rear-left,rear-right", DevFmtQuad },
+        { "front-left,front-right", DevFmtStereo },
+        { "mono", DevFmtMono },
+        { NULL, 0 }
+    };
+    int i;
+    (void)context;
+
+    if(eol)
+    {
+        ppa_threaded_mainloop_signal(data->loop, 0);
+        return;
+    }
+
+    for(i = 0;chanmaps[i].str;i++)
+    {
+        pa_channel_map map;
+        if(!ppa_channel_map_parse(&map, chanmaps[i].str))
+            continue;
+
+        if(ppa_channel_map_equal(&info->channel_map, &map)
+#if PA_CHECK_VERSION(0,9,15)
+           || (ppa_channel_map_superset &&
+               ppa_channel_map_superset(&info->channel_map, &map))
+#endif
+            )
+        {
+            device->FmtChans = chanmaps[i].chans;
+            return;
+        }
+    }
+
+    ppa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
+    AL_PRINT("Failed to find format for channel map:\n    %s\n", chanmap_str);
+}//}}}
+
+static void sink_device_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) //{{{
+{
+    pa_threaded_mainloop *loop = pdata;
+    char str[1024];
+    void *temp;
+    int count;
+    ALuint i;
+
+    (void)context;
+
+    if(eol)
+    {
+        ppa_threaded_mainloop_signal(loop, 0);
+        return;
+    }
+
+    count = 0;
+    do {
+        if(count == 0)
+            snprintf(str, sizeof(str), "%s via PulseAudio", info->description);
+        else
+            snprintf(str, sizeof(str), "%s #%d via PulseAudio", info->description, count+1);
+        count++;
+
+        for(i = 0;i < numDevNames;i++)
+        {
+            if(strcmp(str, allDevNameMap[i].name) == 0)
+                break;
+        }
+    } while(i != numDevNames);
+
+    temp = realloc(allDevNameMap, (numDevNames+1) * sizeof(*allDevNameMap));
+    if(temp)
+    {
+        allDevNameMap = temp;
+        allDevNameMap[numDevNames].name = strdup(str);
+        allDevNameMap[numDevNames].device_name = strdup(info->name);
+        numDevNames++;
+    }
+}//}}}
+
+static void source_device_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata) //{{{
+{
+    pa_threaded_mainloop *loop = pdata;
+    char str[1024];
+    void *temp;
+    int count;
+    ALuint i;
+
+    (void)context;
+
+    if(eol)
+    {
+        ppa_threaded_mainloop_signal(loop, 0);
+        return;
+    }
+
+    count = 0;
+    do {
+        if(count == 0)
+            snprintf(str, sizeof(str), "%s via PulseAudio", info->description);
+        else
+            snprintf(str, sizeof(str), "%s #%d via PulseAudio", info->description, count+1);
+        count++;
+
+        for(i = 0;i < numCaptureDevNames;i++)
+        {
+            if(strcmp(str, allCaptureDevNameMap[i].name) == 0)
+                break;
+        }
+    } while(i != numCaptureDevNames);
+
+    temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
+    if(temp)
+    {
+        allCaptureDevNameMap = temp;
+        allCaptureDevNameMap[numCaptureDevNames].name = strdup(str);
+        allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
+        numCaptureDevNames++;
+    }
+}//}}}
+//}}}
+
+// PulseAudio I/O Callbacks //{{{
+static void stream_write_callback(pa_stream *stream, size_t len, void *pdata) //{{{
+{
+    ALCdevice *Device = pdata;
+    pulse_data *data = Device->ExtraData;
+    (void)stream;
+    (void)len;
+
+    ppa_threaded_mainloop_signal(data->loop, 0);
+} //}}}
+//}}}
+
+static ALuint PulseProc(ALvoid *param)
+{
+    ALCdevice *Device = param;
+    pulse_data *data = Device->ExtraData;
+    ssize_t len;
+
+    SetRTPriority();
+
+    ppa_threaded_mainloop_lock(data->loop);
+    do {
+        len = (Device->Connected ? ppa_stream_writable_size(data->stream) : 0);
+        len -= len%(Device->UpdateSize*data->frame_size);
+        if(len == 0)
+        {
+            ppa_threaded_mainloop_wait(data->loop);
+            continue;
+        }
+
+        while(len > 0)
+        {
+            size_t newlen = len;
+            void *buf;
+            pa_free_cb_t free_func = NULL;
+
+#if PA_CHECK_VERSION(0,9,16)
+            if(!ppa_stream_begin_write ||
+               ppa_stream_begin_write(data->stream, &buf, &newlen) < 0)
+#endif
+            {
+                buf = ppa_xmalloc(newlen);
+                free_func = ppa_xfree;
+            }
+            ppa_threaded_mainloop_unlock(data->loop);
+
+            aluMixData(Device, buf, newlen/data->frame_size);
+
+            ppa_threaded_mainloop_lock(data->loop);
+            ppa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
+            len -= newlen;
+        }
+    } while(Device->Connected && !data->killNow);
+    ppa_threaded_mainloop_unlock(data->loop);
+
+    return 0;
+}
+
+static pa_context *connect_context(pa_threaded_mainloop *loop)
+{
+    const char *name = "OpenAL Soft";
+    char path_name[PATH_MAX];
+    pa_context_state_t state;
+    pa_context *context;
+    int err;
+
+    if(ppa_get_binary_name(path_name, sizeof(path_name)))
+        name = ppa_path_get_filename(path_name);
+
+    context = ppa_context_new(ppa_threaded_mainloop_get_api(loop), name);
+    if(!context)
+    {
+        AL_PRINT("pa_context_new() failed\n");
+        return NULL;
+    }
+
+    ppa_context_set_state_callback(context, context_state_callback, loop);
+
+    if((err=ppa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0)
+    {
+        while((state=ppa_context_get_state(context)) != PA_CONTEXT_READY)
+        {
+            if(!PA_CONTEXT_IS_GOOD(state))
+            {
+                err = ppa_context_errno(context);
+                if(err > 0)  err = -err;
+                break;
+            }
+
+            ppa_threaded_mainloop_wait(loop);
+        }
+    }
+    ppa_context_set_state_callback(context, NULL, NULL);
+
+    if(err < 0)
+    {
+        AL_PRINT("Context did not connect: %s\n", ppa_strerror(err));
+        ppa_context_unref(context);
+        return NULL;
+    }
+
+    return context;
+}
+
+static pa_stream *connect_playback_stream(ALCdevice *device,
+    pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
+    pa_channel_map *chanmap)
+{
+    pulse_data *data = device->ExtraData;
+    pa_stream_state_t state;
+    pa_stream *stream;
+
+    stream = ppa_stream_new(data->context, "Playback Stream", spec, chanmap);
+    if(!stream)
+    {
+        AL_PRINT("pa_stream_new() failed: %s\n",
+                 ppa_strerror(ppa_context_errno(data->context)));
+        return NULL;
+    }
+
+    ppa_stream_set_state_callback(stream, stream_state_callback, data->loop);
+
+    if(ppa_stream_connect_playback(stream, data->device_name, attr, flags, NULL, NULL) < 0)
+    {
+        AL_PRINT("Stream did not connect: %s\n",
+                 ppa_strerror(ppa_context_errno(data->context)));
+        ppa_stream_unref(stream);
+        return NULL;
+    }
+
+    while((state=ppa_stream_get_state(stream)) != PA_STREAM_READY)
+    {
+        if(!PA_STREAM_IS_GOOD(state))
+        {
+            AL_PRINT("Stream did not get ready: %s\n",
+                     ppa_strerror(ppa_context_errno(data->context)));
+            ppa_stream_unref(stream);
+            return NULL;
+        }
+
+        ppa_threaded_mainloop_wait(data->loop);
+    }
+    ppa_stream_set_state_callback(stream, NULL, NULL);
+
+    return stream;
+}
+
+static void probe_devices(ALboolean capture)
+{
+    pa_threaded_mainloop *loop;
+
+    if(capture == AL_FALSE)
+        allDevNameMap = malloc(sizeof(DevMap) * 1);
+    else
+        allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
+
+    if((loop=ppa_threaded_mainloop_new()) &&
+       ppa_threaded_mainloop_start(loop) >= 0)
+    {
+        pa_context *context;
+
+        ppa_threaded_mainloop_lock(loop);
+        context = connect_context(loop);
+        if(context)
+        {
+            pa_operation *o;
+
+            if(capture == AL_FALSE)
+            {
+                allDevNameMap[0].name = strdup(pulse_device);
+                allDevNameMap[0].device_name = NULL;
+                numDevNames = 1;
+
+                o = ppa_context_get_sink_info_list(context, sink_device_callback, loop);
+            }
+            else
+            {
+                allCaptureDevNameMap[0].name = strdup(pulse_device);
+                allCaptureDevNameMap[0].device_name = NULL;
+                numCaptureDevNames = 1;
+
+                o = ppa_context_get_source_info_list(context, source_device_callback, loop);
+            }
+            while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+                ppa_threaded_mainloop_wait(loop);
+            ppa_operation_unref(o);
+
+            ppa_context_disconnect(context);
+            ppa_context_unref(context);
+        }
+        ppa_threaded_mainloop_unlock(loop);
+        ppa_threaded_mainloop_stop(loop);
+    }
+    if(loop)
+        ppa_threaded_mainloop_free(loop);
+}
+
+
+static ALCboolean pulse_open(ALCdevice *device, const ALCchar *device_name) //{{{
+{
+    pulse_data *data = ppa_xmalloc(sizeof(pulse_data));
+    memset(data, 0, sizeof(*data));
+
+    if(!(data->loop = ppa_threaded_mainloop_new()))
+    {
+        AL_PRINT("pa_threaded_mainloop_new() failed!\n");
+        goto out;
+    }
+    if(ppa_threaded_mainloop_start(data->loop) < 0)
+    {
+        AL_PRINT("pa_threaded_mainloop_start() failed\n");
+        goto out;
+    }
+
+    ppa_threaded_mainloop_lock(data->loop);
+    device->ExtraData = data;
+
+    data->context = connect_context(data->loop);
+    if(!data->context)
+    {
+        ppa_threaded_mainloop_unlock(data->loop);
+        goto out;
+    }
+    ppa_context_set_state_callback(data->context, context_state_callback2, device);
+
+    device->szDeviceName = strdup(device_name);
+
+    ppa_threaded_mainloop_unlock(data->loop);
+    return ALC_TRUE;
+
+out:
+    if(data->loop)
+    {
+        ppa_threaded_mainloop_stop(data->loop);
+        ppa_threaded_mainloop_free(data->loop);
+    }
+
+    device->ExtraData = NULL;
+    ppa_xfree(data);
+    return ALC_FALSE;
+} //}}}
+
+static void pulse_close(ALCdevice *device) //{{{
+{
+    pulse_data *data = device->ExtraData;
+
+    ppa_threaded_mainloop_lock(data->loop);
+
+    if(data->stream)
+    {
+        ppa_stream_disconnect(data->stream);
+        ppa_stream_unref(data->stream);
+    }
+
+    ppa_context_disconnect(data->context);
+    ppa_context_unref(data->context);
+
+    ppa_threaded_mainloop_unlock(data->loop);
+
+    ppa_threaded_mainloop_stop(data->loop);
+    ppa_threaded_mainloop_free(data->loop);
+
+    DestroyRingBuffer(data->ring);
+    free(data->device_name);
+
+    device->ExtraData = NULL;
+    ppa_xfree(data);
+} //}}}
+//}}}
+
+// OpenAL {{{
+static ALCboolean pulse_open_playback(ALCdevice *device, const ALCchar *device_name) //{{{
+{
+    char *pulse_name = NULL;
+    pa_sample_spec spec;
+    pulse_data *data;
+
+    if(!pulse_load())
+        return ALC_FALSE;
+
+    if(!allDevNameMap)
+        probe_devices(AL_FALSE);
+
+    if(!device_name && numDevNames > 0)
+        device_name = allDevNameMap[0].name;
+    else
+    {
+        ALuint i;
+
+        for(i = 0;i < numDevNames;i++)
+        {
+            if(strcmp(device_name, allDevNameMap[i].name) == 0)
+            {
+                pulse_name = allDevNameMap[i].device_name;
+                break;
+            }
+        }
+        if(i == numDevNames)
+            return ALC_FALSE;
+    }
+
+    if(pulse_open(device, device_name) == ALC_FALSE)
+        return ALC_FALSE;
+
+    data = device->ExtraData;
+
+    ppa_threaded_mainloop_lock(data->loop);
+
+    spec.format = PA_SAMPLE_S16NE;
+    spec.rate = 44100;
+    spec.channels = 2;
+
+    data->device_name = pulse_name;
+    pa_stream *stream = connect_playback_stream(device, 0, NULL, &spec, NULL);
+    if(!stream)
+    {
+        ppa_threaded_mainloop_unlock(data->loop);
+        goto fail;
+    }
+
+    if(ppa_stream_is_suspended(stream))
+    {
+        AL_PRINT("Device is suspended\n");
+        ppa_stream_disconnect(stream);
+        ppa_stream_unref(stream);
+        ppa_threaded_mainloop_unlock(data->loop);
+        goto fail;
+    }
+    data->device_name = strdup(ppa_stream_get_device_name(stream));
+
+    ppa_stream_disconnect(stream);
+    ppa_stream_unref(stream);
+
+    ppa_threaded_mainloop_unlock(data->loop);
+
+    return ALC_TRUE;
+
+fail:
+    pulse_close(device);
+    return ALC_FALSE;
+} //}}}
+
+static void pulse_close_playback(ALCdevice *device) //{{{
+{
+    pulse_close(device);
+} //}}}
+
+static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{
+{
+    pulse_data *data = device->ExtraData;
+    pa_stream_flags_t flags = 0;
+    pa_channel_map chanmap;
+
+    ppa_threaded_mainloop_lock(data->loop);
+
+    if(!ConfigValueExists(NULL, "format"))
+    {
+        pa_operation *o;
+        o = ppa_context_get_sink_info_by_name(data->context, data->device_name, sink_info_callback, device);
+        while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+            ppa_threaded_mainloop_wait(data->loop);
+        ppa_operation_unref(o);
+    }
+    if(!ConfigValueExists(NULL, "frequency"))
+        flags |= PA_STREAM_FIX_RATE;
+
+    data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    data->attr.prebuf = -1;
+    data->attr.fragsize = -1;
+    data->attr.minreq = device->UpdateSize * data->frame_size;
+    data->attr.tlength = data->attr.minreq * device->NumUpdates;
+    if(data->attr.tlength < data->attr.minreq*2)
+        data->attr.tlength = data->attr.minreq*2;
+    data->attr.maxlength = data->attr.tlength;
+    flags |= PA_STREAM_EARLY_REQUESTS;
+    flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
+
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            device->FmtType = DevFmtUByte;
+            /* fall-through */
+        case DevFmtUByte:
+            data->spec.format = PA_SAMPLE_U8;
+            break;
+        case DevFmtUShort:
+            device->FmtType = DevFmtShort;
+            /* fall-through */
+        case DevFmtShort:
+            data->spec.format = PA_SAMPLE_S16NE;
+            break;
+        case DevFmtFloat:
+            data->spec.format = PA_SAMPLE_FLOAT32NE;
+            break;
+    }
+    data->spec.rate = device->Frequency;
+    data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
+
+    if(ppa_sample_spec_valid(&data->spec) == 0)
+    {
+        AL_PRINT("Invalid sample format\n");
+        ppa_threaded_mainloop_unlock(data->loop);
+        return ALC_FALSE;
+    }
+
+    if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
+    {
+        AL_PRINT("Couldn't build map for channel count (%d)!\n", data->spec.channels);
+        ppa_threaded_mainloop_unlock(data->loop);
+        return ALC_FALSE;
+    }
+    SetDefaultWFXChannelOrder(device);
+
+    data->stream = connect_playback_stream(device, flags, &data->attr, &data->spec, &chanmap);
+    if(!data->stream)
+    {
+        ppa_threaded_mainloop_unlock(data->loop);
+        return ALC_FALSE;
+    }
+
+    ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);
+
+    data->spec = *(ppa_stream_get_sample_spec(data->stream));
+    if(device->Frequency != data->spec.rate)
+    {
+        pa_operation *o;
+
+        /* Server updated our playback rate, so modify the buffer attribs
+         * accordingly. */
+        data->attr.minreq = (ALuint64)(data->attr.minreq/data->frame_size) *
+                            data->spec.rate / device->Frequency * data->frame_size;
+        data->attr.tlength = data->attr.minreq * device->NumUpdates;
+        data->attr.maxlength = data->attr.tlength;
+
+        o = ppa_stream_set_buffer_attr(data->stream, &data->attr,
+                                       stream_success_callback, device);
+        while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+            ppa_threaded_mainloop_wait(data->loop);
+        ppa_operation_unref(o);
+
+        device->Frequency = data->spec.rate;
+    }
+
+    stream_buffer_attr_callback(data->stream, device);
+#if PA_CHECK_VERSION(0,9,15)
+    if(ppa_stream_set_buffer_attr_callback)
+        ppa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device);
+#endif
+    ppa_stream_set_moved_callback(data->stream, stream_device_callback, device);
+    ppa_stream_set_write_callback(data->stream, stream_write_callback, device);
+    ppa_stream_set_underflow_callback(data->stream, stream_signal_callback, device);
+
+    data->thread = StartThread(PulseProc, device);
+    if(!data->thread)
+    {
+#if PA_CHECK_VERSION(0,9,15)
+        if(ppa_stream_set_buffer_attr_callback)
+            ppa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
+#endif
+        ppa_stream_set_moved_callback(data->stream, NULL, NULL);
+        ppa_stream_set_write_callback(data->stream, NULL, NULL);
+        ppa_stream_set_underflow_callback(data->stream, NULL, NULL);
+        ppa_stream_disconnect(data->stream);
+        ppa_stream_unref(data->stream);
+        data->stream = NULL;
+
+        ppa_threaded_mainloop_unlock(data->loop);
+        return ALC_FALSE;
+    }
+
+    ppa_threaded_mainloop_unlock(data->loop);
+    return ALC_TRUE;
+} //}}}
+
+static void pulse_stop_playback(ALCdevice *device) //{{{
+{
+    pulse_data *data = device->ExtraData;
+
+    if(!data->stream)
+        return;
+
+    data->killNow = AL_TRUE;
+    if(data->thread)
+    {
+        ppa_threaded_mainloop_signal(data->loop, 0);
+        StopThread(data->thread);
+        data->thread = NULL;
+    }
+    data->killNow = AL_FALSE;
+
+    ppa_threaded_mainloop_lock(data->loop);
+
+#if PA_CHECK_VERSION(0,9,15)
+    if(ppa_stream_set_buffer_attr_callback)
+        ppa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
+#endif
+    ppa_stream_set_moved_callback(data->stream, NULL, NULL);
+    ppa_stream_set_write_callback(data->stream, NULL, NULL);
+    ppa_stream_set_underflow_callback(data->stream, NULL, NULL);
+    ppa_stream_disconnect(data->stream);
+    ppa_stream_unref(data->stream);
+    data->stream = NULL;
+
+    ppa_threaded_mainloop_unlock(data->loop);
+} //}}}
+
+
+static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{
+{
+    char *pulse_name = NULL;
+    pulse_data *data;
+    pa_stream_flags_t flags = 0;
+    pa_stream_state_t state;
+    pa_channel_map chanmap;
+
+    if(!pulse_load())
+        return ALC_FALSE;
+
+    if(!allCaptureDevNameMap)
+        probe_devices(AL_TRUE);
+
+    if(!device_name && numCaptureDevNames > 0)
+        device_name = allCaptureDevNameMap[0].name;
+    else
+    {
+        ALuint i;
+
+        for(i = 0;i < numCaptureDevNames;i++)
+        {
+            if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0)
+            {
+                pulse_name = allCaptureDevNameMap[i].device_name;
+                break;
+            }
+        }
+        if(i == numCaptureDevNames)
+            return ALC_FALSE;
+    }
+
+    if(pulse_open(device, device_name) == ALC_FALSE)
+        return ALC_FALSE;
+
+    data = device->ExtraData;
+    ppa_threaded_mainloop_lock(data->loop);
+
+    data->samples = device->UpdateSize * device->NumUpdates;
+    data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+    if(data->samples < 100 * device->Frequency / 1000)
+        data->samples = 100 * device->Frequency / 1000;
+
+    if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples)))
+    {
+        ppa_threaded_mainloop_unlock(data->loop);
+        goto fail;
+    }
+
+    data->attr.minreq = -1;
+    data->attr.prebuf = -1;
+    data->attr.maxlength = data->samples * data->frame_size;
+    data->attr.tlength = -1;
+    data->attr.fragsize = min(data->samples, 50 * device->Frequency / 1000) *
+                          data->frame_size;
+
+    data->spec.rate = device->Frequency;
+    data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
+
+    switch(device->FmtType)
+    {
+        case DevFmtUByte:
+            data->spec.format = PA_SAMPLE_U8;
+            break;
+        case DevFmtShort:
+            data->spec.format = PA_SAMPLE_S16NE;
+            break;
+        case DevFmtFloat:
+            data->spec.format = PA_SAMPLE_FLOAT32NE;
+            break;
+        case DevFmtByte:
+        case DevFmtUShort:
+            AL_PRINT("Capture format type %#x capture not supported on PulseAudio\n", device->FmtType);
+            ppa_threaded_mainloop_unlock(data->loop);
+            goto fail;
+    }
+
+    if(ppa_sample_spec_valid(&data->spec) == 0)
+    {
+        AL_PRINT("Invalid sample format\n");
+        ppa_threaded_mainloop_unlock(data->loop);
+        goto fail;
+    }
+
+    if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
+    {
+        AL_PRINT("Couldn't build map for channel count (%d)!\n", data->spec.channels);
+        ppa_threaded_mainloop_unlock(data->loop);
+        goto fail;
+    }
+
+    data->stream = ppa_stream_new(data->context, "Capture Stream", &data->spec, &chanmap);
+    if(!data->stream)
+    {
+        AL_PRINT("pa_stream_new() failed: %s\n",
+                 ppa_strerror(ppa_context_errno(data->context)));
+
+        ppa_threaded_mainloop_unlock(data->loop);
+        goto fail;
+    }
+
+    ppa_stream_set_state_callback(data->stream, stream_state_callback, data->loop);
+
+    flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
+    if(ppa_stream_connect_record(data->stream, pulse_name, &data->attr, flags) < 0)
+    {
+        AL_PRINT("Stream did not connect: %s\n",
+                 ppa_strerror(ppa_context_errno(data->context)));
+
+        ppa_stream_unref(data->stream);
+        data->stream = NULL;
+
+        ppa_threaded_mainloop_unlock(data->loop);
+        goto fail;
+    }
+
+    while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
+    {
+        if(!PA_STREAM_IS_GOOD(state))
+        {
+            AL_PRINT("Stream did not get ready: %s\n",
+                     ppa_strerror(ppa_context_errno(data->context)));
+
+            ppa_stream_unref(data->stream);
+            data->stream = NULL;
+
+            ppa_threaded_mainloop_unlock(data->loop);
+            goto fail;
+        }
+
+        ppa_threaded_mainloop_wait(data->loop);
+    }
+    ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);
+
+    ppa_threaded_mainloop_unlock(data->loop);
+    return ALC_TRUE;
+
+fail:
+    pulse_close(device);
+    return ALC_FALSE;
+} //}}}
+
+static void pulse_close_capture(ALCdevice *device) //{{{
+{
+    pulse_close(device);
+} //}}}
+
+static void pulse_start_capture(ALCdevice *device) //{{{
+{
+    pulse_data *data = device->ExtraData;
+    pa_operation *o;
+
+    ppa_threaded_mainloop_lock(data->loop);
+    o = ppa_stream_cork(data->stream, 0, stream_success_callback, device);
+    while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+        ppa_threaded_mainloop_wait(data->loop);
+    ppa_operation_unref(o);
+    ppa_threaded_mainloop_unlock(data->loop);
+} //}}}
+
+static void pulse_stop_capture(ALCdevice *device) //{{{
+{
+    pulse_data *data = device->ExtraData;
+    pa_operation *o;
+
+    ppa_threaded_mainloop_lock(data->loop);
+    o = ppa_stream_cork(data->stream, 1, stream_success_callback, device);
+    while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
+        ppa_threaded_mainloop_wait(data->loop);
+    ppa_operation_unref(o);
+    ppa_threaded_mainloop_unlock(data->loop);
+} //}}}
+
+static ALCuint pulse_available_samples(ALCdevice *device) //{{{
+{
+    pulse_data *data = device->ExtraData;
+    size_t samples;
+
+    ppa_threaded_mainloop_lock(data->loop);
+    /* Capture is done in fragment-sized chunks, so we loop until we get all
+     * that's available */
+    samples = (device->Connected ? ppa_stream_readable_size(data->stream) : 0);
+    while(samples > 0)
+    {
+        const void *buf;
+        size_t length;
+
+        if(ppa_stream_peek(data->stream, &buf, &length) < 0)
+        {
+            AL_PRINT("pa_stream_peek() failed: %s\n",
+                     ppa_strerror(ppa_context_errno(data->context)));
+            break;
+        }
+
+        WriteRingBuffer(data->ring, buf, length/data->frame_size);
+        samples -= length;
+
+        ppa_stream_drop(data->stream);
+    }
+    ppa_threaded_mainloop_unlock(data->loop);
+
+    return RingBufferSize(data->ring);
+} //}}}
+
+static void pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{
+{
+    pulse_data *data = device->ExtraData;
+
+    if(pulse_available_samples(device) >= samples)
+        ReadRingBuffer(data->ring, buffer, samples);
+    else
+        alcSetError(device, ALC_INVALID_VALUE);
+} //}}}
+
+
+BackendFuncs pulse_funcs = { //{{{
+    pulse_open_playback,
+    pulse_close_playback,
+    pulse_reset_playback,
+    pulse_stop_playback,
+    pulse_open_capture,
+    pulse_close_capture,
+    pulse_start_capture,
+    pulse_stop_capture,
+    pulse_capture_samples,
+    pulse_available_samples
+}; //}}}
+
+void alc_pulse_init(BackendFuncs *func_list) //{{{
+{
+    *func_list = pulse_funcs;
+
+    pulse_ctx_flags = 0;
+    if(!GetConfigValueBool("pulse", "spawn-server", 0))
+        pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
+} //}}}
+
+void alc_pulse_deinit(void) //{{{
+{
+    ALuint i;
+
+    for(i = 0;i < numDevNames;++i)
+    {
+        free(allDevNameMap[i].name);
+        free(allDevNameMap[i].device_name);
+    }
+    free(allDevNameMap);
+    allDevNameMap = NULL;
+    numDevNames = 0;
+
+    for(i = 0;i < numCaptureDevNames;++i)
+    {
+        free(allCaptureDevNameMap[i].name);
+        free(allCaptureDevNameMap[i].device_name);
+    }
+    free(allCaptureDevNameMap);
+    allCaptureDevNameMap = NULL;
+    numCaptureDevNames = 0;
+
+    if(pa_handle)
+    {
+#ifdef _WIN32
+        FreeLibrary(pa_handle);
+#elif defined (HAVE_DLFCN_H)
+        dlclose(pa_handle);
+#endif
+        pa_handle = NULL;
+    }
+} //}}}
+
+void alc_pulse_probe(int type) //{{{
+{
+    if(!pulse_load()) return;
+
+    if(type == DEVICE_PROBE)
+    {
+        pa_threaded_mainloop *loop;
+
+        if((loop=ppa_threaded_mainloop_new()) &&
+           ppa_threaded_mainloop_start(loop) >= 0)
+        {
+            pa_context *context;
+
+            ppa_threaded_mainloop_lock(loop);
+            context = connect_context(loop);
+            if(context)
+            {
+                AppendDeviceList(pulse_device);
+
+                ppa_context_disconnect(context);
+                ppa_context_unref(context);
+            }
+            ppa_threaded_mainloop_unlock(loop);
+            ppa_threaded_mainloop_stop(loop);
+        }
+        if(loop)
+            ppa_threaded_mainloop_free(loop);
+    }
+    else if(type == ALL_DEVICE_PROBE)
+    {
+        ALuint i;
+
+        for(i = 0;i < numDevNames;++i)
+        {
+            free(allDevNameMap[i].name);
+            free(allDevNameMap[i].device_name);
+        }
+        free(allDevNameMap);
+        allDevNameMap = NULL;
+        numDevNames = 0;
+
+        probe_devices(AL_FALSE);
+
+        for(i = 0;i < numDevNames;i++)
+            AppendAllDeviceList(allDevNameMap[i].name);
+    }
+    else if(type == CAPTURE_DEVICE_PROBE)
+    {
+        ALuint i;
+
+        for(i = 0;i < numCaptureDevNames;++i)
+        {
+            free(allCaptureDevNameMap[i].name);
+            free(allCaptureDevNameMap[i].device_name);
+        }
+        free(allCaptureDevNameMap);
+        allCaptureDevNameMap = NULL;
+        numCaptureDevNames = 0;
+
+        probe_devices(AL_TRUE);
+
+        for(i = 0;i < numCaptureDevNames;i++)
+            AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
+    }
+} //}}}
+//}}}
diff --git a/Alc/solaris.c b/Alc/solaris.c
new file mode 100644 (file)
index 0000000..18c7334
--- /dev/null
@@ -0,0 +1,304 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#include <sys/audioio.h>
+
+
+static const ALCchar solaris_device[] = "Solaris Default";
+
+typedef struct {
+    int fd;
+    volatile int killNow;
+    ALvoid *thread;
+
+    ALubyte *mix_data;
+    int data_size;
+} solaris_data;
+
+
+static ALuint SolarisProc(ALvoid *ptr)
+{
+    ALCdevice *pDevice = (ALCdevice*)ptr;
+    solaris_data *data = (solaris_data*)pDevice->ExtraData;
+    ALint frameSize;
+    int wrote;
+
+    SetRTPriority();
+
+    frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+    while(!data->killNow && pDevice->Connected)
+    {
+        ALint len = data->data_size;
+        ALubyte *WritePtr = data->mix_data;
+
+        aluMixData(pDevice, WritePtr, len/frameSize);
+        while(len > 0 && !data->killNow)
+        {
+            wrote = write(data->fd, WritePtr, len);
+            if(wrote < 0)
+            {
+                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
+                {
+                    AL_PRINT("write failed: %s\n", strerror(errno));
+                    aluHandleDisconnect(pDevice);
+                    break;
+                }
+
+                Sleep(1);
+                continue;
+            }
+
+            len -= wrote;
+            WritePtr += wrote;
+        }
+    }
+
+    return 0;
+}
+
+
+static ALCboolean solaris_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+    char driver[64];
+    solaris_data *data;
+
+    strncpy(driver, GetConfigValue("solaris", "device", "/dev/audio"), sizeof(driver)-1);
+    driver[sizeof(driver)-1] = 0;
+
+    if(!deviceName)
+        deviceName = solaris_device;
+    else if(strcmp(deviceName, solaris_device) != 0)
+        return ALC_FALSE;
+
+    data = (solaris_data*)calloc(1, sizeof(solaris_data));
+    data->killNow = 0;
+
+    data->fd = open(driver, O_WRONLY);
+    if(data->fd == -1)
+    {
+        free(data);
+        AL_PRINT("Could not open %s: %s\n", driver, strerror(errno));
+        return ALC_FALSE;
+    }
+
+    device->szDeviceName = strdup(deviceName);
+    device->ExtraData = data;
+    return ALC_TRUE;
+}
+
+static void solaris_close_playback(ALCdevice *device)
+{
+    solaris_data *data = (solaris_data*)device->ExtraData;
+
+    close(data->fd);
+    free(data);
+    device->ExtraData = NULL;
+}
+
+static ALCboolean solaris_reset_playback(ALCdevice *device)
+{
+    solaris_data *data = (solaris_data*)device->ExtraData;
+    audio_info_t info;
+    ALuint frameSize;
+    int numChannels;
+
+    AUDIO_INITINFO(&info);
+
+    info.play.sample_rate = device->Frequency;
+
+    if(device->FmtChans != DevFmtMono)
+        device->FmtChans = DevFmtStereo;
+    numChannels = ChannelsFromDevFmt(device->FmtChans);
+    info.play.channels = numChannels;
+
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            info.play.precision = 8;
+            info.play.encoding = AUDIO_ENCODING_LINEAR;
+            break;
+        case DevFmtUByte:
+            info.play.precision = 8;
+            info.play.encoding = AUDIO_ENCODING_LINEAR8;
+            break;
+        case DevFmtUShort:
+        case DevFmtFloat:
+            device->FmtType = DevFmtShort;
+            /* fall-through */
+        case DevFmtShort:
+            info.play.precision = 16;
+            info.play.encoding = AUDIO_ENCODING_LINEAR;
+            break;
+    }
+
+    frameSize = numChannels * BytesFromDevFmt(device->FmtType);
+    info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize;
+
+    if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0)
+    {
+        AL_PRINT("ioctl failed: %s\n", strerror(errno));
+        return ALC_FALSE;
+    }
+
+    if(ChannelsFromDevFmt(device->FmtChans) != info.play.channels)
+    {
+        AL_PRINT("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), info.play.channels);
+        return ALC_FALSE;
+    }
+
+    if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR &&
+          device->FmtType == DevFmtByte) ||
+         (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 &&
+          device->FmtType == DevFmtUByte) ||
+         (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR &&
+          device->FmtType == DevFmtShort)))
+    {
+        AL_PRINT("Could not set %#x sample type, got %d (%#x)\n",
+                 device->FmtType, info.play.precision, info.play.encoding);
+        return ALC_FALSE;
+    }
+
+    device->Frequency = info.play.sample_rate;
+    device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1;
+
+    data->data_size = device->UpdateSize * frameSize;
+    data->mix_data = calloc(1, data->data_size);
+
+    SetDefaultChannelOrder(device);
+
+    data->thread = StartThread(SolarisProc, device);
+    if(data->thread == NULL)
+    {
+        free(data->mix_data);
+        data->mix_data = NULL;
+        return ALC_FALSE;
+    }
+
+    return ALC_TRUE;
+}
+
+static void solaris_stop_playback(ALCdevice *device)
+{
+    solaris_data *data = (solaris_data*)device->ExtraData;
+
+    if(!data->thread)
+        return;
+
+    data->killNow = 1;
+    StopThread(data->thread);
+    data->thread = NULL;
+
+    data->killNow = 0;
+    if(ioctl(data->fd, AUDIO_DRAIN) < 0)
+        AL_PRINT("Error draining device: %s\n", strerror(errno));
+
+    free(data->mix_data);
+    data->mix_data = NULL;
+}
+
+
+static ALCboolean solaris_open_capture(ALCdevice *device, const ALCchar *deviceName)
+{
+    (void)device;
+    (void)deviceName;
+    return ALC_FALSE;
+}
+
+static void solaris_close_capture(ALCdevice *device)
+{
+    (void)device;
+}
+
+static void solaris_start_capture(ALCdevice *pDevice)
+{
+    (void)pDevice;
+}
+
+static void solaris_stop_capture(ALCdevice *pDevice)
+{
+    (void)pDevice;
+}
+
+static void solaris_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+    (void)pDevice;
+    (void)pBuffer;
+    (void)lSamples;
+}
+
+static ALCuint solaris_available_samples(ALCdevice *pDevice)
+{
+    (void)pDevice;
+    return 0;
+}
+
+
+BackendFuncs solaris_funcs = {
+    solaris_open_playback,
+    solaris_close_playback,
+    solaris_reset_playback,
+    solaris_stop_playback,
+    solaris_open_capture,
+    solaris_close_capture,
+    solaris_start_capture,
+    solaris_stop_capture,
+    solaris_capture_samples,
+    solaris_available_samples
+};
+
+void alc_solaris_init(BackendFuncs *func_list)
+{
+    *func_list = solaris_funcs;
+}
+
+void alc_solaris_deinit(void)
+{
+}
+
+void alc_solaris_probe(int type)
+{
+#ifdef HAVE_STAT
+    struct stat buf;
+    if(stat(GetConfigValue("solaris", "device", "/dev/audio"), &buf) != 0)
+        return;
+#endif
+
+    if(type == DEVICE_PROBE)
+        AppendDeviceList(solaris_device);
+    else if(type == ALL_DEVICE_PROBE)
+        AppendAllDeviceList(solaris_device);
+}
diff --git a/Alc/wave.c b/Alc/wave.c
new file mode 100644 (file)
index 0000000..6ba662c
--- /dev/null
@@ -0,0 +1,355 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+
+typedef struct {
+    FILE *f;
+    long DataStart;
+
+    ALvoid *buffer;
+    ALuint size;
+
+    volatile int killNow;
+    ALvoid *thread;
+} wave_data;
+
+
+static const ALCchar waveDevice[] = "Wave File Writer";
+
+static const ALubyte SUBTYPE_PCM[] = {
+    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
+    0x00, 0x38, 0x9b, 0x71
+};
+static const ALubyte SUBTYPE_FLOAT[] = {
+    0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa,
+    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 void fwrite16le(ALushort val, FILE *f)
+{
+    fputc(val&0xff, f);
+    fputc((val>>8)&0xff, f);
+}
+
+static void fwrite32le(ALuint val, FILE *f)
+{
+    fputc(val&0xff, f);
+    fputc((val>>8)&0xff, f);
+    fputc((val>>16)&0xff, f);
+    fputc((val>>24)&0xff, f);
+}
+
+
+static ALuint WaveProc(ALvoid *ptr)
+{
+    ALCdevice *pDevice = (ALCdevice*)ptr;
+    wave_data *data = (wave_data*)pDevice->ExtraData;
+    ALuint frameSize;
+    ALuint now, start;
+    ALuint64 avail, done;
+    size_t fs;
+    union {
+        short s;
+        char b[sizeof(short)];
+    } uSB;
+    const ALuint restTime = (ALuint64)pDevice->UpdateSize * 1000 /
+                            pDevice->Frequency / 2;
+
+    uSB.s = 1;
+    frameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+    done = 0;
+    start = timeGetTime();
+    while(!data->killNow && pDevice->Connected)
+    {
+        now = timeGetTime();
+
+        avail = (ALuint64)(now-start) * pDevice->Frequency / 1000;
+        if(avail < done)
+        {
+            /* Timer wrapped. Add the remainder of the cycle to the available
+             * count and reset the number of samples done */
+            avail += (ALuint64)0xFFFFFFFFu*pDevice->Frequency/1000 - done;
+            done = 0;
+        }
+        if(avail-done < pDevice->UpdateSize)
+        {
+            Sleep(restTime);
+            continue;
+        }
+
+        while(avail-done >= pDevice->UpdateSize)
+        {
+            aluMixData(pDevice, data->buffer, pDevice->UpdateSize);
+            done += pDevice->UpdateSize;
+
+            if(uSB.b[0] != 1)
+            {
+                ALuint bytesize = BytesFromDevFmt(pDevice->FmtType);
+                ALubyte *bytes = data->buffer;
+                ALuint i;
+
+                if(bytesize == 1)
+                {
+                    for(i = 0;i < data->size;i++)
+                        fputc(bytes[i], data->f);
+                }
+                else if(bytesize == 2)
+                {
+                    for(i = 0;i < data->size;i++)
+                        fputc(bytes[i^1], data->f);
+                }
+                else if(bytesize == 4)
+                {
+                    for(i = 0;i < data->size;i++)
+                        fputc(bytes[i^3], data->f);
+                }
+            }
+            else
+                fs = fwrite(data->buffer, frameSize, pDevice->UpdateSize,
+                            data->f);
+            if(ferror(data->f))
+            {
+                AL_PRINT("Error writing to file\n");
+                aluHandleDisconnect(pDevice);
+                break;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceName)
+{
+    wave_data *data;
+    const char *fname;
+
+    fname = GetConfigValue("wave", "file", "");
+    if(!fname[0])
+        return ALC_FALSE;
+
+    if(!deviceName)
+        deviceName = waveDevice;
+    else if(strcmp(deviceName, waveDevice) != 0)
+        return ALC_FALSE;
+
+    data = (wave_data*)calloc(1, sizeof(wave_data));
+
+    data->f = fopen(fname, "wb");
+    if(!data->f)
+    {
+        free(data);
+        AL_PRINT("Could not open file '%s': %s\n", fname, strerror(errno));
+        return ALC_FALSE;
+    }
+
+    device->szDeviceName = strdup(deviceName);
+    device->ExtraData = data;
+    return ALC_TRUE;
+}
+
+static void wave_close_playback(ALCdevice *device)
+{
+    wave_data *data = (wave_data*)device->ExtraData;
+
+    fclose(data->f);
+    free(data);
+    device->ExtraData = NULL;
+}
+
+static ALCboolean wave_reset_playback(ALCdevice *device)
+{
+    wave_data *data = (wave_data*)device->ExtraData;
+    ALuint channels=0, bits=0;
+    size_t val;
+
+    fseek(data->f, 0, SEEK_SET);
+    clearerr(data->f);
+
+    switch(device->FmtType)
+    {
+        case DevFmtByte:
+            device->FmtType = DevFmtUByte;
+            break;
+        case DevFmtUShort:
+            device->FmtType = DevFmtShort;
+            break;
+        case DevFmtUByte:
+        case DevFmtShort:
+        case DevFmtFloat:
+            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(data->f, "WAVE");
+
+    fprintf(data->f, "fmt ");
+    fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE
+
+    // 16-bit val, format type id (extensible: 0xFFFE)
+    fwrite16le(0xFFFE, data->f);
+    // 16-bit val, channel count
+    fwrite16le(channels, data->f);
+    // 32-bit val, frequency
+    fwrite32le(device->Frequency, data->f);
+    // 32-bit val, bytes per second
+    fwrite32le(device->Frequency * channels * bits / 8, data->f);
+    // 16-bit val, frame size
+    fwrite16le(channels * bits / 8, data->f);
+    // 16-bit val, bits per sample
+    fwrite16le(bits, data->f);
+    // 16-bit val, extra byte count
+    fwrite16le(22, data->f);
+    // 16-bit val, valid bits per sample
+    fwrite16le(bits, data->f);
+    // 32-bit val, channel mask
+    fwrite32le(channel_masks[channels], data->f);
+    // 16 byte GUID, sub-type format
+    val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f);
+
+    fprintf(data->f, "data");
+    fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close
+
+    if(ferror(data->f))
+    {
+        AL_PRINT("Error writing header: %s\n", strerror(errno));
+        return ALC_FALSE;
+    }
+
+    data->DataStart = ftell(data->f);
+
+    data->size = device->UpdateSize * channels * bits / 8;
+    data->buffer = malloc(data->size);
+    if(!data->buffer)
+    {
+        AL_PRINT("buffer malloc failed\n");
+        return ALC_FALSE;
+    }
+
+    SetDefaultWFXChannelOrder(device);
+
+    data->thread = StartThread(WaveProc, device);
+    if(data->thread == NULL)
+    {
+        free(data->buffer);
+        data->buffer = NULL;
+        return ALC_FALSE;
+    }
+
+    return ALC_TRUE;
+}
+
+static void wave_stop_playback(ALCdevice *device)
+{
+    wave_data *data = (wave_data*)device->ExtraData;
+    ALuint dataLen;
+    long size;
+
+    if(!data->thread)
+        return;
+
+    data->killNow = 1;
+    StopThread(data->thread);
+    data->thread = NULL;
+
+    data->killNow = 0;
+
+    free(data->buffer);
+    data->buffer = NULL;
+
+    size = ftell(data->f);
+    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
+    }
+}
+
+
+static ALCboolean wave_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+    (void)pDevice;
+    (void)deviceName;
+    return ALC_FALSE;
+}
+
+
+BackendFuncs wave_funcs = {
+    wave_open_playback,
+    wave_close_playback,
+    wave_reset_playback,
+    wave_stop_playback,
+    wave_open_capture,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+void alc_wave_init(BackendFuncs *func_list)
+{
+    *func_list = wave_funcs;
+}
+
+void alc_wave_deinit(void)
+{
+}
+
+void alc_wave_probe(int type)
+{
+    if(!ConfigValueExists("wave", "file"))
+        return;
+
+    if(type == DEVICE_PROBE)
+        AppendDeviceList(waveDevice);
+    else if(type == ALL_DEVICE_PROBE)
+        AppendAllDeviceList(waveDevice);
+}
diff --git a/Alc/winmm.c b/Alc/winmm.c
new file mode 100644 (file)
index 0000000..10d0c28
--- /dev/null
@@ -0,0 +1,784 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#define _WIN32_WINNT 0x0500
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+
+typedef struct {
+    // MMSYSTEM Device
+    volatile ALboolean bWaveShutdown;
+    HANDLE  hWaveHdrEvent;
+    HANDLE  hWaveThreadEvent;
+    HANDLE  hWaveThread;
+    DWORD   ulWaveThreadID;
+    LONG    lWaveBuffersCommitted;
+    WAVEHDR WaveBuffer[4];
+
+    union {
+        HWAVEIN  In;
+        HWAVEOUT Out;
+    } hWaveHandle;
+
+    ALsizei Frequency;
+
+    RingBuffer *pRing;
+} WinMMData;
+
+
+static const ALCchar woDefault[] = "WaveOut Default";
+
+static ALCchar **PlaybackDeviceList;
+static ALuint  NumPlaybackDevices;
+static ALCchar **CaptureDeviceList;
+static ALuint  NumCaptureDevices;
+
+
+static void ProbePlaybackDevices(void)
+{
+    ALuint i;
+
+    for(i = 0;i < NumPlaybackDevices;i++)
+        free(PlaybackDeviceList[i]);
+
+    NumPlaybackDevices = waveOutGetNumDevs();
+    PlaybackDeviceList = realloc(PlaybackDeviceList, sizeof(ALCchar*) * NumPlaybackDevices);
+    for(i = 0;i < NumPlaybackDevices;i++)
+    {
+        WAVEOUTCAPS WaveCaps;
+
+        PlaybackDeviceList[i] = NULL;
+        if(waveOutGetDevCaps(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR)
+        {
+            char name[1024];
+            ALuint count, j;
+
+            count = 0;
+            do {
+                if(count == 0)
+                    snprintf(name, sizeof(name), "%s via WaveOut", WaveCaps.szPname);
+                else
+                    snprintf(name, sizeof(name), "%s #%d via WaveOut", WaveCaps.szPname, count+1);
+                count++;
+
+                for(j = 0;j < i;j++)
+                {
+                    if(strcmp(name, PlaybackDeviceList[j]) == 0)
+                        break;
+                }
+            } while(j != i);
+
+            PlaybackDeviceList[i] = strdup(name);
+        }
+    }
+}
+
+static void ProbeCaptureDevices(void)
+{
+    ALuint i;
+
+    for(i = 0;i < NumCaptureDevices;i++)
+        free(CaptureDeviceList[i]);
+
+    NumCaptureDevices = waveInGetNumDevs();
+    CaptureDeviceList = realloc(CaptureDeviceList, sizeof(ALCchar*) * NumCaptureDevices);
+    for(i = 0;i < NumCaptureDevices;i++)
+    {
+        WAVEINCAPS WaveInCaps;
+
+        CaptureDeviceList[i] = NULL;
+        if(waveInGetDevCaps(i, &WaveInCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR)
+        {
+            char name[1024];
+            ALuint count, j;
+
+            count = 0;
+            do {
+                if(count == 0)
+                    snprintf(name, sizeof(name), "%s via WaveIn", WaveInCaps.szPname);
+                else
+                    snprintf(name, sizeof(name), "%s #%d via WaveIn", WaveInCaps.szPname, count+1);
+                count++;
+
+                for(j = 0;j < i;j++)
+                {
+                    if(strcmp(name, CaptureDeviceList[j]) == 0)
+                        break;
+                }
+            } while(j != i);
+
+            CaptureDeviceList[i] = strdup(name);
+        }
+    }
+}
+
+
+/*
+    WaveOutProc
+
+    Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and
+    returns to the application (for more data)
+*/
+static void CALLBACK WaveOutProc(HWAVEOUT hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
+{
+    ALCdevice *pDevice = (ALCdevice*)dwInstance;
+    WinMMData *pData = pDevice->ExtraData;
+
+    (void)hDevice;
+    (void)dwParam2;
+
+    if(uMsg != WOM_DONE)
+        return;
+
+    // Decrement number of buffers in use
+    InterlockedDecrement(&pData->lWaveBuffersCommitted);
+
+    if(pData->bWaveShutdown == AL_FALSE)
+    {
+        // Notify Wave Processor Thread that a Wave Header has returned
+        PostThreadMessage(pData->ulWaveThreadID, uMsg, 0, dwParam1);
+    }
+    else
+    {
+        if(pData->lWaveBuffersCommitted == 0)
+        {
+            // Signal Wave Buffers Returned event
+            if(pData->hWaveHdrEvent)
+                SetEvent(pData->hWaveHdrEvent);
+
+            // Post 'Quit' Message to WaveOut Processor Thread
+            PostThreadMessage(pData->ulWaveThreadID, WM_QUIT, 0, 0);
+        }
+    }
+}
+
+/*
+    PlaybackThreadProc
+
+    Used by "MMSYSTEM" Device.  Called when a WaveOut buffer has used up its
+    audio data.
+*/
+static DWORD WINAPI PlaybackThreadProc(LPVOID lpParameter)
+{
+    ALCdevice *pDevice = (ALCdevice*)lpParameter;
+    WinMMData *pData = pDevice->ExtraData;
+    LPWAVEHDR pWaveHdr;
+    ALuint FrameSize;
+    MSG msg;
+
+    FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+    while(GetMessage(&msg, NULL, 0, 0))
+    {
+        if(msg.message != WOM_DONE || pData->bWaveShutdown)
+            continue;
+
+        pWaveHdr = ((LPWAVEHDR)msg.lParam);
+
+        aluMixData(pDevice, pWaveHdr->lpData, pWaveHdr->dwBufferLength/FrameSize);
+
+        // Send buffer back to play more data
+        waveOutWrite(pData->hWaveHandle.Out, pWaveHdr, sizeof(WAVEHDR));
+        InterlockedIncrement(&pData->lWaveBuffersCommitted);
+    }
+
+    // Signal Wave Thread completed event
+    if(pData->hWaveThreadEvent)
+        SetEvent(pData->hWaveThreadEvent);
+
+    ExitThread(0);
+
+    return 0;
+}
+
+/*
+    WaveInProc
+
+    Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and
+    returns to the application (with more data)
+*/
+static void CALLBACK WaveInProc(HWAVEIN hDevice,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
+{
+    ALCdevice *pDevice = (ALCdevice*)dwInstance;
+    WinMMData *pData = pDevice->ExtraData;
+
+    (void)hDevice;
+    (void)dwParam2;
+
+    if(uMsg != WIM_DATA)
+        return;
+
+    // Decrement number of buffers in use
+    InterlockedDecrement(&pData->lWaveBuffersCommitted);
+
+    if(pData->bWaveShutdown == AL_FALSE)
+    {
+        // Notify Wave Processor Thread that a Wave Header has returned
+        PostThreadMessage(pData->ulWaveThreadID,uMsg,0,dwParam1);
+    }
+    else
+    {
+        if(pData->lWaveBuffersCommitted == 0)
+        {
+            // Signal Wave Buffers Returned event
+            if(pData->hWaveHdrEvent)
+                SetEvent(pData->hWaveHdrEvent);
+
+            // Post 'Quit' Message to WaveIn Processor Thread
+            PostThreadMessage(pData->ulWaveThreadID,WM_QUIT,0,0);
+        }
+    }
+}
+
+/*
+    CaptureThreadProc
+
+    Used by "MMSYSTEM" Device.  Called when a WaveIn buffer had been filled with new
+    audio data.
+*/
+static DWORD WINAPI CaptureThreadProc(LPVOID lpParameter)
+{
+    ALCdevice *pDevice = (ALCdevice*)lpParameter;
+    WinMMData *pData = pDevice->ExtraData;
+    LPWAVEHDR pWaveHdr;
+    ALuint FrameSize;
+    MSG msg;
+
+    FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
+
+    while(GetMessage(&msg, NULL, 0, 0))
+    {
+        if(msg.message != WIM_DATA || pData->bWaveShutdown)
+            continue;
+
+        pWaveHdr = ((LPWAVEHDR)msg.lParam);
+
+        WriteRingBuffer(pData->pRing, (ALubyte*)pWaveHdr->lpData,
+                        pWaveHdr->dwBytesRecorded/FrameSize);
+
+        // Send buffer back to capture more data
+        waveInAddBuffer(pData->hWaveHandle.In,pWaveHdr,sizeof(WAVEHDR));
+        InterlockedIncrement(&pData->lWaveBuffersCommitted);
+    }
+
+    // Signal Wave Thread completed event
+    if(pData->hWaveThreadEvent)
+        SetEvent(pData->hWaveThreadEvent);
+
+    ExitThread(0);
+
+    return 0;
+}
+
+
+static ALCboolean WinMMOpenPlayback(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+    WAVEFORMATEX wfexFormat;
+    WinMMData *pData = NULL;
+    UINT lDeviceID = 0;
+    MMRESULT res;
+    ALuint i = 0;
+
+    // Find the Device ID matching the deviceName if valid
+    if(!deviceName || strcmp(deviceName, woDefault) == 0)
+        lDeviceID = WAVE_MAPPER;
+    else
+    {
+        if(!PlaybackDeviceList)
+            ProbePlaybackDevices();
+
+        for(i = 0;i < NumPlaybackDevices;i++)
+        {
+            if(PlaybackDeviceList[i] &&
+               strcmp(deviceName, PlaybackDeviceList[i]) == 0)
+            {
+                lDeviceID = i;
+                break;
+            }
+        }
+        if(i == NumPlaybackDevices)
+            return ALC_FALSE;
+    }
+
+    pData = calloc(1, sizeof(*pData));
+    if(!pData)
+    {
+        alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+        return ALC_FALSE;
+    }
+    pDevice->ExtraData = pData;
+
+    if(pDevice->FmtChans != DevFmtMono)
+        pDevice->FmtChans = DevFmtStereo;
+    switch(pDevice->FmtType)
+    {
+        case DevFmtByte:
+            pDevice->FmtType = DevFmtUByte;
+            break;
+        case DevFmtUShort:
+        case DevFmtFloat:
+            pDevice->FmtType = DevFmtShort;
+            break;
+        case DevFmtUByte:
+        case DevFmtShort:
+            break;
+    }
+
+    memset(&wfexFormat, 0, sizeof(WAVEFORMATEX));
+    wfexFormat.wFormatTag = WAVE_FORMAT_PCM;
+    wfexFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
+    wfexFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
+    wfexFormat.nBlockAlign = wfexFormat.wBitsPerSample *
+                             wfexFormat.nChannels / 8;
+    wfexFormat.nSamplesPerSec = pDevice->Frequency;
+    wfexFormat.nAvgBytesPerSec = wfexFormat.nSamplesPerSec *
+                                 wfexFormat.nBlockAlign;
+    wfexFormat.cbSize = 0;
+
+    if((res=waveOutOpen(&pData->hWaveHandle.Out, lDeviceID, &wfexFormat, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
+    {
+        AL_PRINT("waveInOpen failed: %u\n", res);
+        goto failure;
+    }
+
+    pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveOutAllHeadersReturned");
+    pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveOutThreadDestroyed");
+    if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL)
+    {
+        AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
+        goto failure;
+    }
+
+    pData->Frequency = pDevice->Frequency;
+
+    pDevice->szDeviceName = strdup((lDeviceID==WAVE_MAPPER) ? woDefault :
+                                   PlaybackDeviceList[lDeviceID]);
+    return ALC_TRUE;
+
+failure:
+    if(pData->hWaveThreadEvent)
+        CloseHandle(pData->hWaveThreadEvent);
+    if(pData->hWaveHdrEvent)
+        CloseHandle(pData->hWaveHdrEvent);
+
+    if(pData->hWaveHandle.Out)
+        waveOutClose(pData->hWaveHandle.Out);
+
+    free(pData);
+    pDevice->ExtraData = NULL;
+    return ALC_FALSE;
+}
+
+static void WinMMClosePlayback(ALCdevice *device)
+{
+    WinMMData *pData = (WinMMData*)device->ExtraData;
+
+    // Close the Wave device
+    CloseHandle(pData->hWaveThreadEvent);
+    pData->hWaveThreadEvent = 0;
+
+    CloseHandle(pData->hWaveHdrEvent);
+    pData->hWaveHdrEvent = 0;
+
+    waveInClose(pData->hWaveHandle.In);
+    pData->hWaveHandle.In = 0;
+
+    free(pData);
+    device->ExtraData = NULL;
+}
+
+static ALCboolean WinMMResetPlayback(ALCdevice *device)
+{
+    WinMMData *pData = (WinMMData*)device->ExtraData;
+    ALbyte *BufferData;
+    ALint lBufferSize;
+    ALuint i;
+
+    pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PlaybackThreadProc, (LPVOID)device, 0, &pData->ulWaveThreadID);
+    if(pData->hWaveThread == NULL)
+        return ALC_FALSE;
+
+    device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
+                                  pData->Frequency / device->Frequency);
+    device->Frequency = pData->Frequency;
+
+    pData->lWaveBuffersCommitted = 0;
+
+    // Create 4 Buffers
+    lBufferSize  = device->UpdateSize*device->NumUpdates / 4;
+    lBufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
+
+    BufferData = calloc(4, lBufferSize);
+    for(i = 0;i < 4;i++)
+    {
+        memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
+        pData->WaveBuffer[i].dwBufferLength = lBufferSize;
+        pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
+                                       (pData->WaveBuffer[i-1].lpData +
+                                        pData->WaveBuffer[i-1].dwBufferLength));
+        waveOutPrepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+        waveOutWrite(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+        InterlockedIncrement(&pData->lWaveBuffersCommitted);
+    }
+
+    return ALC_TRUE;
+}
+
+static void WinMMStopPlayback(ALCdevice *device)
+{
+    WinMMData *pData = (WinMMData*)device->ExtraData;
+    int i;
+
+    if(pData->hWaveThread == NULL)
+        return;
+
+    // Set flag to stop processing headers
+    pData->bWaveShutdown = AL_TRUE;
+
+    // Wait for signal that all Wave Buffers have returned
+    WaitForSingleObjectEx(pData->hWaveHdrEvent, 5000, FALSE);
+
+    // Wait for signal that Wave Thread has been destroyed
+    WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
+
+    CloseHandle(pData->hWaveThread);
+    pData->hWaveThread = 0;
+
+    pData->bWaveShutdown = AL_FALSE;
+
+    // Release the wave buffers
+    for(i = 0;i < 4;i++)
+    {
+        waveOutUnprepareHeader(pData->hWaveHandle.Out, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+        if(i == 0)
+            free(pData->WaveBuffer[i].lpData);
+        pData->WaveBuffer[i].lpData = NULL;
+    }
+}
+
+
+static ALCboolean WinMMOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
+{
+    WAVEFORMATEX wfexCaptureFormat;
+    DWORD ulCapturedDataSize;
+    WinMMData *pData = NULL;
+    UINT lDeviceID = 0;
+    ALbyte *BufferData;
+    ALint lBufferSize;
+    MMRESULT res;
+    ALuint i;
+
+    if(!CaptureDeviceList)
+        ProbeCaptureDevices();
+
+    // Find the Device ID matching the deviceName if valid
+    if(deviceName)
+    {
+        for(i = 0;i < NumCaptureDevices;i++)
+        {
+            if(CaptureDeviceList[i] &&
+               strcmp(deviceName, CaptureDeviceList[i]) == 0)
+            {
+                lDeviceID = i;
+                break;
+            }
+        }
+    }
+    else
+    {
+        for(i = 0;i < NumCaptureDevices;i++)
+        {
+            if(CaptureDeviceList[i])
+            {
+                lDeviceID = i;
+                break;
+            }
+        }
+    }
+    if(i == NumCaptureDevices)
+        return ALC_FALSE;
+
+    pData = calloc(1, sizeof(*pData));
+    if(!pData)
+    {
+        alcSetError(pDevice, ALC_OUT_OF_MEMORY);
+        return ALC_FALSE;
+    }
+    pDevice->ExtraData = pData;
+
+    if((pDevice->FmtChans != DevFmtMono && pDevice->FmtChans != DevFmtStereo) ||
+       (pDevice->FmtType != DevFmtUByte && pDevice->FmtType != DevFmtShort))
+    {
+        alcSetError(pDevice, ALC_INVALID_ENUM);
+        goto failure;
+    }
+
+    memset(&wfexCaptureFormat, 0, sizeof(WAVEFORMATEX));
+    wfexCaptureFormat.wFormatTag = WAVE_FORMAT_PCM;
+    wfexCaptureFormat.nChannels = ChannelsFromDevFmt(pDevice->FmtChans);
+    wfexCaptureFormat.wBitsPerSample = BytesFromDevFmt(pDevice->FmtType) * 8;
+    wfexCaptureFormat.nBlockAlign = wfexCaptureFormat.wBitsPerSample *
+                                    wfexCaptureFormat.nChannels / 8;
+    wfexCaptureFormat.nSamplesPerSec = pDevice->Frequency;
+    wfexCaptureFormat.nAvgBytesPerSec = wfexCaptureFormat.nSamplesPerSec *
+                                        wfexCaptureFormat.nBlockAlign;
+    wfexCaptureFormat.cbSize = 0;
+
+    if((res=waveInOpen(&pData->hWaveHandle.In, lDeviceID, &wfexCaptureFormat, (DWORD_PTR)&WaveInProc, (DWORD_PTR)pDevice, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
+    {
+        AL_PRINT("waveInOpen failed: %u\n", res);
+        goto failure;
+    }
+
+    pData->hWaveHdrEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInAllHeadersReturned");
+    pData->hWaveThreadEvent = CreateEvent(NULL, AL_TRUE, AL_FALSE, "WaveInThreadDestroyed");
+    if(pData->hWaveHdrEvent == NULL || pData->hWaveThreadEvent == NULL)
+    {
+        AL_PRINT("CreateEvent failed: %lu\n", GetLastError());
+        goto failure;
+    }
+
+    pData->Frequency = pDevice->Frequency;
+
+    // Allocate circular memory buffer for the captured audio
+    ulCapturedDataSize = pDevice->UpdateSize*pDevice->NumUpdates;
+
+    // Make sure circular buffer is at least 100ms in size
+    if(ulCapturedDataSize < (wfexCaptureFormat.nSamplesPerSec / 10))
+        ulCapturedDataSize = wfexCaptureFormat.nSamplesPerSec / 10;
+
+    pData->pRing = CreateRingBuffer(wfexCaptureFormat.nBlockAlign, ulCapturedDataSize);
+    if(!pData->pRing)
+        goto failure;
+
+    pData->lWaveBuffersCommitted = 0;
+
+    // Create 4 Buffers of 50ms each
+    lBufferSize = wfexCaptureFormat.nAvgBytesPerSec / 20;
+    lBufferSize -= (lBufferSize % wfexCaptureFormat.nBlockAlign);
+
+    BufferData = calloc(4, lBufferSize);
+    if(!BufferData)
+        goto failure;
+
+    for(i = 0;i < 4;i++)
+    {
+        memset(&pData->WaveBuffer[i], 0, sizeof(WAVEHDR));
+        pData->WaveBuffer[i].dwBufferLength = lBufferSize;
+        pData->WaveBuffer[i].lpData = ((i==0) ? (LPSTR)BufferData :
+                                       (pData->WaveBuffer[i-1].lpData +
+                                        pData->WaveBuffer[i-1].dwBufferLength));
+        pData->WaveBuffer[i].dwFlags = 0;
+        pData->WaveBuffer[i].dwLoops = 0;
+        waveInPrepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+        waveInAddBuffer(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+        InterlockedIncrement(&pData->lWaveBuffersCommitted);
+    }
+
+    pData->hWaveThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CaptureThreadProc, (LPVOID)pDevice, 0, &pData->ulWaveThreadID);
+    if (pData->hWaveThread == NULL)
+        goto failure;
+
+    pDevice->szDeviceName = strdup(CaptureDeviceList[lDeviceID]);
+    return ALC_TRUE;
+
+failure:
+    if(pData->hWaveThread)
+        CloseHandle(pData->hWaveThread);
+
+    for(i = 0;i < 4;i++)
+    {
+        if(pData->WaveBuffer[i].lpData)
+        {
+            waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+            if(i == 0)
+                free(pData->WaveBuffer[i].lpData);
+        }
+    }
+
+    if(pData->pRing)
+        DestroyRingBuffer(pData->pRing);
+
+    if(pData->hWaveThreadEvent)
+        CloseHandle(pData->hWaveThreadEvent);
+    if(pData->hWaveHdrEvent)
+        CloseHandle(pData->hWaveHdrEvent);
+
+    if(pData->hWaveHandle.In)
+        waveInClose(pData->hWaveHandle.In);
+
+    free(pData);
+    pDevice->ExtraData = NULL;
+    return ALC_FALSE;
+}
+
+static void WinMMCloseCapture(ALCdevice *pDevice)
+{
+    WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+    int i;
+
+    // Call waveOutReset to shutdown wave device
+    pData->bWaveShutdown = AL_TRUE;
+    waveInReset(pData->hWaveHandle.In);
+
+    // Wait for signal that all Wave Buffers have returned
+    WaitForSingleObjectEx(pData->hWaveHdrEvent, 5000, FALSE);
+
+    // Wait for signal that Wave Thread has been destroyed
+    WaitForSingleObjectEx(pData->hWaveThreadEvent, 5000, FALSE);
+
+    CloseHandle(pData->hWaveThread);
+    pData->hWaveThread = 0;
+
+    // Release the wave buffers
+    for(i = 0;i < 4;i++)
+    {
+        waveInUnprepareHeader(pData->hWaveHandle.In, &pData->WaveBuffer[i], sizeof(WAVEHDR));
+        if(i == 0)
+            free(pData->WaveBuffer[i].lpData);
+        pData->WaveBuffer[i].lpData = NULL;
+    }
+
+    DestroyRingBuffer(pData->pRing);
+    pData->pRing = NULL;
+
+    // Close the Wave device
+    CloseHandle(pData->hWaveThreadEvent);
+    pData->hWaveThreadEvent = 0;
+
+    CloseHandle(pData->hWaveHdrEvent);
+    pData->hWaveHdrEvent = 0;
+
+    waveInClose(pData->hWaveHandle.In);
+    pData->hWaveHandle.In = 0;
+
+    free(pData);
+    pDevice->ExtraData = NULL;
+}
+
+static void WinMMStartCapture(ALCdevice *pDevice)
+{
+    WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+    waveInStart(pData->hWaveHandle.In);
+}
+
+static void WinMMStopCapture(ALCdevice *pDevice)
+{
+    WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+    waveInStop(pData->hWaveHandle.In);
+}
+
+static ALCuint WinMMAvailableSamples(ALCdevice *pDevice)
+{
+    WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+    return RingBufferSize(pData->pRing);
+}
+
+static void WinMMCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
+{
+    WinMMData *pData = (WinMMData*)pDevice->ExtraData;
+
+    if(WinMMAvailableSamples(pDevice) >= lSamples)
+        ReadRingBuffer(pData->pRing, pBuffer, lSamples);
+    else
+        alcSetError(pDevice, ALC_INVALID_VALUE);
+}
+
+
+static BackendFuncs WinMMFuncs = {
+    WinMMOpenPlayback,
+    WinMMClosePlayback,
+    WinMMResetPlayback,
+    WinMMStopPlayback,
+    WinMMOpenCapture,
+    WinMMCloseCapture,
+    WinMMStartCapture,
+    WinMMStopCapture,
+    WinMMCaptureSamples,
+    WinMMAvailableSamples
+};
+
+void alcWinMMInit(BackendFuncs *FuncList)
+{
+    *FuncList = WinMMFuncs;
+}
+
+void alcWinMMDeinit()
+{
+    ALuint lLoop;
+
+    for(lLoop = 0;lLoop < NumPlaybackDevices;lLoop++)
+        free(PlaybackDeviceList[lLoop]);
+    free(PlaybackDeviceList);
+    PlaybackDeviceList = NULL;
+
+    NumPlaybackDevices = 0;
+
+
+    for(lLoop = 0; lLoop < NumCaptureDevices; lLoop++)
+        free(CaptureDeviceList[lLoop]);
+    free(CaptureDeviceList);
+    CaptureDeviceList = NULL;
+
+    NumCaptureDevices = 0;
+}
+
+void alcWinMMProbe(int type)
+{
+    ALuint i;
+
+    if(type == DEVICE_PROBE)
+    {
+        ProbePlaybackDevices();
+        if(NumPlaybackDevices > 0)
+            AppendDeviceList(woDefault);
+    }
+    else if(type == ALL_DEVICE_PROBE)
+    {
+        ProbePlaybackDevices();
+        if(NumPlaybackDevices > 0)
+            AppendAllDeviceList(woDefault);
+        for(i = 0;i < NumPlaybackDevices;i++)
+        {
+            if(PlaybackDeviceList[i])
+                AppendAllDeviceList(PlaybackDeviceList[i]);
+        }
+    }
+    else if(type == CAPTURE_DEVICE_PROBE)
+    {
+        ProbeCaptureDevices();
+        for(i = 0;i < NumCaptureDevices;i++)
+        {
+            if(CaptureDeviceList[i])
+                AppendCaptureDeviceList(CaptureDeviceList[i]);
+        }
+    }
+}
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..2365f69
--- /dev/null
@@ -0,0 +1,563 @@
+# CMake build file list for OpenAL
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
+
+IF(COMMAND CMAKE_POLICY)
+  CMAKE_POLICY(SET CMP0003 NEW)
+ENDIF(COMMAND CMAKE_POLICY)
+
+SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+INCLUDE(CheckFunctionExists)
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckSharedLibraryExists)
+INCLUDE(CheckIncludeFile)
+INCLUDE(CheckIncludeFiles)
+INCLUDE(CheckSymbolExists)
+INCLUDE(CheckCCompilerFlag)
+INCLUDE(CheckCSourceCompiles)
+INCLUDE(CheckTypeSize)
+
+
+PROJECT(OpenAL C)
+
+
+SET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS TRUE)
+
+
+OPTION(ALSA    "Check for ALSA backend"                ON)
+OPTION(OSS     "Check for OSS backend"                 ON)
+OPTION(SOLARIS "Check for Solaris backend"             ON)
+OPTION(DSOUND  "Check for DirectSound backend"         ON)
+OPTION(WINMM   "Check for Windows Multimedia backend"  ON)
+OPTION(PORTAUDIO  "Check for PortAudio backend"        ON)
+OPTION(PULSEAUDIO "Check for PulseAudio backend"       ON)
+OPTION(WAVE    "Enable Wave Writer backend"            ON)
+OPTION(AVSYSTEM    "Check for Avsystem backend"        ON)
+
+OPTION(DLOPEN  "Check for the dlopen API for loading optional libs"  ON)
+
+OPTION(WERROR  "Treat compile warnings as errors"      OFF)
+
+OPTION(UTILS  "Build and install utility programs"  ON)
+
+OPTION(ALSOFT_CONFIG "Install alsoft.conf configuration file" ON)
+
+
+IF(WIN32)
+    SET(LIBNAME OpenAL32)
+    ADD_DEFINITIONS("-D_WIN32")
+ELSE()
+    SET(LIBNAME openal)
+ENDIF()
+
+IF(NOT LIBTYPE)
+    SET(LIBTYPE SHARED)
+ENDIF()
+
+SET(LIB_MAJOR_VERSION "1")
+SET(LIB_MINOR_VERSION "13")
+SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}")
+
+
+CHECK_TYPE_SIZE("long" SIZEOF_LONG)
+CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
+CHECK_TYPE_SIZE("unsigned int" SIZEOF_UINT)
+CHECK_TYPE_SIZE("void*" SIZEOF_VOIDP)
+
+
+# Add definitions, compiler switches, etc.
+INCLUDE_DIRECTORIES(OpenAL32/Include include "${OpenAL_BINARY_DIR}")
+
+IF(NOT CMAKE_BUILD_TYPE)
+    SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
+        "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
+        FORCE)
+ENDIF()
+IF(NOT CMAKE_DEBUG_POSTFIX)
+    SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING
+        "Library postfix for debug builds. Normally left blank."
+        FORCE)
+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)
+
+    IF(NOT DXSDK_DIR)
+        STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "$ENV{DXSDK_DIR}")
+    ELSE()
+        STRING(REGEX REPLACE "\\\\" "/" DXSDK_DIR "${DXSDK_DIR}")
+    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)
+    IF(FORCE_STATIC_VCRT)
+        FOREACH(flag_var
+                CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+                CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
+            IF(${flag_var} MATCHES "/MD")
+                STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+            ENDIF()
+        ENDFOREACH(flag_var)
+    ENDIF()
+ELSE()
+    ADD_DEFINITIONS(-Winline -Wall)
+    CHECK_C_COMPILER_FLAG(-Wextra HAVE_W_EXTRA)
+    IF(HAVE_W_EXTRA)
+        ADD_DEFINITIONS(-Wextra)
+    ENDIF()
+
+    IF(WERROR)
+        ADD_DEFINITIONS(-Werror)
+    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)
+
+    CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor));
+                             int main() {return 0;}" HAVE_GCC_DESTRUCTOR)
+
+    # Set visibility options if available
+    IF(NOT WIN32)
+        CHECK_C_COMPILER_FLAG(-fvisibility=internal HAVE_VISIBILITY_SWITCH)
+        IF(HAVE_VISIBILITY_SWITCH)
+            CHECK_C_SOURCE_COMPILES("int foo() __attribute__((visibility(\"default\")));
+                                     int main() {return 0;}" HAVE_GCC_VISIBILITY)
+            IF(HAVE_GCC_VISIBILITY)
+                ADD_DEFINITIONS(-fvisibility=internal -DHAVE_GCC_VISIBILITY)
+            ENDIF()
+        ENDIF()
+    ENDIF()
+ENDIF()
+
+CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(printf, 1, 2)));
+                         int main() {return 0;}" HAVE_GCC_FORMAT)
+
+CHECK_INCLUDE_FILE(fenv.h HAVE_FENV_H)
+CHECK_INCLUDE_FILE(float.h HAVE_FLOAT_H)
+
+CHECK_LIBRARY_EXISTS(m  powf   "" HAVE_POWF)
+CHECK_LIBRARY_EXISTS(m  sqrtf  "" HAVE_SQRTF)
+CHECK_LIBRARY_EXISTS(m  acosf  "" HAVE_ACOSF)
+CHECK_LIBRARY_EXISTS(m  atanf  "" HAVE_ATANF)
+CHECK_LIBRARY_EXISTS(m  fabsf  "" HAVE_FABSF)
+IF(HAVE_FENV_H)
+    CHECK_LIBRARY_EXISTS(m  fesetround  "" HAVE_FESETROUND)
+ENDIF()
+IF(HAVE_SQRTF OR HAVE_ACOSF OR HAVE_ATANF OR HAVE_FABSF OR HAVE_FESETROUND)
+    SET(EXTRA_LIBS m ${EXTRA_LIBS})
+ENDIF()
+CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF)
+CHECK_FUNCTION_EXISTS(_controlfp HAVE__CONTROLFP)
+
+CHECK_FUNCTION_EXISTS(stat HAVE_STAT)
+CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP)
+IF(NOT HAVE_STRCASECMP)
+    CHECK_FUNCTION_EXISTS(_stricmp HAVE__STRICMP)
+    IF(NOT HAVE__STRICMP)
+        MESSAGE(FATAL_ERROR "No case-insensitive compare function found, please report!")
+    ENDIF()
+
+    ADD_DEFINITIONS(-Dstrcasecmp=_stricmp)
+ENDIF()
+
+CHECK_FUNCTION_EXISTS(strncasecmp HAVE_STRNCASECMP)
+IF(NOT HAVE_STRNCASECMP)
+    CHECK_FUNCTION_EXISTS(_strnicmp HAVE__STRNICMP)
+    IF(NOT HAVE__STRNICMP)
+        MESSAGE(FATAL_ERROR "No case-insensitive size-limitted compare function found, please report!")
+    ENDIF()
+
+    ADD_DEFINITIONS(-Dstrncasecmp=_strnicmp)
+ENDIF()
+
+CHECK_FUNCTION_EXISTS(snprintf HAVE_SNPRINTF)
+IF(NOT HAVE_SNPRINTF)
+    CHECK_FUNCTION_EXISTS(_snprintf HAVE__SNPRINTF)
+    IF(NOT HAVE__SNPRINTF)
+        MESSAGE(FATAL_ERROR "No snprintf function found, please report!")
+    ENDIF()
+
+    ADD_DEFINITIONS(-Dsnprintf=_snprintf)
+ENDIF()
+
+CHECK_FUNCTION_EXISTS(vsnprintf HAVE_VSNPRINTF)
+IF(NOT HAVE_VSNPRINTF)
+    CHECK_FUNCTION_EXISTS(_vsnprintf HAVE__VSNPRINTF)
+    IF(NOT HAVE__VSNPRINTF)
+        MESSAGE(FATAL_ERROR "No vsnprintf function found, please report!")
+    ENDIF()
+
+    ADD_DEFINITIONS(-Dvsnprintf=_vsnprintf)
+ENDIF()
+
+CHECK_SYMBOL_EXISTS(isnan math.h HAVE_ISNAN)
+IF(NOT HAVE_ISNAN)
+    CHECK_FUNCTION_EXISTS(_isnan HAVE__ISNAN)
+    IF(NOT HAVE__ISNAN)
+        MESSAGE(FATAL_ERROR "No isnan function found, please report!")
+    ENDIF()
+
+    ADD_DEFINITIONS(-Disnan=_isnan)
+ENDIF()
+
+
+# Check for the dlopen API (for dynamicly loading backend libs)
+IF(DLOPEN)
+    CHECK_INCLUDE_FILE(dlfcn.h HAVE_DLFCN_H)
+    IF(HAVE_DLFCN_H)
+        CHECK_LIBRARY_EXISTS(dl dlopen "" HAVE_LIBDL)
+        IF(HAVE_LIBDL)
+            SET(EXTRA_LIBS dl ${EXTRA_LIBS})
+        ENDIF()
+    ENDIF()
+ENDIF()
+
+# Check if we have Windows headers
+CHECK_INCLUDE_FILE(windows.h HAVE_WINDOWS_H -D_WIN32_WINNT=0x0500)
+IF(NOT HAVE_WINDOWS_H)
+    CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY)
+    IF(NOT HAVE_GETTIMEOFDAY)
+        MESSAGE(FATAL_ERROR "No timing function found!")
+    ENDIF()
+
+    CHECK_FUNCTION_EXISTS(nanosleep HAVE_NANOSLEEP)
+    IF(NOT HAVE_NANOSLEEP)
+        MESSAGE(FATAL_ERROR "No sleep function found!")
+    ENDIF()
+
+    CHECK_C_COMPILER_FLAG(-pthread HAVE_PTHREAD)
+    IF(HAVE_PTHREAD)
+        ADD_DEFINITIONS(-pthread)
+        SET(EXTRA_LIBS ${EXTRA_LIBS} -pthread)
+    ENDIF()
+
+    # We need pthreads outside of Windows
+    CHECK_INCLUDE_FILE(pthread.h HAVE_PTHREAD_H)
+    IF(NOT HAVE_PTHREAD_H)
+        MESSAGE(FATAL_ERROR "PThreads is required for non-Windows builds!")
+    ENDIF()
+    # Some systems need pthread_np.h to get recursive mutexes
+    CHECK_INCLUDE_FILES("pthread.h;pthread_np.h" HAVE_PTHREAD_NP_H)
+
+    # _GNU_SOURCE is needed on some systems for extra attributes, and
+    # _REENTRANT is needed for libc thread-safety
+    ADD_DEFINITIONS(-D_GNU_SOURCE=1)
+    CHECK_LIBRARY_EXISTS(pthread pthread_create "" HAVE_LIBPTHREAD)
+    IF(HAVE_LIBPTHREAD)
+        SET(EXTRA_LIBS pthread ${EXTRA_LIBS})
+    ENDIF()
+
+    CHECK_LIBRARY_EXISTS(pthread pthread_setschedparam "" HAVE_PTHREAD_SETSCHEDPARAM)
+
+    CHECK_LIBRARY_EXISTS(rt clock_gettime "" HAVE_LIBRT)
+    IF(HAVE_LIBRT)
+        SET(EXTRA_LIBS rt ${EXTRA_LIBS})
+    ENDIF()
+ENDIF()
+
+# Check for a 64-bit type
+CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT_H)
+IF(NOT HAVE_STDINT_H)
+    IF(HAVE_WINDOWS_H)
+        CHECK_C_SOURCE_COMPILES("\#define _WIN32_WINNT 0x0500
+                                 \#include <windows.h>
+                                 __int64 foo;
+                                 int main() {return 0;}" HAVE___INT64)
+    ENDIF()
+    IF(NOT HAVE___INT64)
+        IF(NOT SIZEOF_LONG MATCHES "8")
+            IF(NOT SIZEOF_LONG_LONG MATCHES "8")
+                MESSAGE(FATAL_ERROR "No 64-bit types found, please report!")
+            ENDIF()
+        ENDIF()
+    ENDIF()
+ENDIF()
+
+IF(WIN32)
+    # Windows needs winmm for timeGetTime, even if the backend is disabled
+    CHECK_SHARED_LIBRARY_EXISTS(winmm timeGetTime 0 "" HAVE_LIBWINMM)
+    IF(HAVE_LIBWINMM)
+        SET(EXTRA_LIBS winmm ${EXTRA_LIBS})
+        SET(PKG_CONFIG_LIBS ${PKG_CONFIG_LIBS} -lwinmm)
+    ENDIF()
+ENDIF()
+
+
+SET(OPENAL_OBJS  OpenAL32/alAuxEffectSlot.c
+                 OpenAL32/alBuffer.c
+                 OpenAL32/alDatabuffer.c
+                 OpenAL32/alEffect.c
+                 OpenAL32/alError.c
+                 OpenAL32/alExtension.c
+                 OpenAL32/alFilter.c
+                 OpenAL32/alListener.c
+                 OpenAL32/alSource.c
+                 OpenAL32/alState.c
+                 OpenAL32/alThunk.c
+)
+SET(ALC_OBJS  Alc/ALc.c
+              Alc/ALu.c
+              Alc/alcConfig.c
+              Alc/alcEcho.c
+              Alc/alcModulator.c
+              Alc/alcReverb.c
+              Alc/alcRing.c
+              Alc/alcThread.c
+              Alc/bs2b.c
+              Alc/mixer.c
+              Alc/panning.c
+              Alc/null.c
+)
+
+SET(BACKENDS "")
+SET(HAVE_ALSA       0)
+SET(HAVE_OSS        0)
+SET(HAVE_SOLARIS    0)
+SET(HAVE_DSOUND     0)
+SET(HAVE_WINMM      0)
+SET(HAVE_PORTAUDIO  0)
+SET(HAVE_PULSEAUDIO 0)
+SET(HAVE_WAVE       0)
+SET(HAVE_AVSYSTEM   0)
+
+# Check ALSA backend
+IF(ALSA)
+    CHECK_INCLUDE_FILE(alsa/asoundlib.h HAVE_ALSA_ASOUNDLIB_H)
+    IF(HAVE_ALSA_ASOUNDLIB_H)
+        CHECK_SHARED_LIBRARY_EXISTS(asound snd_pcm_open 4 "" HAVE_LIBASOUND)
+        IF(HAVE_LIBASOUND OR HAVE_DLFCN_H OR WIN32)
+            SET(HAVE_ALSA 1)
+            SET(ALC_OBJS  ${ALC_OBJS} Alc/alsa.c)
+            IF(HAVE_DLFCN_H OR WIN32)
+                SET(BACKENDS  "${BACKENDS} ALSA,")
+            ELSE()
+                SET(BACKENDS  "${BACKENDS} ALSA \(linked\),")
+                SET(EXTRA_LIBS asound ${EXTRA_LIBS})
+            ENDIF()
+        ENDIF()
+    ENDIF()
+ENDIF()
+
+# Check OSS backend
+IF(OSS)
+    CHECK_INCLUDE_FILE(sys/soundcard.h HAVE_SYS_SOUNDCARD_H)
+    IF(HAVE_SYS_SOUNDCARD_H)
+        SET(HAVE_OSS 1)
+        SET(ALC_OBJS  ${ALC_OBJS} Alc/oss.c)
+        SET(BACKENDS  "${BACKENDS} OSS,")
+    ENDIF()
+ENDIF()
+
+# Check Solaris backend
+IF(SOLARIS)
+    CHECK_INCLUDE_FILE(sys/audioio.h HAVE_SYS_AUDIOIO_H)
+    IF(HAVE_SYS_AUDIOIO_H)
+        SET(HAVE_SOLARIS 1)
+        SET(ALC_OBJS  ${ALC_OBJS} Alc/solaris.c)
+        SET(BACKENDS  "${BACKENDS} Solaris,")
+    ENDIF()
+ENDIF()
+
+# Check DSound/MMSystem backend
+IF(DSOUND)
+    CHECK_INCLUDE_FILE(dsound.h HAVE_DSOUND_H)
+    IF(HAVE_DSOUND_H)
+        CHECK_SHARED_LIBRARY_EXISTS(dsound DirectSoundCreate 3 "" HAVE_LIBDSOUND)
+        IF(HAVE_LIBDSOUND OR HAVE_DLFCN_H OR WIN32)
+            SET(HAVE_DSOUND 1)
+            SET(ALC_OBJS  ${ALC_OBJS} Alc/dsound.c)
+
+            IF(HAVE_DLFCN_H OR WIN32)
+                SET(BACKENDS  "${BACKENDS} DirectSound,")
+            ELSE()
+                SET(BACKENDS  "${BACKENDS} DirectSound \(linked\),")
+                SET(EXTRA_LIBS dsound ${EXTRA_LIBS})
+            ENDIF()
+        ENDIF()
+    ENDIF()
+ENDIF()
+
+IF(HAVE_WINDOWS_H)
+    IF(WINMM)
+        CHECK_INCLUDE_FILES("windows.h;mmsystem.h" HAVE_MMSYSTEM_H -D_WIN32_WINNT=0x0500)
+        IF(HAVE_MMSYSTEM_H AND HAVE_LIBWINMM)
+            SET(HAVE_WINMM 1)
+            SET(ALC_OBJS  ${ALC_OBJS} Alc/winmm.c)
+            SET(BACKENDS  "${BACKENDS} WinMM,")
+        ENDIF()
+    ENDIF()
+ENDIF()
+
+# Check PortAudio backend
+IF(PORTAUDIO)
+    CHECK_INCLUDE_FILE(portaudio.h HAVE_PORTAUDIO_H)
+    IF(HAVE_PORTAUDIO_H)
+        CHECK_SHARED_LIBRARY_EXISTS(portaudio Pa_Initialize 0 "" HAVE_LIBPORTAUDIO)
+        IF(HAVE_LIBPORTAUDIO OR HAVE_DLFCN_H OR WIN32)
+            SET(HAVE_PORTAUDIO 1)
+            SET(ALC_OBJS  ${ALC_OBJS} Alc/portaudio.c)
+            IF(HAVE_DLFCN_H OR WIN32)
+                SET(BACKENDS  "${BACKENDS} PortAudio,")
+            ELSE()
+                SET(BACKENDS  "${BACKENDS} PortAudio \(linked\),")
+                SET(EXTRA_LIBS portaudio ${EXTRA_LIBS})
+            ENDIF()
+        ENDIF()
+    ENDIF()
+ENDIF()
+
+# Check PortAudio backend
+IF(PULSEAUDIO)
+    CHECK_INCLUDE_FILE(pulse/pulseaudio.h HAVE_PULSE_PULSEAUDIO_H)
+    IF(HAVE_PULSE_PULSEAUDIO_H)
+        CHECK_SHARED_LIBRARY_EXISTS(pulse pa_context_new 2 "" HAVE_LIBPULSE)
+        IF(HAVE_LIBPULSE OR HAVE_DLFCN_H OR WIN32)
+            SET(HAVE_PULSEAUDIO 1)
+            SET(ALC_OBJS  ${ALC_OBJS} Alc/pulseaudio.c)
+            IF(HAVE_DLFCN_H OR WIN32)
+                SET(BACKENDS  "${BACKENDS} PulseAudio,")
+            ELSE()
+                SET(BACKENDS  "${BACKENDS} PulseAudio \(linked\),")
+                SET(EXTRA_LIBS pulse ${EXTRA_LIBS})
+            ENDIF()
+        ENDIF()
+    ENDIF()
+ENDIF()
+
+# Optionally enable the Wave Writer backend
+IF(WAVE)
+    SET(HAVE_WAVE 1)
+    SET(ALC_OBJS  ${ALC_OBJS} Alc/wave.c)
+    SET(BACKENDS  "${BACKENDS} WaveFile,")
+ENDIF()
+
+# Check AVSYSTEM backend
+IF(AVSYSTEM)
+    CHECK_INCLUDE_FILE(avsystem/avsys-audio.h HAVE_AVSYSTEM_H)
+    IF(HAVE_AVSYSTEM_H)
+        SET(HAVE_AVSYSTEM 1)
+        INCLUDE(FindPkgConfig)
+        pkg_check_modules(REQ_PKGS REQUIRED avsysaudio mm-session audio-session-mgr)
+        FOREACH(flag ${REQ_PKGS_CFLAGS})
+           SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+        ENDFOREACH(flag)
+        FOREACH(flag ${REQ_PKGS_LDFLAGS})
+            SET(EXTRA_LIBS "${EXTRA_LIBS} ${flag}")
+        ENDFOREACH(flag)
+        SET(EXTRA_LIBS avsysaudio mmfsession audio-session-mgr vconf ${EXTRA_LIBS})
+        SET(ALC_OBJS  ${ALC_OBJS} Alc/avsystem.c)
+        SET(BACKENDS  "${BACKENDS} AVSYSTEM,")
+        SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+    ENDIF()
+ENDIF()
+
+# This is always available
+SET(BACKENDS  "${BACKENDS} Null")
+
+IF(LIBTYPE STREQUAL "STATIC")
+    ADD_DEFINITIONS(-DAL_LIBTYPE_STATIC)
+    SET(PKG_CONFIG_CFLAGS -DAL_LIBTYPE_STATIC ${PKG_CONFIG_CFLAGS})
+ENDIF()
+
+# Needed for openal.pc.in
+SET(prefix ${CMAKE_INSTALL_PREFIX})
+SET(exec_prefix "\${prefix}")
+SET(libdir "\${exec_prefix}/lib${LIB_SUFFIX}")
+SET(bindir "\${exec_prefix}/bin")
+SET(includedir "\${prefix}/include")
+SET(PACKAGE_VERSION "${LIB_VERSION}")
+
+# End configuration
+CONFIGURE_FILE(
+    "${OpenAL_SOURCE_DIR}/config.h.in"
+    "${OpenAL_BINARY_DIR}/config.h")
+CONFIGURE_FILE(
+    "${OpenAL_SOURCE_DIR}/openal.pc.in"
+    "${OpenAL_BINARY_DIR}/openal.pc"
+    @ONLY)
+
+# Build a library
+ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS})
+SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES DEFINE_SYMBOL AL_BUILD_LIBRARY
+                                            COMPILE_FLAGS -DAL_ALEXT_PROTOTYPES
+                                            VERSION ${LIB_VERSION}.0
+                                            SOVERSION ${LIB_MAJOR_VERSION})
+IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC")
+    SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES PREFIX "")
+ENDIF()
+
+TARGET_LINK_LIBRARIES(${LIBNAME} ${EXTRA_LIBS})
+
+# Add an install target here
+INSTALL(TARGETS ${LIBNAME}
+        RUNTIME DESTINATION bin
+        LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+        ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+)
+INSTALL(FILES include/AL/al.h
+              include/AL/alc.h
+              include/AL/alext.h
+              include/AL/efx.h
+              include/AL/efx-creative.h
+        DESTINATION include/AL
+)
+INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc"
+        DESTINATION "lib${LIB_SUFFIX}/pkgconfig")
+
+
+MESSAGE(STATUS "")
+MESSAGE(STATUS "Building OpenAL with support for the following backends:")
+MESSAGE(STATUS "    ${BACKENDS}")
+MESSAGE(STATUS "")
+
+IF(WIN32)
+    IF(NOT HAVE_DSOUND)
+        MESSAGE(STATUS "WARNING: Building the Windows version without DirectSound output")
+        MESSAGE(STATUS "         This is probably NOT what you want!")
+        MESSAGE(STATUS "")
+    ENDIF()
+ENDIF()
+
+# Install alsoft.conf configuration file
+IF(ALSOFT_CONFIG)
+    INSTALL(FILES alsoftrc.sample
+            DESTINATION /etc/openal
+            RENAME alsoft.conf
+    )
+    MESSAGE(STATUS "Installing sample alsoft.conf")
+    MESSAGE(STATUS "")
+ENDIF()
+
+IF(UTILS)
+    ADD_EXECUTABLE(openal-info utils/openal-info.c)
+    TARGET_LINK_LIBRARIES(openal-info ${LIBNAME})
+    INSTALL(TARGETS openal-info
+            RUNTIME DESTINATION bin
+            LIBRARY DESTINATION "lib${LIB_SUFFIX}"
+            ARCHIVE DESTINATION "lib${LIB_SUFFIX}"
+    )
+    MESSAGE(STATUS "Building utility programs")
+    MESSAGE(STATUS "")
+ENDIF()
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d0c8978
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,484 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+                    675 Mass Ave, Cambridge, MA 02139, 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
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+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.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+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
+\f
+     Appendix: 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
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
diff --git a/OpenAL32/Include/alAuxEffectSlot.h b/OpenAL32/Include/alAuxEffectSlot.h
new file mode 100755 (executable)
index 0000000..43d2f71
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _AL_AUXEFFECTSLOT_H_
+#define _AL_AUXEFFECTSLOT_H_
+
+#include "AL/al.h"
+#include "alEffect.h"
+#include "alFilter.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ALeffectState ALeffectState;
+
+typedef struct ALeffectslot
+{
+    ALeffect effect;
+
+    ALfloat Gain;
+    ALboolean AuxSendAuto;
+
+    ALeffectState *EffectState;
+
+    ALfloat WetBuffer[BUFFERSIZE];
+
+    ALfloat ClickRemoval[1];
+    ALfloat PendingClicks[1];
+
+    ALuint refcount;
+
+    // Index to itself
+    ALuint effectslot;
+
+    struct ALeffectslot *next;
+} ALeffectslot;
+
+
+ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context);
+
+
+struct ALeffectState {
+    ALvoid (*Destroy)(ALeffectState *State);
+    ALboolean (*DeviceUpdate)(ALeffectState *State, ALCdevice *Device);
+    ALvoid (*Update)(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect);
+    ALvoid (*Process)(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS]);
+};
+
+ALeffectState *NoneCreate(void);
+ALeffectState *EAXVerbCreate(void);
+ALeffectState *VerbCreate(void);
+ALeffectState *EchoCreate(void);
+ALeffectState *ModulatorCreate(void);
+
+#define ALEffect_Destroy(a)         ((a)->Destroy((a)))
+#define ALEffect_DeviceUpdate(a,b)  ((a)->DeviceUpdate((a),(b)))
+#define ALEffect_Update(a,b,c)      ((a)->Update((a),(b),(c)))
+#define ALEffect_Process(a,b,c,d,e) ((a)->Process((a),(b),(c),(d),(e)))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alBuffer.h b/OpenAL32/Include/alBuffer.h
new file mode 100755 (executable)
index 0000000..e22d839
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef _AL_BUFFER_H_
+#define _AL_BUFFER_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Input formats (some are currently theoretical) */
+enum UserFmtType {
+    UserFmtByte,   /* AL_BYTE */
+    UserFmtUByte,  /* AL_UNSIGNED_BYTE */
+    UserFmtShort,  /* AL_SHORT */
+    UserFmtUShort, /* AL_UNSIGNED_SHORT */
+    UserFmtInt,    /* AL_INT */
+    UserFmtUInt,   /* AL_UNSIGNED_INT */
+    UserFmtFloat,  /* AL_FLOAT */
+    UserFmtDouble, /* AL_DOUBLE */
+    UserFmtMulaw,  /* AL_MULAW */
+    UserFmtIMA4,   /* AL_IMA4 */
+};
+enum UserFmtChannels {
+    UserFmtMono,   /* AL_MONO */
+    UserFmtStereo, /* AL_STEREO */
+    UserFmtRear,   /* AL_REAR */
+    UserFmtQuad,   /* AL_QUAD */
+    UserFmtX51,    /* AL_5POINT1 (WFX order) */
+    UserFmtX61,    /* AL_6POINT1 (WFX order) */
+    UserFmtX71,    /* AL_7POINT1 (WFX order) */
+};
+
+ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
+                              enum UserFmtType *type);
+ALuint BytesFromUserFmt(enum UserFmtType type);
+ALuint ChannelsFromUserFmt(enum UserFmtChannels chans);
+static __inline ALuint FrameSizeFromUserFmt(enum UserFmtChannels chans,
+                                            enum UserFmtType type)
+{
+    return ChannelsFromUserFmt(chans) * BytesFromUserFmt(type);
+}
+
+
+/* Storable formats */
+enum FmtType {
+    FmtUByte = UserFmtUByte,
+    FmtShort = UserFmtShort,
+    FmtFloat = UserFmtFloat,
+};
+enum FmtChannels {
+    FmtMono = UserFmtMono,
+    FmtStereo = UserFmtStereo,
+    FmtRear = UserFmtRear,
+    FmtQuad = UserFmtQuad,
+    FmtX51 = UserFmtX51,
+    FmtX61 = UserFmtX61,
+    FmtX71 = UserFmtX71,
+};
+
+ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type);
+ALuint BytesFromFmt(enum FmtType type);
+ALuint ChannelsFromFmt(enum FmtChannels chans);
+static __inline ALuint FrameSizeFromFmt(enum FmtChannels chans, enum FmtType type)
+{
+    return ChannelsFromFmt(chans) * BytesFromFmt(type);
+}
+
+
+typedef struct ALbuffer
+{
+    ALvoid  *data;
+    ALsizei  size;
+
+    ALsizei          Frequency;
+    enum FmtChannels FmtChannels;
+    enum FmtType     FmtType;
+
+    enum UserFmtChannels OriginalChannels;
+    enum UserFmtType     OriginalType;
+    ALsizei OriginalSize;
+    ALsizei OriginalAlign;
+
+    ALsizei  LoopStart;
+    ALsizei  LoopEnd;
+
+    ALuint   refcount; // Number of sources using this buffer (deletion can only occur when this is 0)
+
+    // Index to itself
+    ALuint buffer;
+} ALbuffer;
+
+ALvoid ReleaseALBuffers(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alDatabuffer.h b/OpenAL32/Include/alDatabuffer.h
new file mode 100755 (executable)
index 0000000..2218552
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _AL_DATABUFFER_H_
+#define _AL_DATABUFFER_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UNMAPPED 0
+#define MAPPED   1
+
+typedef struct ALdatabuffer
+{
+    ALubyte     *data;
+    ALintptrEXT size;
+
+    ALenum state;
+    ALenum usage;
+
+    /* Index to self */
+    ALuint databuffer;
+
+    struct ALdatabuffer *next;
+} ALdatabuffer;
+
+ALvoid ReleaseALDatabuffers(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alEffect.h b/OpenAL32/Include/alEffect.h
new file mode 100755 (executable)
index 0000000..500b60a
--- /dev/null
@@ -0,0 +1,83 @@
+// NOTE:  The effect structure is getting too large, it may be a good idea to
+//        start using a union or another form of unified storage.
+#ifndef _AL_EFFECT_H_
+#define _AL_EFFECT_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+    EAXREVERB = 0,
+    REVERB,
+    ECHO,
+    MODULATOR,
+
+    MAX_EFFECTS
+};
+extern ALboolean DisabledEffects[MAX_EFFECTS];
+
+typedef struct ALeffect
+{
+    // Effect type (AL_EFFECT_NULL, ...)
+    ALenum type;
+
+    struct {
+        // Shared Reverb Properties
+        ALfloat Density;
+        ALfloat Diffusion;
+        ALfloat Gain;
+        ALfloat GainHF;
+        ALfloat DecayTime;
+        ALfloat DecayHFRatio;
+        ALfloat ReflectionsGain;
+        ALfloat ReflectionsDelay;
+        ALfloat LateReverbGain;
+        ALfloat LateReverbDelay;
+        ALfloat AirAbsorptionGainHF;
+        ALfloat RoomRolloffFactor;
+        ALboolean DecayHFLimit;
+
+        // Additional EAX Reverb Properties
+        ALfloat GainLF;
+        ALfloat DecayLFRatio;
+        ALfloat ReflectionsPan[3];
+        ALfloat LateReverbPan[3];
+        ALfloat EchoTime;
+        ALfloat EchoDepth;
+        ALfloat ModulationTime;
+        ALfloat ModulationDepth;
+        ALfloat HFReference;
+        ALfloat LFReference;
+    } Reverb;
+
+    struct {
+        ALfloat Delay;
+        ALfloat LRDelay;
+
+        ALfloat Damping;
+        ALfloat Feedback;
+
+        ALfloat Spread;
+    } Echo;
+
+    struct {
+        ALfloat Frequency;
+        ALfloat HighPassCutoff;
+        ALint Waveform;
+    } Modulator;
+
+    // Index to itself
+    ALuint effect;
+} ALeffect;
+
+
+ALvoid ReleaseALEffects(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alError.h b/OpenAL32/Include/alError.h
new file mode 100755 (executable)
index 0000000..7976e50
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef _AL_ERROR_H_
+#define _AL_ERROR_H_
+
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ALvoid alSetError(ALCcontext *Context, ALenum errorCode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h
new file mode 100755 (executable)
index 0000000..ef852d1
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef _AL_FILTER_H_
+#define _AL_FILTER_H_
+
+#include "AL/al.h"
+#include "alu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    ALfloat coeff;
+#ifndef _MSC_VER
+    ALfloat history[0];
+#else
+    ALfloat history[1];
+#endif
+} FILTER;
+
+static __inline ALfloat lpFilter4P(FILTER *iir, ALuint offset, ALfloat input)
+{
+    ALfloat *history = &iir->history[offset];
+    ALfloat a = iir->coeff;
+    ALfloat output = input;
+
+    output = output + (history[0]-output)*a;
+    history[0] = output;
+    output = output + (history[1]-output)*a;
+    history[1] = output;
+    output = output + (history[2]-output)*a;
+    history[2] = output;
+    output = output + (history[3]-output)*a;
+    history[3] = output;
+
+    return output;
+}
+
+static __inline ALfloat lpFilter2P(FILTER *iir, ALuint offset, ALfloat input)
+{
+    ALfloat *history = &iir->history[offset];
+    ALfloat a = iir->coeff;
+    ALfloat output = input;
+
+    output = output + (history[0]-output)*a;
+    history[0] = output;
+    output = output + (history[1]-output)*a;
+    history[1] = output;
+
+    return output;
+}
+
+static __inline ALfloat lpFilter1P(FILTER *iir, ALuint offset, ALfloat input)
+{
+    ALfloat *history = &iir->history[offset];
+    ALfloat a = iir->coeff;
+    ALfloat output = input;
+
+    output = output + (history[0]-output)*a;
+    history[0] = output;
+
+    return output;
+}
+
+static __inline ALfloat lpFilter4PC(const FILTER *iir, ALuint offset, ALfloat input)
+{
+    const ALfloat *history = &iir->history[offset];
+    ALfloat a = iir->coeff;
+    ALfloat output = input;
+
+    output = output + (history[0]-output)*a;
+    output = output + (history[1]-output)*a;
+    output = output + (history[2]-output)*a;
+    output = output + (history[3]-output)*a;
+
+    return output;
+}
+
+static __inline ALfloat lpFilter2PC(const FILTER *iir, ALuint offset, ALfloat input)
+{
+    const ALfloat *history = &iir->history[offset];
+    ALfloat a = iir->coeff;
+    ALfloat output = input;
+
+    output = output + (history[0]-output)*a;
+    output = output + (history[1]-output)*a;
+
+    return output;
+}
+
+static __inline ALfloat lpFilter1PC(FILTER *iir, ALuint offset, ALfloat input)
+{
+    const ALfloat *history = &iir->history[offset];
+    ALfloat a = iir->coeff;
+    ALfloat output = input;
+
+    output = output + (history[0]-output)*a;
+
+    return output;
+}
+
+/* Calculates the low-pass filter coefficient given the pre-scaled gain and
+ * cos(w) value. Note that g should be pre-scaled (sqr(gain) for one-pole,
+ * sqrt(gain) for four-pole, etc) */
+static __inline ALfloat lpCoeffCalc(ALfloat g, ALfloat cw)
+{
+    ALfloat a = 0.0f;
+
+    /* Be careful with gains < 0.01, as that causes the coefficient
+     * head towards 1, which will flatten the signal */
+    g = __max(g, 0.01f);
+    if(g < 0.9999f) /* 1-epsilon */
+        a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) /
+            (1 - g);
+
+    return a;
+}
+
+
+typedef struct ALfilter
+{
+    // Filter type (AL_FILTER_NULL, ...)
+    ALenum type;
+
+    ALfloat Gain;
+    ALfloat GainHF;
+
+    // Index to itself
+    ALuint filter;
+} ALfilter;
+
+
+ALvoid ReleaseALFilters(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alListener.h b/OpenAL32/Include/alListener.h
new file mode 100755 (executable)
index 0000000..467193e
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _AL_LISTENER_H_
+#define _AL_LISTENER_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ALlistener_struct
+{
+    ALfloat Position[3];
+    ALfloat Velocity[3];
+    ALfloat Forward[3];
+    ALfloat Up[3];
+    ALfloat Gain;
+    ALfloat MetersPerUnit;
+} ALlistener;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
new file mode 100755 (executable)
index 0000000..9890bf3
--- /dev/null
@@ -0,0 +1,499 @@
+#ifndef AL_MAIN_H
+#define AL_MAIN_H
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef HAVE_FENV_H
+#include <fenv.h>
+#endif
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#ifndef AL_EXT_sample_buffer_object
+#define AL_EXT_sample_buffer_object 1
+typedef ptrdiff_t ALintptrEXT;
+typedef ptrdiff_t ALsizeiptrEXT;
+#define AL_SAMPLE_SOURCE_EXT                     0x1040
+#define AL_SAMPLE_SINK_EXT                       0x1041
+#define AL_READ_ONLY_EXT                         0x1042
+#define AL_WRITE_ONLY_EXT                        0x1043
+#define AL_READ_WRITE_EXT                        0x1044
+#define AL_STREAM_WRITE_EXT                      0x1045
+#define AL_STREAM_READ_EXT                       0x1046
+#define AL_STREAM_COPY_EXT                       0x1047
+#define AL_STATIC_WRITE_EXT                      0x1048
+#define AL_STATIC_READ_EXT                       0x1049
+#define AL_STATIC_COPY_EXT                       0x104A
+#define AL_DYNAMIC_WRITE_EXT                     0x104B
+#define AL_DYNAMIC_READ_EXT                      0x104C
+#define AL_DYNAMIC_COPY_EXT                      0x104D
+typedef ALvoid (AL_APIENTRY*PFNALGENDATABUFFERSEXTPROC)(ALsizei n,ALuint *puiBuffers);
+typedef ALvoid (AL_APIENTRY*PFNALDELETEDATABUFFERSEXTPROC)(ALsizei n, const ALuint *puiBuffers);
+typedef ALboolean (AL_APIENTRY*PFNALISDATABUFFEREXTPROC)(ALuint uiBuffer);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERDATAEXTPROC)(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERSUBDATAEXTPROC)(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERSUBDATAEXTPROC)(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERFEXTPROC)(ALuint buffer, ALenum eParam, ALfloat flValue);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERFVEXTPROC)(ALuint buffer, ALenum eParam, const ALfloat* flValues);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERIEXTPROC)(ALuint buffer, ALenum eParam, ALint lValue);
+typedef ALvoid (AL_APIENTRY*PFNALDATABUFFERIVEXTPROC)(ALuint buffer, ALenum eParam, const ALint* plValues);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERFEXTPROC)(ALuint buffer, ALenum eParam, ALfloat *pflValue);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERFVEXTPROC)(ALuint buffer, ALenum eParam, ALfloat* pflValues);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERIEXTPROC)(ALuint buffer, ALenum eParam, ALint *plValue);
+typedef ALvoid (AL_APIENTRY*PFNALGETDATABUFFERIVEXTPROC)(ALuint buffer, ALenum eParam, ALint* plValues);
+typedef ALvoid (AL_APIENTRY*PFNALSELECTDATABUFFEREXTPROC)(ALenum target, ALuint uiBuffer);
+typedef ALvoid* (AL_APIENTRY*PFNALMAPDATABUFFEREXTPROC)(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access);
+typedef ALvoid (AL_APIENTRY*PFNALUNMAPDATABUFFEREXTPROC)(ALuint uiBuffer);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers);
+AL_API ALvoid AL_APIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *puiBuffers);
+AL_API ALboolean AL_APIENTRY alIsDatabufferEXT(ALuint uiBuffer);
+AL_API ALvoid AL_APIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage);
+AL_API ALvoid AL_APIENTRY alDatabufferSubDataEXT(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *data);
+AL_API ALvoid AL_APIENTRY alGetDatabufferSubDataEXT(ALuint buffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *data);
+AL_API ALvoid AL_APIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues);
+AL_API ALvoid AL_APIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue);
+AL_API ALvoid AL_APIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues);
+AL_API ALvoid AL_APIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues);
+AL_API ALvoid AL_APIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue);
+AL_API ALvoid AL_APIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues);
+AL_API ALvoid AL_APIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer);
+AL_API ALvoid* AL_APIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access);
+AL_API ALvoid AL_APIENTRY alUnmapDatabufferEXT(ALuint uiBuffer);
+#endif
+#endif
+
+
+#if defined(HAVE_STDINT_H)
+#include <stdint.h>
+typedef int64_t ALint64;
+typedef uint64_t ALuint64;
+#elif defined(HAVE___INT64)
+typedef __int64 ALint64;
+typedef unsigned __int64 ALuint64;
+#elif (SIZEOF_LONG == 8)
+typedef long ALint64;
+typedef unsigned long ALuint64;
+#elif (SIZEOF_LONG_LONG == 8)
+typedef long long ALint64;
+typedef unsigned long long ALuint64;
+#endif
+
+#ifdef HAVE_GCC_FORMAT
+#define PRINTF_STYLE(x, y) __attribute__((format(printf, (x), (y))))
+#else
+#define PRINTF_STYLE(x, y)
+#endif
+
+#ifdef _WIN32
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <windows.h>
+
+typedef DWORD tls_type;
+#define tls_create(x) (*(x) = TlsAlloc())
+#define tls_delete(x) TlsFree((x))
+#define tls_get(x) TlsGetValue((x))
+#define tls_set(x, a) TlsSetValue((x), (a))
+
+#else
+
+#include <unistd.h>
+#include <assert.h>
+#include <pthread.h>
+#ifdef HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#define IsBadWritePtr(a,b) ((a) == NULL && (b) != 0)
+
+typedef pthread_key_t tls_type;
+#define tls_create(x) pthread_key_create((x), NULL)
+#define tls_delete(x) pthread_key_delete((x))
+#define tls_get(x) pthread_getspecific((x))
+#define tls_set(x, a) pthread_setspecific((x), (a))
+
+typedef pthread_mutex_t CRITICAL_SECTION;
+static __inline void EnterCriticalSection(CRITICAL_SECTION *cs)
+{
+    int ret;
+    ret = pthread_mutex_lock(cs);
+    assert(ret == 0);
+}
+static __inline void LeaveCriticalSection(CRITICAL_SECTION *cs)
+{
+    int ret;
+    ret = pthread_mutex_unlock(cs);
+    assert(ret == 0);
+}
+static __inline void InitializeCriticalSection(CRITICAL_SECTION *cs)
+{
+    pthread_mutexattr_t attrib;
+    int ret;
+
+    ret = pthread_mutexattr_init(&attrib);
+    assert(ret == 0);
+
+    ret = pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE);
+#ifdef HAVE_PTHREAD_NP_H
+    if(ret != 0)
+        ret = pthread_mutexattr_setkind_np(&attrib, PTHREAD_MUTEX_RECURSIVE);
+#endif
+    assert(ret == 0);
+    ret = pthread_mutex_init(cs, &attrib);
+    assert(ret == 0);
+
+    pthread_mutexattr_destroy(&attrib);
+}
+
+static __inline void DeleteCriticalSection(CRITICAL_SECTION *cs)
+{
+    int ret;
+    ret = pthread_mutex_destroy(cs);
+    assert(ret == 0);
+}
+
+/* NOTE: This wrapper isn't quite accurate as it returns an ALuint, as opposed
+ * to the expected DWORD. Both are defined as unsigned 32-bit types, however.
+ * Additionally, Win32 is supposed to measure the time since Windows started,
+ * as opposed to the actual time. */
+static __inline ALuint timeGetTime(void)
+{
+#if _POSIX_TIMERS > 0
+    struct timespec ts;
+    int ret = -1;
+
+#if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)
+#if _POSIX_MONOTONIC_CLOCK == 0
+    static int hasmono = 0;
+    if(hasmono > 0 || (hasmono == 0 &&
+                       (hasmono=sysconf(_SC_MONOTONIC_CLOCK)) > 0))
+#endif
+        ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+#endif
+    if(ret != 0)
+        ret = clock_gettime(CLOCK_REALTIME, &ts);
+    assert(ret == 0);
+
+    return ts.tv_nsec/1000000 + ts.tv_sec*1000;
+#else
+    struct timeval tv;
+    int ret;
+
+    ret = gettimeofday(&tv, NULL);
+    assert(ret == 0);
+
+    return tv.tv_usec/1000 + tv.tv_sec*1000;
+#endif
+}
+
+static __inline void Sleep(ALuint t)
+{
+    struct timespec tv, rem;
+    tv.tv_nsec = (t*1000000)%1000000000;
+    tv.tv_sec = t/1000;
+
+    while(nanosleep(&tv, &rem) == -1 && errno == EINTR)
+        tv = rem;
+}
+#define min(x,y) (((x)<(y))?(x):(y))
+#define max(x,y) (((x)>(y))?(x):(y))
+#endif
+
+#include "alListener.h"
+#include "alu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SWMIXER_OUTPUT_RATE        44100
+
+#define SPEEDOFSOUNDMETRESPERSEC   (343.3f)
+#define AIRABSORBGAINDBHF          (-0.05f)
+
+#define LOWPASSFREQCUTOFF          (5000)
+
+#define DEFAULT_HEAD_DAMPEN        (0.25f)
+
+
+// Find the next power-of-2 for non-power-of-2 numbers.
+static __inline ALuint NextPowerOf2(ALuint value)
+{
+    ALuint powerOf2 = 1;
+
+    if(value)
+    {
+        value--;
+        while(value)
+        {
+            value >>= 1;
+            powerOf2 <<= 1;
+        }
+    }
+    return powerOf2;
+}
+
+
+typedef struct {
+    ALCboolean (*OpenPlayback)(ALCdevice*, const ALCchar*);
+    void (*ClosePlayback)(ALCdevice*);
+    ALCboolean (*ResetPlayback)(ALCdevice*);
+    void (*StopPlayback)(ALCdevice*);
+
+    ALCboolean (*OpenCapture)(ALCdevice*, const ALCchar*);
+    void (*CloseCapture)(ALCdevice*);
+    void (*StartCapture)(ALCdevice*);
+    void (*StopCapture)(ALCdevice*);
+    void (*CaptureSamples)(ALCdevice*, void*, ALCuint);
+    ALCuint (*AvailableSamples)(ALCdevice*);
+} BackendFuncs;
+
+enum {
+    DEVICE_PROBE,
+    ALL_DEVICE_PROBE,
+    CAPTURE_DEVICE_PROBE
+};
+
+void alc_alsa_init(BackendFuncs *func_list);
+void alc_alsa_deinit(void);
+void alc_alsa_probe(int type);
+void alc_oss_init(BackendFuncs *func_list);
+void alc_oss_deinit(void);
+void alc_oss_probe(int type);
+void alc_solaris_init(BackendFuncs *func_list);
+void alc_solaris_deinit(void);
+void alc_solaris_probe(int type);
+void alcDSoundInit(BackendFuncs *func_list);
+void alcDSoundDeinit(void);
+void alcDSoundProbe(int type);
+void alcWinMMInit(BackendFuncs *FuncList);
+void alcWinMMDeinit(void);
+void alcWinMMProbe(int type);
+void alc_pa_init(BackendFuncs *func_list);
+void alc_pa_deinit(void);
+void alc_pa_probe(int type);
+void alc_wave_init(BackendFuncs *func_list);
+void alc_wave_deinit(void);
+void alc_wave_probe(int type);
+void alc_pulse_init(BackendFuncs *func_list);
+void alc_pulse_deinit(void);
+void alc_pulse_probe(int type);
+void alc_null_init(BackendFuncs *func_list);
+void alc_null_deinit(void);
+void alc_null_probe(int type);
+
+/*- * avsystem porting- */
+void alc_avsystem_init(BackendFuncs *func_list);
+void alc_avsystem_deinit(void);
+void alc_avsystem_probe(int type);
+
+
+typedef struct UIntMap {
+    struct {
+        ALuint key;
+        ALvoid *value;
+    } *array;
+    ALsizei size;
+    ALsizei maxsize;
+} UIntMap;
+
+void InitUIntMap(UIntMap *map);
+void ResetUIntMap(UIntMap *map);
+ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value);
+void RemoveUIntMapKey(UIntMap *map, ALuint key);
+ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key);
+
+/* Device formats */
+enum DevFmtType {
+    DevFmtByte,   /* AL_BYTE */
+    DevFmtUByte,  /* AL_UNSIGNED_BYTE */
+    DevFmtShort,  /* AL_SHORT */
+    DevFmtUShort, /* AL_UNSIGNED_SHORT */
+    DevFmtFloat,  /* AL_FLOAT */
+};
+enum DevFmtChannels {
+    DevFmtMono,   /* AL_MONO */
+    DevFmtStereo, /* AL_STEREO */
+    DevFmtQuad,   /* AL_QUAD */
+    DevFmtX51,    /* AL_5POINT1 */
+    DevFmtX61,    /* AL_6POINT1 */
+    DevFmtX71,    /* AL_7POINT1 */
+};
+
+ALuint BytesFromDevFmt(enum DevFmtType type);
+ALuint ChannelsFromDevFmt(enum DevFmtChannels chans);
+static __inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans,
+                                           enum DevFmtType type)
+{
+    return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type);
+}
+
+
+struct ALCdevice_struct
+{
+    ALCboolean   Connected;
+    ALboolean    IsCaptureDevice;
+
+    ALuint       Frequency;
+    ALuint       UpdateSize;
+    ALuint       NumUpdates;
+    enum DevFmtChannels FmtChans;
+    enum DevFmtType     FmtType;
+
+    ALCchar      *szDeviceName;
+
+    ALCenum      LastError;
+
+    // Maximum number of sources that can be created
+    ALuint       MaxNoOfSources;
+    // Maximum number of slots that can be created
+    ALuint       AuxiliaryEffectSlotMax;
+
+    ALCuint      NumMonoSources;
+    ALCuint      NumStereoSources;
+    ALuint       NumAuxSends;
+
+    // Map of Buffers for this device
+    UIntMap BufferMap;
+
+    // Map of Effects for this device
+    UIntMap EffectMap;
+
+    // Map of Filters for this device
+    UIntMap FilterMap;
+
+    // Map of Databuffers for this device
+    UIntMap DatabufferMap;
+
+    // Stereo-to-binaural filter
+    struct bs2b *Bs2b;
+    ALCint       Bs2bLevel;
+
+    // Simulated dampening from head occlusion
+    ALfloat      HeadDampen;
+
+    // Duplicate stereo sources on the side/rear channels
+    ALboolean    DuplicateStereo;
+
+    // Dry path buffer mix
+    ALfloat DryBuffer[BUFFERSIZE][MAXCHANNELS];
+
+    ALuint DevChannels[MAXCHANNELS];
+
+    ALfloat ChannelMatrix[MAXCHANNELS][MAXCHANNELS];
+
+    Channel Speaker2Chan[MAXCHANNELS];
+    ALfloat PanningLUT[MAXCHANNELS * LUT_NUM];
+    ALuint  NumChan;
+
+    ALfloat ClickRemoval[MAXCHANNELS];
+    ALfloat PendingClicks[MAXCHANNELS];
+
+    // Contexts created on this device
+    ALCcontext  **Contexts;
+    ALuint        NumContexts;
+
+    BackendFuncs *Funcs;
+    void         *ExtraData; // For the backend's use
+
+    ALCdevice *next;
+};
+
+#define ALCdevice_OpenPlayback(a,b)      ((a)->Funcs->OpenPlayback((a), (b)))
+#define ALCdevice_ClosePlayback(a)       ((a)->Funcs->ClosePlayback((a)))
+#define ALCdevice_ResetPlayback(a)       ((a)->Funcs->ResetPlayback((a)))
+#define ALCdevice_StopPlayback(a)        ((a)->Funcs->StopPlayback((a)))
+#define ALCdevice_OpenCapture(a,b)       ((a)->Funcs->OpenCapture((a), (b)))
+#define ALCdevice_CloseCapture(a)        ((a)->Funcs->CloseCapture((a)))
+#define ALCdevice_StartCapture(a)        ((a)->Funcs->StartCapture((a)))
+#define ALCdevice_StopCapture(a)         ((a)->Funcs->StopCapture((a)))
+#define ALCdevice_CaptureSamples(a,b,c)  ((a)->Funcs->CaptureSamples((a), (b), (c)))
+#define ALCdevice_AvailableSamples(a)    ((a)->Funcs->AvailableSamples((a)))
+
+struct ALCcontext_struct
+{
+    ALlistener  Listener;
+
+    UIntMap SourceMap;
+    UIntMap EffectSlotMap;
+
+    struct ALdatabuffer *SampleSource;
+    struct ALdatabuffer *SampleSink;
+
+    ALenum      LastError;
+
+    ALboolean   Suspended;
+
+    ALenum      DistanceModel;
+    ALboolean   SourceDistanceModel;
+
+    ALfloat     DopplerFactor;
+    ALfloat     DopplerVelocity;
+    ALfloat     flSpeedOfSound;
+
+    struct ALsource **ActiveSources;
+    ALsizei           ActiveSourceCount;
+    ALsizei           MaxActiveSources;
+
+    ALCdevice  *Device;
+    const ALCchar *ExtensionList;
+
+    ALCcontext *next;
+};
+
+void AppendDeviceList(const ALCchar *name);
+void AppendAllDeviceList(const ALCchar *name);
+void AppendCaptureDeviceList(const ALCchar *name);
+
+ALCvoid alcSetError(ALCdevice *device, ALenum errorCode);
+
+ALCvoid SuspendContext(ALCcontext *context);
+ALCvoid ProcessContext(ALCcontext *context);
+
+ALvoid *StartThread(ALuint (*func)(ALvoid*), ALvoid *ptr);
+ALuint StopThread(ALvoid *thread);
+
+ALCcontext *GetContextSuspended(void);
+
+typedef struct RingBuffer RingBuffer;
+RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length);
+void DestroyRingBuffer(RingBuffer *ring);
+ALsizei RingBufferSize(RingBuffer *ring);
+void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len);
+void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len);
+
+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 GetConfigValueInt(const char *blockName, const char *keyName, int def);
+float GetConfigValueFloat(const char *blockName, const char *keyName, float def);
+int GetConfigValueBool(const char *blockName, const char *keyName, int def);
+
+void SetRTPriority(void);
+
+void SetDefaultChannelOrder(ALCdevice *device);
+void SetDefaultWFXChannelOrder(ALCdevice *device);
+
+void al_print(const char *fname, unsigned int line, const char *fmt, ...)
+             PRINTF_STYLE(3,4);
+#define AL_PRINT(...) al_print(__FILE__, __LINE__, __VA_ARGS__)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h
new file mode 100755 (executable)
index 0000000..e43792c
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef _AL_SOURCE_H_
+#define _AL_SOURCE_H_
+
+#define MAX_SENDS                 4
+
+#include "alFilter.h"
+#include "alu.h"
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    POINT_RESAMPLER = 0,
+    LINEAR_RESAMPLER,
+    CUBIC_RESAMPLER,
+
+    RESAMPLER_MAX,
+    RESAMPLER_MIN = -1,
+    RESAMPLER_DEFAULT = LINEAR_RESAMPLER
+} resampler_t;
+extern resampler_t DefaultResampler;
+
+extern const ALsizei ResamplerPadding[RESAMPLER_MAX];
+extern const ALsizei ResamplerPrePadding[RESAMPLER_MAX];
+
+
+typedef struct ALbufferlistitem
+{
+    struct ALbuffer         *buffer;
+    struct ALbufferlistitem *next;
+    struct ALbufferlistitem *prev;
+} ALbufferlistitem;
+
+typedef struct ALsource
+{
+    ALfloat      flPitch;
+    ALfloat      flGain;
+    ALfloat      flOuterGain;
+    ALfloat      flMinGain;
+    ALfloat      flMaxGain;
+    ALfloat      flInnerAngle;
+    ALfloat      flOuterAngle;
+    ALfloat      flRefDistance;
+    ALfloat      flMaxDistance;
+    ALfloat      flRollOffFactor;
+    ALfloat      vPosition[3];
+    ALfloat      vVelocity[3];
+    ALfloat      vOrientation[3];
+    ALboolean    bHeadRelative;
+    ALboolean    bLooping;
+    ALenum       DistanceModel;
+
+    resampler_t  Resampler;
+
+    ALenum       state;
+    ALuint       position;
+    ALuint       position_fraction;
+
+    struct ALbuffer *Buffer;
+
+    ALbufferlistitem *queue; // Linked list of buffers in queue
+    ALuint BuffersInQueue;   // Number of buffers in queue
+    ALuint BuffersPlayed;    // Number of buffers played on this loop
+
+    ALfilter DirectFilter;
+
+    struct {
+        struct ALeffectslot *Slot;
+        ALfilter WetFilter;
+    } Send[MAX_SENDS];
+
+    ALboolean DryGainHFAuto;
+    ALboolean WetGainAuto;
+    ALboolean WetGainHFAuto;
+    ALfloat   OuterGainHF;
+
+    ALfloat AirAbsorptionFactor;
+    ALfloat RoomRolloffFactor;
+    ALfloat DopplerFactor;
+
+    ALint  lOffset;
+    ALint  lOffsetType;
+
+    // Source Type (Static, Streaming, or Undetermined)
+    ALint  lSourceType;
+
+    // Current target parameters used for mixing
+    ALboolean NeedsUpdate;
+    struct {
+        ALint Step;
+
+        /* A mixing matrix. First subscript is the channel number of the input
+         * data (regardless of channel configuration) and the second is the
+         * channel target (eg. FRONT_LEFT) */
+        ALfloat DryGains[MAXCHANNELS][MAXCHANNELS];
+        FILTER iirFilter;
+        ALfloat history[MAXCHANNELS*2];
+
+        struct {
+            ALfloat WetGain;
+            FILTER iirFilter;
+            ALfloat history[MAXCHANNELS];
+        } Send[MAX_SENDS];
+    } Params;
+
+    ALvoid (*Update)(struct ALsource *self, const ALCcontext *context);
+
+    // Index to itself
+    ALuint source;
+} ALsource;
+#define ALsource_Update(s,a)  ((s)->Update(s,a))
+
+ALvoid ReleaseALSources(ALCcontext *Context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alState.h b/OpenAL32/Include/alState.h
new file mode 100644 (file)
index 0000000..332176b
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _AL_STATE_H_
+#define _AL_STATE_H_
+
+#include "AL/al.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/OpenAL32/Include/alThunk.h b/OpenAL32/Include/alThunk.h
new file mode 100755 (executable)
index 0000000..902f00e
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _AL_THUNK_H_
+#define _AL_THUNK_H_
+
+#include "config.h"
+
+#include "AL/al.h"
+#include "AL/alc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void alThunkInit(void);
+void alThunkExit(void);
+ALuint alThunkAddEntry(ALvoid *ptr);
+void alThunkRemoveEntry(ALuint index);
+ALvoid *alThunkLookupEntry(ALuint index);
+
+#if (SIZEOF_VOIDP > SIZEOF_UINT)
+
+#define ALTHUNK_INIT()          alThunkInit()
+#define ALTHUNK_EXIT()          alThunkExit()
+#define ALTHUNK_ADDENTRY(p)     alThunkAddEntry(p)
+#define ALTHUNK_REMOVEENTRY(i)  alThunkRemoveEntry(i)
+#define ALTHUNK_LOOKUPENTRY(i)  alThunkLookupEntry(i)
+
+#else
+
+#define ALTHUNK_INIT()
+#define ALTHUNK_EXIT()
+#define ALTHUNK_ADDENTRY(p)     ((ALuint)p)
+#define ALTHUNK_REMOVEENTRY(i)  ((ALvoid)i)
+#define ALTHUNK_LOOKUPENTRY(i)  ((ALvoid*)(i))
+
+#endif // (SIZEOF_VOIDP > SIZEOF_INT)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_AL_THUNK_H_
+
diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h
new file mode 100755 (executable)
index 0000000..cc47cc1
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef _ALU_H_
+#define _ALU_H_
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include <limits.h>
+#include <math.h>
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+
+#ifndef M_PI
+#define M_PI           3.14159265358979323846  /* pi */
+#define M_PI_2         1.57079632679489661923  /* pi/2 */
+#endif
+
+#ifdef HAVE_POWF
+#define aluPow(x,y) ((ALfloat)powf((float)(x),(float)(y)))
+#else
+#define aluPow(x,y) ((ALfloat)pow((double)(x),(double)(y)))
+#endif
+
+#ifdef HAVE_SQRTF
+#define aluSqrt(x) ((ALfloat)sqrtf((float)(x)))
+#else
+#define aluSqrt(x) ((ALfloat)sqrt((double)(x)))
+#endif
+
+#ifdef HAVE_ACOSF
+#define aluAcos(x) ((ALfloat)acosf((float)(x)))
+#else
+#define aluAcos(x) ((ALfloat)acos((double)(x)))
+#endif
+
+#ifdef HAVE_ATANF
+#define aluAtan(x) ((ALfloat)atanf((float)(x)))
+#else
+#define aluAtan(x) ((ALfloat)atan((double)(x)))
+#endif
+
+#ifdef HAVE_FABSF
+#define aluFabs(x) ((ALfloat)fabsf((float)(x)))
+#else
+#define aluFabs(x) ((ALfloat)fabs((double)(x)))
+#endif
+
+// fixes for mingw32.
+#if defined(max) && !defined(__max)
+#define __max max
+#endif
+#if defined(min) && !defined(__min)
+#define __min min
+#endif
+
+#define QUADRANT_NUM  128
+#define LUT_NUM       (4 * QUADRANT_NUM)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    FRONT_LEFT = 0,
+    FRONT_RIGHT,
+    FRONT_CENTER,
+    LFE,
+    BACK_LEFT,
+    BACK_RIGHT,
+    BACK_CENTER,
+    SIDE_LEFT,
+    SIDE_RIGHT,
+
+    MAXCHANNELS
+} Channel;
+
+#define BUFFERSIZE 4096
+
+#define FRACTIONBITS (14)
+#define FRACTIONONE  (1<<FRACTIONBITS)
+#define FRACTIONMASK (FRACTIONONE-1)
+
+/* Size for temporary stack storage of buffer data. Larger values need more
+ * stack, while smaller values may need more iterations. The value needs to be
+ * a sensible size, however, as it constrains the max stepping value used for
+ * mixing.
+ * The mixer requires being able to do two samplings per mixing loop. A 16KB
+ * buffer can hold 512 sample frames for a 7.1 float buffer. With the cubic
+ * resampler (which requires 3 padding sample frames), this limits the maximum
+ * step to about 508. This means that buffer_freq*source_pitch cannot exceed
+ * device_freq*508 for an 8-channel 32-bit buffer. */
+#ifndef STACK_DATA_SIZE
+#define STACK_DATA_SIZE  16384
+#endif
+
+
+static __inline ALdouble lerp(ALdouble val1, ALdouble val2, ALdouble mu)
+{
+    return val1 + (val2-val1)*mu;
+}
+static __inline ALdouble cubic(ALdouble val0, ALdouble val1, ALdouble val2, ALdouble val3, ALdouble mu)
+{
+    ALdouble mu2 = mu*mu;
+    ALdouble a0 = -0.5*val0 +  1.5*val1 + -1.5*val2 +  0.5*val3;
+    ALdouble a1 =      val0 + -2.5*val1 +  2.0*val2 + -0.5*val3;
+    ALdouble a2 = -0.5*val0             +  0.5*val2;
+    ALdouble a3 =                  val1;
+
+    return a0*mu*mu2 + a1*mu2 + a2*mu + a3;
+}
+
+struct ALsource;
+
+ALvoid aluInitPanning(ALCdevice *Device);
+ALint aluCart2LUTpos(ALfloat re, ALfloat im);
+
+ALvoid CalcSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
+ALvoid CalcNonAttnSourceParams(struct ALsource *ALSource, const ALCcontext *ALContext);
+
+ALvoid MixSource(struct ALsource *Source, ALCdevice *Device, ALuint SamplesToDo);
+
+ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size);
+ALvoid aluHandleDisconnect(ALCdevice *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/OpenAL32/Include/bs2b.h b/OpenAL32/Include/bs2b.h
new file mode 100755 (executable)
index 0000000..4ed576b
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 2005 Boris Mikhaylov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef BS2B_H
+#define BS2B_H
+
+/* Number of crossfeed levels */
+#define BS2B_CLEVELS           3
+
+/* Normal crossfeed levels */
+#define BS2B_HIGH_CLEVEL       3
+#define BS2B_MIDDLE_CLEVEL     2
+#define BS2B_LOW_CLEVEL        1
+
+/* Easy crossfeed levels */
+#define BS2B_HIGH_ECLEVEL      BS2B_HIGH_CLEVEL    + BS2B_CLEVELS
+#define BS2B_MIDDLE_ECLEVEL    BS2B_MIDDLE_CLEVEL  + BS2B_CLEVELS
+#define BS2B_LOW_ECLEVEL       BS2B_LOW_CLEVEL     + BS2B_CLEVELS
+
+/* Default crossfeed levels */
+#define BS2B_DEFAULT_CLEVEL    BS2B_HIGH_ECLEVEL
+/* Default sample rate (Hz) */
+#define BS2B_DEFAULT_SRATE     44100
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+struct bs2b {
+    int level;  /* Crossfeed level */
+    int srate;   /* Sample rate (Hz) */
+
+    /* Lowpass IIR filter coefficients */
+    double a0_lo;
+    double b1_lo;
+
+    /* Highboost IIR filter coefficients */
+    double a0_hi;
+    double a1_hi;
+    double b1_hi;
+
+    /* Global gain against overloading */
+    double gain;
+
+    /* Buffer of last filtered sample.
+     * [0] - first channel, [1] - second channel
+     */
+    struct t_last_sample {
+        double asis[2];
+        double lo[2];
+        double hi[2];
+    } last_sample;
+};
+
+/* Clear buffers and set new coefficients with new crossfeed level value.
+ * level - crossfeed level of *LEVEL values.
+ */
+void bs2b_set_level(struct bs2b *bs2b, int level);
+
+/* 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);
+
+/* Clear buffer */
+void bs2b_clear(struct bs2b *bs2b);
+
+/* Return 1 if buffer is clear */
+int bs2b_is_clear(struct bs2b *bs2b);
+
+/* Crossfeeds one stereo sample that are pointed by sample.
+ * [0] - first channel, [1] - second channel.
+ * Returns crossfided samle by sample pointer.
+ */
+
+/* sample poits to floats */
+void bs2b_cross_feed(struct bs2b *bs2b, float *sample);
+
+#ifdef __cplusplus
+}    /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* BS2B_H */
diff --git a/OpenAL32/alAuxEffectSlot.c b/OpenAL32/alAuxEffectSlot.c
new file mode 100755 (executable)
index 0000000..aab4f96
--- /dev/null
@@ -0,0 +1,527 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alAuxEffectSlot.h"
+#include "alThunk.h"
+#include "alError.h"
+#include "alSource.h"
+
+
+static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect);
+
+#define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
+#define LookupEffect(m, k) ((ALeffect*)LookupUIntMapKey(&(m), (k)))
+
+AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
+{
+    ALCcontext *Context;
+    ALCdevice *Device;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if(n < 0 || IsBadWritePtr((void*)effectslots, n * sizeof(ALuint)))
+        alSetError(Context, AL_INVALID_VALUE);
+    else if((ALuint)n > Device->AuxiliaryEffectSlotMax - Context->EffectSlotMap.size)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        ALenum err;
+        ALsizei i, j;
+
+        i = 0;
+        while(i < n)
+        {
+            ALeffectslot *slot = calloc(1, sizeof(ALeffectslot));
+            if(!slot || !(slot->EffectState=NoneCreate()))
+            {
+                free(slot);
+                // We must have run out or memory
+                alSetError(Context, AL_OUT_OF_MEMORY);
+                alDeleteAuxiliaryEffectSlots(i, effectslots);
+                break;
+            }
+
+            slot->effectslot = (ALuint)ALTHUNK_ADDENTRY(slot);
+            err = InsertUIntMapEntry(&Context->EffectSlotMap,
+                                     slot->effectslot, slot);
+            if(err != AL_NO_ERROR)
+            {
+                ALTHUNK_REMOVEENTRY(slot->effectslot);
+                ALEffect_Destroy(slot->EffectState);
+                free(slot);
+
+                alSetError(Context, err);
+                alDeleteAuxiliaryEffectSlots(i, effectslots);
+                break;
+            }
+
+            effectslots[i++] = slot->effectslot;
+
+            slot->Gain = 1.0;
+            slot->AuxSendAuto = AL_TRUE;
+            for(j = 0;j < BUFFERSIZE;j++)
+                slot->WetBuffer[j] = 0.0f;
+            for(j = 0;j < 1;j++)
+            {
+                slot->ClickRemoval[j] = 0.0f;
+                slot->PendingClicks[j] = 0.0f;
+            }
+            slot->refcount = 0;
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots)
+{
+    ALCcontext *Context;
+    ALeffectslot *EffectSlot;
+    ALboolean SlotsValid = AL_FALSE;
+    ALsizei i;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        SlotsValid = AL_TRUE;
+        // Check that all effectslots are valid
+        for(i = 0;i < n;i++)
+        {
+            if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) == NULL)
+            {
+                alSetError(Context, AL_INVALID_NAME);
+                SlotsValid = AL_FALSE;
+                break;
+            }
+            else if(EffectSlot->refcount > 0)
+            {
+                alSetError(Context, AL_INVALID_NAME);
+                SlotsValid = AL_FALSE;
+                break;
+            }
+        }
+    }
+
+    if(SlotsValid)
+    {
+        // All effectslots are valid
+        for(i = 0;i < n;i++)
+        {
+            // Recheck that the effectslot is valid, because there could be duplicated names
+            if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslots[i])) == NULL)
+                continue;
+
+            ALEffect_Destroy(EffectSlot->EffectState);
+
+            RemoveUIntMapKey(&Context->EffectSlotMap, EffectSlot->effectslot);
+            ALTHUNK_REMOVEENTRY(EffectSlot->effectslot);
+
+            memset(EffectSlot, 0, sizeof(ALeffectslot));
+            free(EffectSlot);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot)
+{
+    ALCcontext *Context;
+    ALboolean  result;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_FALSE;
+
+    result = (LookupEffectSlot(Context->EffectSlotMap, effectslot) ?
+              AL_TRUE : AL_FALSE);
+
+    ProcessContext(Context);
+
+    return result;
+}
+
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue)
+{
+    ALCdevice *Device;
+    ALCcontext *Context;
+    ALboolean updateSources = AL_FALSE;
+    ALeffectslot *EffectSlot;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+    {
+        switch(param)
+        {
+        case AL_EFFECTSLOT_EFFECT: {
+            ALeffect *effect = NULL;
+
+            if(iValue == 0 ||
+               (effect=LookupEffect(Device->EffectMap, iValue)) != NULL)
+            {
+                InitializeEffect(Context, EffectSlot, effect);
+                updateSources = AL_TRUE;
+            }
+            else
+                alSetError(Context, AL_INVALID_VALUE);
+        }   break;
+
+        case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+            if(iValue == AL_TRUE || iValue == AL_FALSE)
+            {
+                EffectSlot->AuxSendAuto = iValue;
+                updateSources = AL_TRUE;
+            }
+            else
+                alSetError(Context, AL_INVALID_VALUE);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    // Force updating the sources that use this slot, since it affects the
+    // sending parameters
+    if(updateSources)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < Context->SourceMap.size;pos++)
+        {
+            ALsource *source = Context->SourceMap.array[pos].value;
+            ALuint i;
+            for(i = 0;i < Device->NumAuxSends;i++)
+            {
+                if(!source->Send[i].Slot ||
+                   source->Send[i].Slot->effectslot != effectslot)
+                    continue;
+                source->NeedsUpdate = AL_TRUE;
+                break;
+            }
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
+{
+    ALCcontext *Context;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
+    {
+        switch(param)
+        {
+        case AL_EFFECTSLOT_EFFECT:
+        case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+            alAuxiliaryEffectSloti(effectslot, param, piValues[0]);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue)
+{
+    ALCcontext *Context;
+    ALeffectslot *EffectSlot;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+    {
+        switch(param)
+        {
+        case AL_EFFECTSLOT_GAIN:
+            if(flValue >= 0.0f && flValue <= 1.0f)
+                EffectSlot->Gain = flValue;
+            else
+                alSetError(Context, AL_INVALID_VALUE);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
+{
+    ALCcontext *Context;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
+    {
+        switch(param)
+        {
+        case AL_EFFECTSLOT_GAIN:
+            alAuxiliaryEffectSlotf(effectslot, param, pflValues[0]);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue)
+{
+    ALCcontext *Context;
+    ALeffectslot *EffectSlot;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+    {
+        switch(param)
+        {
+        case AL_EFFECTSLOT_EFFECT:
+            *piValue = EffectSlot->effect.effect;
+            break;
+
+        case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+            *piValue = EffectSlot->AuxSendAuto;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues)
+{
+    ALCcontext *Context;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
+    {
+        switch(param)
+        {
+        case AL_EFFECTSLOT_EFFECT:
+        case AL_EFFECTSLOT_AUXILIARY_SEND_AUTO:
+            alGetAuxiliaryEffectSloti(effectslot, param, piValues);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue)
+{
+    ALCcontext *Context;
+    ALeffectslot *EffectSlot;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if((EffectSlot=LookupEffectSlot(Context->EffectSlotMap, effectslot)) != NULL)
+    {
+        switch(param)
+        {
+        case AL_EFFECTSLOT_GAIN:
+            *pflValue = EffectSlot->Gain;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues)
+{
+    ALCcontext *Context;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(LookupEffectSlot(Context->EffectSlotMap, effectslot) != NULL)
+    {
+        switch(param)
+        {
+        case AL_EFFECTSLOT_GAIN:
+            alGetAuxiliaryEffectSlotf(effectslot, param, pflValues);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+
+static ALvoid NoneDestroy(ALeffectState *State)
+{ free(State); }
+static ALboolean NoneDeviceUpdate(ALeffectState *State, ALCdevice *Device)
+{
+    return AL_TRUE;
+    (void)State;
+    (void)Device;
+}
+static ALvoid NoneUpdate(ALeffectState *State, ALCcontext *Context, const ALeffect *Effect)
+{
+    (void)State;
+    (void)Context;
+    (void)Effect;
+}
+static ALvoid NoneProcess(ALeffectState *State, const ALeffectslot *Slot, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[MAXCHANNELS])
+{
+    (void)State;
+    (void)Slot;
+    (void)SamplesToDo;
+    (void)SamplesIn;
+    (void)SamplesOut;
+}
+ALeffectState *NoneCreate(void)
+{
+    ALeffectState *state;
+
+    state = calloc(1, sizeof(*state));
+    if(!state)
+        return NULL;
+
+    state->Destroy = NoneDestroy;
+    state->DeviceUpdate = NoneDeviceUpdate;
+    state->Update = NoneUpdate;
+    state->Process = NoneProcess;
+
+    return state;
+}
+
+static ALvoid InitializeEffect(ALCcontext *Context, ALeffectslot *EffectSlot, ALeffect *effect)
+{
+    if(EffectSlot->effect.type != (effect?effect->type:AL_EFFECT_NULL))
+    {
+        ALeffectState *NewState = NULL;
+        if(!effect || effect->type == AL_EFFECT_NULL)
+            NewState = NoneCreate();
+        else if(effect->type == AL_EFFECT_EAXREVERB)
+            NewState = EAXVerbCreate();
+        else if(effect->type == AL_EFFECT_REVERB)
+            NewState = VerbCreate();
+        else if(effect->type == AL_EFFECT_ECHO)
+            NewState = EchoCreate();
+        else if(effect->type == AL_EFFECT_RING_MODULATOR)
+            NewState = ModulatorCreate();
+        /* No new state? An error occured.. */
+        if(NewState == NULL ||
+           ALEffect_DeviceUpdate(NewState, Context->Device) == AL_FALSE)
+        {
+            if(NewState)
+                ALEffect_Destroy(NewState);
+            alSetError(Context, AL_OUT_OF_MEMORY);
+            return;
+        }
+        if(EffectSlot->EffectState)
+            ALEffect_Destroy(EffectSlot->EffectState);
+        EffectSlot->EffectState = NewState;
+    }
+    if(!effect)
+        memset(&EffectSlot->effect, 0, sizeof(EffectSlot->effect));
+    else
+        memcpy(&EffectSlot->effect, effect, sizeof(*effect));
+    ALEffect_Update(EffectSlot->EffectState, Context, effect);
+}
+
+
+ALvoid ReleaseALAuxiliaryEffectSlots(ALCcontext *Context)
+{
+    ALsizei pos;
+    for(pos = 0;pos < Context->EffectSlotMap.size;pos++)
+    {
+        ALeffectslot *temp = Context->EffectSlotMap.array[pos].value;
+        Context->EffectSlotMap.array[pos].value = NULL;
+
+        // Release effectslot structure
+        ALEffect_Destroy(temp->EffectState);
+
+        ALTHUNK_REMOVEENTRY(temp->effectslot);
+        memset(temp, 0, sizeof(ALeffectslot));
+        free(temp);
+    }
+}
diff --git a/OpenAL32/alBuffer.c b/OpenAL32/alBuffer.c
new file mode 100755 (executable)
index 0000000..cb5a928
--- /dev/null
@@ -0,0 +1,1896 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alError.h"
+#include "alBuffer.h"
+#include "alDatabuffer.h"
+#include "alThunk.h"
+
+
+static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei size, enum UserFmtChannels chans, enum UserFmtType type, const ALvoid *data);
+static void ConvertData(ALvoid *dst, enum FmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei len);
+static void ConvertDataIMA4(ALvoid *dst, enum FmtType dstType, const ALvoid *src, ALint chans, ALsizei len);
+
+#define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
+
+
+/*
+ * Global Variables
+ */
+
+/* IMA ADPCM Stepsize table */
+static const long IMAStep_size[89] = {
+       7,    8,    9,   10,   11,   12,   13,   14,   16,   17,   19,
+      21,   23,   25,   28,   31,   34,   37,   41,   45,   50,   55,
+      60,   66,   73,   80,   88,   97,  107,  118,  130,  143,  157,
+     173,  190,  209,  230,  253,  279,  307,  337,  371,  408,  449,
+     494,  544,  598,  658,  724,  796,  876,  963, 1060, 1166, 1282,
+    1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660,
+    4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493,10442,
+   11487,12635,13899,15289,16818,18500,20350,22358,24633,27086,29794,
+   32767
+};
+
+/* IMA4 ADPCM Codeword decode table */
+static const long IMA4Codeword[16] = {
+    1, 3, 5, 7, 9, 11, 13, 15,
+   -1,-3,-5,-7,-9,-11,-13,-15,
+};
+
+/* IMA4 ADPCM Step index adjust decode table */
+static const long IMA4Index_adjust[16] = {
+   -1,-1,-1,-1, 2, 4, 6, 8,
+   -1,-1,-1,-1, 2, 4, 6, 8
+};
+
+/* A quick'n'dirty lookup table to decode a muLaw-encoded byte sample into a
+ * signed 16-bit sample */
+static const ALshort muLawDecompressionTable[256] = {
+    -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
+    -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
+    -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
+    -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
+     -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+     -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+     -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+     -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+     -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+     -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
+      -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
+      -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
+      -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
+      -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
+      -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
+       -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
+     32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+     23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+     15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+     11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
+      7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
+      5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
+      3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
+      2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
+      1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
+      1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
+       876,   844,   812,   780,   748,   716,   684,   652,
+       620,   588,   556,   524,   492,   460,   428,   396,
+       372,   356,   340,   324,   308,   292,   276,   260,
+       244,   228,   212,   196,   180,   164,   148,   132,
+       120,   112,   104,    96,    88,    80,    72,    64,
+        56,    48,    40,    32,    24,    16,     8,     0
+};
+
+/* Values used when encoding a muLaw sample */
+static const int muLawBias = 0x84;
+static const int muLawClip = 32635;
+static const char muLawCompressTable[256] =
+{
+     0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+     4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+     5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+     6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+     7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+};
+
+/*
+ *    alGenBuffers(ALsizei n, ALuint *buffers)
+ *
+ *    Generates n AL Buffers, and stores the Buffers Names in the array pointed
+ *    to by buffers
+ */
+AL_API ALvoid AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
+{
+    ALCcontext *Context;
+    ALsizei i=0;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    /* Check that we are actually generating some Buffers */
+    if(n < 0 || IsBadWritePtr((void*)buffers, n * sizeof(ALuint)))
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        ALCdevice *device = Context->Device;
+        ALenum err;
+
+        // Create all the new Buffers
+        while(i < n)
+        {
+            ALbuffer *buffer = calloc(1, sizeof(ALbuffer));
+            if(!buffer)
+            {
+                alSetError(Context, AL_OUT_OF_MEMORY);
+                alDeleteBuffers(i, buffers);
+                break;
+            }
+
+            buffer->buffer = (ALuint)ALTHUNK_ADDENTRY(buffer);
+            err = InsertUIntMapEntry(&device->BufferMap, buffer->buffer, buffer);
+            if(err != AL_NO_ERROR)
+            {
+                ALTHUNK_REMOVEENTRY(buffer->buffer);
+                memset(buffer, 0, sizeof(ALbuffer));
+                free(buffer);
+
+                alSetError(Context, err);
+                alDeleteBuffers(i, buffers);
+                break;
+            }
+            buffers[i++] = buffer->buffer;
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+/*
+ *    alDeleteBuffers(ALsizei n, ALuint *buffers)
+ *
+ *    Deletes the n AL Buffers pointed to by buffers
+ */
+AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers)
+{
+    ALCcontext *Context;
+    ALCdevice *device;
+    ALboolean Failed;
+    ALbuffer *ALBuf;
+    ALsizei i;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Failed = AL_TRUE;
+    device = Context->Device;
+    /* Check we are actually Deleting some Buffers */
+    if(n < 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        Failed = AL_FALSE;
+
+        /* Check that all the buffers are valid and can actually be deleted */
+        for(i = 0;i < n;i++)
+        {
+            if(!buffers[i])
+                continue;
+
+            /* Check for valid Buffer ID */
+            if((ALBuf=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
+            {
+                alSetError(Context, AL_INVALID_NAME);
+                Failed = AL_TRUE;
+                break;
+            }
+            else if(ALBuf->refcount != 0)
+            {
+                /* Buffer still in use, cannot be deleted */
+                alSetError(Context, AL_INVALID_OPERATION);
+                Failed = AL_TRUE;
+                break;
+            }
+        }
+    }
+
+    /* If all the Buffers were valid (and have Reference Counts of 0), then we
+     * can delete them */
+    if(!Failed)
+    {
+        for(i = 0;i < n;i++)
+        {
+            if((ALBuf=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
+                continue;
+
+            /* Release the memory used to store audio data */
+            free(ALBuf->data);
+
+            /* Release buffer structure */
+            RemoveUIntMapKey(&device->BufferMap, ALBuf->buffer);
+            ALTHUNK_REMOVEENTRY(ALBuf->buffer);
+
+            memset(ALBuf, 0, sizeof(ALbuffer));
+            free(ALBuf);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+/*
+ *    alIsBuffer(ALuint buffer)
+ *
+ *    Checks if buffer is a valid Buffer Name
+ */
+AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer)
+{
+    ALCcontext *Context;
+    ALboolean  result;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_FALSE;
+
+    result = ((!buffer || LookupBuffer(Context->Device->BufferMap, buffer)) ?
+              AL_TRUE : AL_FALSE);
+
+    ProcessContext(Context);
+
+    return result;
+}
+
+/*
+ *    alBufferData(ALuint buffer, ALenum format, const ALvoid *data,
+ *                 ALsizei size, ALsizei freq)
+ *
+ *    Fill buffer with audio data
+ */
+AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer,ALenum format,const ALvoid *data,ALsizei size,ALsizei freq)
+{
+    enum UserFmtChannels SrcChannels;
+    enum UserFmtType SrcType;
+    ALCcontext *Context;
+    ALCdevice *device;
+    ALbuffer *ALBuf;
+    ALenum err;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(Context->SampleSource)
+    {
+        ALintptrEXT offset;
+
+        if(Context->SampleSource->state == MAPPED)
+        {
+            alSetError(Context, AL_INVALID_OPERATION);
+            ProcessContext(Context);
+            return;
+        }
+
+        offset = (const ALubyte*)data - (ALubyte*)NULL;
+        data = Context->SampleSource->data + offset;
+    }
+
+    device = Context->Device;
+    if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL)
+        alSetError(Context, AL_INVALID_NAME);
+    else if(ALBuf->refcount != 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else if(size < 0 || freq < 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else if(DecomposeUserFormat(format, &SrcChannels, &SrcType) == AL_FALSE)
+        alSetError(Context, AL_INVALID_ENUM);
+    else switch(SrcType)
+    {
+        case UserFmtByte:
+        case UserFmtUByte:
+        case UserFmtShort:
+        case UserFmtUShort:
+        case UserFmtInt:
+        case UserFmtUInt:
+        case UserFmtFloat:
+            err = LoadData(ALBuf, freq, format, size, SrcChannels, SrcType, data);
+            if(err != AL_NO_ERROR)
+                alSetError(Context, err);
+            break;
+
+        case UserFmtDouble: {
+            ALenum NewFormat = AL_FORMAT_MONO_FLOAT32;
+            switch(SrcChannels)
+            {
+                case UserFmtMono: NewFormat = AL_FORMAT_MONO_FLOAT32; break;
+                case UserFmtStereo: NewFormat = AL_FORMAT_STEREO_FLOAT32; break;
+                case UserFmtRear: NewFormat = AL_FORMAT_REAR32; break;
+                case UserFmtQuad: NewFormat = AL_FORMAT_QUAD32; break;
+                case UserFmtX51: NewFormat = AL_FORMAT_51CHN32; break;
+                case UserFmtX61: NewFormat = AL_FORMAT_61CHN32; break;
+                case UserFmtX71: NewFormat = AL_FORMAT_71CHN32; break;
+            }
+            err = LoadData(ALBuf, freq, NewFormat, size, SrcChannels, SrcType, data);
+            if(err != AL_NO_ERROR)
+                alSetError(Context, err);
+        }   break;
+
+        case UserFmtMulaw:
+        case UserFmtIMA4: {
+            ALenum NewFormat = AL_FORMAT_MONO16;
+            switch(SrcChannels)
+            {
+                case UserFmtMono: NewFormat = AL_FORMAT_MONO16; break;
+                case UserFmtStereo: NewFormat = AL_FORMAT_STEREO16; break;
+                case UserFmtRear: NewFormat = AL_FORMAT_REAR16; break;
+                case UserFmtQuad: NewFormat = AL_FORMAT_QUAD16; break;
+                case UserFmtX51: NewFormat = AL_FORMAT_51CHN16; break;
+                case UserFmtX61: NewFormat = AL_FORMAT_61CHN16; break;
+                case UserFmtX71: NewFormat = AL_FORMAT_71CHN16; break;
+            }
+            err = LoadData(ALBuf, freq, NewFormat, size, SrcChannels, SrcType, data);
+            if(err != AL_NO_ERROR)
+                alSetError(Context, err);
+        }   break;
+    }
+
+    ProcessContext(Context);
+}
+
+/*
+ *    alBufferSubDataSOFT(ALuint buffer, ALenum format, const ALvoid *data,
+ *                        ALsizei offset, ALsizei length)
+ *
+ *    Update buffer's audio data
+ */
+AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length)
+{
+    enum UserFmtChannels SrcChannels;
+    enum UserFmtType SrcType;
+    ALCcontext *Context;
+    ALCdevice  *device;
+    ALbuffer   *ALBuf;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(Context->SampleSource)
+    {
+        ALintptrEXT offset;
+
+        if(Context->SampleSource->state == MAPPED)
+        {
+            alSetError(Context, AL_INVALID_OPERATION);
+            ProcessContext(Context);
+            return;
+        }
+
+        offset = (const ALubyte*)data - (ALubyte*)NULL;
+        data = Context->SampleSource->data + offset;
+    }
+
+    device = Context->Device;
+    if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL)
+        alSetError(Context, AL_INVALID_NAME);
+    else if(length < 0 || offset < 0 || (length > 0 && data == NULL))
+        alSetError(Context, AL_INVALID_VALUE);
+    else if(DecomposeUserFormat(format, &SrcChannels, &SrcType) == AL_FALSE ||
+            SrcChannels != ALBuf->OriginalChannels ||
+            SrcType != ALBuf->OriginalType)
+        alSetError(Context, AL_INVALID_ENUM);
+    else if(offset > ALBuf->OriginalSize ||
+            length > ALBuf->OriginalSize-offset ||
+            (offset%ALBuf->OriginalAlign) != 0 ||
+            (length%ALBuf->OriginalAlign) != 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        if(SrcType == UserFmtIMA4)
+        {
+            ALuint Channels = ChannelsFromFmt(ALBuf->FmtChannels);
+            ALuint Bytes = BytesFromFmt(ALBuf->FmtType);
+
+            /* offset -> byte offset, length -> block count */
+            offset /= 36;
+            offset *= 65;
+            offset *= Bytes;
+            length /= ALBuf->OriginalAlign;
+
+            ConvertDataIMA4(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
+                            data, Channels, length);
+        }
+        else
+        {
+            ALuint OldBytes = BytesFromUserFmt(SrcType);
+            ALuint Bytes = BytesFromFmt(ALBuf->FmtType);
+
+            offset /= OldBytes;
+            offset *= Bytes;
+            length /= OldBytes;
+
+            ConvertData(&((ALubyte*)ALBuf->data)[offset], ALBuf->FmtType,
+                        data, SrcType, length);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+
+AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum eParam, ALfloat flValue)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    (void)flValue;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum eParam, ALfloat flValue1, ALfloat flValue2, ALfloat flValue3)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    (void)flValue1;
+    (void)flValue2;
+    (void)flValue3;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum eParam, const ALfloat* flValues)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(!flValues)
+        alSetError(pContext, AL_INVALID_VALUE);
+    else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum eParam, ALint lValue)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    (void)lValue;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBuffer3i( ALuint buffer, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    (void)lValue1;
+    (void)lValue2;
+    (void)lValue3;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum eParam, const ALint* plValues)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+    ALbuffer      *ALBuf;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(!plValues)
+        alSetError(pContext, AL_INVALID_VALUE);
+    else if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        case AL_LOOP_POINTS_SOFT:
+            if(ALBuf->refcount > 0)
+                alSetError(pContext, AL_INVALID_OPERATION);
+            else if(plValues[0] < 0 || plValues[1] < 0 ||
+                    plValues[0] >= plValues[1] || ALBuf->size == 0)
+                alSetError(pContext, AL_INVALID_VALUE);
+            else
+            {
+                ALint maxlen = ALBuf->size /
+                               FrameSizeFromFmt(ALBuf->FmtChannels, ALBuf->FmtType);
+                if(plValues[0] > maxlen || plValues[1] > maxlen)
+                    alSetError(pContext, AL_INVALID_VALUE);
+                else
+                {
+                    ALBuf->LoopStart = plValues[0];
+                    ALBuf->LoopEnd = plValues[1];
+                }
+            }
+            break;
+
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetBufferf(ALuint buffer, ALenum eParam, ALfloat *pflValue)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(!pflValue)
+        alSetError(pContext, AL_INVALID_VALUE);
+    else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(!pflValue1 || !pflValue2 || !pflValue3)
+        alSetError(pContext, AL_INVALID_VALUE);
+    else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum eParam, ALfloat* pflValues)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(!pflValues)
+        alSetError(pContext, AL_INVALID_VALUE);
+    else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum eParam, ALint *plValue)
+{
+    ALCcontext    *pContext;
+    ALbuffer      *pBuffer;
+    ALCdevice     *device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(!plValue)
+        alSetError(pContext, AL_INVALID_VALUE);
+    else if((pBuffer=LookupBuffer(device->BufferMap, buffer)) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        case AL_FREQUENCY:
+            *plValue = pBuffer->Frequency;
+            break;
+
+        case AL_BITS:
+            *plValue = BytesFromFmt(pBuffer->FmtType) * 8;
+            break;
+
+        case AL_CHANNELS:
+            *plValue = ChannelsFromFmt(pBuffer->FmtChannels);
+            break;
+
+        case AL_SIZE:
+            *plValue = pBuffer->size;
+            break;
+
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(!plValue1 || !plValue2 || !plValue3)
+        alSetError(pContext, AL_INVALID_VALUE);
+    else if(LookupBuffer(device->BufferMap, buffer) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum eParam, ALint* plValues)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *device;
+    ALbuffer      *ALBuf;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    device = pContext->Device;
+    if(!plValues)
+        alSetError(pContext, AL_INVALID_VALUE);
+    else if((ALBuf=LookupBuffer(device->BufferMap, buffer)) == NULL)
+        alSetError(pContext, AL_INVALID_NAME);
+    else
+    {
+        switch(eParam)
+        {
+        case AL_FREQUENCY:
+        case AL_BITS:
+        case AL_CHANNELS:
+        case AL_SIZE:
+            alGetBufferi(buffer, eParam, plValues);
+            break;
+
+        case AL_LOOP_POINTS_SOFT:
+            plValues[0] = ALBuf->LoopStart;
+            plValues[1] = ALBuf->LoopEnd;
+            break;
+
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+typedef ALubyte ALmulaw;
+
+static __inline ALshort DecodeMuLaw(ALmulaw val)
+{ return muLawDecompressionTable[val]; }
+
+static ALmulaw EncodeMuLaw(ALshort val)
+{
+    ALint mant, exp, sign;
+
+    sign = (val>>8) & 0x80;
+    if(sign)
+    {
+        /* -32768 doesn't properly negate on a short; it results in itself.
+         * So clamp to -32767 */
+        val = max(val, -32767);
+        val = -val;
+    }
+
+    val = min(val, muLawClip);
+    val += muLawBias;
+
+    exp = muLawCompressTable[(val>>7) & 0xff];
+    mant = (val >> (exp+3)) & 0x0f;
+
+    return ~(sign | (exp<<4) | mant);
+}
+
+static void DecodeIMA4Block(ALshort *dst, const ALubyte *src, ALint numchans)
+{
+    ALint sample[MAXCHANNELS], index[MAXCHANNELS];
+    ALuint code[MAXCHANNELS];
+    ALsizei j,k,c;
+
+    for(c = 0;c < numchans;c++)
+    {
+        sample[c]  = *(src++);
+        sample[c] |= *(src++) << 8;
+        sample[c]  = (sample[c]^0x8000) - 32768;
+        index[c]  = *(src++);
+        index[c] |= *(src++) << 8;
+        index[c]  = (index[c]^0x8000) - 32768;
+
+        index[c] = max(0, index[c]);
+        index[c] = min(index[c], 88);
+
+        dst[c] = sample[c];
+    }
+
+    j = 1;
+    while(j < 65)
+    {
+        for(c = 0;c < numchans;c++)
+        {
+            code[c]  = *(src++);
+            code[c] |= *(src++) << 8;
+            code[c] |= *(src++) << 16;
+            code[c] |= *(src++) << 24;
+        }
+
+        for(k = 0;k < 8;k++,j++)
+        {
+            for(c = 0;c < numchans;c++)
+            {
+                int nibble = code[c]&0xf;
+                code[c] >>= 4;
+
+                sample[c] += IMA4Codeword[nibble] * IMAStep_size[index[c]] / 8;
+                sample[c] = max(-32768, sample[c]);
+                sample[c] = min(sample[c], 32767);
+
+                index[c] += IMA4Index_adjust[nibble];
+                index[c] = max(0, index[c]);
+                index[c] = min(index[c], 88);
+
+                dst[j*numchans + c] = sample[c];
+            }
+        }
+    }
+}
+
+static void EncodeIMA4Block(ALubyte *dst, const ALshort *src, ALint *sample, ALint *index, ALint numchans)
+{
+    ALsizei j,k,c;
+
+    for(c = 0;c < numchans;c++)
+    {
+        int diff = src[c] - sample[c];
+        int step = IMAStep_size[index[c]];
+        int nibble;
+
+        nibble = 0;
+        if(diff < 0)
+        {
+            nibble = 0x8;
+            diff = -diff;
+        }
+
+        diff = min(step*2, diff);
+        nibble |= (diff*8/step - 1) / 2;
+
+        sample[c] += IMA4Codeword[nibble] * step / 8;
+        sample[c] = max(-32768, sample[c]);
+        sample[c] = min(sample[c], 32767);
+
+        index[c] += IMA4Index_adjust[nibble];
+        index[c] = max(0, index[c]);
+        index[c] = min(index[c], 88);
+
+        *(dst++) = sample[c] & 0xff;
+        *(dst++) = (sample[c]>>8) & 0xff;
+        *(dst++) = index[c] & 0xff;
+        *(dst++) = (index[c]>>8) & 0xff;
+    }
+
+    j = 1;
+    while(j < 65)
+    {
+        for(c = 0;c < numchans;c++)
+        {
+            for(k = 0;k < 8;k++)
+            {
+                int diff = src[(j+k)*numchans + c] - sample[c];
+                int step = IMAStep_size[index[c]];
+                int nibble;
+
+                nibble = 0;
+                if(diff < 0)
+                {
+                    nibble = 0x8;
+                    diff = -diff;
+                }
+
+                diff = min(step*2, diff);
+                nibble |= (diff*8/step - 1) / 2;
+
+                sample[c] += IMA4Codeword[nibble] * step / 8;
+                sample[c] = max(-32768, sample[c]);
+                sample[c] = min(sample[c], 32767);
+
+                index[c] += IMA4Index_adjust[nibble];
+                index[c] = max(0, index[c]);
+                index[c] = min(index[c], 88);
+
+                if(!(k&1)) *dst = nibble;
+                else *(dst++) |= nibble<<4;
+            }
+        }
+        j += 8;
+    }
+}
+
+
+static __inline ALbyte Conv_ALbyte_ALbyte(ALbyte val)
+{ return val; }
+static __inline ALbyte Conv_ALbyte_ALubyte(ALubyte val)
+{ return val-128; }
+static __inline ALbyte Conv_ALbyte_ALshort(ALshort val)
+{ return val>>8; }
+static __inline ALbyte Conv_ALbyte_ALushort(ALushort val)
+{ return (val>>8)-128; }
+static __inline ALbyte Conv_ALbyte_ALint(ALint val)
+{ return val>>24; }
+static __inline ALbyte Conv_ALbyte_ALuint(ALuint val)
+{ return (val>>24)-128; }
+static __inline ALbyte Conv_ALbyte_ALfloat(ALfloat val)
+{
+    if(val > 1.0f) return 127;
+    if(val < -1.0f) return -128;
+    return (ALint)(val * 127.0f);
+}
+static __inline ALbyte Conv_ALbyte_ALdouble(ALdouble val)
+{
+    if(val > 1.0) return 127;
+    if(val < -1.0) return -128;
+    return (ALint)(val * 127.0);
+}
+static __inline ALbyte Conv_ALbyte_ALmulaw(ALmulaw val)
+{ return Conv_ALbyte_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALubyte Conv_ALubyte_ALbyte(ALbyte val)
+{ return val+128; }
+static __inline ALubyte Conv_ALubyte_ALubyte(ALubyte val)
+{ return val; }
+static __inline ALubyte Conv_ALubyte_ALshort(ALshort val)
+{ return (val>>8)+128; }
+static __inline ALubyte Conv_ALubyte_ALushort(ALushort val)
+{ return val>>8; }
+static __inline ALubyte Conv_ALubyte_ALint(ALint val)
+{ return (val>>24)+128; }
+static __inline ALubyte Conv_ALubyte_ALuint(ALuint val)
+{ return val>>24; }
+static __inline ALubyte Conv_ALubyte_ALfloat(ALfloat val)
+{
+    if(val > 1.0f) return 255;
+    if(val < -1.0f) return 0;
+    return (ALint)(val * 127.0f) + 128;
+}
+static __inline ALubyte Conv_ALubyte_ALdouble(ALdouble val)
+{
+    if(val > 1.0) return 255;
+    if(val < -1.0) return 0;
+    return (ALint)(val * 127.0) + 128;
+}
+static __inline ALubyte Conv_ALubyte_ALmulaw(ALmulaw val)
+{ return Conv_ALubyte_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALshort Conv_ALshort_ALbyte(ALbyte val)
+{ return val<<8; }
+static __inline ALshort Conv_ALshort_ALubyte(ALubyte val)
+{ return (val-128)<<8; }
+static __inline ALshort Conv_ALshort_ALshort(ALshort val)
+{ return val; }
+static __inline ALshort Conv_ALshort_ALushort(ALushort val)
+{ return val-32768; }
+static __inline ALshort Conv_ALshort_ALint(ALint val)
+{ return val>>16; }
+static __inline ALshort Conv_ALshort_ALuint(ALuint val)
+{ return (val>>16)-32768; }
+static __inline ALshort Conv_ALshort_ALfloat(ALfloat val)
+{
+    if(val > 1.0f) return 32767;
+    if(val < -1.0f) return -32768;
+    return (ALint)(val * 32767.0f);
+}
+static __inline ALshort Conv_ALshort_ALdouble(ALdouble val)
+{
+    if(val > 1.0) return 32767;
+    if(val < -1.0) return -32768;
+    return (ALint)(val * 32767.0);
+}
+static __inline ALshort Conv_ALshort_ALmulaw(ALmulaw val)
+{ return Conv_ALshort_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALushort Conv_ALushort_ALbyte(ALbyte val)
+{ return (val+128)<<8; }
+static __inline ALushort Conv_ALushort_ALubyte(ALubyte val)
+{ return val<<8; }
+static __inline ALushort Conv_ALushort_ALshort(ALshort val)
+{ return val+32768; }
+static __inline ALushort Conv_ALushort_ALushort(ALushort val)
+{ return val; }
+static __inline ALushort Conv_ALushort_ALint(ALint val)
+{ return (val>>16)+32768; }
+static __inline ALushort Conv_ALushort_ALuint(ALuint val)
+{ return val>>16; }
+static __inline ALushort Conv_ALushort_ALfloat(ALfloat val)
+{
+    if(val > 1.0f) return 65535;
+    if(val < -1.0f) return 0;
+    return (ALint)(val * 32767.0f) + 32768;
+}
+static __inline ALushort Conv_ALushort_ALdouble(ALdouble val)
+{
+    if(val > 1.0) return 65535;
+    if(val < -1.0) return 0;
+    return (ALint)(val * 32767.0) + 32768;
+}
+static __inline ALushort Conv_ALushort_ALmulaw(ALmulaw val)
+{ return Conv_ALushort_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALint Conv_ALint_ALbyte(ALbyte val)
+{ return val<<24; }
+static __inline ALint Conv_ALint_ALubyte(ALubyte val)
+{ return (val-128)<<24; }
+static __inline ALint Conv_ALint_ALshort(ALshort val)
+{ return val<<16; }
+static __inline ALint Conv_ALint_ALushort(ALushort val)
+{ return (val-32768)<<16; }
+static __inline ALint Conv_ALint_ALint(ALint val)
+{ return val; }
+static __inline ALint Conv_ALint_ALuint(ALuint val)
+{ return val-2147483648u; }
+static __inline ALint Conv_ALint_ALfloat(ALfloat val)
+{
+    if(val > 1.0f) return 2147483647;
+    if(val < -1.0f) return -2147483647-1;
+    return (ALint)(val * 2147483647.0);
+}
+static __inline ALint Conv_ALint_ALdouble(ALdouble val)
+{
+    if(val > 1.0) return 2147483647;
+    if(val < -1.0) return -2147483647-1;
+    return (ALint)(val * 2147483647.0);
+}
+static __inline ALint Conv_ALint_ALmulaw(ALmulaw val)
+{ return Conv_ALint_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALuint Conv_ALuint_ALbyte(ALbyte val)
+{ return (val+128)<<24; }
+static __inline ALuint Conv_ALuint_ALubyte(ALubyte val)
+{ return val<<24; }
+static __inline ALuint Conv_ALuint_ALshort(ALshort val)
+{ return (val+32768)<<16; }
+static __inline ALuint Conv_ALuint_ALushort(ALushort val)
+{ return val<<16; }
+static __inline ALuint Conv_ALuint_ALint(ALint val)
+{ return val+2147483648u; }
+static __inline ALuint Conv_ALuint_ALuint(ALuint val)
+{ return val; }
+static __inline ALuint Conv_ALuint_ALfloat(ALfloat val)
+{
+    if(val > 1.0f) return 4294967295u;
+    if(val < -1.0f) return 0;
+    return (ALint)(val * 2147483647.0) + 2147483648u;
+}
+static __inline ALuint Conv_ALuint_ALdouble(ALdouble val)
+{
+    if(val > 1.0) return 4294967295u;
+    if(val < -1.0) return 0;
+    return (ALint)(val * 2147483647.0) + 2147483648u;
+}
+static __inline ALuint Conv_ALuint_ALmulaw(ALmulaw val)
+{ return Conv_ALuint_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALfloat Conv_ALfloat_ALbyte(ALbyte val)
+{ return val * (1.0f/127.0f); }
+static __inline ALfloat Conv_ALfloat_ALubyte(ALubyte val)
+{ return (val-128) * (1.0f/127.0f); }
+static __inline ALfloat Conv_ALfloat_ALshort(ALshort val)
+{ return val * (1.0f/32767.0f); }
+static __inline ALfloat Conv_ALfloat_ALushort(ALushort val)
+{ return (val-32768) * (1.0f/32767.0f); }
+static __inline ALfloat Conv_ALfloat_ALint(ALint val)
+{ return val * (1.0/2147483647.0); }
+static __inline ALfloat Conv_ALfloat_ALuint(ALuint val)
+{ return (ALint)(val-2147483648u) * (1.0/2147483647.0); }
+static __inline ALfloat Conv_ALfloat_ALfloat(ALfloat val)
+{ return val; }
+static __inline ALfloat Conv_ALfloat_ALdouble(ALdouble val)
+{ return val; }
+static __inline ALfloat Conv_ALfloat_ALmulaw(ALmulaw val)
+{ return Conv_ALfloat_ALshort(DecodeMuLaw(val)); }
+
+static __inline ALdouble Conv_ALdouble_ALbyte(ALbyte val)
+{ return val * (1.0/127.0); }
+static __inline ALdouble Conv_ALdouble_ALubyte(ALubyte val)
+{ return (val-128) * (1.0/127.0); }
+static __inline ALdouble Conv_ALdouble_ALshort(ALshort val)
+{ return val * (1.0/32767.0); }
+static __inline ALdouble Conv_ALdouble_ALushort(ALushort val)
+{ return (val-32768) * (1.0/32767.0); }
+static __inline ALdouble Conv_ALdouble_ALint(ALint val)
+{ return val * (1.0/2147483647.0); }
+static __inline ALdouble Conv_ALdouble_ALuint(ALuint val)
+{ return (ALint)(val-2147483648u) * (1.0/2147483647.0); }
+static __inline ALdouble Conv_ALdouble_ALfloat(ALfloat val)
+{ return val; }
+static __inline ALdouble Conv_ALdouble_ALdouble(ALdouble val)
+{ return val; }
+static __inline ALdouble Conv_ALdouble_ALmulaw(ALmulaw val)
+{ return Conv_ALdouble_ALshort(DecodeMuLaw(val)); }
+
+#define DECL_TEMPLATE(T)                                                      \
+static __inline ALmulaw Conv_ALmulaw_##T(T val)                               \
+{ return EncodeMuLaw(Conv_ALshort_##T(val)); }
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+static __inline ALmulaw Conv_ALmulaw_ALmulaw(ALmulaw val)
+{ return val; }
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T1, T2)                                                 \
+static void Convert_##T1##_##T2(T1 *dst, const T2 *src, ALuint len)           \
+{                                                                             \
+    ALuint i;                                                                 \
+    for(i = 0;i < len;i++)                                                    \
+        *(dst++) = Conv_##T1##_##T2(*(src++));                                \
+}
+
+DECL_TEMPLATE(ALbyte, ALbyte)
+DECL_TEMPLATE(ALbyte, ALubyte)
+DECL_TEMPLATE(ALbyte, ALshort)
+DECL_TEMPLATE(ALbyte, ALushort)
+DECL_TEMPLATE(ALbyte, ALint)
+DECL_TEMPLATE(ALbyte, ALuint)
+DECL_TEMPLATE(ALbyte, ALfloat)
+DECL_TEMPLATE(ALbyte, ALdouble)
+DECL_TEMPLATE(ALbyte, ALmulaw)
+
+DECL_TEMPLATE(ALubyte, ALbyte)
+DECL_TEMPLATE(ALubyte, ALubyte)
+DECL_TEMPLATE(ALubyte, ALshort)
+DECL_TEMPLATE(ALubyte, ALushort)
+DECL_TEMPLATE(ALubyte, ALint)
+DECL_TEMPLATE(ALubyte, ALuint)
+DECL_TEMPLATE(ALubyte, ALfloat)
+DECL_TEMPLATE(ALubyte, ALdouble)
+DECL_TEMPLATE(ALubyte, ALmulaw)
+
+DECL_TEMPLATE(ALshort, ALbyte)
+DECL_TEMPLATE(ALshort, ALubyte)
+DECL_TEMPLATE(ALshort, ALshort)
+DECL_TEMPLATE(ALshort, ALushort)
+DECL_TEMPLATE(ALshort, ALint)
+DECL_TEMPLATE(ALshort, ALuint)
+DECL_TEMPLATE(ALshort, ALfloat)
+DECL_TEMPLATE(ALshort, ALdouble)
+DECL_TEMPLATE(ALshort, ALmulaw)
+
+DECL_TEMPLATE(ALushort, ALbyte)
+DECL_TEMPLATE(ALushort, ALubyte)
+DECL_TEMPLATE(ALushort, ALshort)
+DECL_TEMPLATE(ALushort, ALushort)
+DECL_TEMPLATE(ALushort, ALint)
+DECL_TEMPLATE(ALushort, ALuint)
+DECL_TEMPLATE(ALushort, ALfloat)
+DECL_TEMPLATE(ALushort, ALdouble)
+DECL_TEMPLATE(ALushort, ALmulaw)
+
+DECL_TEMPLATE(ALint, ALbyte)
+DECL_TEMPLATE(ALint, ALubyte)
+DECL_TEMPLATE(ALint, ALshort)
+DECL_TEMPLATE(ALint, ALushort)
+DECL_TEMPLATE(ALint, ALint)
+DECL_TEMPLATE(ALint, ALuint)
+DECL_TEMPLATE(ALint, ALfloat)
+DECL_TEMPLATE(ALint, ALdouble)
+DECL_TEMPLATE(ALint, ALmulaw)
+
+DECL_TEMPLATE(ALuint, ALbyte)
+DECL_TEMPLATE(ALuint, ALubyte)
+DECL_TEMPLATE(ALuint, ALshort)
+DECL_TEMPLATE(ALuint, ALushort)
+DECL_TEMPLATE(ALuint, ALint)
+DECL_TEMPLATE(ALuint, ALuint)
+DECL_TEMPLATE(ALuint, ALfloat)
+DECL_TEMPLATE(ALuint, ALdouble)
+DECL_TEMPLATE(ALuint, ALmulaw)
+
+DECL_TEMPLATE(ALfloat, ALbyte)
+DECL_TEMPLATE(ALfloat, ALubyte)
+DECL_TEMPLATE(ALfloat, ALshort)
+DECL_TEMPLATE(ALfloat, ALushort)
+DECL_TEMPLATE(ALfloat, ALint)
+DECL_TEMPLATE(ALfloat, ALuint)
+DECL_TEMPLATE(ALfloat, ALfloat)
+DECL_TEMPLATE(ALfloat, ALdouble)
+DECL_TEMPLATE(ALfloat, ALmulaw)
+
+DECL_TEMPLATE(ALdouble, ALbyte)
+DECL_TEMPLATE(ALdouble, ALubyte)
+DECL_TEMPLATE(ALdouble, ALshort)
+DECL_TEMPLATE(ALdouble, ALushort)
+DECL_TEMPLATE(ALdouble, ALint)
+DECL_TEMPLATE(ALdouble, ALuint)
+DECL_TEMPLATE(ALdouble, ALfloat)
+DECL_TEMPLATE(ALdouble, ALdouble)
+DECL_TEMPLATE(ALdouble, ALmulaw)
+
+DECL_TEMPLATE(ALmulaw, ALbyte)
+DECL_TEMPLATE(ALmulaw, ALubyte)
+DECL_TEMPLATE(ALmulaw, ALshort)
+DECL_TEMPLATE(ALmulaw, ALushort)
+DECL_TEMPLATE(ALmulaw, ALint)
+DECL_TEMPLATE(ALmulaw, ALuint)
+DECL_TEMPLATE(ALmulaw, ALfloat)
+DECL_TEMPLATE(ALmulaw, ALdouble)
+DECL_TEMPLATE(ALmulaw, ALmulaw)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T)                                                      \
+static void Convert_##T##_IMA4(T *dst, const ALubyte *src, ALuint numchans,   \
+                               ALuint numblocks)                              \
+{                                                                             \
+    ALuint i, j;                                                              \
+    ALshort tmp[65*MAXCHANNELS]; /* Max samples an IMA4 frame can be */       \
+    for(i = 0;i < numblocks;i++)                                              \
+    {                                                                         \
+        DecodeIMA4Block(tmp, src, numchans);                                  \
+        src += 36*numchans;                                                   \
+        for(j = 0;j < 65*numchans;j++)                                        \
+            *(dst++) = Conv_##T##_ALshort(tmp[j]);                            \
+    }                                                                         \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+DECL_TEMPLATE(ALmulaw)
+
+#undef DECL_TEMPLATE
+
+#define DECL_TEMPLATE(T)                                                      \
+static void Convert_IMA4_##T(ALubyte *dst, const T *src, ALuint numchans,     \
+                             ALuint numblocks)                                \
+{                                                                             \
+    ALuint i, j;                                                              \
+    ALshort tmp[65*MAXCHANNELS]; /* Max samples an IMA4 frame can be */       \
+    ALint sample[MAXCHANNELS] = {0,0,0,0,0,0,0,0};                            \
+    ALint index[MAXCHANNELS] = {0,0,0,0,0,0,0,0};                             \
+    for(i = 0;i < numblocks;i++)                                              \
+    {                                                                         \
+        for(j = 0;j < 65*numchans;j++)                                        \
+            tmp[j] = Conv_ALshort_##T(*(src++));                              \
+        EncodeIMA4Block(dst, tmp, sample, index, numchans);                   \
+        dst += 36*numchans;                                                   \
+    }                                                                         \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+DECL_TEMPLATE(ALmulaw)
+
+#undef DECL_TEMPLATE
+
+static void Convert_IMA4_IMA4(ALubyte *dst, const ALubyte *src, ALuint numchans,
+                              ALuint numblocks)
+{
+    memcpy(dst, src, numblocks*36*numchans);
+}
+
+#define DECL_TEMPLATE(T)                                                      \
+static void Convert_##T(T *dst, const ALvoid *src, enum UserFmtType srcType,  \
+                        ALsizei len)                                          \
+{                                                                             \
+    switch(srcType)                                                           \
+    {                                                                         \
+        case UserFmtByte:                                                     \
+            Convert_##T##_ALbyte(dst, src, len);                              \
+            break;                                                            \
+        case UserFmtUByte:                                                    \
+            Convert_##T##_ALubyte(dst, src, len);                             \
+            break;                                                            \
+        case UserFmtShort:                                                    \
+            Convert_##T##_ALshort(dst, src, len);                             \
+            break;                                                            \
+        case UserFmtUShort:                                                   \
+            Convert_##T##_ALushort(dst, src, len);                            \
+            break;                                                            \
+        case UserFmtInt:                                                      \
+            Convert_##T##_ALint(dst, src, len);                               \
+            break;                                                            \
+        case UserFmtUInt:                                                     \
+            Convert_##T##_ALuint(dst, src, len);                              \
+            break;                                                            \
+        case UserFmtFloat:                                                    \
+            Convert_##T##_ALfloat(dst, src, len);                             \
+            break;                                                            \
+        case UserFmtDouble:                                                   \
+            Convert_##T##_ALdouble(dst, src, len);                            \
+            break;                                                            \
+        case UserFmtMulaw:                                                    \
+            Convert_##T##_ALmulaw(dst, src, len);                             \
+            break;                                                            \
+        case UserFmtIMA4:                                                     \
+            break; /* not handled here */                                     \
+    }                                                                         \
+}
+
+DECL_TEMPLATE(ALbyte)
+DECL_TEMPLATE(ALubyte)
+DECL_TEMPLATE(ALshort)
+DECL_TEMPLATE(ALushort)
+DECL_TEMPLATE(ALint)
+DECL_TEMPLATE(ALuint)
+DECL_TEMPLATE(ALfloat)
+DECL_TEMPLATE(ALdouble)
+DECL_TEMPLATE(ALmulaw)
+
+#undef DECL_TEMPLATE
+
+static void Convert_IMA4(ALubyte *dst, const ALvoid *src, enum UserFmtType srcType,
+                         ALint chans, ALsizei len)
+{
+    switch(srcType)
+    {
+        case UserFmtByte:
+            Convert_IMA4_ALbyte(dst, src, chans, len);
+            break;
+        case UserFmtUByte:
+            Convert_IMA4_ALubyte(dst, src, chans, len);
+            break;
+        case UserFmtShort:
+            Convert_IMA4_ALshort(dst, src, chans, len);
+            break;
+        case UserFmtUShort:
+            Convert_IMA4_ALushort(dst, src, chans, len);
+            break;
+        case UserFmtInt:
+            Convert_IMA4_ALint(dst, src, chans, len);
+            break;
+        case UserFmtUInt:
+            Convert_IMA4_ALuint(dst, src, chans, len);
+            break;
+        case UserFmtFloat:
+            Convert_IMA4_ALfloat(dst, src, chans, len);
+            break;
+        case UserFmtDouble:
+            Convert_IMA4_ALdouble(dst, src, chans, len);
+            break;
+        case UserFmtMulaw:
+            Convert_IMA4_ALmulaw(dst, src, chans, len);
+            break;
+        case UserFmtIMA4:
+            Convert_IMA4_IMA4(dst, src, chans, len);
+            break;
+    }
+}
+
+
+static void ConvertData(ALvoid *dst, enum FmtType dstType, const ALvoid *src, enum UserFmtType srcType, ALsizei len)
+{
+    switch(dstType)
+    {
+        (void)Convert_ALbyte;
+        case FmtUByte:
+            Convert_ALubyte(dst, src, srcType, len);
+            break;
+        case FmtShort:
+            Convert_ALshort(dst, src, srcType, len);
+            break;
+        (void)Convert_ALushort;
+        (void)Convert_ALint;
+        (void)Convert_ALuint;
+        case FmtFloat:
+            Convert_ALfloat(dst, src, srcType, len);
+            break;
+        (void)Convert_ALdouble;
+        (void)Convert_ALmulaw;
+        (void)Convert_IMA4;
+    }
+}
+
+static void ConvertDataIMA4(ALvoid *dst, enum FmtType dstType, const ALvoid *src, ALint chans, ALsizei len)
+{
+    switch(dstType)
+    {
+        (void)Convert_ALbyte_IMA4;
+        case FmtUByte:
+            Convert_ALubyte_IMA4(dst, src, chans, len);
+            break;
+        case FmtShort:
+            Convert_ALshort_IMA4(dst, src, chans, len);
+            break;
+        (void)Convert_ALushort_IMA4;
+        (void)Convert_ALint_IMA4;
+        (void)Convert_ALuint_IMA4;
+        case FmtFloat:
+            Convert_ALfloat_IMA4(dst, src, chans, len);
+            break;
+        (void)Convert_ALdouble_IMA4;
+        (void)Convert_ALmulaw_IMA4;
+    }
+}
+
+
+/*
+ * LoadData
+ *
+ * Loads the specified data into the buffer, using the specified formats.
+ * Currently, the new format must have the same channel configuration as the
+ * original format.
+ */
+static ALenum LoadData(ALbuffer *ALBuf, ALuint freq, ALenum NewFormat, ALsizei size, enum UserFmtChannels SrcChannels, enum UserFmtType SrcType, const ALvoid *data)
+{
+    ALuint NewChannels, NewBytes;
+    enum FmtChannels DstChannels;
+    enum FmtType DstType;
+    ALuint64 newsize;
+    ALvoid *temp;
+
+    DecomposeFormat(NewFormat, &DstChannels, &DstType);
+    NewChannels = ChannelsFromFmt(DstChannels);
+    NewBytes = BytesFromFmt(DstType);
+
+    assert(SrcChannels == DstChannels);
+
+    if(SrcType == UserFmtIMA4)
+    {
+        ALuint OrigChannels = ChannelsFromUserFmt(SrcChannels);
+
+        /* Here is where things vary:
+         * nVidia and Apple use 64+1 sample frames per block -> block_size=36 bytes per channel
+         * Most PC sound software uses 2040+1 sample frames per block -> block_size=1024 bytes per channel
+         */
+        if((size%(36*OrigChannels)) != 0)
+            return AL_INVALID_VALUE;
+
+        newsize = size / 36;
+        newsize *= 65;
+        newsize *= NewBytes;
+        if(newsize > INT_MAX)
+            return AL_OUT_OF_MEMORY;
+
+        temp = realloc(ALBuf->data, newsize);
+        if(!temp && newsize) return AL_OUT_OF_MEMORY;
+        ALBuf->data = temp;
+        ALBuf->size = newsize;
+
+        if(data != NULL)
+            ConvertDataIMA4(ALBuf->data, DstType, data, OrigChannels,
+                            newsize/(65*NewChannels*NewBytes));
+
+        ALBuf->OriginalChannels = SrcChannels;
+        ALBuf->OriginalType     = SrcType;
+        ALBuf->OriginalSize     = size;
+        ALBuf->OriginalAlign    = 36 * OrigChannels;
+    }
+    else
+    {
+        ALuint OrigBytes = BytesFromUserFmt(SrcType);
+        ALuint OrigChannels = ChannelsFromUserFmt(SrcChannels);
+
+        if((size%(OrigBytes*OrigChannels)) != 0)
+            return AL_INVALID_VALUE;
+
+        newsize = size / OrigBytes;
+        newsize *= NewBytes;
+        if(newsize > INT_MAX)
+            return AL_OUT_OF_MEMORY;
+
+        temp = realloc(ALBuf->data, newsize);
+        if(!temp && newsize) return AL_OUT_OF_MEMORY;
+        ALBuf->data = temp;
+        ALBuf->size = newsize;
+
+        if(data != NULL)
+            ConvertData(ALBuf->data, DstType, data, SrcType, newsize/NewBytes);
+
+        ALBuf->OriginalChannels = SrcChannels;
+        ALBuf->OriginalType     = SrcType;
+        ALBuf->OriginalSize     = size;
+        ALBuf->OriginalAlign    = OrigBytes * OrigChannels;
+    }
+
+    ALBuf->Frequency = freq;
+    ALBuf->FmtChannels = DstChannels;
+    ALBuf->FmtType = DstType;
+
+    ALBuf->LoopStart = 0;
+    ALBuf->LoopEnd = newsize / NewChannels / NewBytes;
+
+    return AL_NO_ERROR;
+}
+
+
+ALuint BytesFromUserFmt(enum UserFmtType type)
+{
+    switch(type)
+    {
+    case UserFmtByte: return sizeof(ALbyte);
+    case UserFmtUByte: return sizeof(ALubyte);
+    case UserFmtShort: return sizeof(ALshort);
+    case UserFmtUShort: return sizeof(ALushort);
+    case UserFmtInt: return sizeof(ALint);
+    case UserFmtUInt: return sizeof(ALuint);
+    case UserFmtFloat: return sizeof(ALfloat);
+    case UserFmtDouble: return sizeof(ALdouble);
+    case UserFmtMulaw: return sizeof(ALubyte);
+    case UserFmtIMA4: break; /* not handled here */
+    }
+    return 0;
+}
+ALuint ChannelsFromUserFmt(enum UserFmtChannels chans)
+{
+    switch(chans)
+    {
+    case UserFmtMono: return 1;
+    case UserFmtStereo: return 2;
+    case UserFmtRear: return 2;
+    case UserFmtQuad: return 4;
+    case UserFmtX51: return 6;
+    case UserFmtX61: return 7;
+    case UserFmtX71: return 8;
+    }
+    return 0;
+}
+ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans,
+                              enum UserFmtType *type)
+{
+    switch(format)
+    {
+        case AL_FORMAT_MONO8:
+            *chans = UserFmtMono;
+            *type  = UserFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_MONO16:
+            *chans = UserFmtMono;
+            *type  = UserFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_MONO_FLOAT32:
+            *chans = UserFmtMono;
+            *type  = UserFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_MONO_DOUBLE_EXT:
+            *chans = UserFmtMono;
+            *type  = UserFmtDouble;
+            return AL_TRUE;
+        case AL_FORMAT_MONO_IMA4:
+            *chans = UserFmtMono;
+            *type  = UserFmtIMA4;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO8:
+            *chans = UserFmtStereo;
+            *type  = UserFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO16:
+            *chans = UserFmtStereo;
+            *type  = UserFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO_FLOAT32:
+            *chans = UserFmtStereo;
+            *type  = UserFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO_DOUBLE_EXT:
+            *chans = UserFmtStereo;
+            *type  = UserFmtDouble;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO_IMA4:
+            *chans = UserFmtStereo;
+            *type  = UserFmtIMA4;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD8_LOKI:
+        case AL_FORMAT_QUAD8:
+            *chans = UserFmtQuad;
+            *type  = UserFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD16_LOKI:
+        case AL_FORMAT_QUAD16:
+            *chans = UserFmtQuad;
+            *type  = UserFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD32:
+            *chans = UserFmtQuad;
+            *type  = UserFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_REAR8:
+            *chans = UserFmtRear;
+            *type  = UserFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_REAR16:
+            *chans = UserFmtRear;
+            *type  = UserFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_REAR32:
+            *chans = UserFmtRear;
+            *type  = UserFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN8:
+            *chans = UserFmtX51;
+            *type  = UserFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN16:
+            *chans = UserFmtX51;
+            *type  = UserFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN32:
+            *chans = UserFmtX51;
+            *type  = UserFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN8:
+            *chans = UserFmtX61;
+            *type  = UserFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN16:
+            *chans = UserFmtX61;
+            *type  = UserFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN32:
+            *chans = UserFmtX61;
+            *type  = UserFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN8:
+            *chans = UserFmtX71;
+            *type  = UserFmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN16:
+            *chans = UserFmtX71;
+            *type  = UserFmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN32:
+            *chans = UserFmtX71;
+            *type  = UserFmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_MONO_MULAW:
+            *chans = UserFmtMono;
+            *type  = UserFmtMulaw;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO_MULAW:
+            *chans = UserFmtStereo;
+            *type  = UserFmtMulaw;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD_MULAW:
+            *chans = UserFmtQuad;
+            *type  = UserFmtMulaw;
+            return AL_TRUE;
+        case AL_FORMAT_REAR_MULAW:
+            *chans = UserFmtRear;
+            *type  = UserFmtMulaw;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN_MULAW:
+            *chans = UserFmtX51;
+            *type  = UserFmtMulaw;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN_MULAW:
+            *chans = UserFmtX61;
+            *type  = UserFmtMulaw;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN_MULAW:
+            *chans = UserFmtX71;
+            *type  = UserFmtMulaw;
+            return AL_TRUE;
+    }
+    return AL_FALSE;
+}
+
+ALuint BytesFromFmt(enum FmtType type)
+{
+    switch(type)
+    {
+    case FmtUByte: return sizeof(ALubyte);
+    case FmtShort: return sizeof(ALshort);
+    case FmtFloat: return sizeof(ALfloat);
+    }
+    return 0;
+}
+ALuint ChannelsFromFmt(enum FmtChannels chans)
+{
+    switch(chans)
+    {
+    case FmtMono: return 1;
+    case FmtStereo: return 2;
+    case FmtRear: return 2;
+    case FmtQuad: return 4;
+    case FmtX51: return 6;
+    case FmtX61: return 7;
+    case FmtX71: return 8;
+    }
+    return 0;
+}
+ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum FmtType *type)
+{
+    switch(format)
+    {
+        case AL_FORMAT_MONO8:
+            *chans = FmtMono;
+            *type  = FmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_MONO16:
+            *chans = FmtMono;
+            *type  = FmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_MONO_FLOAT32:
+            *chans = FmtMono;
+            *type  = FmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO8:
+            *chans = FmtStereo;
+            *type  = FmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO16:
+            *chans = FmtStereo;
+            *type  = FmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_STEREO_FLOAT32:
+            *chans = FmtStereo;
+            *type  = FmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD8_LOKI:
+        case AL_FORMAT_QUAD8:
+            *chans = FmtQuad;
+            *type  = FmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD16_LOKI:
+        case AL_FORMAT_QUAD16:
+            *chans = FmtQuad;
+            *type  = FmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_QUAD32:
+            *chans = FmtQuad;
+            *type  = FmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_REAR8:
+            *chans = FmtRear;
+            *type  = FmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_REAR16:
+            *chans = FmtRear;
+            *type  = FmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_REAR32:
+            *chans = FmtRear;
+            *type  = FmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN8:
+            *chans = FmtX51;
+            *type  = FmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN16:
+            *chans = FmtX51;
+            *type  = FmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_51CHN32:
+            *chans = FmtX51;
+            *type  = FmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN8:
+            *chans = FmtX61;
+            *type  = FmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN16:
+            *chans = FmtX61;
+            *type  = FmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_61CHN32:
+            *chans = FmtX61;
+            *type  = FmtFloat;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN8:
+            *chans = FmtX71;
+            *type  = FmtUByte;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN16:
+            *chans = FmtX71;
+            *type  = FmtShort;
+            return AL_TRUE;
+        case AL_FORMAT_71CHN32:
+            *chans = FmtX71;
+            *type  = FmtFloat;
+            return AL_TRUE;
+    }
+    return AL_FALSE;
+}
+
+
+/*
+ *    ReleaseALBuffers()
+ *
+ *    INTERNAL: Called to destroy any buffers that still exist on the device
+ */
+ALvoid ReleaseALBuffers(ALCdevice *device)
+{
+    ALsizei i;
+    for(i = 0;i < device->BufferMap.size;i++)
+    {
+        ALbuffer *temp = device->BufferMap.array[i].value;
+        device->BufferMap.array[i].value = NULL;
+
+        free(temp->data);
+
+        ALTHUNK_REMOVEENTRY(temp->buffer);
+        memset(temp, 0, sizeof(ALbuffer));
+        free(temp);
+    }
+}
diff --git a/OpenAL32/alDatabuffer.c b/OpenAL32/alDatabuffer.c
new file mode 100755 (executable)
index 0000000..cbe65a0
--- /dev/null
@@ -0,0 +1,648 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+#include "alError.h"
+#include "alDatabuffer.h"
+#include "alThunk.h"
+
+
+#define LookupDatabuffer(m, k) ((ALdatabuffer*)LookupUIntMapKey(&(m), (k)))
+
+/*
+*    alGenDatabuffersEXT(ALsizei n, ALuint *puiBuffers)
+*
+*    Generates n AL Databuffers, and stores the Databuffers Names in the array pointed to by puiBuffers
+*/
+AL_API ALvoid AL_APIENTRY alGenDatabuffersEXT(ALsizei n,ALuint *puiBuffers)
+{
+    ALCcontext *Context;
+    ALsizei i=0;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    /* Check that we are actually generation some Databuffers */
+    if(n < 0 || IsBadWritePtr((void*)puiBuffers, n * sizeof(ALuint)))
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        ALCdevice *device = Context->Device;
+        ALenum err;
+
+        /* Create all the new Databuffers */
+        while(i < n)
+        {
+            ALdatabuffer *buffer = calloc(1, sizeof(ALdatabuffer));
+            if(!buffer)
+            {
+                alSetError(Context, AL_OUT_OF_MEMORY);
+                alDeleteDatabuffersEXT(i, puiBuffers);
+                break;
+            }
+
+            buffer->databuffer = ALTHUNK_ADDENTRY(buffer);
+            err = InsertUIntMapEntry(&device->DatabufferMap,
+                                     buffer->databuffer, buffer);
+            if(err != AL_NO_ERROR)
+            {
+                ALTHUNK_REMOVEENTRY(buffer->databuffer);
+                memset(buffer, 0, sizeof(ALdatabuffer));
+                free(buffer);
+
+                alSetError(Context, err);
+                alDeleteDatabuffersEXT(i, puiBuffers);
+                break;
+            }
+            puiBuffers[i++] = buffer->databuffer;
+
+            buffer->state = UNMAPPED;
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+/*
+*    alDatabeleteBuffersEXT(ALsizei n, ALuint *puiBuffers)
+*
+*    Deletes the n AL Databuffers pointed to by puiBuffers
+*/
+AL_API ALvoid AL_APIENTRY alDeleteDatabuffersEXT(ALsizei n, const ALuint *buffers)
+{
+    ALCcontext *Context;
+    ALCdevice *device;
+    ALdatabuffer *ALBuf;
+    ALboolean Failed;
+    ALsizei i;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    /* Check we are actually Deleting some Databuffers */
+    Failed = AL_TRUE;
+    device = Context->Device;
+    if(n < 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        Failed = AL_FALSE;
+        /* Check that all the databuffers are valid and can actually be
+         * deleted */
+        for(i = 0;i < n;i++)
+        {
+            if(!buffers[i])
+                continue;
+
+            /* Check for valid Buffer ID */
+            if((ALBuf=LookupDatabuffer(device->DatabufferMap, buffers[i])) == NULL)
+            {
+                /* Invalid Databuffer */
+                alSetError(Context, AL_INVALID_NAME);
+                Failed = AL_TRUE;
+                break;
+            }
+            else if(ALBuf->state != UNMAPPED)
+            {
+                /* Databuffer still in use, cannot be deleted */
+                alSetError(Context, AL_INVALID_OPERATION);
+                Failed = AL_TRUE;
+                break;
+            }
+        }
+    }
+
+    /* If all the Databuffers were valid (and unmapped), then we can delete them */
+    if(!Failed)
+    {
+        for(i = 0;i < n;i++)
+        {
+            if((ALBuf=LookupDatabuffer(device->DatabufferMap, buffers[i])) == NULL)
+                continue;
+
+            if(ALBuf == Context->SampleSource)
+                Context->SampleSource = NULL;
+            if(ALBuf == Context->SampleSink)
+                Context->SampleSink = NULL;
+
+            // Release the memory used to store audio data
+            free(ALBuf->data);
+
+            // Release buffer structure
+            RemoveUIntMapKey(&device->DatabufferMap, ALBuf->databuffer);
+            ALTHUNK_REMOVEENTRY(ALBuf->databuffer);
+
+            memset(ALBuf, 0, sizeof(ALdatabuffer));
+            free(ALBuf);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+/*
+*    alIsDatabufferEXT(ALuint uiBuffer)
+*
+*    Checks if ulBuffer is a valid Databuffer Name
+*/
+AL_API ALboolean AL_APIENTRY alIsDatabufferEXT(ALuint buffer)
+{
+    ALCcontext *Context;
+    ALboolean  result;
+    ALCdevice *device;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_FALSE;
+
+    device = Context->Device;
+    result = ((!buffer || LookupDatabuffer(device->DatabufferMap, buffer)) ?
+              AL_TRUE : AL_FALSE);
+
+    ProcessContext(Context);
+
+    return result;
+}
+
+/*
+*    alDatabufferDataEXT(ALuint buffer,ALvoid *data,ALsizei size,ALenum usage)
+*
+*    Fill databuffer with data
+*/
+AL_API ALvoid AL_APIENTRY alDatabufferDataEXT(ALuint buffer,const ALvoid *data,ALsizeiptrEXT size,ALenum usage)
+{
+    ALCcontext *Context;
+    ALdatabuffer *ALBuf;
+    ALCdevice *Device;
+    ALvoid *temp;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALBuf=LookupDatabuffer(Device->DatabufferMap, buffer)) != NULL)
+    {
+        if(ALBuf->state == UNMAPPED)
+        {
+            if(usage == AL_STREAM_WRITE_EXT || usage == AL_STREAM_READ_EXT ||
+               usage == AL_STREAM_COPY_EXT || usage == AL_STATIC_WRITE_EXT ||
+               usage == AL_STATIC_READ_EXT || usage == AL_STATIC_COPY_EXT ||
+               usage == AL_DYNAMIC_WRITE_EXT || usage == AL_DYNAMIC_READ_EXT ||
+               usage == AL_DYNAMIC_COPY_EXT)
+            {
+                if(size >= 0)
+                {
+                    /* (Re)allocate data */
+                    temp = realloc(ALBuf->data, size);
+                    if(temp)
+                    {
+                        ALBuf->data = temp;
+                        ALBuf->size = size;
+                        ALBuf->usage = usage;
+                        if(data)
+                            memcpy(ALBuf->data, data, size);
+                    }
+                    else
+                        alSetError(Context, AL_OUT_OF_MEMORY);
+                }
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+            }
+            else
+                alSetError(Context, AL_INVALID_ENUM);
+        }
+        else
+            alSetError(Context, AL_INVALID_OPERATION);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDatabufferSubDataEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, const ALvoid *data)
+{
+    ALCcontext    *pContext;
+    ALdatabuffer  *pBuffer;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    Device = pContext->Device;
+    if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+    {
+        if(start >= 0 && length >= 0 && start+length <= pBuffer->size)
+        {
+            if(pBuffer->state == UNMAPPED)
+                memcpy(pBuffer->data+start, data, length);
+            else
+                alSetError(pContext, AL_INVALID_OPERATION);
+        }
+        else
+            alSetError(pContext, AL_INVALID_VALUE);
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferSubDataEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALvoid *data)
+{
+    ALCcontext    *pContext;
+    ALdatabuffer  *pBuffer;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    Device = pContext->Device;
+    if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+    {
+        if(start >= 0 && length >= 0 && start+length <= pBuffer->size)
+        {
+            if(pBuffer->state == UNMAPPED)
+                memcpy(data, pBuffer->data+start, length);
+            else
+                alSetError(pContext, AL_INVALID_OPERATION);
+        }
+        else
+            alSetError(pContext, AL_INVALID_VALUE);
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat flValue)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *Device;
+
+    (void)flValue;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    Device = pContext->Device;
+    if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alDatabufferfvEXT(ALuint buffer, ALenum eParam, const ALfloat* flValues)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *Device;
+
+    (void)flValues;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    Device = pContext->Device;
+    if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alDatabufferiEXT(ALuint buffer, ALenum eParam, ALint lValue)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *Device;
+
+    (void)lValue;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    Device = pContext->Device;
+    if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alDatabufferivEXT(ALuint buffer, ALenum eParam, const ALint* plValues)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *Device;
+
+    (void)plValues;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    Device = pContext->Device;
+    if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+    {
+        switch(eParam)
+        {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferfEXT(ALuint buffer, ALenum eParam, ALfloat *pflValue)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValue)
+    {
+        Device = pContext->Device;
+        if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+        {
+            switch(eParam)
+            {
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferfvEXT(ALuint buffer, ALenum eParam, ALfloat* pflValues)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValues)
+    {
+        Device = pContext->Device;
+        if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+        {
+            switch(eParam)
+            {
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferiEXT(ALuint buffer, ALenum eParam, ALint *plValue)
+{
+    ALCcontext    *pContext;
+    ALdatabuffer  *pBuffer;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValue)
+    {
+        Device = pContext->Device;
+        if((pBuffer=LookupDatabuffer(Device->DatabufferMap, buffer)) != NULL)
+        {
+            switch(eParam)
+            {
+            case AL_SIZE:
+                *plValue = (ALint)pBuffer->size;
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDatabufferivEXT(ALuint buffer, ALenum eParam, ALint* plValues)
+{
+    ALCcontext    *pContext;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValues)
+    {
+        Device = pContext->Device;
+        if(LookupDatabuffer(Device->DatabufferMap, buffer) != NULL)
+        {
+            switch (eParam)
+            {
+            case AL_SIZE:
+                alGetDatabufferiEXT(buffer, eParam, plValues);
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSelectDatabufferEXT(ALenum target, ALuint uiBuffer)
+{
+    ALCcontext    *pContext;
+    ALdatabuffer  *pBuffer = NULL;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    Device = pContext->Device;
+    if(uiBuffer == 0 ||
+       (pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+    {
+        if(target == AL_SAMPLE_SOURCE_EXT)
+            pContext->SampleSource = pBuffer;
+        else if(target == AL_SAMPLE_SINK_EXT)
+            pContext->SampleSink = pBuffer;
+        else
+            alSetError(pContext, AL_INVALID_VALUE);
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid* AL_APIENTRY alMapDatabufferEXT(ALuint uiBuffer, ALintptrEXT start, ALsizeiptrEXT length, ALenum access)
+{
+    ALCcontext    *pContext;
+    ALdatabuffer  *pBuffer;
+    ALvoid        *ret = NULL;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return NULL;
+
+    Device = pContext->Device;
+    if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+    {
+        if(start >= 0 && length >= 0 && start+length <= pBuffer->size)
+        {
+            if(access == AL_READ_ONLY_EXT || access == AL_WRITE_ONLY_EXT ||
+               access == AL_READ_WRITE_EXT)
+            {
+                if(pBuffer->state == UNMAPPED)
+                {
+                    ret = pBuffer->data + start;
+                    pBuffer->state = MAPPED;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_OPERATION);
+            }
+            else
+                alSetError(pContext, AL_INVALID_ENUM);
+        }
+        else
+            alSetError(pContext, AL_INVALID_VALUE);
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+
+    return ret;
+}
+
+AL_API ALvoid AL_APIENTRY alUnmapDatabufferEXT(ALuint uiBuffer)
+{
+    ALCcontext    *pContext;
+    ALdatabuffer  *pBuffer;
+    ALCdevice     *Device;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    Device = pContext->Device;
+    if((pBuffer=LookupDatabuffer(Device->DatabufferMap, uiBuffer)) != NULL)
+    {
+        if(pBuffer->state == MAPPED)
+            pBuffer->state = UNMAPPED;
+        else
+            alSetError(pContext, AL_INVALID_OPERATION);
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+
+/*
+*    ReleaseALDatabuffers()
+*
+*    INTERNAL FN : Called by DLLMain on exit to destroy any buffers that still exist
+*/
+ALvoid ReleaseALDatabuffers(ALCdevice *device)
+{
+    ALsizei i;
+    for(i = 0;i < device->DatabufferMap.size;i++)
+    {
+        ALdatabuffer *temp = device->DatabufferMap.array[i].value;
+        device->DatabufferMap.array[i].value = NULL;
+
+        // Release buffer data
+        free(temp->data);
+
+        // Release Buffer structure
+        ALTHUNK_REMOVEENTRY(temp->databuffer);
+        memset(temp, 0, sizeof(ALdatabuffer));
+        free(temp);
+    }
+}
diff --git a/OpenAL32/alEffect.c b/OpenAL32/alEffect.c
new file mode 100755 (executable)
index 0000000..0814cfe
--- /dev/null
@@ -0,0 +1,1376 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alEffect.h"
+#include "alThunk.h"
+#include "alError.h"
+
+
+ALboolean DisabledEffects[MAX_EFFECTS];
+
+
+static void InitEffectParams(ALeffect *effect, ALenum type);
+
+#define LookupEffect(m, k) ((ALeffect*)LookupUIntMapKey(&(m), (k)))
+
+AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects)
+{
+    ALCcontext *Context;
+    ALsizei i=0;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0 || IsBadWritePtr((void*)effects, n * sizeof(ALuint)))
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        ALCdevice *device = Context->Device;
+        ALenum err;
+
+        while(i < n)
+        {
+            ALeffect *effect = calloc(1, sizeof(ALeffect));
+            if(!effect)
+            {
+                alSetError(Context, AL_OUT_OF_MEMORY);
+                alDeleteEffects(i, effects);
+                break;
+            }
+
+            effect->effect = ALTHUNK_ADDENTRY(effect);
+            err = InsertUIntMapEntry(&device->EffectMap, effect->effect, effect);
+            if(err != AL_NO_ERROR)
+            {
+                ALTHUNK_REMOVEENTRY(effect->effect);
+                memset(effect, 0, sizeof(ALeffect));
+                free(effect);
+
+                alSetError(Context, err);
+                alDeleteEffects(i, effects);
+                break;
+            }
+
+            effects[i++] = effect->effect;
+            InitEffectParams(effect, AL_EFFECT_NULL);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects)
+{
+    ALCcontext *Context;
+    ALCdevice *device;
+    ALeffect *ALEffect;
+    ALboolean Failed;
+    ALsizei i;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Failed = AL_TRUE;
+    device = Context->Device;
+    if(n < 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        Failed = AL_FALSE;
+        // Check that all effects are valid
+        for(i = 0;i < n;i++)
+        {
+            if(!effects[i])
+                continue;
+
+            if(LookupEffect(device->EffectMap, effects[i]) == NULL)
+            {
+                alSetError(Context, AL_INVALID_NAME);
+                Failed = AL_TRUE;
+                break;
+            }
+        }
+    }
+
+    if(!Failed)
+    {
+        // All effects are valid
+        for(i = 0;i < n;i++)
+        {
+            // Recheck that the effect is valid, because there could be duplicated names
+            if((ALEffect=LookupEffect(device->EffectMap, effects[i])) == NULL)
+                continue;
+
+            RemoveUIntMapKey(&device->EffectMap, ALEffect->effect);
+            ALTHUNK_REMOVEENTRY(ALEffect->effect);
+
+            memset(ALEffect, 0, sizeof(ALeffect));
+            free(ALEffect);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect)
+{
+    ALCcontext *Context;
+    ALboolean  result;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_FALSE;
+
+    result = ((!effect || LookupEffect(Context->Device->EffectMap, effect)) ?
+              AL_TRUE : AL_FALSE);
+
+    ProcessContext(Context);
+
+    return result;
+}
+
+AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALeffect   *ALEffect;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+    {
+        if(param == AL_EFFECT_TYPE)
+        {
+            ALboolean isOk = (iValue == AL_EFFECT_NULL ||
+                (iValue == AL_EFFECT_EAXREVERB && !DisabledEffects[EAXREVERB]) ||
+                (iValue == AL_EFFECT_REVERB && !DisabledEffects[REVERB]) ||
+                (iValue == AL_EFFECT_ECHO && !DisabledEffects[ECHO]) ||
+                (iValue == AL_EFFECT_RING_MODULATOR && !DisabledEffects[MODULATOR]));
+
+            if(isOk)
+                InitEffectParams(ALEffect, iValue);
+            else
+                alSetError(Context, AL_INVALID_VALUE);
+        }
+        else if(ALEffect->type == AL_EFFECT_EAXREVERB)
+        {
+            switch(param)
+            {
+            case AL_EAXREVERB_DECAY_HFLIMIT:
+                if(iValue >= AL_EAXREVERB_MIN_DECAY_HFLIMIT &&
+                   iValue <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)
+                    ALEffect->Reverb.DecayHFLimit = iValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_REVERB)
+        {
+            switch(param)
+            {
+            case AL_REVERB_DECAY_HFLIMIT:
+                if(iValue >= AL_REVERB_MIN_DECAY_HFLIMIT &&
+                   iValue <= AL_REVERB_MAX_DECAY_HFLIMIT)
+                    ALEffect->Reverb.DecayHFLimit = iValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_ECHO)
+        {
+            switch(param)
+            {
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+        {
+            switch(param)
+            {
+            case AL_RING_MODULATOR_FREQUENCY:
+            case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+                alEffectf(effect, param, (ALfloat)iValue);
+                break;
+
+            case AL_RING_MODULATOR_WAVEFORM:
+                if(iValue >= AL_RING_MODULATOR_MIN_WAVEFORM &&
+                   iValue <= AL_RING_MODULATOR_MAX_WAVEFORM)
+                    ALEffect->Modulator.Waveform = iValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(Context, AL_INVALID_ENUM);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALeffect   *ALEffect;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+    {
+        if(param == AL_EFFECT_TYPE)
+        {
+            alEffecti(effect, param, piValues[0]);
+        }
+        else if(ALEffect->type == AL_EFFECT_EAXREVERB)
+        {
+            switch(param)
+            {
+            case AL_EAXREVERB_DECAY_HFLIMIT:
+                alEffecti(effect, param, piValues[0]);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_REVERB)
+        {
+            switch(param)
+            {
+            case AL_REVERB_DECAY_HFLIMIT:
+                alEffecti(effect, param, piValues[0]);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_ECHO)
+        {
+            switch(param)
+            {
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+        {
+            switch(param)
+            {
+            case AL_RING_MODULATOR_FREQUENCY:
+            case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+            case AL_RING_MODULATOR_WAVEFORM:
+                alEffecti(effect, param, piValues[0]);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(Context, AL_INVALID_ENUM);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALeffect   *ALEffect;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+    {
+        if(ALEffect->type == AL_EFFECT_EAXREVERB)
+        {
+            switch(param)
+            {
+            case AL_EAXREVERB_DENSITY:
+                if(flValue >= AL_EAXREVERB_MIN_DENSITY &&
+                   flValue <= AL_EAXREVERB_MAX_DENSITY)
+                    ALEffect->Reverb.Density = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_DIFFUSION:
+                if(flValue >= AL_EAXREVERB_MIN_DIFFUSION &&
+                   flValue <= AL_EAXREVERB_MAX_DIFFUSION)
+                    ALEffect->Reverb.Diffusion = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_GAIN:
+                if(flValue >= AL_EAXREVERB_MIN_GAIN &&
+                   flValue <= AL_EAXREVERB_MAX_GAIN)
+                    ALEffect->Reverb.Gain = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_GAINHF:
+                if(flValue >= AL_EAXREVERB_MIN_GAINHF &&
+                   flValue <= AL_EAXREVERB_MAX_GAIN)
+                    ALEffect->Reverb.GainHF = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_GAINLF:
+                if(flValue >= AL_EAXREVERB_MIN_GAINLF &&
+                   flValue <= AL_EAXREVERB_MAX_GAINLF)
+                    ALEffect->Reverb.GainLF = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_DECAY_TIME:
+                if(flValue >= AL_EAXREVERB_MIN_DECAY_TIME &&
+                   flValue <= AL_EAXREVERB_MAX_DECAY_TIME)
+                    ALEffect->Reverb.DecayTime = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_DECAY_HFRATIO:
+                if(flValue >= AL_EAXREVERB_MIN_DECAY_HFRATIO &&
+                   flValue <= AL_EAXREVERB_MAX_DECAY_HFRATIO)
+                    ALEffect->Reverb.DecayHFRatio = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_DECAY_LFRATIO:
+                if(flValue >= AL_EAXREVERB_MIN_DECAY_LFRATIO &&
+                   flValue <= AL_EAXREVERB_MAX_DECAY_LFRATIO)
+                    ALEffect->Reverb.DecayLFRatio = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_REFLECTIONS_GAIN:
+                if(flValue >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN &&
+                   flValue <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)
+                    ALEffect->Reverb.ReflectionsGain = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_REFLECTIONS_DELAY:
+                if(flValue >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY &&
+                   flValue <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)
+                    ALEffect->Reverb.ReflectionsDelay = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_LATE_REVERB_GAIN:
+                if(flValue >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN &&
+                   flValue <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)
+                    ALEffect->Reverb.LateReverbGain = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_LATE_REVERB_DELAY:
+                if(flValue >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY &&
+                   flValue <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)
+                    ALEffect->Reverb.LateReverbDelay = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+                if(flValue >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF &&
+                   flValue <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)
+                    ALEffect->Reverb.AirAbsorptionGainHF = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_ECHO_TIME:
+                if(flValue >= AL_EAXREVERB_MIN_ECHO_TIME &&
+                   flValue <= AL_EAXREVERB_MAX_ECHO_TIME)
+                    ALEffect->Reverb.EchoTime = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_ECHO_DEPTH:
+                if(flValue >= AL_EAXREVERB_MIN_ECHO_DEPTH &&
+                   flValue <= AL_EAXREVERB_MAX_ECHO_DEPTH)
+                    ALEffect->Reverb.EchoDepth = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_MODULATION_TIME:
+                if(flValue >= AL_EAXREVERB_MIN_MODULATION_TIME &&
+                   flValue <= AL_EAXREVERB_MAX_MODULATION_TIME)
+                    ALEffect->Reverb.ModulationTime = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_MODULATION_DEPTH:
+                if(flValue >= AL_EAXREVERB_MIN_MODULATION_DEPTH &&
+                   flValue <= AL_EAXREVERB_MAX_MODULATION_DEPTH)
+                    ALEffect->Reverb.ModulationDepth = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_HFREFERENCE:
+                if(flValue >= AL_EAXREVERB_MIN_HFREFERENCE &&
+                   flValue <= AL_EAXREVERB_MAX_HFREFERENCE)
+                    ALEffect->Reverb.HFReference = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_LFREFERENCE:
+                if(flValue >= AL_EAXREVERB_MIN_LFREFERENCE &&
+                   flValue <= AL_EAXREVERB_MAX_LFREFERENCE)
+                    ALEffect->Reverb.LFReference = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+                if(flValue >= 0.0f && flValue <= 10.0f)
+                    ALEffect->Reverb.RoomRolloffFactor = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_REVERB)
+        {
+            switch(param)
+            {
+            case AL_REVERB_DENSITY:
+                if(flValue >= AL_REVERB_MIN_DENSITY &&
+                   flValue <= AL_REVERB_MAX_DENSITY)
+                    ALEffect->Reverb.Density = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_DIFFUSION:
+                if(flValue >= AL_REVERB_MIN_DIFFUSION &&
+                   flValue <= AL_REVERB_MAX_DIFFUSION)
+                    ALEffect->Reverb.Diffusion = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_GAIN:
+                if(flValue >= AL_REVERB_MIN_GAIN &&
+                   flValue <= AL_REVERB_MAX_GAIN)
+                    ALEffect->Reverb.Gain = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_GAINHF:
+                if(flValue >= AL_REVERB_MIN_GAINHF &&
+                   flValue <= AL_REVERB_MAX_GAINHF)
+                    ALEffect->Reverb.GainHF = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_DECAY_TIME:
+                if(flValue >= AL_REVERB_MIN_DECAY_TIME &&
+                   flValue <= AL_REVERB_MAX_DECAY_TIME)
+                    ALEffect->Reverb.DecayTime = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_DECAY_HFRATIO:
+                if(flValue >= AL_REVERB_MIN_DECAY_HFRATIO &&
+                   flValue <= AL_REVERB_MAX_DECAY_HFRATIO)
+                    ALEffect->Reverb.DecayHFRatio = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_REFLECTIONS_GAIN:
+                if(flValue >= AL_REVERB_MIN_REFLECTIONS_GAIN &&
+                   flValue <= AL_REVERB_MAX_REFLECTIONS_GAIN)
+                    ALEffect->Reverb.ReflectionsGain = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_REFLECTIONS_DELAY:
+                if(flValue >= AL_REVERB_MIN_REFLECTIONS_DELAY &&
+                   flValue <= AL_REVERB_MAX_REFLECTIONS_DELAY)
+                    ALEffect->Reverb.ReflectionsDelay = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_LATE_REVERB_GAIN:
+                if(flValue >= AL_REVERB_MIN_LATE_REVERB_GAIN &&
+                   flValue <= AL_REVERB_MAX_LATE_REVERB_GAIN)
+                    ALEffect->Reverb.LateReverbGain = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_LATE_REVERB_DELAY:
+                if(flValue >= AL_REVERB_MIN_LATE_REVERB_DELAY &&
+                   flValue <= AL_REVERB_MAX_LATE_REVERB_DELAY)
+                    ALEffect->Reverb.LateReverbDelay = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_AIR_ABSORPTION_GAINHF:
+                if(flValue >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF &&
+                   flValue <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)
+                    ALEffect->Reverb.AirAbsorptionGainHF = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+                if(flValue >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR &&
+                   flValue <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)
+                    ALEffect->Reverb.RoomRolloffFactor = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_ECHO)
+        {
+            switch(param)
+            {
+            case AL_ECHO_DELAY:
+                if(flValue >= AL_ECHO_MIN_DELAY && flValue <= AL_ECHO_MAX_DELAY)
+                    ALEffect->Echo.Delay = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_ECHO_LRDELAY:
+                if(flValue >= AL_ECHO_MIN_LRDELAY && flValue <= AL_ECHO_MAX_LRDELAY)
+                    ALEffect->Echo.LRDelay = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_ECHO_DAMPING:
+                if(flValue >= AL_ECHO_MIN_DAMPING && flValue <= AL_ECHO_MAX_DAMPING)
+                    ALEffect->Echo.Damping = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_ECHO_FEEDBACK:
+                if(flValue >= AL_ECHO_MIN_FEEDBACK && flValue <= AL_ECHO_MAX_FEEDBACK)
+                    ALEffect->Echo.Feedback = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_ECHO_SPREAD:
+                if(flValue >= AL_ECHO_MIN_SPREAD && flValue <= AL_ECHO_MAX_SPREAD)
+                    ALEffect->Echo.Spread = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+        {
+            switch(param)
+            {
+            case AL_RING_MODULATOR_FREQUENCY:
+                if(flValue >= AL_RING_MODULATOR_MIN_FREQUENCY &&
+                   flValue <= AL_RING_MODULATOR_MAX_FREQUENCY)
+                    ALEffect->Modulator.Frequency = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+                if(flValue >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF &&
+                   flValue <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF)
+                    ALEffect->Modulator.HighPassCutoff = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(Context, AL_INVALID_ENUM);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALeffect   *ALEffect;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+    {
+        if(ALEffect->type == AL_EFFECT_EAXREVERB)
+        {
+            switch(param)
+            {
+            case AL_EAXREVERB_DENSITY:
+            case AL_EAXREVERB_DIFFUSION:
+            case AL_EAXREVERB_GAIN:
+            case AL_EAXREVERB_GAINHF:
+            case AL_EAXREVERB_GAINLF:
+            case AL_EAXREVERB_DECAY_TIME:
+            case AL_EAXREVERB_DECAY_HFRATIO:
+            case AL_EAXREVERB_DECAY_LFRATIO:
+            case AL_EAXREVERB_REFLECTIONS_GAIN:
+            case AL_EAXREVERB_REFLECTIONS_DELAY:
+            case AL_EAXREVERB_LATE_REVERB_GAIN:
+            case AL_EAXREVERB_LATE_REVERB_DELAY:
+            case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+            case AL_EAXREVERB_ECHO_TIME:
+            case AL_EAXREVERB_ECHO_DEPTH:
+            case AL_EAXREVERB_MODULATION_TIME:
+            case AL_EAXREVERB_MODULATION_DEPTH:
+            case AL_EAXREVERB_HFREFERENCE:
+            case AL_EAXREVERB_LFREFERENCE:
+            case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+                alEffectf(effect, param, pflValues[0]);
+                break;
+
+            case AL_EAXREVERB_REFLECTIONS_PAN:
+                if(!isnan(pflValues[0]) && !isnan(pflValues[1]) && !isnan(pflValues[2]))
+                {
+                    ALEffect->Reverb.ReflectionsPan[0] = pflValues[0];
+                    ALEffect->Reverb.ReflectionsPan[1] = pflValues[1];
+                    ALEffect->Reverb.ReflectionsPan[2] = pflValues[2];
+                }
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+            case AL_EAXREVERB_LATE_REVERB_PAN:
+                if(!isnan(pflValues[0]) && !isnan(pflValues[1]) && !isnan(pflValues[2]))
+                {
+                    ALEffect->Reverb.LateReverbPan[0] = pflValues[0];
+                    ALEffect->Reverb.LateReverbPan[1] = pflValues[1];
+                    ALEffect->Reverb.LateReverbPan[2] = pflValues[2];
+                }
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_REVERB)
+        {
+            switch(param)
+            {
+            case AL_REVERB_DENSITY:
+            case AL_REVERB_DIFFUSION:
+            case AL_REVERB_GAIN:
+            case AL_REVERB_GAINHF:
+            case AL_REVERB_DECAY_TIME:
+            case AL_REVERB_DECAY_HFRATIO:
+            case AL_REVERB_REFLECTIONS_GAIN:
+            case AL_REVERB_REFLECTIONS_DELAY:
+            case AL_REVERB_LATE_REVERB_GAIN:
+            case AL_REVERB_LATE_REVERB_DELAY:
+            case AL_REVERB_AIR_ABSORPTION_GAINHF:
+            case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+                alEffectf(effect, param, pflValues[0]);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_ECHO)
+        {
+            switch(param)
+            {
+            case AL_ECHO_DELAY:
+            case AL_ECHO_LRDELAY:
+            case AL_ECHO_DAMPING:
+            case AL_ECHO_FEEDBACK:
+            case AL_ECHO_SPREAD:
+                alEffectf(effect, param, pflValues[0]);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+        {
+            switch(param)
+            {
+            case AL_RING_MODULATOR_FREQUENCY:
+            case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+                alEffectf(effect, param, pflValues[0]);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(Context, AL_INVALID_ENUM);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALeffect   *ALEffect;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+    {
+        if(param == AL_EFFECT_TYPE)
+        {
+            *piValue = ALEffect->type;
+        }
+        else if(ALEffect->type == AL_EFFECT_EAXREVERB)
+        {
+            switch(param)
+            {
+            case AL_EAXREVERB_DECAY_HFLIMIT:
+                *piValue = ALEffect->Reverb.DecayHFLimit;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_REVERB)
+        {
+            switch(param)
+            {
+            case AL_REVERB_DECAY_HFLIMIT:
+                *piValue = ALEffect->Reverb.DecayHFLimit;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_ECHO)
+        {
+            switch(param)
+            {
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+        {
+            switch(param)
+            {
+            case AL_RING_MODULATOR_FREQUENCY:
+                *piValue = (ALint)ALEffect->Modulator.Frequency;
+                break;
+            case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+                *piValue = (ALint)ALEffect->Modulator.HighPassCutoff;
+                break;
+            case AL_RING_MODULATOR_WAVEFORM:
+                *piValue = ALEffect->Modulator.Waveform;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(Context, AL_INVALID_ENUM);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALeffect   *ALEffect;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+    {
+        if(param == AL_EFFECT_TYPE)
+        {
+            alGetEffecti(effect, param, piValues);
+        }
+        else if(ALEffect->type == AL_EFFECT_EAXREVERB)
+        {
+            switch(param)
+            {
+            case AL_EAXREVERB_DECAY_HFLIMIT:
+                alGetEffecti(effect, param, piValues);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_REVERB)
+        {
+            switch(param)
+            {
+            case AL_REVERB_DECAY_HFLIMIT:
+                alGetEffecti(effect, param, piValues);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_ECHO)
+        {
+            switch(param)
+            {
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+        {
+            switch(param)
+            {
+            case AL_RING_MODULATOR_FREQUENCY:
+            case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+            case AL_RING_MODULATOR_WAVEFORM:
+                alGetEffecti(effect, param, piValues);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(Context, AL_INVALID_ENUM);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALeffect   *ALEffect;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+    {
+        if(ALEffect->type == AL_EFFECT_EAXREVERB)
+        {
+            switch(param)
+            {
+            case AL_EAXREVERB_DENSITY:
+                *pflValue = ALEffect->Reverb.Density;
+                break;
+
+            case AL_EAXREVERB_DIFFUSION:
+                *pflValue = ALEffect->Reverb.Diffusion;
+                break;
+
+            case AL_EAXREVERB_GAIN:
+                *pflValue = ALEffect->Reverb.Gain;
+                break;
+
+            case AL_EAXREVERB_GAINHF:
+                *pflValue = ALEffect->Reverb.GainHF;
+                break;
+
+            case AL_EAXREVERB_GAINLF:
+                *pflValue = ALEffect->Reverb.GainLF;
+                break;
+
+            case AL_EAXREVERB_DECAY_TIME:
+                *pflValue = ALEffect->Reverb.DecayTime;
+                break;
+
+            case AL_EAXREVERB_DECAY_HFRATIO:
+                *pflValue = ALEffect->Reverb.DecayHFRatio;
+                break;
+
+            case AL_EAXREVERB_DECAY_LFRATIO:
+                *pflValue = ALEffect->Reverb.DecayLFRatio;
+                break;
+
+            case AL_EAXREVERB_REFLECTIONS_GAIN:
+                *pflValue = ALEffect->Reverb.ReflectionsGain;
+                break;
+
+            case AL_EAXREVERB_REFLECTIONS_DELAY:
+                *pflValue = ALEffect->Reverb.ReflectionsDelay;
+                break;
+
+            case AL_EAXREVERB_LATE_REVERB_GAIN:
+                *pflValue = ALEffect->Reverb.LateReverbGain;
+                break;
+
+            case AL_EAXREVERB_LATE_REVERB_DELAY:
+                *pflValue = ALEffect->Reverb.LateReverbDelay;
+                break;
+
+            case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+                *pflValue = ALEffect->Reverb.AirAbsorptionGainHF;
+                break;
+
+            case AL_EAXREVERB_ECHO_TIME:
+                *pflValue = ALEffect->Reverb.EchoTime;
+                break;
+
+            case AL_EAXREVERB_ECHO_DEPTH:
+                *pflValue = ALEffect->Reverb.EchoDepth;
+                break;
+
+            case AL_EAXREVERB_MODULATION_TIME:
+                *pflValue = ALEffect->Reverb.ModulationTime;
+                break;
+
+            case AL_EAXREVERB_MODULATION_DEPTH:
+                *pflValue = ALEffect->Reverb.ModulationDepth;
+                break;
+
+            case AL_EAXREVERB_HFREFERENCE:
+                *pflValue = ALEffect->Reverb.HFReference;
+                break;
+
+            case AL_EAXREVERB_LFREFERENCE:
+                *pflValue = ALEffect->Reverb.LFReference;
+                break;
+
+            case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+                *pflValue = ALEffect->Reverb.RoomRolloffFactor;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_REVERB)
+        {
+            switch(param)
+            {
+            case AL_REVERB_DENSITY:
+                *pflValue = ALEffect->Reverb.Density;
+                break;
+
+            case AL_REVERB_DIFFUSION:
+                *pflValue = ALEffect->Reverb.Diffusion;
+                break;
+
+            case AL_REVERB_GAIN:
+                *pflValue = ALEffect->Reverb.Gain;
+                break;
+
+            case AL_REVERB_GAINHF:
+                *pflValue = ALEffect->Reverb.GainHF;
+                break;
+
+            case AL_REVERB_DECAY_TIME:
+                *pflValue = ALEffect->Reverb.DecayTime;
+                break;
+
+            case AL_REVERB_DECAY_HFRATIO:
+                *pflValue = ALEffect->Reverb.DecayHFRatio;
+                break;
+
+            case AL_REVERB_REFLECTIONS_GAIN:
+                *pflValue = ALEffect->Reverb.ReflectionsGain;
+                break;
+
+            case AL_REVERB_REFLECTIONS_DELAY:
+                *pflValue = ALEffect->Reverb.ReflectionsDelay;
+                break;
+
+            case AL_REVERB_LATE_REVERB_GAIN:
+                *pflValue = ALEffect->Reverb.LateReverbGain;
+                break;
+
+            case AL_REVERB_LATE_REVERB_DELAY:
+                *pflValue = ALEffect->Reverb.LateReverbDelay;
+                break;
+
+            case AL_REVERB_AIR_ABSORPTION_GAINHF:
+                *pflValue = ALEffect->Reverb.AirAbsorptionGainHF;
+                break;
+
+            case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+                *pflValue = ALEffect->Reverb.RoomRolloffFactor;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_ECHO)
+        {
+            switch(param)
+            {
+            case AL_ECHO_DELAY:
+                *pflValue = ALEffect->Echo.Delay;
+                break;
+
+            case AL_ECHO_LRDELAY:
+                *pflValue = ALEffect->Echo.LRDelay;
+                break;
+
+            case AL_ECHO_DAMPING:
+                *pflValue = ALEffect->Echo.Damping;
+                break;
+
+            case AL_ECHO_FEEDBACK:
+                *pflValue = ALEffect->Echo.Feedback;
+                break;
+
+            case AL_ECHO_SPREAD:
+                *pflValue = ALEffect->Echo.Spread;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+        {
+            switch(param)
+            {
+            case AL_RING_MODULATOR_FREQUENCY:
+                *pflValue = ALEffect->Modulator.Frequency;
+                break;
+            case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+                *pflValue = ALEffect->Modulator.HighPassCutoff;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(Context, AL_INVALID_ENUM);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALeffect   *ALEffect;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALEffect=LookupEffect(Device->EffectMap, effect)) != NULL)
+    {
+        if(ALEffect->type == AL_EFFECT_EAXREVERB)
+        {
+            switch(param)
+            {
+            case AL_EAXREVERB_DENSITY:
+            case AL_EAXREVERB_DIFFUSION:
+            case AL_EAXREVERB_GAIN:
+            case AL_EAXREVERB_GAINHF:
+            case AL_EAXREVERB_GAINLF:
+            case AL_EAXREVERB_DECAY_TIME:
+            case AL_EAXREVERB_DECAY_HFRATIO:
+            case AL_EAXREVERB_DECAY_LFRATIO:
+            case AL_EAXREVERB_REFLECTIONS_GAIN:
+            case AL_EAXREVERB_REFLECTIONS_DELAY:
+            case AL_EAXREVERB_LATE_REVERB_GAIN:
+            case AL_EAXREVERB_LATE_REVERB_DELAY:
+            case AL_EAXREVERB_AIR_ABSORPTION_GAINHF:
+            case AL_EAXREVERB_ECHO_TIME:
+            case AL_EAXREVERB_ECHO_DEPTH:
+            case AL_EAXREVERB_MODULATION_TIME:
+            case AL_EAXREVERB_MODULATION_DEPTH:
+            case AL_EAXREVERB_HFREFERENCE:
+            case AL_EAXREVERB_LFREFERENCE:
+            case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR:
+                alGetEffectf(effect, param, pflValues);
+                break;
+
+            case AL_EAXREVERB_REFLECTIONS_PAN:
+                pflValues[0] = ALEffect->Reverb.ReflectionsPan[0];
+                pflValues[1] = ALEffect->Reverb.ReflectionsPan[1];
+                pflValues[2] = ALEffect->Reverb.ReflectionsPan[2];
+                break;
+            case AL_EAXREVERB_LATE_REVERB_PAN:
+                pflValues[0] = ALEffect->Reverb.LateReverbPan[0];
+                pflValues[1] = ALEffect->Reverb.LateReverbPan[1];
+                pflValues[2] = ALEffect->Reverb.LateReverbPan[2];
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_REVERB)
+        {
+            switch(param)
+            {
+            case AL_REVERB_DENSITY:
+            case AL_REVERB_DIFFUSION:
+            case AL_REVERB_GAIN:
+            case AL_REVERB_GAINHF:
+            case AL_REVERB_DECAY_TIME:
+            case AL_REVERB_DECAY_HFRATIO:
+            case AL_REVERB_REFLECTIONS_GAIN:
+            case AL_REVERB_REFLECTIONS_DELAY:
+            case AL_REVERB_LATE_REVERB_GAIN:
+            case AL_REVERB_LATE_REVERB_DELAY:
+            case AL_REVERB_AIR_ABSORPTION_GAINHF:
+            case AL_REVERB_ROOM_ROLLOFF_FACTOR:
+                alGetEffectf(effect, param, pflValues);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_ECHO)
+        {
+            switch(param)
+            {
+            case AL_ECHO_DELAY:
+            case AL_ECHO_LRDELAY:
+            case AL_ECHO_DAMPING:
+            case AL_ECHO_FEEDBACK:
+            case AL_ECHO_SPREAD:
+                alGetEffectf(effect, param, pflValues);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else if(ALEffect->type == AL_EFFECT_RING_MODULATOR)
+        {
+            switch(param)
+            {
+            case AL_RING_MODULATOR_FREQUENCY:
+            case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
+                alGetEffectf(effect, param, pflValues);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+        }
+        else
+            alSetError(Context, AL_INVALID_ENUM);
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+
+ALvoid ReleaseALEffects(ALCdevice *device)
+{
+    ALsizei i;
+    for(i = 0;i < device->EffectMap.size;i++)
+    {
+        ALeffect *temp = device->EffectMap.array[i].value;
+        device->EffectMap.array[i].value = NULL;
+
+        // Release effect structure
+        ALTHUNK_REMOVEENTRY(temp->effect);
+        memset(temp, 0, sizeof(ALeffect));
+        free(temp);
+    }
+}
+
+
+static void InitEffectParams(ALeffect *effect, ALenum type)
+{
+    effect->type = type;
+    switch(type)
+    {
+    /* NOTE: Standard reverb and EAX reverb use the same defaults for the
+     *       shared parameters, and EAX's additional parameters default to
+     *       values assumed by standard reverb.
+     */
+    case AL_EFFECT_EAXREVERB:
+    case AL_EFFECT_REVERB:
+        effect->Reverb.Density = AL_EAXREVERB_DEFAULT_DENSITY;
+        effect->Reverb.Diffusion = AL_EAXREVERB_DEFAULT_DIFFUSION;
+        effect->Reverb.Gain = AL_EAXREVERB_DEFAULT_GAIN;
+        effect->Reverb.GainHF = AL_EAXREVERB_DEFAULT_GAINHF;
+        effect->Reverb.GainLF = AL_EAXREVERB_DEFAULT_GAINLF;
+        effect->Reverb.DecayTime = AL_EAXREVERB_DEFAULT_DECAY_TIME;
+        effect->Reverb.DecayHFRatio = AL_EAXREVERB_DEFAULT_DECAY_HFRATIO;
+        effect->Reverb.DecayLFRatio = AL_EAXREVERB_DEFAULT_DECAY_LFRATIO;
+        effect->Reverb.ReflectionsGain = AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN;
+        effect->Reverb.ReflectionsDelay = AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY;
+        effect->Reverb.ReflectionsPan[0] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+        effect->Reverb.ReflectionsPan[1] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+        effect->Reverb.ReflectionsPan[2] = AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ;
+        effect->Reverb.LateReverbGain = AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN;
+        effect->Reverb.LateReverbDelay = AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY;
+        effect->Reverb.LateReverbPan[0] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+        effect->Reverb.LateReverbPan[1] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+        effect->Reverb.LateReverbPan[2] = AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ;
+        effect->Reverb.EchoTime = AL_EAXREVERB_DEFAULT_ECHO_TIME;
+        effect->Reverb.EchoDepth = AL_EAXREVERB_DEFAULT_ECHO_DEPTH;
+        effect->Reverb.ModulationTime = AL_EAXREVERB_DEFAULT_MODULATION_TIME;
+        effect->Reverb.ModulationDepth = AL_EAXREVERB_DEFAULT_MODULATION_DEPTH;
+        effect->Reverb.AirAbsorptionGainHF = AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF;
+        effect->Reverb.HFReference = AL_EAXREVERB_DEFAULT_HFREFERENCE;
+        effect->Reverb.LFReference = AL_EAXREVERB_DEFAULT_LFREFERENCE;
+        effect->Reverb.RoomRolloffFactor = AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR;
+        effect->Reverb.DecayHFLimit = AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT;
+        break;
+    case AL_EFFECT_ECHO:
+        effect->Echo.Delay = AL_ECHO_DEFAULT_DELAY;
+        effect->Echo.LRDelay = AL_ECHO_DEFAULT_LRDELAY;
+        effect->Echo.Damping = AL_ECHO_DEFAULT_DAMPING;
+        effect->Echo.Feedback = AL_ECHO_DEFAULT_FEEDBACK;
+        effect->Echo.Spread = AL_ECHO_DEFAULT_SPREAD;
+        break;
+    case AL_EFFECT_RING_MODULATOR:
+        effect->Modulator.Frequency = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
+        effect->Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
+        effect->Modulator.Waveform = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
+        break;
+    }
+}
diff --git a/OpenAL32/alError.c b/OpenAL32/alError.c
new file mode 100755 (executable)
index 0000000..43b8e44
--- /dev/null
@@ -0,0 +1,47 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2000 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include "alMain.h"
+#include "AL/alc.h"
+#include "alError.h"
+
+AL_API ALenum AL_APIENTRY alGetError(ALvoid)
+{
+    ALCcontext *Context;
+    ALenum errorCode;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_INVALID_OPERATION;
+
+    errorCode = Context->LastError;
+    Context->LastError = AL_NO_ERROR;
+
+    ProcessContext(Context);
+
+    return errorCode;
+}
+
+ALvoid alSetError(ALCcontext *Context, ALenum errorCode)
+{
+    if(Context->LastError == AL_NO_ERROR)
+        Context->LastError = errorCode;
+}
diff --git a/OpenAL32/alExtension.c b/OpenAL32/alExtension.c
new file mode 100755 (executable)
index 0000000..0febf22
--- /dev/null
@@ -0,0 +1,331 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "alError.h"
+#include "alMain.h"
+#include "alFilter.h"
+#include "alEffect.h"
+#include "alAuxEffectSlot.h"
+#include "alDatabuffer.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+
+typedef struct ALenums {
+    const ALchar *enumName;
+    ALenum value;
+} ALenums;
+
+
+static const ALenums enumeration[] = {
+    // Types
+    { "AL_INVALID",                           AL_INVALID                          },
+    { "AL_NONE",                              AL_NONE                             },
+    { "AL_FALSE",                             AL_FALSE                            },
+    { "AL_TRUE",                              AL_TRUE                             },
+
+    // Source and Listener Properties
+    { "AL_SOURCE_RELATIVE",                   AL_SOURCE_RELATIVE                  },
+    { "AL_CONE_INNER_ANGLE",                  AL_CONE_INNER_ANGLE                 },
+    { "AL_CONE_OUTER_ANGLE",                  AL_CONE_OUTER_ANGLE                 },
+    { "AL_PITCH",                             AL_PITCH                            },
+    { "AL_POSITION",                          AL_POSITION                         },
+    { "AL_DIRECTION",                         AL_DIRECTION                        },
+    { "AL_VELOCITY",                          AL_VELOCITY                         },
+    { "AL_LOOPING",                           AL_LOOPING                          },
+    { "AL_BUFFER",                            AL_BUFFER                           },
+    { "AL_GAIN",                              AL_GAIN                             },
+    { "AL_MIN_GAIN",                          AL_MIN_GAIN                         },
+    { "AL_MAX_GAIN",                          AL_MAX_GAIN                         },
+    { "AL_ORIENTATION",                       AL_ORIENTATION                      },
+    { "AL_REFERENCE_DISTANCE",                AL_REFERENCE_DISTANCE               },
+    { "AL_ROLLOFF_FACTOR",                    AL_ROLLOFF_FACTOR                   },
+    { "AL_CONE_OUTER_GAIN",                   AL_CONE_OUTER_GAIN                  },
+    { "AL_MAX_DISTANCE",                      AL_MAX_DISTANCE                     },
+    { "AL_SEC_OFFSET",                        AL_SEC_OFFSET                       },
+    { "AL_SAMPLE_OFFSET",                     AL_SAMPLE_OFFSET                    },
+    { "AL_SAMPLE_RW_OFFSETS_SOFT",            AL_SAMPLE_RW_OFFSETS_SOFT           },
+    { "AL_BYTE_OFFSET",                       AL_BYTE_OFFSET                      },
+    { "AL_BYTE_RW_OFFSETS_SOFT",              AL_BYTE_RW_OFFSETS_SOFT             },
+    { "AL_SOURCE_TYPE",                       AL_SOURCE_TYPE                      },
+    { "AL_STATIC",                            AL_STATIC                           },
+    { "AL_STREAMING",                         AL_STREAMING                        },
+    { "AL_UNDETERMINED",                      AL_UNDETERMINED                     },
+    { "AL_METERS_PER_UNIT",                   AL_METERS_PER_UNIT                  },
+
+    // Source EFX Properties
+    { "AL_DIRECT_FILTER",                     AL_DIRECT_FILTER                    },
+    { "AL_AUXILIARY_SEND_FILTER",             AL_AUXILIARY_SEND_FILTER            },
+    { "AL_AIR_ABSORPTION_FACTOR",             AL_AIR_ABSORPTION_FACTOR            },
+    { "AL_ROOM_ROLLOFF_FACTOR",               AL_ROOM_ROLLOFF_FACTOR              },
+    { "AL_CONE_OUTER_GAINHF",                 AL_CONE_OUTER_GAINHF                },
+    { "AL_DIRECT_FILTER_GAINHF_AUTO",         AL_DIRECT_FILTER_GAINHF_AUTO        },
+    { "AL_AUXILIARY_SEND_FILTER_GAIN_AUTO",   AL_AUXILIARY_SEND_FILTER_GAIN_AUTO  },
+    { "AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO", AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO},
+
+    // Source State information
+    { "AL_SOURCE_STATE",                      AL_SOURCE_STATE                     },
+    { "AL_INITIAL",                           AL_INITIAL                          },
+    { "AL_PLAYING",                           AL_PLAYING                          },
+    { "AL_PAUSED",                            AL_PAUSED                           },
+    { "AL_STOPPED",                           AL_STOPPED                          },
+
+    // Queue information
+    { "AL_BUFFERS_QUEUED",                    AL_BUFFERS_QUEUED                   },
+    { "AL_BUFFERS_PROCESSED",                 AL_BUFFERS_PROCESSED                },
+
+    // Buffer Formats
+    { "AL_FORMAT_MONO8",                      AL_FORMAT_MONO8                     },
+    { "AL_FORMAT_MONO16",                     AL_FORMAT_MONO16                    },
+    { "AL_FORMAT_MONO_FLOAT32",               AL_FORMAT_MONO_FLOAT32              },
+    { "AL_FORMAT_MONO_DOUBLE_EXT",            AL_FORMAT_MONO_DOUBLE_EXT           },
+    { "AL_FORMAT_STEREO8",                    AL_FORMAT_STEREO8                   },
+    { "AL_FORMAT_STEREO16",                   AL_FORMAT_STEREO16                  },
+    { "AL_FORMAT_STEREO_FLOAT32",             AL_FORMAT_STEREO_FLOAT32            },
+    { "AL_FORMAT_STEREO_DOUBLE_EXT",          AL_FORMAT_STEREO_DOUBLE_EXT         },
+    { "AL_FORMAT_MONO_IMA4",                  AL_FORMAT_MONO_IMA4                 },
+    { "AL_FORMAT_STEREO_IMA4",                AL_FORMAT_STEREO_IMA4               },
+    { "AL_FORMAT_QUAD8_LOKI",                 AL_FORMAT_QUAD8_LOKI                },
+    { "AL_FORMAT_QUAD16_LOKI",                AL_FORMAT_QUAD16_LOKI               },
+    { "AL_FORMAT_QUAD8",                      AL_FORMAT_QUAD8                     },
+    { "AL_FORMAT_QUAD16",                     AL_FORMAT_QUAD16                    },
+    { "AL_FORMAT_QUAD32",                     AL_FORMAT_QUAD32                    },
+    { "AL_FORMAT_51CHN8",                     AL_FORMAT_51CHN8                    },
+    { "AL_FORMAT_51CHN16",                    AL_FORMAT_51CHN16                   },
+    { "AL_FORMAT_51CHN32",                    AL_FORMAT_51CHN32                   },
+    { "AL_FORMAT_61CHN8",                     AL_FORMAT_61CHN8                    },
+    { "AL_FORMAT_61CHN16",                    AL_FORMAT_61CHN16                   },
+    { "AL_FORMAT_61CHN32",                    AL_FORMAT_61CHN32                   },
+    { "AL_FORMAT_71CHN8",                     AL_FORMAT_71CHN8                    },
+    { "AL_FORMAT_71CHN16",                    AL_FORMAT_71CHN16                   },
+    { "AL_FORMAT_71CHN32",                    AL_FORMAT_71CHN32                   },
+    { "AL_FORMAT_REAR8",                      AL_FORMAT_REAR8                     },
+    { "AL_FORMAT_REAR16",                     AL_FORMAT_REAR16                    },
+    { "AL_FORMAT_REAR32",                     AL_FORMAT_REAR32                    },
+    { "AL_FORMAT_MONO_MULAW",                 AL_FORMAT_MONO_MULAW                },
+    { "AL_FORMAT_MONO_MULAW_EXT",             AL_FORMAT_MONO_MULAW                },
+    { "AL_FORMAT_STEREO_MULAW",               AL_FORMAT_STEREO_MULAW              },
+    { "AL_FORMAT_STEREO_MULAW_EXT",           AL_FORMAT_STEREO_MULAW              },
+    { "AL_FORMAT_QUAD_MULAW",                 AL_FORMAT_QUAD_MULAW                },
+    { "AL_FORMAT_51CHN_MULAW",                AL_FORMAT_51CHN_MULAW               },
+    { "AL_FORMAT_61CHN_MULAW",                AL_FORMAT_61CHN_MULAW               },
+    { "AL_FORMAT_71CHN_MULAW",                AL_FORMAT_71CHN_MULAW               },
+    { "AL_FORMAT_REAR_MULAW",                 AL_FORMAT_REAR_MULAW                },
+
+    // Buffer attributes
+    { "AL_FREQUENCY",                         AL_FREQUENCY                        },
+    { "AL_BITS",                              AL_BITS                             },
+    { "AL_CHANNELS",                          AL_CHANNELS                         },
+    { "AL_SIZE",                              AL_SIZE                             },
+
+    // Buffer States (not supported yet)
+    { "AL_UNUSED",                            AL_UNUSED                           },
+    { "AL_PENDING",                           AL_PENDING                          },
+    { "AL_PROCESSED",                         AL_PROCESSED                        },
+
+    // AL Error Messages
+    { "AL_NO_ERROR",                          AL_NO_ERROR                         },
+    { "AL_INVALID_NAME",                      AL_INVALID_NAME                     },
+    { "AL_INVALID_ENUM",                      AL_INVALID_ENUM                     },
+    { "AL_INVALID_VALUE",                     AL_INVALID_VALUE                    },
+    { "AL_INVALID_OPERATION",                 AL_INVALID_OPERATION                },
+    { "AL_OUT_OF_MEMORY",                     AL_OUT_OF_MEMORY                    },
+
+    // Context strings
+    { "AL_VENDOR",                            AL_VENDOR                           },
+    { "AL_VERSION",                           AL_VERSION                          },
+    { "AL_RENDERER",                          AL_RENDERER                         },
+    { "AL_EXTENSIONS",                        AL_EXTENSIONS                       },
+
+    // Global states
+    { "AL_DOPPLER_FACTOR",                    AL_DOPPLER_FACTOR                   },
+    { "AL_DOPPLER_VELOCITY",                  AL_DOPPLER_VELOCITY                 },
+    { "AL_DISTANCE_MODEL",                    AL_DISTANCE_MODEL                   },
+    { "AL_SPEED_OF_SOUND",                    AL_SPEED_OF_SOUND                   },
+    { "AL_SOURCE_DISTANCE_MODEL",             AL_SOURCE_DISTANCE_MODEL            },
+
+    // Distance Models
+    { "AL_INVERSE_DISTANCE",                  AL_INVERSE_DISTANCE                 },
+    { "AL_INVERSE_DISTANCE_CLAMPED",          AL_INVERSE_DISTANCE_CLAMPED         },
+    { "AL_LINEAR_DISTANCE",                   AL_LINEAR_DISTANCE                  },
+    { "AL_LINEAR_DISTANCE_CLAMPED",           AL_LINEAR_DISTANCE_CLAMPED          },
+    { "AL_EXPONENT_DISTANCE",                 AL_EXPONENT_DISTANCE                },
+    { "AL_EXPONENT_DISTANCE_CLAMPED",         AL_EXPONENT_DISTANCE_CLAMPED        },
+
+    // Filter types
+    { "AL_FILTER_TYPE",                       AL_FILTER_TYPE                      },
+    { "AL_FILTER_NULL",                       AL_FILTER_NULL                      },
+    { "AL_FILTER_LOWPASS",                    AL_FILTER_LOWPASS                   },
+#if 0
+    { "AL_FILTER_HIGHPASS",                   AL_FILTER_HIGHPASS                  },
+    { "AL_FILTER_BANDPASS",                   AL_FILTER_BANDPASS                  },
+#endif
+
+    // Filter params
+    { "AL_LOWPASS_GAIN",                      AL_LOWPASS_GAIN                     },
+    { "AL_LOWPASS_GAINHF",                    AL_LOWPASS_GAINHF                   },
+
+    // Effect types
+    { "AL_EFFECT_TYPE",                       AL_EFFECT_TYPE                      },
+    { "AL_EFFECT_NULL",                       AL_EFFECT_NULL                      },
+    { "AL_EFFECT_REVERB",                     AL_EFFECT_REVERB                    },
+    { "AL_EFFECT_EAXREVERB",                  AL_EFFECT_EAXREVERB                 },
+#if 0
+    { "AL_EFFECT_CHORUS",                     AL_EFFECT_CHORUS                    },
+    { "AL_EFFECT_DISTORTION",                 AL_EFFECT_DISTORTION                },
+#endif
+    { "AL_EFFECT_ECHO",                       AL_EFFECT_ECHO                      },
+#if 0
+    { "AL_EFFECT_FLANGER",                    AL_EFFECT_FLANGER                   },
+    { "AL_EFFECT_FREQUENCY_SHIFTER",          AL_EFFECT_FREQUENCY_SHIFTER         },
+    { "AL_EFFECT_VOCAL_MORPHER",              AL_EFFECT_VOCAL_MORPHER             },
+    { "AL_EFFECT_PITCH_SHIFTER",              AL_EFFECT_PITCH_SHIFTER             },
+#endif
+    { "AL_EFFECT_RING_MODULATOR",             AL_EFFECT_RING_MODULATOR            },
+#if 0
+    { "AL_EFFECT_AUTOWAH",                    AL_EFFECT_AUTOWAH                   },
+    { "AL_EFFECT_COMPRESSOR",                 AL_EFFECT_COMPRESSOR                },
+    { "AL_EFFECT_EQUALIZER",                  AL_EFFECT_EQUALIZER                 },
+#endif
+
+    // Reverb params
+    { "AL_REVERB_DENSITY",                    AL_REVERB_DENSITY                   },
+    { "AL_REVERB_DIFFUSION",                  AL_REVERB_DIFFUSION                 },
+    { "AL_REVERB_GAIN",                       AL_REVERB_GAIN                      },
+    { "AL_REVERB_GAINHF",                     AL_REVERB_GAINHF                    },
+    { "AL_REVERB_DECAY_TIME",                 AL_REVERB_DECAY_TIME                },
+    { "AL_REVERB_DECAY_HFRATIO",              AL_REVERB_DECAY_HFRATIO             },
+    { "AL_REVERB_REFLECTIONS_GAIN",           AL_REVERB_REFLECTIONS_GAIN          },
+    { "AL_REVERB_REFLECTIONS_DELAY",          AL_REVERB_REFLECTIONS_DELAY         },
+    { "AL_REVERB_LATE_REVERB_GAIN",           AL_REVERB_LATE_REVERB_GAIN          },
+    { "AL_REVERB_LATE_REVERB_DELAY",          AL_REVERB_LATE_REVERB_DELAY         },
+    { "AL_REVERB_AIR_ABSORPTION_GAINHF",      AL_REVERB_AIR_ABSORPTION_GAINHF     },
+    { "AL_REVERB_ROOM_ROLLOFF_FACTOR",        AL_REVERB_ROOM_ROLLOFF_FACTOR       },
+    { "AL_REVERB_DECAY_HFLIMIT",              AL_REVERB_DECAY_HFLIMIT             },
+
+    // EAX Reverb params
+    { "AL_EAXREVERB_DENSITY",                 AL_EAXREVERB_DENSITY                },
+    { "AL_EAXREVERB_DIFFUSION",               AL_EAXREVERB_DIFFUSION              },
+    { "AL_EAXREVERB_GAIN",                    AL_EAXREVERB_GAIN                   },
+    { "AL_EAXREVERB_GAINHF",                  AL_EAXREVERB_GAINHF                 },
+    { "AL_EAXREVERB_GAINLF",                  AL_EAXREVERB_GAINLF                 },
+    { "AL_EAXREVERB_DECAY_TIME",              AL_EAXREVERB_DECAY_TIME             },
+    { "AL_EAXREVERB_DECAY_HFRATIO",           AL_EAXREVERB_DECAY_HFRATIO          },
+    { "AL_EAXREVERB_DECAY_LFRATIO",           AL_EAXREVERB_DECAY_LFRATIO          },
+    { "AL_EAXREVERB_REFLECTIONS_GAIN",        AL_EAXREVERB_REFLECTIONS_GAIN       },
+    { "AL_EAXREVERB_REFLECTIONS_DELAY",       AL_EAXREVERB_REFLECTIONS_DELAY      },
+    { "AL_EAXREVERB_REFLECTIONS_PAN",         AL_EAXREVERB_REFLECTIONS_PAN        },
+    { "AL_EAXREVERB_LATE_REVERB_GAIN",        AL_EAXREVERB_LATE_REVERB_GAIN       },
+    { "AL_EAXREVERB_LATE_REVERB_DELAY",       AL_EAXREVERB_LATE_REVERB_DELAY      },
+    { "AL_EAXREVERB_LATE_REVERB_PAN",         AL_EAXREVERB_LATE_REVERB_PAN        },
+    { "AL_EAXREVERB_ECHO_TIME",               AL_EAXREVERB_ECHO_TIME              },
+    { "AL_EAXREVERB_ECHO_DEPTH",              AL_EAXREVERB_ECHO_DEPTH             },
+    { "AL_EAXREVERB_MODULATION_TIME",         AL_EAXREVERB_MODULATION_TIME        },
+    { "AL_EAXREVERB_MODULATION_DEPTH",        AL_EAXREVERB_MODULATION_DEPTH       },
+    { "AL_EAXREVERB_AIR_ABSORPTION_GAINHF",   AL_EAXREVERB_AIR_ABSORPTION_GAINHF  },
+    { "AL_EAXREVERB_HFREFERENCE",             AL_EAXREVERB_HFREFERENCE            },
+    { "AL_EAXREVERB_LFREFERENCE",             AL_EAXREVERB_LFREFERENCE            },
+    { "AL_EAXREVERB_ROOM_ROLLOFF_FACTOR",     AL_EAXREVERB_ROOM_ROLLOFF_FACTOR    },
+    { "AL_EAXREVERB_DECAY_HFLIMIT",           AL_EAXREVERB_DECAY_HFLIMIT          },
+
+    // Echo params
+    { "AL_ECHO_DELAY",                        AL_ECHO_DELAY                       },
+    { "AL_ECHO_LRDELAY",                      AL_ECHO_LRDELAY                     },
+    { "AL_ECHO_DAMPING",                      AL_ECHO_DAMPING                     },
+    { "AL_ECHO_FEEDBACK",                     AL_ECHO_FEEDBACK                    },
+    { "AL_ECHO_SPREAD",                       AL_ECHO_SPREAD                      },
+
+    // Ring Modulator params
+    { "AL_RING_MODULATOR_FREQUENCY",          AL_RING_MODULATOR_FREQUENCY         },
+    { "AL_RING_MODULATOR_HIGHPASS_CUTOFF",    AL_RING_MODULATOR_HIGHPASS_CUTOFF   },
+    { "AL_RING_MODULATOR_WAVEFORM",           AL_RING_MODULATOR_WAVEFORM          },
+
+
+    // Default
+    { NULL,                                   (ALenum)0                           }
+};
+
+
+
+AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extName)
+{
+    ALboolean bIsSupported = AL_FALSE;
+    ALCcontext *pContext;
+    const char *ptr;
+    size_t len;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return AL_FALSE;
+
+    if(!extName)
+    {
+        alSetError(pContext, AL_INVALID_VALUE);
+        ProcessContext(pContext);
+        return AL_FALSE;
+    }
+
+    len = strlen(extName);
+    ptr = pContext->ExtensionList;
+    while(ptr && *ptr)
+    {
+        if(strncasecmp(ptr, extName, len) == 0 &&
+           (ptr[len] == '\0' || isspace(ptr[len])))
+        {
+            bIsSupported = AL_TRUE;
+            break;
+        }
+        if((ptr=strchr(ptr, ' ')) != NULL)
+        {
+            do {
+                ++ptr;
+            } while(isspace(*ptr));
+        }
+    }
+
+    ProcessContext(pContext);
+
+    return bIsSupported;
+}
+
+
+AL_API ALvoid* AL_APIENTRY alGetProcAddress(const ALchar *funcName)
+{
+    if(!funcName)
+        return NULL;
+    return alcGetProcAddress(NULL, funcName);
+}
+
+AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *enumName)
+{
+    ALsizei i = 0;
+
+    while(enumeration[i].enumName &&
+          strcmp(enumeration[i].enumName, enumName) != 0)
+        i++;
+
+    return enumeration[i].value;
+}
diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c
new file mode 100755 (executable)
index 0000000..d63e8e8
--- /dev/null
@@ -0,0 +1,431 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alMain.h"
+#include "alFilter.h"
+#include "alThunk.h"
+#include "alError.h"
+
+
+static void InitFilterParams(ALfilter *filter, ALenum type);
+
+#define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
+
+AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters)
+{
+    ALCcontext *Context;
+    ALsizei i=0;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0 || IsBadWritePtr((void*)filters, n * sizeof(ALuint)))
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        ALCdevice *device = Context->Device;
+        ALenum err;
+
+        while(i < n)
+        {
+            ALfilter *filter = calloc(1, sizeof(ALfilter));
+            if(!filter)
+            {
+                alSetError(Context, AL_OUT_OF_MEMORY);
+                alDeleteFilters(i, filters);
+                break;
+            }
+
+            filter->filter = ALTHUNK_ADDENTRY(filter);
+            err = InsertUIntMapEntry(&device->FilterMap, filter->filter, filter);
+            if(err != AL_NO_ERROR)
+            {
+                ALTHUNK_REMOVEENTRY(filter->filter);
+                memset(filter, 0, sizeof(ALfilter));
+                free(filter);
+
+                alSetError(Context, err);
+                alDeleteFilters(i, filters);
+                break;
+            }
+
+            filters[i++] = filter->filter;
+            InitFilterParams(filter, AL_FILTER_NULL);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters)
+{
+    ALCcontext *Context;
+    ALCdevice *device;
+    ALfilter *ALFilter;
+    ALboolean Failed;
+    ALsizei i;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Failed = AL_TRUE;
+    device = Context->Device;
+    if(n < 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        Failed = AL_FALSE;
+        // Check that all filters are valid
+        for(i = 0;i < n;i++)
+        {
+            if(!filters[i])
+                continue;
+
+            if(LookupFilter(device->FilterMap, filters[i]) == NULL)
+            {
+                alSetError(Context, AL_INVALID_NAME);
+                Failed = AL_TRUE;
+                break;
+            }
+        }
+    }
+
+    if(!Failed)
+    {
+        // All filters are valid
+        for(i = 0;i < n;i++)
+        {
+            // Recheck that the filter is valid, because there could be duplicated names
+            if((ALFilter=LookupFilter(device->FilterMap, filters[i])) == NULL)
+                continue;
+
+            RemoveUIntMapKey(&device->FilterMap, ALFilter->filter);
+            ALTHUNK_REMOVEENTRY(ALFilter->filter);
+
+            memset(ALFilter, 0, sizeof(ALfilter));
+            free(ALFilter);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter)
+{
+    ALCcontext *Context;
+    ALboolean  result;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_FALSE;
+
+    result = ((!filter || LookupFilter(Context->Device->FilterMap, filter)) ?
+              AL_TRUE : AL_FALSE);
+
+    ProcessContext(Context);
+
+    return result;
+}
+
+AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALfilter   *ALFilter;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
+    {
+        switch(param)
+        {
+        case AL_FILTER_TYPE:
+            if(iValue == AL_FILTER_NULL ||
+               iValue == AL_FILTER_LOWPASS)
+                InitFilterParams(ALFilter, iValue);
+            else
+                alSetError(Context, AL_INVALID_VALUE);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if(LookupFilter(Device->FilterMap, filter) != NULL)
+    {
+        switch(param)
+        {
+        case AL_FILTER_TYPE:
+            alFilteri(filter, param, piValues[0]);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALfilter   *ALFilter;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
+    {
+        switch(ALFilter->type)
+        {
+        case AL_FILTER_LOWPASS:
+            switch(param)
+            {
+            case AL_LOWPASS_GAIN:
+                if(flValue >= 0.0f && flValue <= 1.0f)
+                    ALFilter->Gain = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            case AL_LOWPASS_GAINHF:
+                if(flValue >= 0.0f && flValue <= 1.0f)
+                    ALFilter->GainHF = flValue;
+                else
+                    alSetError(Context, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if(LookupFilter(Device->FilterMap, filter) != NULL)
+    {
+        switch(param)
+        {
+        default:
+            alFilterf(filter, param, pflValues[0]);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALfilter   *ALFilter;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
+    {
+        switch(param)
+        {
+        case AL_FILTER_TYPE:
+            *piValue = ALFilter->type;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if(LookupFilter(Device->FilterMap, filter) != NULL)
+    {
+        switch(param)
+        {
+        case AL_FILTER_TYPE:
+            alGetFilteri(filter, param, piValues);
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+    ALfilter   *ALFilter;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if((ALFilter=LookupFilter(Device->FilterMap, filter)) != NULL)
+    {
+        switch(ALFilter->type)
+        {
+        case AL_FILTER_LOWPASS:
+            switch(param)
+            {
+            case AL_LOWPASS_GAIN:
+                *pflValue = ALFilter->Gain;
+                break;
+
+            case AL_LOWPASS_GAINHF:
+                *pflValue = ALFilter->GainHF;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+            }
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues)
+{
+    ALCcontext *Context;
+    ALCdevice  *Device;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if(LookupFilter(Device->FilterMap, filter) != NULL)
+    {
+        switch(param)
+        {
+        default:
+            alGetFilterf(filter, param, pflValues);
+            break;
+        }
+    }
+    else
+        alSetError(Context, AL_INVALID_NAME);
+
+    ProcessContext(Context);
+}
+
+
+ALvoid ReleaseALFilters(ALCdevice *device)
+{
+    ALsizei i;
+    for(i = 0;i < device->FilterMap.size;i++)
+    {
+        ALfilter *temp = device->FilterMap.array[i].value;
+        device->FilterMap.array[i].value = NULL;
+
+        // Release filter structure
+        ALTHUNK_REMOVEENTRY(temp->filter);
+        memset(temp, 0, sizeof(ALfilter));
+        free(temp);
+    }
+}
+
+
+static void InitFilterParams(ALfilter *filter, ALenum type)
+{
+    filter->type = type;
+
+    filter->Gain = 1.0;
+    filter->GainHF = 1.0;
+}
diff --git a/OpenAL32/alListener.c b/OpenAL32/alListener.c
new file mode 100755 (executable)
index 0000000..b3c192d
--- /dev/null
@@ -0,0 +1,484 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2000 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include "alMain.h"
+#include "AL/alc.h"
+#include "alError.h"
+#include "alListener.h"
+#include "alSource.h"
+
+AL_API ALvoid AL_APIENTRY alListenerf(ALenum eParam, ALfloat flValue)
+{
+    ALCcontext *pContext;
+    ALboolean updateAll = AL_FALSE;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    switch(eParam)
+    {
+        case AL_GAIN:
+            if(flValue >= 0.0f)
+            {
+                pContext->Listener.Gain = flValue;
+                updateAll = AL_TRUE;
+            }
+            else
+                alSetError(pContext, AL_INVALID_VALUE);
+            break;
+
+        case AL_METERS_PER_UNIT:
+            if(flValue > 0.0f)
+            {
+                pContext->Listener.MetersPerUnit = flValue;
+                updateAll = AL_TRUE;
+            }
+            else
+                alSetError(pContext, AL_INVALID_VALUE);
+            break;
+
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+    }
+
+    // Force updating the sources for these parameters, since even head-
+    // relative sources are affected
+    if(updateAll)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < pContext->SourceMap.size;pos++)
+        {
+            ALsource *source = pContext->SourceMap.array[pos].value;
+            source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alListener3f(ALenum eParam, ALfloat flValue1, ALfloat flValue2, ALfloat flValue3)
+{
+    ALCcontext *pContext;
+    ALboolean updateWorld = AL_FALSE;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    switch(eParam)
+    {
+        case AL_POSITION:
+            pContext->Listener.Position[0] = flValue1;
+            pContext->Listener.Position[1] = flValue2;
+            pContext->Listener.Position[2] = flValue3;
+            updateWorld = AL_TRUE;
+            break;
+
+        case AL_VELOCITY:
+            pContext->Listener.Velocity[0] = flValue1;
+            pContext->Listener.Velocity[1] = flValue2;
+            pContext->Listener.Velocity[2] = flValue3;
+            updateWorld = AL_TRUE;
+            break;
+
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+    }
+
+    if(updateWorld)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < pContext->SourceMap.size;pos++)
+        {
+            ALsource *source = pContext->SourceMap.array[pos].value;
+            if(!source->bHeadRelative)
+                source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alListenerfv(ALenum eParam, const ALfloat *pflValues)
+{
+    ALCcontext *pContext;
+    ALboolean updateWorld = AL_FALSE;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValues)
+    {
+        switch(eParam)
+        {
+            case AL_GAIN:
+            case AL_METERS_PER_UNIT:
+                alListenerf(eParam, pflValues[0]);
+                break;
+
+            case AL_POSITION:
+            case AL_VELOCITY:
+                alListener3f(eParam, pflValues[0], pflValues[1], pflValues[2]);
+                break;
+
+            case AL_ORIENTATION:
+                // AT then UP
+                pContext->Listener.Forward[0] = pflValues[0];
+                pContext->Listener.Forward[1] = pflValues[1];
+                pContext->Listener.Forward[2] = pflValues[2];
+                pContext->Listener.Up[0] = pflValues[3];
+                pContext->Listener.Up[1] = pflValues[4];
+                pContext->Listener.Up[2] = pflValues[5];
+                updateWorld = AL_TRUE;
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    if(updateWorld)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < pContext->SourceMap.size;pos++)
+        {
+            ALsource *source = pContext->SourceMap.array[pos].value;
+            if(!source->bHeadRelative)
+                source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alListeneri(ALenum eParam, ALint lValue)
+{
+    ALCcontext *pContext;
+
+    (void)lValue;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    switch(eParam)
+    {
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alListener3i(ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
+{
+    ALCcontext *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    switch(eParam)
+    {
+        case AL_POSITION:
+        case AL_VELOCITY:
+            alListener3f(eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
+            break;
+
+        default:
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alListeneriv( ALenum eParam, const ALint* plValues )
+{
+    ALCcontext *pContext;
+    ALfloat flValues[6];
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValues)
+    {
+        switch(eParam)
+        {
+            case AL_POSITION:
+            case AL_VELOCITY:
+                flValues[0] = (ALfloat)plValues[0];
+                flValues[1] = (ALfloat)plValues[1];
+                flValues[2] = (ALfloat)plValues[2];
+                alListenerfv(eParam, flValues);
+                break;
+
+            case AL_ORIENTATION:
+                flValues[0] = (ALfloat)plValues[0];
+                flValues[1] = (ALfloat)plValues[1];
+                flValues[2] = (ALfloat)plValues[2];
+                flValues[3] = (ALfloat)plValues[3];
+                flValues[4] = (ALfloat)plValues[4];
+                flValues[5] = (ALfloat)plValues[5];
+                alListenerfv(eParam, flValues);
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetListenerf(ALenum eParam, ALfloat *pflValue)
+{
+    ALCcontext *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValue)
+    {
+        switch(eParam)
+        {
+            case AL_GAIN:
+                *pflValue = pContext->Listener.Gain;
+                break;
+
+            case AL_METERS_PER_UNIT:
+                *pflValue = pContext->Listener.MetersPerUnit;
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum eParam, ALfloat *pflValue1, ALfloat *pflValue2, ALfloat *pflValue3)
+{
+    ALCcontext *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValue1 && pflValue2 && pflValue3)
+    {
+        switch(eParam)
+        {
+            case AL_POSITION:
+                *pflValue1 = pContext->Listener.Position[0];
+                *pflValue2 = pContext->Listener.Position[1];
+                *pflValue3 = pContext->Listener.Position[2];
+                break;
+
+            case AL_VELOCITY:
+                *pflValue1 = pContext->Listener.Velocity[0];
+                *pflValue2 = pContext->Listener.Velocity[1];
+                *pflValue3 = pContext->Listener.Velocity[2];
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetListenerfv(ALenum eParam, ALfloat *pflValues)
+{
+    ALCcontext *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValues)
+    {
+        switch(eParam)
+        {
+            case AL_GAIN:
+                pflValues[0] = pContext->Listener.Gain;
+                break;
+
+            case AL_METERS_PER_UNIT:
+                pflValues[0] = pContext->Listener.MetersPerUnit;
+                break;
+
+            case AL_POSITION:
+                pflValues[0] = pContext->Listener.Position[0];
+                pflValues[1] = pContext->Listener.Position[1];
+                pflValues[2] = pContext->Listener.Position[2];
+                break;
+
+            case AL_VELOCITY:
+                pflValues[0] = pContext->Listener.Velocity[0];
+                pflValues[1] = pContext->Listener.Velocity[1];
+                pflValues[2] = pContext->Listener.Velocity[2];
+                break;
+
+            case AL_ORIENTATION:
+                // AT then UP
+                pflValues[0] = pContext->Listener.Forward[0];
+                pflValues[1] = pContext->Listener.Forward[1];
+                pflValues[2] = pContext->Listener.Forward[2];
+                pflValues[3] = pContext->Listener.Up[0];
+                pflValues[4] = pContext->Listener.Up[1];
+                pflValues[5] = pContext->Listener.Up[2];
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetListeneri(ALenum eParam, ALint *plValue)
+{
+    ALCcontext *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValue)
+    {
+        switch(eParam)
+        {
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetListener3i(ALenum eParam, ALint *plValue1, ALint *plValue2, ALint *plValue3)
+{
+    ALCcontext *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValue1 && plValue2 && plValue3)
+    {
+        switch (eParam)
+        {
+            case AL_POSITION:
+                *plValue1 = (ALint)pContext->Listener.Position[0];
+                *plValue2 = (ALint)pContext->Listener.Position[1];
+                *plValue3 = (ALint)pContext->Listener.Position[2];
+                break;
+
+            case AL_VELOCITY:
+                *plValue1 = (ALint)pContext->Listener.Velocity[0];
+                *plValue2 = (ALint)pContext->Listener.Velocity[1];
+                *plValue3 = (ALint)pContext->Listener.Velocity[2];
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetListeneriv(ALenum eParam, ALint* plValues)
+{
+    ALCcontext *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValues)
+    {
+        switch(eParam)
+        {
+            case AL_POSITION:
+                plValues[0] = (ALint)pContext->Listener.Position[0];
+                plValues[1] = (ALint)pContext->Listener.Position[1];
+                plValues[2] = (ALint)pContext->Listener.Position[2];
+                break;
+
+            case AL_VELOCITY:
+                plValues[0] = (ALint)pContext->Listener.Velocity[0];
+                plValues[1] = (ALint)pContext->Listener.Velocity[1];
+                plValues[2] = (ALint)pContext->Listener.Velocity[2];
+                break;
+
+            case AL_ORIENTATION:
+                // AT then UP
+                plValues[0] = (ALint)pContext->Listener.Forward[0];
+                plValues[1] = (ALint)pContext->Listener.Forward[1];
+                plValues[2] = (ALint)pContext->Listener.Forward[2];
+                plValues[3] = (ALint)pContext->Listener.Up[0];
+                plValues[4] = (ALint)pContext->Listener.Up[1];
+                plValues[5] = (ALint)pContext->Listener.Up[2];
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c
new file mode 100755 (executable)
index 0000000..ed69af3
--- /dev/null
@@ -0,0 +1,2067 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include "alMain.h"
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "alError.h"
+#include "alSource.h"
+#include "alBuffer.h"
+#include "alThunk.h"
+#include "alAuxEffectSlot.h"
+
+
+resampler_t DefaultResampler;
+const ALsizei ResamplerPadding[RESAMPLER_MAX] = {
+    0, /* Point */
+    1, /* Linear */
+    2, /* Cubic */
+};
+const ALsizei ResamplerPrePadding[RESAMPLER_MAX] = {
+    0, /* Point */
+    0, /* Linear */
+    1, /* Cubic */
+};
+
+
+static ALvoid InitSourceParams(ALsource *Source);
+static ALvoid GetSourceOffset(ALsource *Source, ALenum eName, ALdouble *Offsets, ALdouble updateLen);
+static ALboolean ApplyOffset(ALsource *Source);
+static ALint GetByteOffset(ALsource *Source);
+
+#define LookupSource(m, k) ((ALsource*)LookupUIntMapKey(&(m), (k)))
+#define LookupBuffer(m, k) ((ALbuffer*)LookupUIntMapKey(&(m), (k)))
+#define LookupFilter(m, k) ((ALfilter*)LookupUIntMapKey(&(m), (k)))
+#define LookupEffectSlot(m, k) ((ALeffectslot*)LookupUIntMapKey(&(m), (k)))
+
+AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n,ALuint *sources)
+{
+    ALCcontext *Context;
+    ALCdevice *Device;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    Device = Context->Device;
+    if(n < 0 || IsBadWritePtr((void*)sources, n * sizeof(ALuint)))
+        alSetError(Context, AL_INVALID_VALUE);
+    else if((ALuint)n > Device->MaxNoOfSources - Context->SourceMap.size)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        ALenum err;
+        ALsizei i;
+
+        // Add additional sources to the list
+        i = 0;
+        while(i < n)
+        {
+            ALsource *source = calloc(1, sizeof(ALsource));
+            if(!source)
+            {
+                alSetError(Context, AL_OUT_OF_MEMORY);
+                alDeleteSources(i, sources);
+                break;
+            }
+
+            source->source = (ALuint)ALTHUNK_ADDENTRY(source);
+            err = InsertUIntMapEntry(&Context->SourceMap, source->source,
+                                     source);
+            if(err != AL_NO_ERROR)
+            {
+                ALTHUNK_REMOVEENTRY(source->source);
+                memset(source, 0, sizeof(ALsource));
+                free(source);
+
+                alSetError(Context, err);
+                alDeleteSources(i, sources);
+                break;
+            }
+
+            sources[i++] = source->source;
+            InitSourceParams(source);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+
+AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources)
+{
+    ALCcontext *Context;
+    ALsource *Source;
+    ALsizei i, j;
+    ALbufferlistitem *BufferList;
+    ALboolean SourcesValid = AL_FALSE;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0)
+        alSetError(Context, AL_INVALID_VALUE);
+    else
+    {
+        SourcesValid = AL_TRUE;
+        // Check that all Sources are valid (and can therefore be deleted)
+        for(i = 0;i < n;i++)
+        {
+            if(LookupSource(Context->SourceMap, sources[i]) == NULL)
+            {
+                alSetError(Context, AL_INVALID_NAME);
+                SourcesValid = AL_FALSE;
+                break;
+            }
+        }
+    }
+
+    if(SourcesValid)
+    {
+        // All Sources are valid, and can be deleted
+        for(i = 0;i < n;i++)
+        {
+            // Recheck that the Source is valid, because there could be duplicated Source names
+            if((Source=LookupSource(Context->SourceMap, sources[i])) == NULL)
+                continue;
+
+            for(j = 0;j < Context->ActiveSourceCount;j++)
+            {
+                if(Context->ActiveSources[j] == Source)
+                {
+                    ALsizei end = --(Context->ActiveSourceCount);
+                    Context->ActiveSources[j] = Context->ActiveSources[end];
+                    break;
+                }
+            }
+
+            // For each buffer in the source's queue...
+            while(Source->queue != NULL)
+            {
+                BufferList = Source->queue;
+                Source->queue = BufferList->next;
+
+                if(BufferList->buffer != NULL)
+                    BufferList->buffer->refcount--;
+                free(BufferList);
+            }
+
+            for(j = 0;j < MAX_SENDS;++j)
+            {
+                if(Source->Send[j].Slot)
+                    Source->Send[j].Slot->refcount--;
+                Source->Send[j].Slot = NULL;
+            }
+
+            // Remove Source from list of Sources
+            RemoveUIntMapKey(&Context->SourceMap, Source->source);
+            ALTHUNK_REMOVEENTRY(Source->source);
+
+            memset(Source,0,sizeof(ALsource));
+            free(Source);
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+
+AL_API ALboolean AL_APIENTRY alIsSource(ALuint source)
+{
+    ALCcontext *Context;
+    ALboolean  result;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_FALSE;
+
+    result = (LookupSource(Context->SourceMap, source) ? AL_TRUE : AL_FALSE);
+
+    ProcessContext(Context);
+
+    return result;
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum eParam, ALfloat flValue)
+{
+    ALCcontext    *pContext;
+    ALsource    *Source;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+    {
+        switch(eParam)
+        {
+            case AL_PITCH:
+                if(flValue >= 0.0f)
+                {
+                    Source->flPitch = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_CONE_INNER_ANGLE:
+                if(flValue >= 0.0f && flValue <= 360.0f)
+                {
+                    Source->flInnerAngle = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_CONE_OUTER_ANGLE:
+                if(flValue >= 0.0f && flValue <= 360.0f)
+                {
+                    Source->flOuterAngle = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_GAIN:
+                if(flValue >= 0.0f)
+                {
+                    Source->flGain = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_MAX_DISTANCE:
+                if(flValue >= 0.0f)
+                {
+                    Source->flMaxDistance = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_ROLLOFF_FACTOR:
+                if(flValue >= 0.0f)
+                {
+                    Source->flRollOffFactor = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_REFERENCE_DISTANCE:
+                if(flValue >= 0.0f)
+                {
+                    Source->flRefDistance = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_MIN_GAIN:
+                if(flValue >= 0.0f && flValue <= 1.0f)
+                {
+                    Source->flMinGain = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_MAX_GAIN:
+                if(flValue >= 0.0f && flValue <= 1.0f)
+                {
+                    Source->flMaxGain = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_CONE_OUTER_GAIN:
+                if(flValue >= 0.0f && flValue <= 1.0f)
+                {
+                    Source->flOuterGain = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_CONE_OUTER_GAINHF:
+                if(flValue >= 0.0f && flValue <= 1.0f)
+                {
+                    Source->OuterGainHF = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_AIR_ABSORPTION_FACTOR:
+                if(flValue >= 0.0f && flValue <= 10.0f)
+                {
+                    Source->AirAbsorptionFactor = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_ROOM_ROLLOFF_FACTOR:
+                if(flValue >= 0.0f && flValue <= 10.0f)
+                {
+                    Source->RoomRolloffFactor = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_DOPPLER_FACTOR:
+                if(flValue >= 0.0f && flValue <= 1.0f)
+                {
+                    Source->DopplerFactor = flValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_SEC_OFFSET:
+            case AL_SAMPLE_OFFSET:
+            case AL_BYTE_OFFSET:
+                if(flValue >= 0.0f)
+                {
+                    Source->lOffsetType = eParam;
+
+                    // Store Offset (convert Seconds into Milliseconds)
+                    if(eParam == AL_SEC_OFFSET)
+                        Source->lOffset = (ALint)(flValue * 1000.0f);
+                    else
+                        Source->lOffset = (ALint)flValue;
+
+                    if ((Source->state == AL_PLAYING) || (Source->state == AL_PAUSED))
+                    {
+                        if(ApplyOffset(Source) == AL_FALSE)
+                            alSetError(pContext, AL_INVALID_VALUE);
+                    }
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+    {
+        // Invalid Source Name
+        alSetError(pContext, AL_INVALID_NAME);
+    }
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum eParam, ALfloat flValue1,ALfloat flValue2,ALfloat flValue3)
+{
+    ALCcontext    *pContext;
+    ALsource    *Source;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+    {
+        switch(eParam)
+        {
+            case AL_POSITION:
+                Source->vPosition[0] = flValue1;
+                Source->vPosition[1] = flValue2;
+                Source->vPosition[2] = flValue3;
+                Source->NeedsUpdate = AL_TRUE;
+                break;
+
+            case AL_VELOCITY:
+                Source->vVelocity[0] = flValue1;
+                Source->vVelocity[1] = flValue2;
+                Source->vVelocity[2] = flValue3;
+                Source->NeedsUpdate = AL_TRUE;
+                break;
+
+            case AL_DIRECTION:
+                Source->vOrientation[0] = flValue1;
+                Source->vOrientation[1] = flValue2;
+                Source->vOrientation[2] = flValue3;
+                Source->NeedsUpdate = AL_TRUE;
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum eParam, const ALfloat *pflValues)
+{
+    ALCcontext    *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValues)
+    {
+        if(LookupSource(pContext->SourceMap, source) != NULL)
+        {
+            switch(eParam)
+            {
+                case AL_PITCH:
+                case AL_CONE_INNER_ANGLE:
+                case AL_CONE_OUTER_ANGLE:
+                case AL_GAIN:
+                case AL_MAX_DISTANCE:
+                case AL_ROLLOFF_FACTOR:
+                case AL_REFERENCE_DISTANCE:
+                case AL_MIN_GAIN:
+                case AL_MAX_GAIN:
+                case AL_CONE_OUTER_GAIN:
+                case AL_CONE_OUTER_GAINHF:
+                case AL_SEC_OFFSET:
+                case AL_SAMPLE_OFFSET:
+                case AL_BYTE_OFFSET:
+                case AL_AIR_ABSORPTION_FACTOR:
+                case AL_ROOM_ROLLOFF_FACTOR:
+                    alSourcef(source, eParam, pflValues[0]);
+                    break;
+
+                case AL_POSITION:
+                case AL_VELOCITY:
+                case AL_DIRECTION:
+                    alSource3f(source, eParam, pflValues[0], pflValues[1], pflValues[2]);
+                    break;
+
+                default:
+                    alSetError(pContext, AL_INVALID_ENUM);
+                    break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourcei(ALuint source,ALenum eParam,ALint lValue)
+{
+    ALCcontext          *pContext;
+    ALsource            *Source;
+    ALbufferlistitem    *BufferListItem;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+    {
+        ALCdevice *device = pContext->Device;
+
+        switch(eParam)
+        {
+            case AL_MAX_DISTANCE:
+            case AL_ROLLOFF_FACTOR:
+            case AL_CONE_INNER_ANGLE:
+            case AL_CONE_OUTER_ANGLE:
+            case AL_REFERENCE_DISTANCE:
+                alSourcef(source, eParam, (ALfloat)lValue);
+                break;
+
+            case AL_SOURCE_RELATIVE:
+                if(lValue == AL_FALSE || lValue == AL_TRUE)
+                {
+                    Source->bHeadRelative = (ALboolean)lValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_LOOPING:
+                if(lValue == AL_FALSE || lValue == AL_TRUE)
+                    Source->bLooping = (ALboolean)lValue;
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_BUFFER:
+                if(Source->state == AL_STOPPED || Source->state == AL_INITIAL)
+                {
+                    ALbuffer *buffer = NULL;
+
+                    if(lValue == 0 ||
+                       (buffer=LookupBuffer(device->BufferMap, lValue)) != NULL)
+                    {
+                        // Remove all elements in the queue
+                        while(Source->queue != NULL)
+                        {
+                            BufferListItem = Source->queue;
+                            Source->queue = BufferListItem->next;
+
+                            if(BufferListItem->buffer)
+                                BufferListItem->buffer->refcount--;
+                            free(BufferListItem);
+                        }
+                        Source->BuffersInQueue = 0;
+
+                        // Add the buffer to the queue (as long as it is NOT the NULL buffer)
+                        if(buffer != NULL)
+                        {
+                            // Source is now in STATIC mode
+                            Source->lSourceType = AL_STATIC;
+
+                            // Add the selected buffer to the queue
+                            BufferListItem = malloc(sizeof(ALbufferlistitem));
+                            BufferListItem->buffer = buffer;
+                            BufferListItem->next = NULL;
+                            BufferListItem->prev = NULL;
+
+                            Source->queue = BufferListItem;
+                            Source->BuffersInQueue = 1;
+
+                            if(buffer->FmtChannels == FmtMono)
+                                Source->Update = CalcSourceParams;
+                            else
+                                Source->Update = CalcNonAttnSourceParams;
+
+                            // Increment reference counter for buffer
+                            buffer->refcount++;
+                        }
+                        else
+                        {
+                            // Source is now in UNDETERMINED mode
+                            Source->lSourceType = AL_UNDETERMINED;
+                        }
+                        Source->BuffersPlayed = 0;
+
+                        // Update AL_BUFFER parameter
+                        Source->Buffer = buffer;
+                        Source->NeedsUpdate = AL_TRUE;
+                    }
+                    else
+                        alSetError(pContext, AL_INVALID_VALUE);
+                }
+                else
+                    alSetError(pContext, AL_INVALID_OPERATION);
+                break;
+
+            case AL_SOURCE_STATE:
+                // Query only
+                alSetError(pContext, AL_INVALID_OPERATION);
+                break;
+
+            case AL_SEC_OFFSET:
+            case AL_SAMPLE_OFFSET:
+            case AL_BYTE_OFFSET:
+                if(lValue >= 0)
+                {
+                    Source->lOffsetType = eParam;
+
+                    // Store Offset (convert Seconds into Milliseconds)
+                    if(eParam == AL_SEC_OFFSET)
+                        Source->lOffset = lValue * 1000;
+                    else
+                        Source->lOffset = lValue;
+
+                    if(Source->state == AL_PLAYING || Source->state == AL_PAUSED)
+                    {
+                        if(ApplyOffset(Source) == AL_FALSE)
+                            alSetError(pContext, AL_INVALID_VALUE);
+                    }
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_DIRECT_FILTER: {
+                ALfilter *filter = NULL;
+
+                if(lValue == 0 ||
+                   (filter=LookupFilter(pContext->Device->FilterMap, lValue)) != NULL)
+                {
+                    if(!filter)
+                    {
+                        Source->DirectFilter.type = AL_FILTER_NULL;
+                        Source->DirectFilter.filter = 0;
+                    }
+                    else
+                        memcpy(&Source->DirectFilter, filter, sizeof(*filter));
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+            }   break;
+
+            case AL_DIRECT_FILTER_GAINHF_AUTO:
+                if(lValue == AL_TRUE || lValue == AL_FALSE)
+                {
+                    Source->DryGainHFAuto = lValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+                if(lValue == AL_TRUE || lValue == AL_FALSE)
+                {
+                    Source->WetGainAuto = lValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+                if(lValue == AL_TRUE || lValue == AL_FALSE)
+                {
+                    Source->WetGainHFAuto = lValue;
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            case AL_DISTANCE_MODEL:
+                if(lValue == AL_NONE ||
+                   lValue == AL_INVERSE_DISTANCE ||
+                   lValue == AL_INVERSE_DISTANCE_CLAMPED ||
+                   lValue == AL_LINEAR_DISTANCE ||
+                   lValue == AL_LINEAR_DISTANCE_CLAMPED ||
+                   lValue == AL_EXPONENT_DISTANCE ||
+                   lValue == AL_EXPONENT_DISTANCE_CLAMPED)
+                {
+                    Source->DistanceModel = lValue;
+                    if(pContext->SourceDistanceModel)
+                        Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+                break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum eParam, ALint lValue1, ALint lValue2, ALint lValue3)
+{
+    ALCcontext *pContext;
+    ALsource   *Source;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+    {
+        ALCdevice *device = pContext->Device;
+
+        switch (eParam)
+        {
+            case AL_POSITION:
+            case AL_VELOCITY:
+            case AL_DIRECTION:
+                alSource3f(source, eParam, (ALfloat)lValue1, (ALfloat)lValue2, (ALfloat)lValue3);
+                break;
+
+            case AL_AUXILIARY_SEND_FILTER: {
+                ALeffectslot *ALEffectSlot = NULL;
+                ALfilter     *ALFilter = NULL;
+
+                if((ALuint)lValue2 < device->NumAuxSends &&
+                   (lValue1 == 0 ||
+                    (ALEffectSlot=LookupEffectSlot(pContext->EffectSlotMap, lValue1)) != NULL) &&
+                   (lValue3 == 0 ||
+                    (ALFilter=LookupFilter(device->FilterMap, lValue3)) != NULL))
+                {
+                    /* Release refcount on the previous slot, and add one for
+                     * the new slot */
+                    if(Source->Send[lValue2].Slot)
+                        Source->Send[lValue2].Slot->refcount--;
+                    Source->Send[lValue2].Slot = ALEffectSlot;
+                    if(Source->Send[lValue2].Slot)
+                        Source->Send[lValue2].Slot->refcount++;
+
+                    if(!ALFilter)
+                    {
+                        /* Disable filter */
+                        Source->Send[lValue2].WetFilter.type = 0;
+                        Source->Send[lValue2].WetFilter.filter = 0;
+                    }
+                    else
+                        memcpy(&Source->Send[lValue2].WetFilter, ALFilter, sizeof(*ALFilter));
+                    Source->NeedsUpdate = AL_TRUE;
+                }
+                else
+                    alSetError(pContext, AL_INVALID_VALUE);
+            }    break;
+
+            default:
+                alSetError(pContext, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+        alSetError(pContext, AL_INVALID_NAME);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum eParam, const ALint* plValues)
+{
+    ALCcontext    *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValues)
+    {
+        if(LookupSource(pContext->SourceMap, source) != NULL)
+        {
+            switch(eParam)
+            {
+                case AL_SOURCE_RELATIVE:
+                case AL_CONE_INNER_ANGLE:
+                case AL_CONE_OUTER_ANGLE:
+                case AL_LOOPING:
+                case AL_BUFFER:
+                case AL_SOURCE_STATE:
+                case AL_SEC_OFFSET:
+                case AL_SAMPLE_OFFSET:
+                case AL_BYTE_OFFSET:
+                case AL_MAX_DISTANCE:
+                case AL_ROLLOFF_FACTOR:
+                case AL_REFERENCE_DISTANCE:
+                case AL_DIRECT_FILTER:
+                case AL_DIRECT_FILTER_GAINHF_AUTO:
+                case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+                case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+                case AL_DISTANCE_MODEL:
+                    alSourcei(source, eParam, plValues[0]);
+                    break;
+
+                case AL_POSITION:
+                case AL_VELOCITY:
+                case AL_DIRECTION:
+                case AL_AUXILIARY_SEND_FILTER:
+                    alSource3i(source, eParam, plValues[0], plValues[1], plValues[2]);
+                    break;
+
+                default:
+                    alSetError(pContext, AL_INVALID_ENUM);
+                    break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum eParam, ALfloat *pflValue)
+{
+    ALCcontext  *pContext;
+    ALsource    *Source;
+    ALdouble    Offsets[2];
+    ALdouble    updateLen;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValue)
+    {
+        if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+        {
+            switch(eParam)
+            {
+                case AL_PITCH:
+                    *pflValue = Source->flPitch;
+                    break;
+
+                case AL_GAIN:
+                    *pflValue = Source->flGain;
+                    break;
+
+                case AL_MIN_GAIN:
+                    *pflValue = Source->flMinGain;
+                    break;
+
+                case AL_MAX_GAIN:
+                    *pflValue = Source->flMaxGain;
+                    break;
+
+                case AL_MAX_DISTANCE:
+                    *pflValue = Source->flMaxDistance;
+                    break;
+
+                case AL_ROLLOFF_FACTOR:
+                    *pflValue = Source->flRollOffFactor;
+                    break;
+
+                case AL_CONE_OUTER_GAIN:
+                    *pflValue = Source->flOuterGain;
+                    break;
+
+                case AL_CONE_OUTER_GAINHF:
+                    *pflValue = Source->OuterGainHF;
+                    break;
+
+                case AL_SEC_OFFSET:
+                case AL_SAMPLE_OFFSET:
+                case AL_BYTE_OFFSET:
+                    updateLen = (ALdouble)pContext->Device->UpdateSize /
+                                pContext->Device->Frequency;
+                    GetSourceOffset(Source, eParam, Offsets, updateLen);
+                    *pflValue = Offsets[0];
+                    break;
+
+                case AL_CONE_INNER_ANGLE:
+                    *pflValue = Source->flInnerAngle;
+                    break;
+
+                case AL_CONE_OUTER_ANGLE:
+                    *pflValue = Source->flOuterAngle;
+                    break;
+
+                case AL_REFERENCE_DISTANCE:
+                    *pflValue = Source->flRefDistance;
+                    break;
+
+                case AL_AIR_ABSORPTION_FACTOR:
+                    *pflValue = Source->AirAbsorptionFactor;
+                    break;
+
+                case AL_ROOM_ROLLOFF_FACTOR:
+                    *pflValue = Source->RoomRolloffFactor;
+                    break;
+
+                case AL_DOPPLER_FACTOR:
+                    *pflValue = Source->DopplerFactor;
+                    break;
+
+                default:
+                    alSetError(pContext, AL_INVALID_ENUM);
+                    break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum eParam, ALfloat* pflValue1, ALfloat* pflValue2, ALfloat* pflValue3)
+{
+    ALCcontext    *pContext;
+    ALsource    *Source;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValue1 && pflValue2 && pflValue3)
+    {
+        if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+        {
+            switch(eParam)
+            {
+                case AL_POSITION:
+                    *pflValue1 = Source->vPosition[0];
+                    *pflValue2 = Source->vPosition[1];
+                    *pflValue3 = Source->vPosition[2];
+                    break;
+
+                case AL_VELOCITY:
+                    *pflValue1 = Source->vVelocity[0];
+                    *pflValue2 = Source->vVelocity[1];
+                    *pflValue3 = Source->vVelocity[2];
+                    break;
+
+                case AL_DIRECTION:
+                    *pflValue1 = Source->vOrientation[0];
+                    *pflValue2 = Source->vOrientation[1];
+                    *pflValue3 = Source->vOrientation[2];
+                    break;
+
+                default:
+                    alSetError(pContext, AL_INVALID_ENUM);
+                    break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum eParam, ALfloat *pflValues)
+{
+    ALCcontext  *pContext;
+    ALsource    *Source;
+    ALdouble    Offsets[2];
+    ALdouble    updateLen;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(pflValues)
+    {
+        if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+        {
+            switch(eParam)
+            {
+                case AL_PITCH:
+                case AL_GAIN:
+                case AL_MIN_GAIN:
+                case AL_MAX_GAIN:
+                case AL_MAX_DISTANCE:
+                case AL_ROLLOFF_FACTOR:
+                case AL_DOPPLER_FACTOR:
+                case AL_CONE_OUTER_GAIN:
+                case AL_SEC_OFFSET:
+                case AL_SAMPLE_OFFSET:
+                case AL_BYTE_OFFSET:
+                case AL_CONE_INNER_ANGLE:
+                case AL_CONE_OUTER_ANGLE:
+                case AL_REFERENCE_DISTANCE:
+                case AL_CONE_OUTER_GAINHF:
+                case AL_AIR_ABSORPTION_FACTOR:
+                case AL_ROOM_ROLLOFF_FACTOR:
+                    alGetSourcef(source, eParam, pflValues);
+                    break;
+
+                case AL_POSITION:
+                case AL_VELOCITY:
+                case AL_DIRECTION:
+                    alGetSource3f(source, eParam, pflValues+0, pflValues+1, pflValues+2);
+                    break;
+
+                case AL_SAMPLE_RW_OFFSETS_SOFT:
+                case AL_BYTE_RW_OFFSETS_SOFT:
+                    updateLen = (ALdouble)pContext->Device->UpdateSize /
+                                pContext->Device->Frequency;
+                    GetSourceOffset(Source, eParam, Offsets, updateLen);
+                    pflValues[0] = Offsets[0];
+                    pflValues[1] = Offsets[1];
+                    break;
+
+                default:
+                    alSetError(pContext, AL_INVALID_ENUM);
+                    break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum eParam, ALint *plValue)
+{
+    ALCcontext *pContext;
+    ALsource   *Source;
+    ALdouble   Offsets[2];
+    ALdouble   updateLen;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValue)
+    {
+        if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+        {
+            switch(eParam)
+            {
+                case AL_MAX_DISTANCE:
+                    *plValue = (ALint)Source->flMaxDistance;
+                    break;
+
+                case AL_ROLLOFF_FACTOR:
+                    *plValue = (ALint)Source->flRollOffFactor;
+                    break;
+
+                case AL_REFERENCE_DISTANCE:
+                    *plValue = (ALint)Source->flRefDistance;
+                    break;
+
+                case AL_SOURCE_RELATIVE:
+                    *plValue = Source->bHeadRelative;
+                    break;
+
+                case AL_CONE_INNER_ANGLE:
+                    *plValue = (ALint)Source->flInnerAngle;
+                    break;
+
+                case AL_CONE_OUTER_ANGLE:
+                    *plValue = (ALint)Source->flOuterAngle;
+                    break;
+
+                case AL_LOOPING:
+                    *plValue = Source->bLooping;
+                    break;
+
+                case AL_BUFFER:
+                    *plValue = (Source->Buffer ? Source->Buffer->buffer : 0);
+                    break;
+
+                case AL_SOURCE_STATE:
+                    *plValue = Source->state;
+                    break;
+
+                case AL_BUFFERS_QUEUED:
+                    *plValue = Source->BuffersInQueue;
+                    break;
+
+                case AL_BUFFERS_PROCESSED:
+                    if(Source->bLooping || Source->lSourceType != AL_STREAMING)
+                    {
+                        /* Buffers on a looping source are in a perpetual state
+                         * of PENDING, so don't report any as PROCESSED */
+                        *plValue = 0;
+                    }
+                    else
+                        *plValue = Source->BuffersPlayed;
+                    break;
+
+                case AL_SOURCE_TYPE:
+                    *plValue = Source->lSourceType;
+                    break;
+
+                case AL_SEC_OFFSET:
+                case AL_SAMPLE_OFFSET:
+                case AL_BYTE_OFFSET:
+                    updateLen = (ALdouble)pContext->Device->UpdateSize /
+                                pContext->Device->Frequency;
+                    GetSourceOffset(Source, eParam, Offsets, updateLen);
+                    *plValue = (ALint)Offsets[0];
+                    break;
+
+                case AL_DIRECT_FILTER:
+                    *plValue = Source->DirectFilter.filter;
+                    break;
+
+                case AL_DIRECT_FILTER_GAINHF_AUTO:
+                    *plValue = Source->DryGainHFAuto;
+                    break;
+
+                case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+                    *plValue = Source->WetGainAuto;
+                    break;
+
+                case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+                    *plValue = Source->WetGainHFAuto;
+                    break;
+
+                case AL_DOPPLER_FACTOR:
+                    *plValue = (ALint)Source->DopplerFactor;
+                    break;
+
+                case AL_DISTANCE_MODEL:
+                    *plValue = Source->DistanceModel;
+                    break;
+
+                default:
+                    alSetError(pContext, AL_INVALID_ENUM);
+                    break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum eParam, ALint* plValue1, ALint* plValue2, ALint* plValue3)
+{
+    ALCcontext  *pContext;
+    ALsource    *Source;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValue1 && plValue2 && plValue3)
+    {
+        if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+        {
+            switch(eParam)
+            {
+                case AL_POSITION:
+                    *plValue1 = (ALint)Source->vPosition[0];
+                    *plValue2 = (ALint)Source->vPosition[1];
+                    *plValue3 = (ALint)Source->vPosition[2];
+                    break;
+
+                case AL_VELOCITY:
+                    *plValue1 = (ALint)Source->vVelocity[0];
+                    *plValue2 = (ALint)Source->vVelocity[1];
+                    *plValue3 = (ALint)Source->vVelocity[2];
+                    break;
+
+                case AL_DIRECTION:
+                    *plValue1 = (ALint)Source->vOrientation[0];
+                    *plValue2 = (ALint)Source->vOrientation[1];
+                    *plValue3 = (ALint)Source->vOrientation[2];
+                    break;
+
+                default:
+                    alSetError(pContext, AL_INVALID_ENUM);
+                    break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum eParam, ALint* plValues)
+{
+    ALCcontext  *pContext;
+    ALsource    *Source;
+    ALdouble    Offsets[2];
+    ALdouble    updateLen;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(plValues)
+    {
+        if((Source=LookupSource(pContext->SourceMap, source)) != NULL)
+        {
+            switch(eParam)
+            {
+                case AL_SOURCE_RELATIVE:
+                case AL_CONE_INNER_ANGLE:
+                case AL_CONE_OUTER_ANGLE:
+                case AL_LOOPING:
+                case AL_BUFFER:
+                case AL_SOURCE_STATE:
+                case AL_BUFFERS_QUEUED:
+                case AL_BUFFERS_PROCESSED:
+                case AL_SEC_OFFSET:
+                case AL_SAMPLE_OFFSET:
+                case AL_BYTE_OFFSET:
+                case AL_MAX_DISTANCE:
+                case AL_ROLLOFF_FACTOR:
+                case AL_DOPPLER_FACTOR:
+                case AL_REFERENCE_DISTANCE:
+                case AL_SOURCE_TYPE:
+                case AL_DIRECT_FILTER:
+                case AL_DIRECT_FILTER_GAINHF_AUTO:
+                case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO:
+                case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO:
+                case AL_DISTANCE_MODEL:
+                    alGetSourcei(source, eParam, plValues);
+                    break;
+
+                case AL_POSITION:
+                case AL_VELOCITY:
+                case AL_DIRECTION:
+                    alGetSource3i(source, eParam, plValues+0, plValues+1, plValues+2);
+                    break;
+
+                case AL_SAMPLE_RW_OFFSETS_SOFT:
+                case AL_BYTE_RW_OFFSETS_SOFT:
+                    updateLen = (ALdouble)pContext->Device->UpdateSize /
+                                pContext->Device->Frequency;
+                    GetSourceOffset(Source, eParam, Offsets, updateLen);
+                    plValues[0] = (ALint)Offsets[0];
+                    plValues[1] = (ALint)Offsets[1];
+                    break;
+
+                default:
+                    alSetError(pContext, AL_INVALID_ENUM);
+                    break;
+            }
+        }
+        else
+            alSetError(pContext, AL_INVALID_NAME);
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    ProcessContext(pContext);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source)
+{
+    alSourcePlayv(1, &source);
+}
+
+AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources)
+{
+    ALCcontext       *Context;
+    ALsource         *Source;
+    ALbufferlistitem *BufferList;
+    ALsizei          i, j;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+    if(n > 0 && !sources)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+
+    // Check that all the Sources are valid
+    for(i = 0;i < n;i++)
+    {
+        if(!LookupSource(Context->SourceMap, sources[i]))
+        {
+            alSetError(Context, AL_INVALID_NAME);
+            goto done;
+        }
+    }
+
+    while(Context->MaxActiveSources-Context->ActiveSourceCount < n)
+    {
+        void *temp = NULL;
+        ALsizei newcount;
+
+        newcount = Context->MaxActiveSources << 1;
+        if(newcount > 0)
+            temp = realloc(Context->ActiveSources,
+                           sizeof(*Context->ActiveSources) * newcount);
+        if(!temp)
+        {
+            alSetError(Context, AL_OUT_OF_MEMORY);
+            goto done;
+        }
+
+        Context->ActiveSources = temp;
+        Context->MaxActiveSources = newcount;
+    }
+
+    for(i = 0;i < n;i++)
+    {
+        Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
+
+        // Check that there is a queue containing at least one non-null, non zero length AL Buffer
+        BufferList = Source->queue;
+        while(BufferList)
+        {
+            if(BufferList->buffer != NULL && BufferList->buffer->size)
+                break;
+            BufferList = BufferList->next;
+        }
+
+        if(!BufferList)
+        {
+            Source->state = AL_STOPPED;
+            Source->BuffersPlayed = Source->BuffersInQueue;
+            Source->position = 0;
+            Source->position_fraction = 0;
+            Source->lOffset = 0;
+            continue;
+        }
+
+        if(Source->state != AL_PAUSED)
+        {
+            Source->state = AL_PLAYING;
+            Source->position = 0;
+            Source->position_fraction = 0;
+            Source->BuffersPlayed = 0;
+
+            Source->Buffer = Source->queue->buffer;
+        }
+        else
+            Source->state = AL_PLAYING;
+
+        // Check if an Offset has been set
+        if(Source->lOffset)
+            ApplyOffset(Source);
+
+        // If device is disconnected, go right to stopped
+        if(!Context->Device->Connected)
+        {
+            Source->state = AL_STOPPED;
+            Source->BuffersPlayed = Source->BuffersInQueue;
+            Source->position = 0;
+            Source->position_fraction = 0;
+        }
+        else
+        {
+            for(j = 0;j < Context->ActiveSourceCount;j++)
+            {
+                if(Context->ActiveSources[j] == Source)
+                    break;
+            }
+            if(j == Context->ActiveSourceCount)
+                Context->ActiveSources[Context->ActiveSourceCount++] = Source;
+        }
+    }
+
+done:
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source)
+{
+    alSourcePausev(1, &source);
+}
+
+AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources)
+{
+    ALCcontext *Context;
+    ALsource *Source;
+    ALsizei i;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+    if(n > 0 && !sources)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+
+    // Check all the Sources are valid
+    for(i = 0;i < n;i++)
+    {
+        if(!LookupSource(Context->SourceMap, sources[i]))
+        {
+            alSetError(Context, AL_INVALID_NAME);
+            goto done;
+        }
+    }
+
+    for(i = 0;i < n;i++)
+    {
+        Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
+        if(Source->state == AL_PLAYING)
+            Source->state = AL_PAUSED;
+    }
+
+done:
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source)
+{
+    alSourceStopv(1, &source);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources)
+{
+    ALCcontext *Context;
+    ALsource *Source;
+    ALsizei i;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+    if(n > 0 && !sources)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+
+    // Check all the Sources are valid
+    for(i = 0;i < n;i++)
+    {
+        if(!LookupSource(Context->SourceMap, sources[i]))
+        {
+            alSetError(Context, AL_INVALID_NAME);
+            goto done;
+        }
+    }
+
+    for(i = 0;i < n;i++)
+    {
+        Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
+        if(Source->state != AL_INITIAL)
+        {
+            Source->state = AL_STOPPED;
+            Source->BuffersPlayed = Source->BuffersInQueue;
+        }
+        Source->lOffset = 0;
+    }
+
+done:
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source)
+{
+    alSourceRewindv(1, &source);
+}
+
+AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources)
+{
+    ALCcontext *Context;
+    ALsource *Source;
+    ALsizei i;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+    if(n > 0 && !sources)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+
+    // Check all the Sources are valid
+    for(i = 0;i < n;i++)
+    {
+        if(!LookupSource(Context->SourceMap, sources[i]))
+        {
+            alSetError(Context, AL_INVALID_NAME);
+            goto done;
+        }
+    }
+
+    for(i = 0;i < n;i++)
+    {
+        Source = (ALsource*)ALTHUNK_LOOKUPENTRY(sources[i]);
+        if(Source->state != AL_INITIAL)
+        {
+            Source->state = AL_INITIAL;
+            Source->position = 0;
+            Source->position_fraction = 0;
+            Source->BuffersPlayed = 0;
+            if(Source->queue)
+                Source->Buffer = Source->queue->buffer;
+        }
+        Source->lOffset = 0;
+    }
+
+done:
+    ProcessContext(Context);
+}
+
+
+AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei n, const ALuint *buffers)
+{
+    ALCcontext *Context;
+    ALCdevice *device;
+    ALsource *Source;
+    ALbuffer *buffer;
+    ALsizei i;
+    ALbufferlistitem *BufferListStart;
+    ALbufferlistitem *BufferList;
+    ALbuffer *BufferFmt;
+
+    if(n == 0)
+        return;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+
+    // Check that all buffers are valid or zero and that the source is valid
+
+    // Check that this is a valid source
+    if((Source=LookupSource(Context->SourceMap, source)) == NULL)
+    {
+        alSetError(Context, AL_INVALID_NAME);
+        goto done;
+    }
+
+    // Check that this is not a STATIC Source
+    if(Source->lSourceType == AL_STATIC)
+    {
+        // Invalid Source Type (can't queue on a Static Source)
+        alSetError(Context, AL_INVALID_OPERATION);
+        goto done;
+    }
+
+    device = Context->Device;
+
+    BufferFmt = NULL;
+
+    // Check existing Queue (if any) for a valid Buffers and get its frequency and format
+    BufferList = Source->queue;
+    while(BufferList)
+    {
+        if(BufferList->buffer)
+        {
+            BufferFmt = BufferList->buffer;
+            break;
+        }
+        BufferList = BufferList->next;
+    }
+
+    for(i = 0;i < n;i++)
+    {
+        if(!buffers[i])
+            continue;
+
+        if((buffer=LookupBuffer(device->BufferMap, buffers[i])) == NULL)
+        {
+            alSetError(Context, AL_INVALID_NAME);
+            goto done;
+        }
+
+        if(BufferFmt == NULL)
+        {
+            BufferFmt = buffer;
+
+            if(buffer->FmtChannels == FmtMono)
+                Source->Update = CalcSourceParams;
+            else
+                Source->Update = CalcNonAttnSourceParams;
+
+            Source->NeedsUpdate = AL_TRUE;
+        }
+        else if(BufferFmt->Frequency != buffer->Frequency ||
+                BufferFmt->OriginalChannels != buffer->OriginalChannels ||
+                BufferFmt->OriginalType != buffer->OriginalType)
+        {
+            alSetError(Context, AL_INVALID_OPERATION);
+            goto done;
+        }
+    }
+
+    // Change Source Type
+    Source->lSourceType = AL_STREAMING;
+
+    buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[0]);
+
+    // All buffers are valid - so add them to the list
+    BufferListStart = malloc(sizeof(ALbufferlistitem));
+    BufferListStart->buffer = buffer;
+    BufferListStart->next = NULL;
+    BufferListStart->prev = NULL;
+
+    // Increment reference counter for buffer
+    if(buffer) buffer->refcount++;
+
+    BufferList = BufferListStart;
+
+    for(i = 1;i < n;i++)
+    {
+        buffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(buffers[i]);
+
+        BufferList->next = malloc(sizeof(ALbufferlistitem));
+        BufferList->next->buffer = buffer;
+        BufferList->next->next = NULL;
+        BufferList->next->prev = BufferList;
+
+        // Increment reference counter for buffer
+        if(buffer) buffer->refcount++;
+
+        BufferList = BufferList->next;
+    }
+
+    if(Source->queue == NULL)
+    {
+        Source->queue = BufferListStart;
+        // Update Current Buffer
+        Source->Buffer = BufferListStart->buffer;
+    }
+    else
+    {
+        // Find end of queue
+        BufferList = Source->queue;
+        while(BufferList->next != NULL)
+            BufferList = BufferList->next;
+
+        BufferList->next = BufferListStart;
+        BufferList->next->prev = BufferList;
+    }
+
+    // Update number of buffers in queue
+    Source->BuffersInQueue += n;
+
+done:
+    ProcessContext(Context);
+}
+
+
+// Implementation assumes that n is the number of buffers to be removed from the queue and buffers is
+// an array of buffer IDs that are to be filled with the names of the buffers removed
+AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers )
+{
+    ALCcontext *Context;
+    ALsource *Source;
+    ALsizei i;
+    ALbufferlistitem *BufferList;
+
+    if(n == 0)
+        return;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(n < 0)
+    {
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+
+    if((Source=LookupSource(Context->SourceMap, source)) == NULL)
+    {
+        alSetError(Context, AL_INVALID_NAME);
+        goto done;
+    }
+
+    if(Source->bLooping || Source->lSourceType != AL_STREAMING ||
+       (ALuint)n > Source->BuffersPlayed)
+    {
+        // Some buffers can't be unqueue because they have not been processed
+        alSetError(Context, AL_INVALID_VALUE);
+        goto done;
+    }
+
+    for(i = 0;i < n;i++)
+    {
+        BufferList = Source->queue;
+        Source->queue = BufferList->next;
+
+        if(BufferList->buffer)
+        {
+            // Record name of buffer
+            buffers[i] = BufferList->buffer->buffer;
+            // Decrement buffer reference counter
+            BufferList->buffer->refcount--;
+        }
+        else
+            buffers[i] = 0;
+
+        // Release memory for buffer list item
+        free(BufferList);
+        Source->BuffersInQueue--;
+    }
+    if(Source->queue)
+        Source->queue->prev = NULL;
+
+    if(Source->state != AL_PLAYING)
+    {
+        if(Source->queue)
+            Source->Buffer = Source->queue->buffer;
+        else
+            Source->Buffer = NULL;
+    }
+    Source->BuffersPlayed -= n;
+
+done:
+    ProcessContext(Context);
+}
+
+
+static ALvoid InitSourceParams(ALsource *Source)
+{
+    Source->flInnerAngle = 360.0f;
+    Source->flOuterAngle = 360.0f;
+    Source->flPitch = 1.0f;
+    Source->vPosition[0] = 0.0f;
+    Source->vPosition[1] = 0.0f;
+    Source->vPosition[2] = 0.0f;
+    Source->vOrientation[0] = 0.0f;
+    Source->vOrientation[1] = 0.0f;
+    Source->vOrientation[2] = 0.0f;
+    Source->vVelocity[0] = 0.0f;
+    Source->vVelocity[1] = 0.0f;
+    Source->vVelocity[2] = 0.0f;
+    Source->flRefDistance = 1.0f;
+    Source->flMaxDistance = FLT_MAX;
+    Source->flRollOffFactor = 1.0f;
+    Source->bLooping = AL_FALSE;
+    Source->flGain = 1.0f;
+    Source->flMinGain = 0.0f;
+    Source->flMaxGain = 1.0f;
+    Source->flOuterGain = 0.0f;
+    Source->OuterGainHF = 1.0f;
+
+    Source->DryGainHFAuto = AL_TRUE;
+    Source->WetGainAuto = AL_TRUE;
+    Source->WetGainHFAuto = AL_TRUE;
+    Source->AirAbsorptionFactor = 0.0f;
+    Source->RoomRolloffFactor = 0.0f;
+    Source->DopplerFactor = 1.0f;
+
+    Source->DistanceModel = AL_INVERSE_DISTANCE_CLAMPED;
+
+    Source->Resampler = DefaultResampler;
+
+    Source->state = AL_INITIAL;
+    Source->lSourceType = AL_UNDETERMINED;
+
+    Source->NeedsUpdate = AL_TRUE;
+
+    Source->Buffer = NULL;
+}
+
+
+/*
+    GetSourceOffset
+
+    Gets the current playback position in the given Source, in the appropriate format (Bytes, Samples or MilliSeconds)
+    The offset is relative to the start of the queue (not the start of the current buffer)
+*/
+static ALvoid GetSourceOffset(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen)
+{
+    const ALbufferlistitem *BufferList;
+    const ALbuffer         *Buffer = NULL;
+    enum UserFmtType OriginalType;
+    ALsizei BufferFreq;
+    ALint   Channels, Bytes;
+    ALuint  readPos, writePos;
+    ALuint  TotalBufferDataSize;
+    ALuint  i;
+
+    // Find the first non-NULL Buffer in the Queue
+    BufferList = Source->queue;
+    while(BufferList)
+    {
+        if(BufferList->buffer)
+        {
+            Buffer = BufferList->buffer;
+            break;
+        }
+        BufferList = BufferList->next;
+    }
+
+    if((Source->state != AL_PLAYING && Source->state != AL_PAUSED) || !Buffer)
+    {
+        offset[0] = 0.0;
+        offset[1] = 0.0;
+        return;
+    }
+
+    // Get Current Buffer Size and frequency (in milliseconds)
+    BufferFreq = Buffer->Frequency;
+    OriginalType = Buffer->OriginalType;
+    Channels = ChannelsFromFmt(Buffer->FmtChannels);
+    Bytes = BytesFromFmt(Buffer->FmtType);
+
+    // Get Current BytesPlayed (NOTE : This is the byte offset into the *current* buffer)
+    readPos = Source->position * Channels * Bytes;
+    // Add byte length of any processed buffers in the queue
+    TotalBufferDataSize = 0;
+    BufferList = Source->queue;
+    for(i = 0;BufferList;i++)
+    {
+        if(BufferList->buffer)
+        {
+            if(i < Source->BuffersPlayed)
+                readPos += BufferList->buffer->size;
+            TotalBufferDataSize += BufferList->buffer->size;
+        }
+        BufferList = BufferList->next;
+    }
+    if(Source->state == AL_PLAYING)
+        writePos = readPos + ((ALuint)(updateLen*BufferFreq) * Channels * Bytes);
+    else
+        writePos = readPos;
+
+    if(Source->bLooping)
+    {
+        readPos %= TotalBufferDataSize;
+        writePos %= TotalBufferDataSize;
+    }
+    else
+    {
+        // Wrap positions back to 0
+        if(readPos >= TotalBufferDataSize)
+            readPos = 0;
+        if(writePos >= TotalBufferDataSize)
+            writePos = 0;
+    }
+
+    switch(name)
+    {
+        case AL_SEC_OFFSET:
+            offset[0] = (ALdouble)readPos / (Channels * Bytes * BufferFreq);
+            offset[1] = (ALdouble)writePos / (Channels * Bytes * BufferFreq);
+            break;
+        case AL_SAMPLE_OFFSET:
+        case AL_SAMPLE_RW_OFFSETS_SOFT:
+            offset[0] = (ALdouble)(readPos / (Channels * Bytes));
+            offset[1] = (ALdouble)(writePos / (Channels * Bytes));
+            break;
+        case AL_BYTE_OFFSET:
+        case AL_BYTE_RW_OFFSETS_SOFT:
+            // Take into account the original format of the Buffer
+            if(OriginalType == UserFmtIMA4)
+            {
+                ALuint FrameBlockSize = 65 * Bytes * Channels;
+                ALuint BlockSize = 36 * Channels;
+
+                // Round down to nearest ADPCM block
+                offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize);
+                if(Source->state != AL_PLAYING)
+                    offset[1] = offset[0];
+                else
+                {
+                    // Round up to nearest ADPCM block
+                    offset[1] = (ALdouble)((writePos+FrameBlockSize-1) /
+                                           FrameBlockSize * BlockSize);
+                }
+            }
+            else
+            {
+                ALuint OrigBytes = BytesFromUserFmt(OriginalType);
+                offset[0] = (ALdouble)(readPos / Bytes * OrigBytes);
+                offset[1] = (ALdouble)(writePos / Bytes * OrigBytes);
+            }
+            break;
+    }
+}
+
+
+/*
+    ApplyOffset
+
+    Apply a playback offset to the Source.  This function will update the queue (to correctly
+    mark buffers as 'pending' or 'processed' depending upon the new offset.
+*/
+static ALboolean ApplyOffset(ALsource *Source)
+{
+    const ALbufferlistitem *BufferList;
+    const ALbuffer         *Buffer;
+    ALint lBufferSize, lTotalBufferSize;
+    ALint BuffersPlayed;
+    ALint lByteOffset;
+
+    // Get true byte offset
+    lByteOffset = GetByteOffset(Source);
+
+    // If the offset is invalid, don't apply it
+    if(lByteOffset == -1)
+        return AL_FALSE;
+
+    // Sort out the queue (pending and processed states)
+    BufferList = Source->queue;
+    lTotalBufferSize = 0;
+    BuffersPlayed = 0;
+
+    while(BufferList)
+    {
+        Buffer = BufferList->buffer;
+        lBufferSize = Buffer ? Buffer->size : 0;
+
+        if(lBufferSize <= lByteOffset-lTotalBufferSize)
+        {
+            // Offset is past this buffer so increment BuffersPlayed
+            BuffersPlayed++;
+        }
+        else if(lTotalBufferSize <= lByteOffset)
+        {
+            // Offset is within this buffer
+            // Set Current Buffer
+            Source->Buffer = BufferList->buffer;
+            Source->BuffersPlayed = BuffersPlayed;
+
+            // SW Mixer Positions are in Samples
+            Source->position = (lByteOffset - lTotalBufferSize) /
+                                FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
+            return AL_TRUE;
+        }
+
+        // Increment the TotalBufferSize
+        lTotalBufferSize += lBufferSize;
+
+        // Move on to next buffer in the Queue
+        BufferList = BufferList->next;
+    }
+    // Offset is out of range of the buffer queue
+    return AL_FALSE;
+}
+
+
+/*
+    GetByteOffset
+
+    Returns the 'true' byte offset into the Source's queue (from the Sample, Byte or Millisecond
+    offset supplied by the application).   This takes into account the fact that the buffer format
+    may have been modifed by AL (e.g 8bit samples are converted to float)
+*/
+static ALint GetByteOffset(ALsource *Source)
+{
+    const ALbuffer *Buffer = NULL;
+    const ALbufferlistitem *BufferList;
+    ALint ByteOffset = -1;
+
+    // Find the first non-NULL Buffer in the Queue
+    BufferList = Source->queue;
+    while(BufferList)
+    {
+        if(BufferList->buffer)
+        {
+            Buffer = BufferList->buffer;
+            break;
+        }
+        BufferList = BufferList->next;
+    }
+
+    if(!Buffer)
+    {
+        Source->lOffset = 0;
+        return -1;
+    }
+
+    // Determine the ByteOffset (and ensure it is block aligned)
+    switch(Source->lOffsetType)
+    {
+    case AL_BYTE_OFFSET:
+        // Take into consideration the original format
+        ByteOffset = Source->lOffset;
+        if(Buffer->OriginalType == UserFmtIMA4)
+        {
+            // Round down to nearest ADPCM block
+            ByteOffset /= 36 * ChannelsFromUserFmt(Buffer->OriginalChannels);
+            // Multiply by compression rate (65 sample frames per block)
+            ByteOffset *= 65;
+        }
+        else
+            ByteOffset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType);
+        ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
+        break;
+
+    case AL_SAMPLE_OFFSET:
+        ByteOffset = Source->lOffset * FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
+        break;
+
+    case AL_SEC_OFFSET:
+        // Note - lOffset is internally stored as Milliseconds
+        ByteOffset  = (ALint)(Source->lOffset / 1000.0 * Buffer->Frequency);
+        ByteOffset *= FrameSizeFromFmt(Buffer->FmtChannels, Buffer->FmtType);
+        break;
+    }
+    // Clear Offset
+    Source->lOffset = 0;
+
+    return ByteOffset;
+}
+
+
+ALvoid ReleaseALSources(ALCcontext *Context)
+{
+    ALsizei pos;
+    ALuint j;
+    for(pos = 0;pos < Context->SourceMap.size;pos++)
+    {
+        ALsource *temp = Context->SourceMap.array[pos].value;
+        Context->SourceMap.array[pos].value = NULL;
+
+        // For each buffer in the source's queue, decrement its reference counter and remove it
+        while(temp->queue != NULL)
+        {
+            ALbufferlistitem *BufferList = temp->queue;
+            temp->queue = BufferList->next;
+
+            if(BufferList->buffer != NULL)
+                BufferList->buffer->refcount--;
+            free(BufferList);
+        }
+
+        for(j = 0;j < MAX_SENDS;++j)
+        {
+            if(temp->Send[j].Slot)
+                temp->Send[j].Slot->refcount--;
+            temp->Send[j].Slot = NULL;
+        }
+
+        // Release source structure
+        ALTHUNK_REMOVEENTRY(temp->source);
+        memset(temp, 0, sizeof(ALsource));
+        free(temp);
+    }
+}
diff --git a/OpenAL32/alState.c b/OpenAL32/alState.c
new file mode 100755 (executable)
index 0000000..953b1a1
--- /dev/null
@@ -0,0 +1,661 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2000 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include "alMain.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+#include "alError.h"
+#include "alSource.h"
+#include "alState.h"
+#include "alDatabuffer.h"
+
+static const ALchar alVendor[] = "OpenAL Community";
+static const ALchar alVersion[] = "1.1 ALSOFT "ALSOFT_VERSION;
+static const ALchar alRenderer[] = "OpenAL Soft";
+
+// Error Messages
+static const ALchar alNoError[] = "No Error";
+static const ALchar alErrInvalidName[] = "Invalid Name";
+static const ALchar alErrInvalidEnum[] = "Invalid Enum";
+static const ALchar alErrInvalidValue[] = "Invalid Value";
+static const ALchar alErrInvalidOp[] = "Invalid Operation";
+static const ALchar alErrOutOfMemory[] = "Out of Memory";
+
+AL_API ALvoid AL_APIENTRY alEnable(ALenum capability)
+{
+    ALCcontext *Context;
+    ALboolean  updateSources = AL_FALSE;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    switch(capability)
+    {
+        case AL_SOURCE_DISTANCE_MODEL:
+            Context->SourceDistanceModel = AL_TRUE;
+            updateSources = AL_TRUE;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+    }
+
+    if(updateSources)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < Context->SourceMap.size;pos++)
+        {
+            ALsource *source = Context->SourceMap.array[pos].value;
+            source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDisable(ALenum capability)
+{
+    ALCcontext *Context;
+    ALboolean  updateSources = AL_FALSE;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    switch(capability)
+    {
+        case AL_SOURCE_DISTANCE_MODEL:
+            Context->SourceDistanceModel = AL_FALSE;
+            updateSources = AL_TRUE;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+    }
+
+    if(updateSources)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < Context->SourceMap.size;pos++)
+        {
+            ALsource *source = Context->SourceMap.array[pos].value;
+            source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
+{
+    ALCcontext *Context;
+    ALboolean value=AL_FALSE;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_FALSE;
+
+    switch(capability)
+    {
+        case AL_SOURCE_DISTANCE_MODEL:
+            value = Context->SourceDistanceModel;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+    }
+
+    ProcessContext(Context);
+
+    return value;
+}
+
+AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
+{
+    ALCcontext *Context;
+    ALboolean value=AL_FALSE;
+
+    Context = GetContextSuspended();
+    if(!Context) return AL_FALSE;
+
+    switch(pname)
+    {
+        case AL_DOPPLER_FACTOR:
+            if(Context->DopplerFactor != 0.0f)
+                value = AL_TRUE;
+            break;
+
+        case AL_DOPPLER_VELOCITY:
+            if(Context->DopplerVelocity != 0.0f)
+                value = AL_TRUE;
+            break;
+
+        case AL_DISTANCE_MODEL:
+            if(Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED)
+                value = AL_TRUE;
+            break;
+
+        case AL_SPEED_OF_SOUND:
+            if(Context->flSpeedOfSound != 0.0f)
+                value = AL_TRUE;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+    }
+
+    ProcessContext(Context);
+
+    return value;
+}
+
+AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
+{
+    ALCcontext *Context;
+    ALdouble value = 0.0;
+
+    Context = GetContextSuspended();
+    if(!Context) return 0.0;
+
+    switch(pname)
+    {
+        case AL_DOPPLER_FACTOR:
+            value = (double)Context->DopplerFactor;
+            break;
+
+        case AL_DOPPLER_VELOCITY:
+            value = (double)Context->DopplerVelocity;
+            break;
+
+        case AL_DISTANCE_MODEL:
+            value = (double)Context->DistanceModel;
+            break;
+
+        case AL_SPEED_OF_SOUND:
+            value = (double)Context->flSpeedOfSound;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+    }
+
+    ProcessContext(Context);
+
+    return value;
+}
+
+AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
+{
+    ALCcontext *Context;
+    ALfloat value = 0.0f;
+
+    Context = GetContextSuspended();
+    if(!Context) return 0.0f;
+
+    switch(pname)
+    {
+        case AL_DOPPLER_FACTOR:
+            value = Context->DopplerFactor;
+            break;
+
+        case AL_DOPPLER_VELOCITY:
+            value = Context->DopplerVelocity;
+            break;
+
+        case AL_DISTANCE_MODEL:
+            value = (float)Context->DistanceModel;
+            break;
+
+        case AL_SPEED_OF_SOUND:
+            value = Context->flSpeedOfSound;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+    }
+
+    ProcessContext(Context);
+
+    return value;
+}
+
+AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
+{
+    ALCcontext *Context;
+    ALint value = 0;
+
+    Context = GetContextSuspended();
+    if(!Context) return 0;
+
+    switch(pname)
+    {
+        case AL_DOPPLER_FACTOR:
+            value = (ALint)Context->DopplerFactor;
+            break;
+
+        case AL_DOPPLER_VELOCITY:
+            value = (ALint)Context->DopplerVelocity;
+            break;
+
+        case AL_DISTANCE_MODEL:
+            value = (ALint)Context->DistanceModel;
+            break;
+
+        case AL_SPEED_OF_SOUND:
+            value = (ALint)Context->flSpeedOfSound;
+            break;
+
+        case AL_SAMPLE_SOURCE_EXT:
+            if(Context->SampleSource)
+                value = (ALint)Context->SampleSource->databuffer;
+            else
+                value = 0;
+            break;
+
+        case AL_SAMPLE_SINK_EXT:
+            if(Context->SampleSink)
+                value = (ALint)Context->SampleSink->databuffer;
+            else
+                value = 0;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_ENUM);
+            break;
+    }
+
+    ProcessContext(Context);
+
+    return value;
+}
+
+AL_API ALvoid AL_APIENTRY alGetBooleanv(ALenum pname,ALboolean *data)
+{
+    ALCcontext *Context;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(data)
+    {
+        switch(pname)
+        {
+            case AL_DOPPLER_FACTOR:
+                *data = (ALboolean)((Context->DopplerFactor != 0.0f) ? AL_TRUE : AL_FALSE);
+                break;
+
+            case AL_DOPPLER_VELOCITY:
+                *data = (ALboolean)((Context->DopplerVelocity != 0.0f) ? AL_TRUE : AL_FALSE);
+                break;
+
+            case AL_DISTANCE_MODEL:
+                *data = (ALboolean)((Context->DistanceModel == AL_INVERSE_DISTANCE_CLAMPED) ? AL_TRUE : AL_FALSE);
+                break;
+
+            case AL_SPEED_OF_SOUND:
+                *data = (ALboolean)((Context->flSpeedOfSound != 0.0f) ? AL_TRUE : AL_FALSE);
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+    {
+        // data is a NULL pointer
+        alSetError(Context, AL_INVALID_VALUE);
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname,ALdouble *data)
+{
+    ALCcontext *Context;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(data)
+    {
+        switch(pname)
+        {
+            case AL_DOPPLER_FACTOR:
+                *data = (double)Context->DopplerFactor;
+                break;
+
+            case AL_DOPPLER_VELOCITY:
+                *data = (double)Context->DopplerVelocity;
+                break;
+
+            case AL_DISTANCE_MODEL:
+                *data = (double)Context->DistanceModel;
+                break;
+
+            case AL_SPEED_OF_SOUND:
+                *data = (double)Context->flSpeedOfSound;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+    {
+        // data is a NULL pointer
+        alSetError(Context, AL_INVALID_VALUE);
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname,ALfloat *data)
+{
+    ALCcontext *Context;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(data)
+    {
+        switch(pname)
+        {
+            case AL_DOPPLER_FACTOR:
+                *data = Context->DopplerFactor;
+                break;
+
+            case AL_DOPPLER_VELOCITY:
+                *data = Context->DopplerVelocity;
+                break;
+
+            case AL_DISTANCE_MODEL:
+                *data = (float)Context->DistanceModel;
+                break;
+
+            case AL_SPEED_OF_SOUND:
+                *data = Context->flSpeedOfSound;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+    {
+        // data is a NULL pointer
+        alSetError(Context, AL_INVALID_VALUE);
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname,ALint *data)
+{
+    ALCcontext *Context;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(data)
+    {
+        switch(pname)
+        {
+            case AL_DOPPLER_FACTOR:
+                *data = (ALint)Context->DopplerFactor;
+                break;
+
+            case AL_DOPPLER_VELOCITY:
+                *data = (ALint)Context->DopplerVelocity;
+                break;
+
+            case AL_DISTANCE_MODEL:
+                *data = (ALint)Context->DistanceModel;
+                break;
+
+            case AL_SPEED_OF_SOUND:
+                *data = (ALint)Context->flSpeedOfSound;
+                break;
+
+            case AL_SAMPLE_SOURCE_EXT:
+                if(Context->SampleSource)
+                    *data = (ALint)Context->SampleSource->databuffer;
+                else
+                    *data = 0;
+                break;
+
+            case AL_SAMPLE_SINK_EXT:
+                if(Context->SampleSink)
+                    *data = (ALint)Context->SampleSink->databuffer;
+                else
+                    *data = 0;
+                break;
+
+            default:
+                alSetError(Context, AL_INVALID_ENUM);
+                break;
+        }
+    }
+    else
+    {
+        // data is a NULL pointer
+        alSetError(Context, AL_INVALID_VALUE);
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
+{
+    const ALchar *value;
+    ALCcontext *pContext;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return NULL;
+
+    switch(pname)
+    {
+        case AL_VENDOR:
+            value=alVendor;
+            break;
+
+        case AL_VERSION:
+            value=alVersion;
+            break;
+
+        case AL_RENDERER:
+            value=alRenderer;
+            break;
+
+        case AL_EXTENSIONS:
+            value=pContext->ExtensionList;//alExtensions;
+            break;
+
+        case AL_NO_ERROR:
+            value=alNoError;
+            break;
+
+        case AL_INVALID_NAME:
+            value=alErrInvalidName;
+            break;
+
+        case AL_INVALID_ENUM:
+            value=alErrInvalidEnum;
+            break;
+
+        case AL_INVALID_VALUE:
+            value=alErrInvalidValue;
+            break;
+
+        case AL_INVALID_OPERATION:
+            value=alErrInvalidOp;
+            break;
+
+        case AL_OUT_OF_MEMORY:
+            value=alErrOutOfMemory;
+            break;
+
+        default:
+            value=NULL;
+            alSetError(pContext, AL_INVALID_ENUM);
+            break;
+    }
+
+    ProcessContext(pContext);
+
+    return value;
+}
+
+AL_API ALvoid AL_APIENTRY alDopplerFactor(ALfloat value)
+{
+    ALCcontext *Context;
+    ALboolean updateSources = AL_FALSE;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(value >= 0.0f)
+    {
+        Context->DopplerFactor = value;
+        updateSources = AL_TRUE;
+    }
+    else
+        alSetError(Context, AL_INVALID_VALUE);
+
+    // Force updating the sources for these parameters, since even head-
+    // relative sources are affected
+    if(updateSources)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < Context->SourceMap.size;pos++)
+        {
+            ALsource *source = Context->SourceMap.array[pos].value;
+            source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alDopplerVelocity(ALfloat value)
+{
+    ALCcontext *Context;
+    ALboolean updateSources = AL_FALSE;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    if(value > 0.0f)
+    {
+        Context->DopplerVelocity=value;
+        updateSources = AL_TRUE;
+    }
+    else
+        alSetError(Context, AL_INVALID_VALUE);
+
+    if(updateSources)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < Context->SourceMap.size;pos++)
+        {
+            ALsource *source = Context->SourceMap.array[pos].value;
+            source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(Context);
+}
+
+AL_API ALvoid AL_APIENTRY alSpeedOfSound(ALfloat flSpeedOfSound)
+{
+    ALCcontext *pContext;
+    ALboolean updateSources = AL_FALSE;
+
+    pContext = GetContextSuspended();
+    if(!pContext) return;
+
+    if(flSpeedOfSound > 0.0f)
+    {
+        pContext->flSpeedOfSound = flSpeedOfSound;
+        updateSources = AL_TRUE;
+    }
+    else
+        alSetError(pContext, AL_INVALID_VALUE);
+
+    if(updateSources)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < pContext->SourceMap.size;pos++)
+        {
+            ALsource *source = pContext->SourceMap.array[pos].value;
+            source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(pContext);
+}
+
+AL_API ALvoid AL_APIENTRY alDistanceModel(ALenum value)
+{
+    ALCcontext *Context;
+    ALboolean updateSources = AL_FALSE;
+
+    Context = GetContextSuspended();
+    if(!Context) return;
+
+    switch(value)
+    {
+        case AL_NONE:
+        case AL_INVERSE_DISTANCE:
+        case AL_INVERSE_DISTANCE_CLAMPED:
+        case AL_LINEAR_DISTANCE:
+        case AL_LINEAR_DISTANCE_CLAMPED:
+        case AL_EXPONENT_DISTANCE:
+        case AL_EXPONENT_DISTANCE_CLAMPED:
+            Context->DistanceModel = value;
+            updateSources = !Context->SourceDistanceModel;
+            break;
+
+        default:
+            alSetError(Context, AL_INVALID_VALUE);
+            break;
+    }
+
+    if(updateSources)
+    {
+        ALsizei pos;
+        for(pos = 0;pos < Context->SourceMap.size;pos++)
+        {
+            ALsource *source = Context->SourceMap.array[pos].value;
+            source->NeedsUpdate = AL_TRUE;
+        }
+    }
+
+    ProcessContext(Context);
+}
diff --git a/OpenAL32/alThunk.c b/OpenAL32/alThunk.c
new file mode 100644 (file)
index 0000000..08b80b0
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 1999-2007 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "alMain.h"
+#include "alThunk.h"
+
+typedef struct {
+    ALvoid *ptr;
+    ALboolean InUse;
+} ThunkEntry;
+
+static ThunkEntry *g_ThunkArray;
+static ALuint      g_ThunkArraySize;
+
+static CRITICAL_SECTION g_ThunkLock;
+
+void alThunkInit(void)
+{
+    InitializeCriticalSection(&g_ThunkLock);
+    g_ThunkArraySize = 1;
+    g_ThunkArray = calloc(1, g_ThunkArraySize * sizeof(ThunkEntry));
+}
+
+void alThunkExit(void)
+{
+    free(g_ThunkArray);
+    g_ThunkArray = NULL;
+    g_ThunkArraySize = 0;
+    DeleteCriticalSection(&g_ThunkLock);
+}
+
+ALuint alThunkAddEntry(ALvoid *ptr)
+{
+    ALuint index;
+
+    EnterCriticalSection(&g_ThunkLock);
+
+    for(index = 0;index < g_ThunkArraySize;index++)
+    {
+        if(g_ThunkArray[index].InUse == AL_FALSE)
+            break;
+    }
+
+    if(index == g_ThunkArraySize)
+    {
+        ThunkEntry *NewList;
+
+        NewList = realloc(g_ThunkArray, g_ThunkArraySize*2 * sizeof(ThunkEntry));
+        if(!NewList)
+        {
+            LeaveCriticalSection(&g_ThunkLock);
+            AL_PRINT("Realloc failed to increase to %u enties!\n", g_ThunkArraySize*2);
+            return 0;
+        }
+        memset(&NewList[g_ThunkArraySize], 0, g_ThunkArraySize*sizeof(ThunkEntry));
+        g_ThunkArraySize *= 2;
+        g_ThunkArray = NewList;
+    }
+
+    g_ThunkArray[index].ptr = ptr;
+    g_ThunkArray[index].InUse = AL_TRUE;
+
+    LeaveCriticalSection(&g_ThunkLock);
+
+    return index+1;
+}
+
+void alThunkRemoveEntry(ALuint index)
+{
+    EnterCriticalSection(&g_ThunkLock);
+
+    if(index > 0 && index <= g_ThunkArraySize)
+        g_ThunkArray[index-1].InUse = AL_FALSE;
+
+    LeaveCriticalSection(&g_ThunkLock);
+}
+
+ALvoid *alThunkLookupEntry(ALuint index)
+{
+    ALvoid *ptr = NULL;
+
+    EnterCriticalSection(&g_ThunkLock);
+
+    if(index > 0 && index <= g_ThunkArraySize)
+        ptr = g_ThunkArray[index-1].ptr;
+
+    LeaveCriticalSection(&g_ThunkLock);
+
+    return ptr;
+}
diff --git a/README b/README
new file mode 100755 (executable)
index 0000000..ebca8f9
--- /dev/null
+++ b/README
@@ -0,0 +1,53 @@
+Source Install
+==============
+
+To install OpenAL Soft, use your favorite shell to go into the build/
+directory, and run:
+
+cmake ..
+
+Assuming configuration went well, you can then build it, typically using GNU
+Make (KDevelop, MSVC, and others are possible depending on your system setup
+and CMake configuration).
+
+Please Note: Double check that the appropriate backends were detected. Often,
+complaints of no sound, crashing, and missing devices can be solved by making
+sure the correct backends are being used. CMake's output will identify which
+backends were enabled.
+
+For most systems, you will likely want to make sure ALSA, OSS, and PulseAudio
+were detected (if your target system uses them). For Windows, make sure
+DirectSound was detected.
+
+
+Utilities
+=========
+
+The source package comes with an informational utility, openal-info, and is
+built by default. It prints out information provided by the ALC and AL sub-
+systems, including discovered devices, version information, and extensions.
+
+
+Configuration
+=============
+
+OpenAL Soft can be configured on a per-user and per-system basis. This allows
+users and sysadmins to control information provided to applications, as well
+as application-agnostic behavior of the library. See alsoftrc.sample for
+available settings.
+
+
+Acknowledgements
+================
+
+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.
+
+Christian Borss for the 3D panning code the current implementation is heavilly
+based on.
+
+Ben Davis for the idea behind the current click-removal code.
diff --git a/XCompile.txt b/XCompile.txt
new file mode 100644 (file)
index 0000000..9826d17
--- /dev/null
@@ -0,0 +1,23 @@
+# Cross-compiling requires CMake 2.6 or newer. To cross-compile, first modify
+# this file to set the proper settings and paths. Then use it from build/ like:
+# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt \
+#          -DCMAKE_INSTALL_PREFIX=/usr/mingw32/mingw
+# If you already have a toolchain file setup, you may use that instead of this
+# file.
+
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Windows)
+
+# which compilers to use for C and C++
+SET(CMAKE_C_COMPILER mingw32-gcc)
+SET(CMAKE_CXX_COMPILER mingw32-g++)
+
+# here is the target environment located
+SET(CMAKE_FIND_ROOT_PATH /usr/mingw32/mingw)
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search 
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/alsoftrc.sample b/alsoftrc.sample
new file mode 100755 (executable)
index 0000000..74220e8
--- /dev/null
@@ -0,0 +1,260 @@
+# OpenAL config file. Options that are not under a block or are under the
+# [general] block are for general, non-backend-specific options. Blocks may
+# appear multiple times, and duplicated options will take the last value
+# specified.
+# The system-wide settings can be put in /etc/openal/alsoft.conf and user-
+# specific override settings in ~/.alsoftrc.
+# For Windows, these settings should go into %AppData%\alsoft.ini
+# The environment variable ALSOFT_CONF can be used to specify another config
+# override
+
+# Option and block names are case-insenstive. The supplied values are only
+# hints and may not be honored (though generally it'll try to get as close as
+# possible). Note: options that are left unset may default to app- or system-
+# specified values. These are the current available settings:
+
+## format:
+#  Sets the output format. Can be one of:
+#  AL_FORMAT_MONO8    (8-bit mono)
+#  AL_FORMAT_STEREO8  (8-bit stereo)
+#  AL_FORMAT_QUAD8    (8-bit 4-channel)
+#  AL_FORMAT_51CHN8   (8-bit 5.1 output)
+#  AL_FORMAT_61CHN8   (8-bit 6.1 output)
+#  AL_FORMAT_71CHN8   (8-bit 7.1 output)
+#  AL_FORMAT_MONO16   (16-bit mono)
+#  AL_FORMAT_STEREO16 (16-bit stereo)
+#  AL_FORMAT_QUAD16   (16-bit 4-channel)
+#  AL_FORMAT_51CHN16  (16-bit 5.1 output)
+#  AL_FORMAT_61CHN16  (16-bit 6.1 output)
+#  AL_FORMAT_71CHN16  (16-bit 7.1 output)
+#  AL_FORMAT_MONO32   (32-bit float mono)
+#  AL_FORMAT_STEREO32 (32-bit float stereo)
+#  AL_FORMAT_QUAD32   (32-bit float 4-channel)
+#  AL_FORMAT_51CHN32  (32-bit float 5.1 output)
+#  AL_FORMAT_61CHN32  (32-bit float 6.1 output)
+#  AL_FORMAT_71CHN32  (32-bit float 7.1 output)
+#format = AL_FORMAT_STEREO16
+
+## cf_level:
+#  Sets the crossfeed level for stereo output. Valid values are:
+#  0 - No crossfeed
+#  1 - Low crossfeed
+#  2 - Middle crossfeed
+#  3 - High crossfeed (virtual speakers are closer to itself)
+#  4 - Low easy crossfeed
+#  5 - Middle easy crossfeed
+#  6 - High easy crossfeed
+#  Users of headphones may want to try various settings. Has no effect on non-
+#  stereo modes.
+#cf_level = 0
+
+## head_dampen:
+#  Sets the amount of dampening on sounds emanating from behind the listener.
+#  This is used to simulate the natural occlusion of the head, which is
+#  typically missing with mono and stereo output, and as such, only works on
+#  mono and stereo output modes. Valid values range from 0 to 1 (inclusive),
+#  and higher values provide a stronger effect.
+#head_dampen = 0.25
+
+## frequency:
+#  Sets the output frequency.
+#frequency = 44100
+
+## resampler:
+#  Selects the resampler used when mixing sources. Valid values are:
+#  0 - None (nearest sample, no interpolation)
+#  1 - Linear (extrapolates samples using a linear slope between samples)
+#  2 - Cubic (extrapolates samples using a Catmull-Rom spline)
+#  Specifying other values will result in using the default (linear).
+#resampler = 1
+resampler = 0
+
+## rt-prio:
+#  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
+#  security risk since a real-time priority thread can indefinitely block
+#  normal-priority threads if it fails to wait. As such, the default is
+#  disabled.
+#rt-prio = 0
+
+## period_size:
+#  Sets the update period size, in frames. This is the number of frames needed
+#  for each mixing update.
+#period_size = 1024
+period_size = 2048
+
+## 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.
+#periods = 4
+periods = 8
+
+## 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
+sources = 32
+
+## stereodup:
+#  Sets whether to duplicate stereo sounds on the rear and side speakers for 4+
+#  channel output. This provides a "fuller" playback quality for 4+ channel
+#  output modes, although each individual speaker will have a slight reduction
+#  in volume to compensate for the extra output speakers. True, yes, on, and
+#  non-0 values will duplicate stereo sources. 0 and anything else will cause
+#  stereo sounds to only play out the front speakers. This only has an effect
+#  when a suitable output format is used (ie. those that contain side and/or
+#  rear speakers).
+#stereodup = true
+
+## scalemix:
+#  Sets whether to scale the remixed output. When the final mix is written to
+#  the device, the multi-channel data is remixed so pure-virtual channels (eg.
+#  front-center on stereo output) are remixed and added to available channels
+#  (eg. front-left and front-right). Scaling helps ensure that no single source
+#  will put out more than 100% on a given physical channel. This can cause a
+#  noticeable reduction in overall volume, however, so it is off by default.
+#scalemix = false
+
+## drivers:
+#  Sets the backend driver list order, comma-seperated. Unknown backends and
+#  duplicated names are ignored. Unlisted backends won't be considered for use
+#  unless the list is ended with a comma (eg. 'oss,' will list OSS first
+#  followed by all other available backends, while 'oss' will list OSS only).
+#  An empty list means the default.
+#drivers = pulse,alsa,oss,solaris,dsound,winmm,port,wave
+drivers = avsystem
+
+## 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,echo
+#excludefx =
+excludefx = eaxreverb,reverb,echo
+
+## 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
+#  if no sources are feeding it, so this may help when apps use more than the
+#  system can handle.
+#slots = 4
+
+## sends:
+#  Sets the number of auxiliary sends per source. When not specified (default),
+#  it allows the app to request how many it wants. The maximum value currently
+#  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_51CHN  = fl=-30, fr=30, fc=0, bl=-110, br=110
+#layout_61CHN  = fl=-30, fr=30, fc=0, sl=-90, sr=90, bc=180
+#layout_71CHN  = fl=-30, fr=30, fc=0, sl=-90, sr=90, bl=-150, br=150
+
+##
+## ALSA backend stuff
+##
+[alsa]
+
+## device:
+#  Sets the device name for the default playback device.
+#device = default
+
+## capture:
+#  Sets the device name for the default capture device.
+#capture = default
+
+## mmap:
+#  Sets whether to try using mmap mode (helps reduce latencies and CPU
+#  consumption). If mmap isn't available, it will automatically fall back to
+#  non-mmap mode. True, yes, on, and non-0 values will attempt to use mmap. 0
+#  and anything else will force mmap off.
+#mmap = true
+
+##
+## OSS backend stuff
+##
+[oss]
+
+## device:
+#  Sets the device name for OSS output.
+#device = /dev/dsp
+
+## capture:
+#  Sets the device name for OSS capture.
+#capture = /dev/dsp
+
+##
+## Solaris backend stuff
+##
+[solaris]
+
+## device:
+#  Sets the device name for Solaris output.
+#device = /dev/audio
+
+##
+## DirectSound backend stuff
+##
+[dsound]
+
+##
+## Windows Multimedia backend stuff
+##
+[winmm]
+
+##
+## PortAudio backend stuff
+##
+[port]
+
+## device:
+#  Sets the device index for output. Negative values will use the default as
+#  given by PortAudio itself.
+#device = -1
+
+## capture:
+#  Sets the device index for capture. Negative values will use the default as
+#  given by PortAudio itself.
+#capture = -1
+
+##
+## PulseAudio backend stuff
+##
+[pulse]
+
+## spawn-server:
+#  Attempts to spawn a PulseAudio server when requesting to open a PulseAudio
+#  device. Note that some apps may open and probe all enumerated devices on
+#  startup, causing a server to spawn even if a PulseAudio device is not
+#  actually selected. Setting autospawn to false in Pulse's client.conf will
+#  still prevent autospawning even if this is set to true.
+#spawn-server = false
+
+##
+## Wave File Writer stuff
+##
+[wave]
+
+## file:
+#  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 =
+
+[avsystem]
+device = avsystem_playback
diff --git a/build/.empty b/build/.empty
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/cmake/CheckCCompilerFlag.cmake b/cmake/CheckCCompilerFlag.cmake
new file mode 100755 (executable)
index 0000000..8b2361a
--- /dev/null
@@ -0,0 +1,59 @@
+# - Check if the C source code provided in the SOURCE argument compiles.
+# CHECK_C_SOURCE_COMPILES(SOURCE VAR)
+#
+#  FLAG   - compiler flag to check
+#  VAR    - variable to store whether the source code compiled
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+#  CMAKE_REQUIRED_FLAGS = string of compile command line flags
+#  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+#  CMAKE_REQUIRED_INCLUDES = list of include directories
+#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+MACRO(CHECK_C_COMPILER_FLAG FLAG VAR)
+  IF("${VAR}" MATCHES "^${VAR}$")
+    SET(MACRO_CHECK_FUNCTION_DEFINITIONS
+      "${FLAG} ${CMAKE_REQUIRED_FLAGS}")
+    IF(CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_C_COMPILER_FLAG_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+    ELSE(CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_C_COMPILER_FLAG_ADD_LIBRARIES)
+    ENDIF(CMAKE_REQUIRED_LIBRARIES)
+    IF(CMAKE_REQUIRED_INCLUDES)
+      SET(CHECK_C_COMPILER_FLAG_ADD_INCLUDES
+        "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+    ELSE(CMAKE_REQUIRED_INCLUDES)
+      SET(CHECK_C_COMPILER_FLAG_ADD_INCLUDES)
+    ENDIF(CMAKE_REQUIRED_INCLUDES)
+    FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
+      "int main() {return 0;}\n")
+
+    MESSAGE(STATUS "Checking if C compiler supports ${FLAG}")
+    TRY_COMPILE(${VAR}
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+      "${CHECK_C_COMPILER_FLAG_ADD_LIBRARIES}"
+      "${CHECK_C_COMPILER_FLAG_ADD_INCLUDES}"
+      OUTPUT_VARIABLE OUTPUT)
+    IF(${VAR})
+      SET(${VAR} 1 CACHE INTERNAL "Test ${VAR}")
+      MESSAGE(STATUS "Checking if C compiler supports ${FLAG} - Success")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "Performing C SOURCE FILE Test ${VAR} succeded with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${SOURCE}\n")
+    ELSE(${VAR})
+      MESSAGE(STATUS "Checking if C compiler supports ${FLAG} - Failed")
+      SET(${VAR} "" CACHE INTERNAL "Test ${VAR}")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+        "Performing C SOURCE FILE Test ${VAR} failed with the following output:\n"
+        "${OUTPUT}\n"
+        "Source file was:\n${SOURCE}\n")
+    ENDIF(${VAR})
+  ENDIF("${VAR}" MATCHES "^${VAR}$")
+ENDMACRO(CHECK_C_COMPILER_FLAG)
diff --git a/cmake/CheckSharedFunctionExists.c b/cmake/CheckSharedFunctionExists.c
new file mode 100755 (executable)
index 0000000..31e3fa9
--- /dev/null
@@ -0,0 +1,38 @@
+#ifdef CHECK_SHARED_FUNCTION_EXISTS
+
+#include <stdlib.h>
+
+#ifndef CALLSTACK
+#define CALLSTACK
+#endif
+
+#ifdef _WIN32
+#ifdef ARGSTACK
+char __stdcall CHECK_SHARED_FUNCTION_EXISTS(ARGSTACK);
+#else
+char __stdcall CHECK_SHARED_FUNCTION_EXISTS(void);
+#endif
+#else
+char CHECK_SHARED_FUNCTION_EXISTS();
+#endif
+
+#ifdef __CLASSIC_C__
+int main(){
+  int ac;
+  char*av[];
+#else
+int main(int ac, char*av[]){
+#endif
+  CHECK_SHARED_FUNCTION_EXISTS(CALLSTACK);
+  if(ac > 1000)
+    {
+    return *av[0];
+    }
+  return 0;
+}
+
+#else  /* CHECK_SHARED_FUNCTION_EXISTS */
+
+#  error "CHECK_SHARED_FUNCTION_EXISTS has to specify the function"
+
+#endif /* CHECK_SHARED_FUNCTION_EXISTS */
diff --git a/cmake/CheckSharedLibraryExists.cmake b/cmake/CheckSharedLibraryExists.cmake
new file mode 100755 (executable)
index 0000000..0069d89
--- /dev/null
@@ -0,0 +1,70 @@
+# - Check if the function exists.
+# CHECK_LIBRARY_EXISTS (LIBRARY FUNCTION LOCATION VARIABLE)
+#
+#  LIBRARY  - the name of the library you are looking for
+#  FUNCTION - the name of the function
+#  ARGCOUNT - number of arguments for stdcall functions
+#  LOCATION - location where the library should be found
+#  VARIABLE - variable to store the result
+#
+# The following variables may be set before calling this macro to
+# modify the way the check is run:
+#
+#  CMAKE_REQUIRED_FLAGS = string of compile command line flags
+#  CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
+#  CMAKE_REQUIRED_LIBRARIES = list of libraries to link
+
+MACRO(CHECK_SHARED_LIBRARY_EXISTS LIBRARY FUNCTION ARGCOUNT LOCATION VARIABLE)
+  IF("${VARIABLE}" MATCHES "^${VARIABLE}$")
+    SET(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION 
+      "-DCHECK_SHARED_FUNCTION_EXISTS=${FUNCTION} ${CMAKE_REQUIRED_FLAGS}")
+    IF(WIN32)
+        IF(${ARGCOUNT} GREATER 0)
+            SET(ARGSTACK "void*")
+            SET(CALLSTACK "NULL")
+            SET(CURARG 1)
+            WHILE(${ARGCOUNT} GREATER ${CURARG})
+                SET(ARGSTACK "${ARGSTACK},void*")
+                SET(CALLSTACK "${CALLSTACK},NULL")
+                MATH(EXPR CURARG "${CURARG} + 1")
+            ENDWHILE(${ARGCOUNT} GREATER ${CURARG})
+            SET(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION
+                "-D_WIN32 -DARGSTACK=\"${ARGSTACK}\" -DCALLSTACK=\"${CALLSTACK}\" ${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}")
+        ELSE(${ARGCOUNT} GREATER 0)
+            SET(MACRO_CHECK_LIBRARY_EXISTS_DEFINITION
+                "-D_WIN32 ${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}")
+        ENDIF(${ARGCOUNT} GREATER 0)
+    ENDIF(WIN32)
+    MESSAGE(STATUS "Looking for ${FUNCTION} in ${LIBRARY}")
+    SET(CHECK_LIBRARY_EXISTS_LIBRARIES ${LIBRARY})
+    IF(CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_LIBRARY_EXISTS_LIBRARIES 
+        ${CHECK_LIBRARY_EXISTS_LIBRARIES} ${CMAKE_REQUIRED_LIBRARIES})
+    ENDIF(CMAKE_REQUIRED_LIBRARIES)
+    TRY_COMPILE(${VARIABLE}
+      ${CMAKE_BINARY_DIR}
+      ${CMAKE_SOURCE_DIR}/cmake/CheckSharedFunctionExists.c
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      CMAKE_FLAGS 
+      -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_LIBRARY_EXISTS_DEFINITION}
+      -DLINK_DIRECTORIES:STRING=${LOCATION}
+      "-DLINK_LIBRARIES:STRING=${CHECK_LIBRARY_EXISTS_LIBRARIES}"
+      OUTPUT_VARIABLE OUTPUT)
+
+    IF(${VARIABLE})
+      MESSAGE(STATUS "Looking for ${FUNCTION} in ${LIBRARY} - found")
+      SET(${VARIABLE} 1 CACHE INTERNAL "Have library ${LIBRARY}")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log 
+        "Determining if the function ${FUNCTION} exists in the ${LIBRARY} "
+        "passed with the following output:\n"
+        "${OUTPUT}\n\n")
+    ELSE(${VARIABLE})
+      MESSAGE(STATUS "Looking for ${FUNCTION} in ${LIBRARY} - not found")
+      SET(${VARIABLE} "" CACHE INTERNAL "Have library ${LIBRARY}")
+      FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log 
+        "Determining if the function ${FUNCTION} exists in the ${LIBRARY} "
+        "failed with the following output:\n"
+        "${OUTPUT}\n\n")
+    ENDIF(${VARIABLE})
+  ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")
+ENDMACRO(CHECK_SHARED_LIBRARY_EXISTS)
diff --git a/config.h.in b/config.h.in
new file mode 100755 (executable)
index 0000000..06a7e47
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Define to the library version */
+#define ALSOFT_VERSION "${LIB_VERSION}"
+
+/* Define if we have the ALSA backend */
+#cmakedefine HAVE_ALSA
+
+/* Define if we have the OSS backend */
+#cmakedefine HAVE_OSS
+
+/* Define if we have the Solaris backend */
+#cmakedefine HAVE_SOLARIS
+
+/* Define if we have the DSound backend */
+#cmakedefine HAVE_DSOUND
+
+/* Define if we have the Windows Multimedia backend */
+#cmakedefine HAVE_WINMM
+
+/* Define if we have the PortAudio backend */
+#cmakedefine HAVE_PORTAUDIO
+
+/* Define if we have the PulseAudio backend */
+#cmakedefine HAVE_PULSEAUDIO
+
+/* Define if we have the Wave Writer backend */
+#cmakedefine HAVE_WAVE
+
+/* Define if we have the AVSYSTEM backend */
+#cmakedefine HAVE_AVSYSTEM
+
+/* Define if we have dlfcn.h */
+#cmakedefine HAVE_DLFCN_H
+
+/* Define if we have the stat function */
+#cmakedefine HAVE_STAT
+
+/* Define if we have the powf function */
+#cmakedefine HAVE_POWF
+
+/* Define if we have the sqrtf function */
+#cmakedefine HAVE_SQRTF
+
+/* Define if we have the acosf function */
+#cmakedefine HAVE_ACOSF
+
+/* Define if we have the atanf function */
+#cmakedefine HAVE_ATANF
+
+/* Define if we have the fabsf function */
+#cmakedefine HAVE_FABSF
+
+/* Define if we have the strtof function */
+#cmakedefine HAVE_STRTOF
+
+/* Define if we have stdint.h */
+#cmakedefine HAVE_STDINT_H
+
+/* Define if we have the __int64 type */
+#cmakedefine HAVE___INT64
+
+/* Define to the size of a long int type */
+#cmakedefine SIZEOF_LONG ${SIZEOF_LONG}
+
+/* Define to the size of a long long int type */
+#cmakedefine SIZEOF_LONG_LONG ${SIZEOF_LONG_LONG}
+
+/* Define to the size of an unsigned int type */
+#cmakedefine SIZEOF_UINT ${SIZEOF_UINT}
+
+/* Define to the size of a void pointer type */
+#cmakedefine SIZEOF_VOIDP ${SIZEOF_VOIDP}
+
+/* Define if we have GCC's destructor attribute */
+#cmakedefine HAVE_GCC_DESTRUCTOR
+
+/* Define if we have GCC's format attribute */
+#cmakedefine HAVE_GCC_FORMAT
+
+/* Define if we have pthread_np.h */
+#cmakedefine HAVE_PTHREAD_NP_H
+
+/* Define if we have float.h */
+#cmakedefine HAVE_FLOAT_H
+
+/* Define if we have fenv.h */
+#cmakedefine HAVE_FENV_H
+
+/* Define if we have fesetround() */
+#cmakedefine HAVE_FESETROUND
+
+/* Define if we have _controlfp() */
+#cmakedefine HAVE__CONTROLFP
+
+/* Define if we have pthread_setschedparam() */
+#cmakedefine HAVE_PTHREAD_SETSCHEDPARAM
+
+#endif
diff --git a/include/AL/al.h b/include/AL/al.h
new file mode 100644 (file)
index 0000000..44db779
--- /dev/null
@@ -0,0 +1,724 @@
+#ifndef AL_AL_H
+#define AL_AL_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(AL_LIBTYPE_STATIC)
+ #define AL_API
+#elif defined(_WIN32) && !defined(_XBOX)
+ #if defined(AL_BUILD_LIBRARY)
+  #define AL_API __declspec(dllexport)
+ #else
+  #define AL_API __declspec(dllimport)
+ #endif
+#else
+ #if defined(AL_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY)
+  #define AL_API __attribute__((visibility("protected")))
+ #else
+  #define AL_API extern
+ #endif
+#endif
+
+#if defined(_WIN32)
+ #define AL_APIENTRY __cdecl
+#else
+ #define AL_APIENTRY
+#endif
+
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
+ #pragma export on
+#endif
+
+/*
+ * The OPENAL, ALAPI, ALAPIENTRY, AL_INVALID, AL_ILLEGAL_ENUM, and
+ * AL_ILLEGAL_COMMAND macros are deprecated, but are included for
+ * applications porting code from AL 1.0
+ */
+#define OPENAL
+#define ALAPI AL_API
+#define ALAPIENTRY AL_APIENTRY
+#define AL_INVALID                                (-1)
+#define AL_ILLEGAL_ENUM                           AL_INVALID_ENUM
+#define AL_ILLEGAL_COMMAND                        AL_INVALID_OPERATION
+
+#define AL_VERSION_1_0
+#define AL_VERSION_1_1
+
+
+/** 8-bit boolean */
+typedef char ALboolean;
+
+/** character */
+typedef char ALchar;
+
+/** signed 8-bit 2's complement integer */
+typedef signed char ALbyte;
+
+/** unsigned 8-bit integer */
+typedef unsigned char ALubyte;
+
+/** signed 16-bit 2's complement integer */
+typedef short ALshort;
+
+/** unsigned 16-bit integer */
+typedef unsigned short ALushort;
+
+/** signed 32-bit 2's complement integer */
+typedef int ALint;
+
+/** unsigned 32-bit integer */
+typedef unsigned int ALuint;
+
+/** non-negative 32-bit binary integer size */
+typedef int ALsizei;
+
+/** enumerated 32-bit value */
+typedef int ALenum;
+
+/** 32-bit IEEE754 floating-point */
+typedef float ALfloat;
+
+/** 64-bit IEEE754 floating-point */
+typedef double ALdouble;
+
+/** void type (for opaque pointers only) */
+typedef void ALvoid;
+
+
+/* Enumerant values begin at column 50. No tabs. */
+
+/* "no distance model" or "no buffer" */
+#define AL_NONE                                   0
+
+/* Boolean False. */
+#define AL_FALSE                                  0
+
+/** Boolean True. */
+#define AL_TRUE                                   1
+
+/** Indicate Source has relative coordinates. */
+#define AL_SOURCE_RELATIVE                        0x202
+
+
+
+/**
+ * Directional source, inner cone angle, in degrees.
+ * Range:    [0-360] 
+ * Default:  360
+ */
+#define AL_CONE_INNER_ANGLE                       0x1001
+
+/**
+ * Directional source, outer cone angle, in degrees.
+ * Range:    [0-360] 
+ * Default:  360
+ */
+#define AL_CONE_OUTER_ANGLE                       0x1002
+
+/**
+ * Specify the pitch to be applied at source.
+ * Range:   [0.5-2.0]
+ * Default: 1.0
+ */
+#define AL_PITCH                                  0x1003
+  
+/** 
+ * Specify the current location in three dimensional space.
+ * OpenAL, like OpenGL, uses a right handed coordinate system,
+ *  where in a frontal default view X (thumb) points right, 
+ *  Y points up (index finger), and Z points towards the
+ *  viewer/camera (middle finger). 
+ * To switch from a left handed coordinate system, flip the
+ *  sign on the Z coordinate.
+ * Listener position is always in the world coordinate system.
+ */ 
+#define AL_POSITION                               0x1004
+  
+/** Specify the current direction. */
+#define AL_DIRECTION                              0x1005
+  
+/** Specify the current velocity in three dimensional space. */
+#define AL_VELOCITY                               0x1006
+
+/**
+ * Indicate whether source is looping.
+ * Type: ALboolean?
+ * Range:   [AL_TRUE, AL_FALSE]
+ * Default: FALSE.
+ */
+#define AL_LOOPING                                0x1007
+
+/**
+ * Indicate the buffer to provide sound samples. 
+ * Type: ALuint.
+ * Range: any valid Buffer id.
+ */
+#define AL_BUFFER                                 0x1009
+  
+/**
+ * Indicate the gain (volume amplification) applied. 
+ * Type:   ALfloat.
+ * Range:  ]0.0-  ]
+ * A value of 1.0 means un-attenuated/unchanged.
+ * Each division by 2 equals an attenuation of -6dB.
+ * Each multiplicaton with 2 equals an amplification of +6dB.
+ * A value of 0.0 is meaningless with respect to a logarithmic
+ *  scale; it is interpreted as zero volume - the channel
+ *  is effectively disabled.
+ */
+#define AL_GAIN                                   0x100A
+
+/*
+ * Indicate minimum source attenuation
+ * Type: ALfloat
+ * Range:  [0.0 - 1.0]
+ *
+ * Logarthmic
+ */
+#define AL_MIN_GAIN                               0x100D
+
+/**
+ * Indicate maximum source attenuation
+ * Type: ALfloat
+ * Range:  [0.0 - 1.0]
+ *
+ * Logarthmic
+ */
+#define AL_MAX_GAIN                               0x100E
+
+/**
+ * Indicate listener orientation.
+ *
+ * at/up 
+ */
+#define AL_ORIENTATION                            0x100F
+
+/**
+ * Source state information.
+ */
+#define AL_SOURCE_STATE                           0x1010
+#define AL_INITIAL                                0x1011
+#define AL_PLAYING                                0x1012
+#define AL_PAUSED                                 0x1013
+#define AL_STOPPED                                0x1014
+
+/**
+ * Buffer Queue params
+ */
+#define AL_BUFFERS_QUEUED                         0x1015
+#define AL_BUFFERS_PROCESSED                      0x1016
+
+/**
+ * Source buffer position information
+ */
+#define AL_SEC_OFFSET                             0x1024
+#define AL_SAMPLE_OFFSET                          0x1025
+#define AL_BYTE_OFFSET                            0x1026
+
+/*
+ * Source type (Static, Streaming or undetermined)
+ * Source is Static if a Buffer has been attached using AL_BUFFER
+ * Source is Streaming if one or more Buffers have been attached using alSourceQueueBuffers
+ * Source is undetermined when it has the NULL buffer attached
+ */
+#define AL_SOURCE_TYPE                            0x1027
+#define AL_STATIC                                 0x1028
+#define AL_STREAMING                              0x1029
+#define AL_UNDETERMINED                           0x1030
+
+/** Sound samples: format specifier. */
+#define AL_FORMAT_MONO8                           0x1100
+#define AL_FORMAT_MONO16                          0x1101
+#define AL_FORMAT_STEREO8                         0x1102
+#define AL_FORMAT_STEREO16                        0x1103
+
+/**
+ * source specific reference distance
+ * Type: ALfloat
+ * Range:  0.0 - +inf
+ *
+ * At 0.0, no distance attenuation occurs.  Default is
+ * 1.0.
+ */
+#define AL_REFERENCE_DISTANCE                     0x1020
+
+/**
+ * source specific rolloff factor
+ * Type: ALfloat
+ * Range:  0.0 - +inf
+ *
+ */
+#define AL_ROLLOFF_FACTOR                         0x1021
+
+/**
+ * Directional source, outer cone gain.
+ *
+ * Default:  0.0
+ * Range:    [0.0 - 1.0]
+ * Logarithmic
+ */
+#define AL_CONE_OUTER_GAIN                        0x1022
+
+/**
+ * Indicate distance above which sources are not
+ * attenuated using the inverse clamped distance model.
+ *
+ * Default: +inf
+ * Type: ALfloat
+ * Range:  0.0 - +inf
+ */
+#define AL_MAX_DISTANCE                           0x1023
+
+/** 
+ * Sound samples: frequency, in units of Hertz [Hz].
+ * This is the number of samples per second. Half of the
+ *  sample frequency marks the maximum significant
+ *  frequency component.
+ */
+#define AL_FREQUENCY                              0x2001
+#define AL_BITS                                   0x2002
+#define AL_CHANNELS                               0x2003
+#define AL_SIZE                                   0x2004
+
+/**
+ * Buffer state.
+ *
+ * Not supported for public use (yet).
+ */
+#define AL_UNUSED                                 0x2010
+#define AL_PENDING                                0x2011
+#define AL_PROCESSED                              0x2012
+
+
+/** Errors: No Error. */
+#define AL_NO_ERROR                               AL_FALSE
+
+/** 
+ * Invalid Name paramater passed to AL call.
+ */
+#define AL_INVALID_NAME                           0xA001
+
+/** 
+ * Invalid parameter passed to AL call.
+ */
+#define AL_INVALID_ENUM                           0xA002
+
+/** 
+ * Invalid enum parameter value.
+ */
+#define AL_INVALID_VALUE                          0xA003
+
+/** 
+ * Illegal call.
+ */
+#define AL_INVALID_OPERATION                      0xA004
+
+  
+/**
+ * No mojo.
+ */
+#define AL_OUT_OF_MEMORY                          0xA005
+
+
+/** Context strings: Vendor Name. */
+#define AL_VENDOR                                 0xB001
+#define AL_VERSION                                0xB002
+#define AL_RENDERER                               0xB003
+#define AL_EXTENSIONS                             0xB004
+
+/** Global tweakage. */
+
+/**
+ * Doppler scale.  Default 1.0
+ */
+#define AL_DOPPLER_FACTOR                         0xC000
+
+/**
+ * Tweaks speed of propagation.
+ */
+#define AL_DOPPLER_VELOCITY                       0xC001
+
+/**
+ * Speed of Sound in units per second
+ */
+#define AL_SPEED_OF_SOUND                         0xC003
+
+/**
+ * Distance models
+ *
+ * used in conjunction with DistanceModel
+ *
+ * implicit: NONE, which disances distance attenuation.
+ */
+#define AL_DISTANCE_MODEL                         0xD000
+#define AL_INVERSE_DISTANCE                       0xD001
+#define AL_INVERSE_DISTANCE_CLAMPED               0xD002
+#define AL_LINEAR_DISTANCE                        0xD003
+#define AL_LINEAR_DISTANCE_CLAMPED                0xD004
+#define AL_EXPONENT_DISTANCE                      0xD005
+#define AL_EXPONENT_DISTANCE_CLAMPED              0xD006
+
+/*
+ * Renderer State management
+ */
+AL_API void AL_APIENTRY alEnable( ALenum capability );
+
+AL_API void AL_APIENTRY alDisable( ALenum capability ); 
+
+AL_API ALboolean AL_APIENTRY alIsEnabled( ALenum capability ); 
+
+
+/*
+ * State retrieval
+ */
+AL_API const ALchar* AL_APIENTRY alGetString( ALenum param );
+
+AL_API void AL_APIENTRY alGetBooleanv( ALenum param, ALboolean* data );
+
+AL_API void AL_APIENTRY alGetIntegerv( ALenum param, ALint* data );
+
+AL_API void AL_APIENTRY alGetFloatv( ALenum param, ALfloat* data );
+
+AL_API void AL_APIENTRY alGetDoublev( ALenum param, ALdouble* data );
+
+AL_API ALboolean AL_APIENTRY alGetBoolean( ALenum param );
+
+AL_API ALint AL_APIENTRY alGetInteger( ALenum param );
+
+AL_API ALfloat AL_APIENTRY alGetFloat( ALenum param );
+
+AL_API ALdouble AL_APIENTRY alGetDouble( ALenum param );
+
+
+/*
+ * Error support.
+ * Obtain the most recent error generated in the AL state machine.
+ */
+AL_API ALenum AL_APIENTRY alGetError( void );
+
+
+/* 
+ * Extension support.
+ * Query for the presence of an extension, and obtain any appropriate
+ * function pointers and enum values.
+ */
+AL_API ALboolean AL_APIENTRY alIsExtensionPresent( const ALchar* extname );
+
+AL_API void* AL_APIENTRY alGetProcAddress( const ALchar* fname );
+
+AL_API ALenum AL_APIENTRY alGetEnumValue( const ALchar* ename );
+
+
+/*
+ * LISTENER
+ * Listener represents the location and orientation of the
+ * 'user' in 3D-space.
+ *
+ * Properties include: -
+ *
+ * Gain         AL_GAIN         ALfloat
+ * Position     AL_POSITION     ALfloat[3]
+ * Velocity     AL_VELOCITY     ALfloat[3]
+ * Orientation  AL_ORIENTATION  ALfloat[6] (Forward then Up vectors)
+*/
+
+/*
+ * Set Listener parameters
+ */
+AL_API void AL_APIENTRY alListenerf( ALenum param, ALfloat value );
+
+AL_API void AL_APIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+
+AL_API void AL_APIENTRY alListenerfv( ALenum param, const ALfloat* values ); 
+
+AL_API void AL_APIENTRY alListeneri( ALenum param, ALint value );
+
+AL_API void AL_APIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 );
+
+AL_API void AL_APIENTRY alListeneriv( ALenum param, const ALint* values );
+
+/*
+ * Get Listener parameters
+ */
+AL_API void AL_APIENTRY alGetListenerf( ALenum param, ALfloat* value );
+
+AL_API void AL_APIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 );
+
+AL_API void AL_APIENTRY alGetListenerfv( ALenum param, ALfloat* values );
+
+AL_API void AL_APIENTRY alGetListeneri( ALenum param, ALint* value );
+
+AL_API void AL_APIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 );
+
+AL_API void AL_APIENTRY alGetListeneriv( ALenum param, ALint* values );
+
+
+/**
+ * SOURCE
+ * Sources represent individual sound objects in 3D-space.
+ * Sources take the PCM data provided in the specified Buffer,
+ * apply Source-specific modifications, and then
+ * submit them to be mixed according to spatial arrangement etc.
+ * 
+ * Properties include: -
+ *
+ * Gain                              AL_GAIN                 ALfloat
+ * Min Gain                          AL_MIN_GAIN             ALfloat
+ * Max Gain                          AL_MAX_GAIN             ALfloat
+ * Position                          AL_POSITION             ALfloat[3]
+ * Velocity                          AL_VELOCITY             ALfloat[3]
+ * Direction                         AL_DIRECTION            ALfloat[3]
+ * Head Relative Mode                AL_SOURCE_RELATIVE      ALint (AL_TRUE or AL_FALSE)
+ * Reference Distance                AL_REFERENCE_DISTANCE   ALfloat
+ * Max Distance                      AL_MAX_DISTANCE         ALfloat
+ * RollOff Factor                    AL_ROLLOFF_FACTOR       ALfloat
+ * Inner Angle                       AL_CONE_INNER_ANGLE     ALint or ALfloat
+ * Outer Angle                       AL_CONE_OUTER_ANGLE     ALint or ALfloat
+ * Cone Outer Gain                   AL_CONE_OUTER_GAIN      ALint or ALfloat
+ * Pitch                             AL_PITCH                ALfloat
+ * Looping                           AL_LOOPING              ALint (AL_TRUE or AL_FALSE)
+ * MS Offset                         AL_MSEC_OFFSET          ALint or ALfloat
+ * Byte Offset                       AL_BYTE_OFFSET          ALint or ALfloat
+ * Sample Offset                     AL_SAMPLE_OFFSET        ALint or ALfloat
+ * Attached Buffer                   AL_BUFFER               ALint
+ * State (Query only)                AL_SOURCE_STATE         ALint
+ * Buffers Queued (Query only)       AL_BUFFERS_QUEUED       ALint
+ * Buffers Processed (Query only)    AL_BUFFERS_PROCESSED    ALint
+ */
+
+/* Create Source objects */
+AL_API void AL_APIENTRY alGenSources( ALsizei n, ALuint* sources ); 
+
+/* Delete Source objects */
+AL_API void AL_APIENTRY alDeleteSources( ALsizei n, const ALuint* sources );
+
+/* Verify a handle is a valid Source */ 
+AL_API ALboolean AL_APIENTRY alIsSource( ALuint sid ); 
+
+/*
+ * Set Source parameters
+ */
+AL_API void AL_APIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value ); 
+
+AL_API void AL_APIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+
+AL_API void AL_APIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values ); 
+
+AL_API void AL_APIENTRY alSourcei( ALuint sid, ALenum param, ALint value ); 
+
+AL_API void AL_APIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 );
+
+AL_API void AL_APIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values );
+
+/*
+ * Get Source parameters
+ */
+AL_API void AL_APIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value );
+
+AL_API void AL_APIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
+
+AL_API void AL_APIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values );
+
+AL_API void AL_APIENTRY alGetSourcei( ALuint sid,  ALenum param, ALint* value );
+
+AL_API void AL_APIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
+
+AL_API void AL_APIENTRY alGetSourceiv( ALuint sid,  ALenum param, ALint* values );
+
+
+/*
+ * Source vector based playback calls
+ */
+
+/* Play, replay, or resume (if paused) a list of Sources */
+AL_API void AL_APIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids );
+
+/* Stop a list of Sources */
+AL_API void AL_APIENTRY alSourceStopv( ALsizei ns, const ALuint *sids );
+
+/* Rewind a list of Sources */
+AL_API void AL_APIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids );
+
+/* Pause a list of Sources */
+AL_API void AL_APIENTRY alSourcePausev( ALsizei ns, const ALuint *sids );
+
+/*
+ * Source based playback calls
+ */
+
+/* Play, replay, or resume a Source */
+AL_API void AL_APIENTRY alSourcePlay( ALuint sid );
+
+/* Stop a Source */
+AL_API void AL_APIENTRY alSourceStop( ALuint sid );
+
+/* Rewind a Source (set playback postiton to beginning) */
+AL_API void AL_APIENTRY alSourceRewind( ALuint sid );
+
+/* Pause a Source */
+AL_API void AL_APIENTRY alSourcePause( ALuint sid );
+
+/*
+ * Source Queuing 
+ */
+AL_API void AL_APIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids );
+
+AL_API void AL_APIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids );
+
+
+/**
+ * BUFFER
+ * Buffer objects are storage space for sample data.
+ * Buffers are referred to by Sources. One Buffer can be used
+ * by multiple Sources.
+ *
+ * Properties include: -
+ *
+ * Frequency (Query only)    AL_FREQUENCY      ALint
+ * Size (Query only)         AL_SIZE           ALint
+ * Bits (Query only)         AL_BITS           ALint
+ * Channels (Query only)     AL_CHANNELS       ALint
+ */
+
+/* Create Buffer objects */
+AL_API void AL_APIENTRY alGenBuffers( ALsizei n, ALuint* buffers );
+
+/* Delete Buffer objects */
+AL_API void AL_APIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers );
+
+/* Verify a handle is a valid Buffer */
+AL_API ALboolean AL_APIENTRY alIsBuffer( ALuint bid );
+
+/* Specify the data to be copied into a buffer */
+AL_API void AL_APIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq );
+
+/*
+ * Set Buffer parameters
+ */
+AL_API void AL_APIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value );
+
+AL_API void AL_APIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+
+AL_API void AL_APIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values );
+
+AL_API void AL_APIENTRY alBufferi( ALuint bid, ALenum param, ALint value );
+
+AL_API void AL_APIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 );
+
+AL_API void AL_APIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values );
+
+/*
+ * Get Buffer parameters
+ */
+AL_API void AL_APIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value );
+
+AL_API void AL_APIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
+
+AL_API void AL_APIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values );
+
+AL_API void AL_APIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value );
+
+AL_API void AL_APIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
+
+AL_API void AL_APIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values );
+
+
+/*
+ * Global Parameters
+ */
+AL_API void AL_APIENTRY alDopplerFactor( ALfloat value );
+
+AL_API void AL_APIENTRY alDopplerVelocity( ALfloat value );
+
+AL_API void AL_APIENTRY alSpeedOfSound( ALfloat value );
+
+AL_API void AL_APIENTRY alDistanceModel( ALenum distanceModel );
+
+/*
+ * Pointer-to-function types, useful for dynamically getting AL entry points.
+ */
+typedef void           (AL_APIENTRY *LPALENABLE)( ALenum capability );
+typedef void           (AL_APIENTRY *LPALDISABLE)( ALenum capability ); 
+typedef ALboolean      (AL_APIENTRY *LPALISENABLED)( ALenum capability ); 
+typedef const ALchar*  (AL_APIENTRY *LPALGETSTRING)( ALenum param );
+typedef void           (AL_APIENTRY *LPALGETBOOLEANV)( ALenum param, ALboolean* data );
+typedef void           (AL_APIENTRY *LPALGETINTEGERV)( ALenum param, ALint* data );
+typedef void           (AL_APIENTRY *LPALGETFLOATV)( ALenum param, ALfloat* data );
+typedef void           (AL_APIENTRY *LPALGETDOUBLEV)( ALenum param, ALdouble* data );
+typedef ALboolean      (AL_APIENTRY *LPALGETBOOLEAN)( ALenum param );
+typedef ALint          (AL_APIENTRY *LPALGETINTEGER)( ALenum param );
+typedef ALfloat        (AL_APIENTRY *LPALGETFLOAT)( ALenum param );
+typedef ALdouble       (AL_APIENTRY *LPALGETDOUBLE)( ALenum param );
+typedef ALenum         (AL_APIENTRY *LPALGETERROR)( void );
+typedef ALboolean      (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar* extname );
+typedef void*          (AL_APIENTRY *LPALGETPROCADDRESS)( const ALchar* fname );
+typedef ALenum         (AL_APIENTRY *LPALGETENUMVALUE)( const ALchar* ename );
+typedef void           (AL_APIENTRY *LPALLISTENERF)( ALenum param, ALfloat value );
+typedef void           (AL_APIENTRY *LPALLISTENER3F)( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+typedef void           (AL_APIENTRY *LPALLISTENERFV)( ALenum param, const ALfloat* values );
+typedef void           (AL_APIENTRY *LPALLISTENERI)( ALenum param, ALint value );
+typedef void           (AL_APIENTRY *LPALLISTENER3I)( ALenum param, ALint value1, ALint value2, ALint value3 );
+typedef void           (AL_APIENTRY *LPALLISTENERIV)( ALenum param, const ALint* values );
+typedef void           (AL_APIENTRY *LPALGETLISTENERF)( ALenum param, ALfloat* value );
+typedef void           (AL_APIENTRY *LPALGETLISTENER3F)( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 );
+typedef void           (AL_APIENTRY *LPALGETLISTENERFV)( ALenum param, ALfloat* values );
+typedef void           (AL_APIENTRY *LPALGETLISTENERI)( ALenum param, ALint* value );
+typedef void           (AL_APIENTRY *LPALGETLISTENER3I)( ALenum param, ALint *value1, ALint *value2, ALint *value3 );
+typedef void           (AL_APIENTRY *LPALGETLISTENERIV)( ALenum param, ALint* values );
+typedef void           (AL_APIENTRY *LPALGENSOURCES)( ALsizei n, ALuint* sources ); 
+typedef void           (AL_APIENTRY *LPALDELETESOURCES)( ALsizei n, const ALuint* sources );
+typedef ALboolean      (AL_APIENTRY *LPALISSOURCE)( ALuint sid ); 
+typedef void           (AL_APIENTRY *LPALSOURCEF)( ALuint sid, ALenum param, ALfloat value); 
+typedef void           (AL_APIENTRY *LPALSOURCE3F)( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+typedef void           (AL_APIENTRY *LPALSOURCEFV)( ALuint sid, ALenum param, const ALfloat* values );
+typedef void           (AL_APIENTRY *LPALSOURCEI)( ALuint sid, ALenum param, ALint value); 
+typedef void           (AL_APIENTRY *LPALSOURCE3I)( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 );
+typedef void           (AL_APIENTRY *LPALSOURCEIV)( ALuint sid, ALenum param, const ALint* values );
+typedef void           (AL_APIENTRY *LPALGETSOURCEF)( ALuint sid, ALenum param, ALfloat* value );
+typedef void           (AL_APIENTRY *LPALGETSOURCE3F)( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
+typedef void           (AL_APIENTRY *LPALGETSOURCEFV)( ALuint sid, ALenum param, ALfloat* values );
+typedef void           (AL_APIENTRY *LPALGETSOURCEI)( ALuint sid, ALenum param, ALint* value );
+typedef void           (AL_APIENTRY *LPALGETSOURCE3I)( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
+typedef void           (AL_APIENTRY *LPALGETSOURCEIV)( ALuint sid, ALenum param, ALint* values );
+typedef void           (AL_APIENTRY *LPALSOURCEPLAYV)( ALsizei ns, const ALuint *sids );
+typedef void           (AL_APIENTRY *LPALSOURCESTOPV)( ALsizei ns, const ALuint *sids );
+typedef void           (AL_APIENTRY *LPALSOURCEREWINDV)( ALsizei ns, const ALuint *sids );
+typedef void           (AL_APIENTRY *LPALSOURCEPAUSEV)( ALsizei ns, const ALuint *sids );
+typedef void           (AL_APIENTRY *LPALSOURCEPLAY)( ALuint sid );
+typedef void           (AL_APIENTRY *LPALSOURCESTOP)( ALuint sid );
+typedef void           (AL_APIENTRY *LPALSOURCEREWIND)( ALuint sid );
+typedef void           (AL_APIENTRY *LPALSOURCEPAUSE)( ALuint sid );
+typedef void           (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, const ALuint *bids );
+typedef void           (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, ALuint *bids );
+typedef void           (AL_APIENTRY *LPALGENBUFFERS)( ALsizei n, ALuint* buffers );
+typedef void           (AL_APIENTRY *LPALDELETEBUFFERS)( ALsizei n, const ALuint* buffers );
+typedef ALboolean      (AL_APIENTRY *LPALISBUFFER)( ALuint bid );
+typedef void           (AL_APIENTRY *LPALBUFFERDATA)( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq );
+typedef void           (AL_APIENTRY *LPALBUFFERF)( ALuint bid, ALenum param, ALfloat value);
+typedef void           (AL_APIENTRY *LPALBUFFER3F)( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 );
+typedef void           (AL_APIENTRY *LPALBUFFERFV)( ALuint bid, ALenum param, const ALfloat* values );
+typedef void           (AL_APIENTRY *LPALBUFFERI)( ALuint bid, ALenum param, ALint value);
+typedef void           (AL_APIENTRY *LPALBUFFER3I)( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 );
+typedef void           (AL_APIENTRY *LPALBUFFERIV)( ALuint bid, ALenum param, const ALint* values );
+typedef void           (AL_APIENTRY *LPALGETBUFFERF)( ALuint bid, ALenum param, ALfloat* value );
+typedef void           (AL_APIENTRY *LPALGETBUFFER3F)( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3);
+typedef void           (AL_APIENTRY *LPALGETBUFFERFV)( ALuint bid, ALenum param, ALfloat* values );
+typedef void           (AL_APIENTRY *LPALGETBUFFERI)( ALuint bid, ALenum param, ALint* value );
+typedef void           (AL_APIENTRY *LPALGETBUFFER3I)( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3);
+typedef void           (AL_APIENTRY *LPALGETBUFFERIV)( ALuint bid, ALenum param, ALint* values );
+typedef void           (AL_APIENTRY *LPALDOPPLERFACTOR)( ALfloat value );
+typedef void           (AL_APIENTRY *LPALDOPPLERVELOCITY)( ALfloat value );
+typedef void           (AL_APIENTRY *LPALSPEEDOFSOUND)( ALfloat value );
+typedef void           (AL_APIENTRY *LPALDISTANCEMODEL)( ALenum distanceModel );
+
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
+ #pragma export off
+#endif
+
+#if defined(__cplusplus)
+}  /* extern "C" */
+#endif
+
+#endif /* AL_AL_H */
diff --git a/include/AL/alc.h b/include/AL/alc.h
new file mode 100644 (file)
index 0000000..04543a0
--- /dev/null
@@ -0,0 +1,277 @@
+#ifndef AL_ALC_H
+#define AL_ALC_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if defined(AL_LIBTYPE_STATIC)
+ #define ALC_API
+#elif defined(_WIN32) && !defined(_XBOX)
+ #if defined(AL_BUILD_LIBRARY)
+  #define ALC_API __declspec(dllexport)
+ #else
+  #define ALC_API __declspec(dllimport)
+ #endif
+#else
+ #if defined(AL_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY)
+  #define ALC_API __attribute__((visibility("protected")))
+ #else
+  #define ALC_API extern
+ #endif
+#endif
+
+#if defined(_WIN32)
+ #define ALC_APIENTRY __cdecl
+#else
+ #define ALC_APIENTRY
+#endif
+
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
+ #pragma export on
+#endif
+
+/*
+ * The ALCAPI, ALCAPIENTRY, and ALC_INVALID macros are deprecated, but are
+ * included for applications porting code from AL 1.0
+ */
+#define ALCAPI ALC_API
+#define ALCAPIENTRY ALC_APIENTRY
+#define ALC_INVALID 0
+
+
+#define ALC_VERSION_0_1         1
+
+typedef struct ALCdevice_struct ALCdevice;
+typedef struct ALCcontext_struct ALCcontext;
+
+
+/** 8-bit boolean */
+typedef char ALCboolean;
+
+/** character */
+typedef char ALCchar;
+
+/** signed 8-bit 2's complement integer */
+typedef signed char ALCbyte;
+
+/** unsigned 8-bit integer */
+typedef unsigned char ALCubyte;
+
+/** signed 16-bit 2's complement integer */
+typedef short ALCshort;
+
+/** unsigned 16-bit integer */
+typedef unsigned short ALCushort;
+
+/** signed 32-bit 2's complement integer */
+typedef int ALCint;
+
+/** unsigned 32-bit integer */
+typedef unsigned int ALCuint;
+
+/** non-negative 32-bit binary integer size */
+typedef int ALCsizei;
+
+/** enumerated 32-bit value */
+typedef int ALCenum;
+
+/** 32-bit IEEE754 floating-point */
+typedef float ALCfloat;
+
+/** 64-bit IEEE754 floating-point */
+typedef double ALCdouble;
+
+/** void type (for opaque pointers only) */
+typedef void ALCvoid;
+
+
+/* Enumerant values begin at column 50. No tabs. */
+
+/* Boolean False. */
+#define ALC_FALSE                                0
+
+/* Boolean True. */
+#define ALC_TRUE                                 1
+
+/**
+ * followed by <int> Hz
+ */
+#define ALC_FREQUENCY                            0x1007
+
+/**
+ * followed by <int> Hz
+ */
+#define ALC_REFRESH                              0x1008
+
+/**
+ * followed by AL_TRUE, AL_FALSE
+ */
+#define ALC_SYNC                                 0x1009
+
+/**
+ * followed by <int> Num of requested Mono (3D) Sources
+ */
+#define ALC_MONO_SOURCES                         0x1010
+
+/**
+ * followed by <int> Num of requested Stereo Sources
+ */
+#define ALC_STEREO_SOURCES                       0x1011
+
+/**
+ * errors
+ */
+
+/**
+ * No error
+ */
+#define ALC_NO_ERROR                             ALC_FALSE
+
+/**
+ * No device
+ */
+#define ALC_INVALID_DEVICE                       0xA001
+
+/**
+ * invalid context ID
+ */
+#define ALC_INVALID_CONTEXT                      0xA002
+
+/**
+ * bad enum
+ */
+#define ALC_INVALID_ENUM                         0xA003
+
+/**
+ * bad value
+ */
+#define ALC_INVALID_VALUE                        0xA004
+
+/**
+ * Out of memory.
+ */
+#define ALC_OUT_OF_MEMORY                        0xA005
+
+
+/**
+ * The Specifier string for default device
+ */
+#define ALC_DEFAULT_DEVICE_SPECIFIER             0x1004
+#define ALC_DEVICE_SPECIFIER                     0x1005
+#define ALC_EXTENSIONS                           0x1006
+
+#define ALC_MAJOR_VERSION                        0x1000
+#define ALC_MINOR_VERSION                        0x1001
+
+#define ALC_ATTRIBUTES_SIZE                      0x1002
+#define ALC_ALL_ATTRIBUTES                       0x1003
+
+
+/**
+ * Capture extension
+ */
+#define ALC_CAPTURE_DEVICE_SPECIFIER             0x310
+#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER     0x311
+#define ALC_CAPTURE_SAMPLES                      0x312
+
+
+/*
+ * Context Management
+ */
+ALC_API ALCcontext *    ALC_APIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist );
+
+ALC_API ALCboolean      ALC_APIENTRY alcMakeContextCurrent( ALCcontext *context );
+
+ALC_API void            ALC_APIENTRY alcProcessContext( ALCcontext *context );
+
+ALC_API void            ALC_APIENTRY alcSuspendContext( ALCcontext *context );
+
+ALC_API void            ALC_APIENTRY alcDestroyContext( ALCcontext *context );
+
+ALC_API ALCcontext *    ALC_APIENTRY alcGetCurrentContext( void );
+
+ALC_API ALCdevice*      ALC_APIENTRY alcGetContextsDevice( ALCcontext *context );
+
+
+/*
+ * Device Management
+ */
+ALC_API ALCdevice *     ALC_APIENTRY alcOpenDevice( const ALCchar *devicename );
+
+ALC_API ALCboolean      ALC_APIENTRY alcCloseDevice( ALCdevice *device );
+
+
+/*
+ * Error support.
+ * Obtain the most recent Context error
+ */
+ALC_API ALCenum         ALC_APIENTRY alcGetError( ALCdevice *device );
+
+
+/* 
+ * Extension support.
+ * Query for the presence of an extension, and obtain any appropriate
+ * function pointers and enum values.
+ */
+ALC_API ALCboolean      ALC_APIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname );
+
+ALC_API void  *         ALC_APIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname );
+
+ALC_API ALCenum         ALC_APIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname );
+
+
+/*
+ * Query functions
+ */
+ALC_API const ALCchar * ALC_APIENTRY alcGetString( ALCdevice *device, ALCenum param );
+
+ALC_API void            ALC_APIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data );
+
+
+/*
+ * Capture functions
+ */
+ALC_API ALCdevice*      ALC_APIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize );
+
+ALC_API ALCboolean      ALC_APIENTRY alcCaptureCloseDevice( ALCdevice *device );
+
+ALC_API void            ALC_APIENTRY alcCaptureStart( ALCdevice *device );
+
+ALC_API void            ALC_APIENTRY alcCaptureStop( ALCdevice *device );
+
+ALC_API void            ALC_APIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples );
+
+/*
+ * Pointer-to-function types, useful for dynamically getting ALC entry points.
+ */
+typedef ALCcontext *   (ALC_APIENTRY *LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist);
+typedef ALCboolean     (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)( ALCcontext *context );
+typedef void           (ALC_APIENTRY *LPALCPROCESSCONTEXT)( ALCcontext *context );
+typedef void           (ALC_APIENTRY *LPALCSUSPENDCONTEXT)( ALCcontext *context );
+typedef void           (ALC_APIENTRY *LPALCDESTROYCONTEXT)( ALCcontext *context );
+typedef ALCcontext *   (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)( void );
+typedef ALCdevice *    (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)( ALCcontext *context );
+typedef ALCdevice *    (ALC_APIENTRY *LPALCOPENDEVICE)( const ALCchar *devicename );
+typedef ALCboolean     (ALC_APIENTRY *LPALCCLOSEDEVICE)( ALCdevice *device );
+typedef ALCenum        (ALC_APIENTRY *LPALCGETERROR)( ALCdevice *device );
+typedef ALCboolean     (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)( ALCdevice *device, const ALCchar *extname );
+typedef void *         (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname );
+typedef ALCenum        (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname );
+typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)( ALCdevice *device, ALCenum param );
+typedef void           (ALC_APIENTRY *LPALCGETINTEGERV)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *dest );
+typedef ALCdevice *    (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize );
+typedef ALCboolean     (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)( ALCdevice *device );
+typedef void           (ALC_APIENTRY *LPALCCAPTURESTART)( ALCdevice *device );
+typedef void           (ALC_APIENTRY *LPALCCAPTURESTOP)( ALCdevice *device );
+typedef void           (ALC_APIENTRY *LPALCCAPTURESAMPLES)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples );
+
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC
+ #pragma export off
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* AL_ALC_H */
diff --git a/include/AL/alext.h b/include/AL/alext.h
new file mode 100644 (file)
index 0000000..f3c7bca
--- /dev/null
@@ -0,0 +1,165 @@
+/**
+ * OpenAL cross platform audio library
+ * Copyright (C) 2008 by authors.
+ * This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ *  License along with this library; if not, write to the
+ *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *  Boston, MA  02111-1307, USA.
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef AL_ALEXT_H
+#define AL_ALEXT_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef AL_LOKI_IMA_ADPCM_format
+#define AL_LOKI_IMA_ADPCM_format 1
+#define AL_FORMAT_IMA_ADPCM_MONO16_EXT           0x10000
+#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT         0x10001
+#endif
+
+#ifndef AL_LOKI_WAVE_format
+#define AL_LOKI_WAVE_format 1
+#define AL_FORMAT_WAVE_EXT                       0x10002
+#endif
+
+#ifndef AL_EXT_vorbis
+#define AL_EXT_vorbis 1
+#define AL_FORMAT_VORBIS_EXT                     0x10003
+#endif
+
+#ifndef AL_LOKI_quadriphonic
+#define AL_LOKI_quadriphonic 1
+#define AL_FORMAT_QUAD8_LOKI                     0x10004
+#define AL_FORMAT_QUAD16_LOKI                    0x10005
+#endif
+
+#ifndef AL_EXT_float32
+#define AL_EXT_float32 1
+#define AL_FORMAT_MONO_FLOAT32                   0x10010
+#define AL_FORMAT_STEREO_FLOAT32                 0x10011
+#endif
+
+#ifndef AL_EXT_double
+#define AL_EXT_double 1
+#define AL_FORMAT_MONO_DOUBLE_EXT                0x10012
+#define AL_FORMAT_STEREO_DOUBLE_EXT              0x10013
+#endif
+
+#ifndef ALC_LOKI_audio_channel
+#define ALC_LOKI_audio_channel 1
+#define ALC_CHAN_MAIN_LOKI                       0x500001
+#define ALC_CHAN_PCM_LOKI                        0x500002
+#define ALC_CHAN_CD_LOKI                         0x500003
+#endif
+
+#ifndef ALC_ENUMERATE_ALL_EXT
+#define ALC_ENUMERATE_ALL_EXT 1
+#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER        0x1012
+#define ALC_ALL_DEVICES_SPECIFIER                0x1013
+#endif
+
+#ifndef AL_EXT_MCFORMATS
+#define AL_EXT_MCFORMATS 1
+#define AL_FORMAT_QUAD8                          0x1204
+#define AL_FORMAT_QUAD16                         0x1205
+#define AL_FORMAT_QUAD32                         0x1206
+#define AL_FORMAT_REAR8                          0x1207
+#define AL_FORMAT_REAR16                         0x1208
+#define AL_FORMAT_REAR32                         0x1209
+#define AL_FORMAT_51CHN8                         0x120A
+#define AL_FORMAT_51CHN16                        0x120B
+#define AL_FORMAT_51CHN32                        0x120C
+#define AL_FORMAT_61CHN8                         0x120D
+#define AL_FORMAT_61CHN16                        0x120E
+#define AL_FORMAT_61CHN32                        0x120F
+#define AL_FORMAT_71CHN8                         0x1210
+#define AL_FORMAT_71CHN16                        0x1211
+#define AL_FORMAT_71CHN32                        0x1212
+#endif
+
+#ifndef AL_EXT_MULAW_MCFORMATS
+#define AL_EXT_MULAW_MCFORMATS 1
+#define AL_FORMAT_MONO_MULAW                     0x10014
+#define AL_FORMAT_STEREO_MULAW                   0x10015
+#define AL_FORMAT_QUAD_MULAW                     0x10021
+#define AL_FORMAT_REAR_MULAW                     0x10022
+#define AL_FORMAT_51CHN_MULAW                    0x10023
+#define AL_FORMAT_61CHN_MULAW                    0x10024
+#define AL_FORMAT_71CHN_MULAW                    0x10025
+#endif
+
+#ifndef AL_EXT_IMA4
+#define AL_EXT_IMA4 1
+#define AL_FORMAT_MONO_IMA4                      0x1300
+#define AL_FORMAT_STEREO_IMA4                    0x1301
+#endif
+
+#ifndef AL_EXT_STATIC_BUFFER
+#define AL_EXT_STATIC_BUFFER 1
+typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq);
+#endif
+#endif
+
+#ifndef ALC_EXT_EFX
+#define ALC_EXT_EFX 1
+#include "efx.h"
+#endif
+
+#ifndef ALC_EXT_disconnect
+#define ALC_EXT_disconnect 1
+#define ALC_CONNECTED                            0x313
+#endif
+
+#ifndef ALC_EXT_thread_local_context
+#define ALC_EXT_thread_local_context 1
+typedef ALCboolean  (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context);
+typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void);
+#ifdef AL_ALEXT_PROTOTYPES
+ALC_API ALCboolean  ALC_APIENTRY alcSetThreadContext(ALCcontext *context);
+ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void);
+#endif
+#endif
+
+#ifndef AL_EXT_source_distance_model
+#define AL_EXT_source_distance_model 1
+#define AL_SOURCE_DISTANCE_MODEL                 0x200
+#endif
+
+#ifndef AL_SOFT_buffer_sub_data
+#define AL_SOFT_buffer_sub_data 1
+#define AL_BYTE_RW_OFFSETS_SOFT                  0x1031
+#define AL_SAMPLE_RW_OFFSETS_SOFT                0x1032
+typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei);
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length);
+#endif
+#endif
+
+#ifndef AL_SOFT_loop_points
+#define AL_SOFT_loop_points 1
+#define AL_LOOP_POINTS_SOFT                      0x2015
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/AL/efx-creative.h b/include/AL/efx-creative.h
new file mode 100644 (file)
index 0000000..0a04c98
--- /dev/null
@@ -0,0 +1,3 @@
+/* The tokens that would be defined here are already defined in efx.h. This
+ * empty file is here to provide compatibility with Windows-based projects
+ * that would include it. */
diff --git a/include/AL/efx.h b/include/AL/efx.h
new file mode 100644 (file)
index 0000000..0ccef95
--- /dev/null
@@ -0,0 +1,758 @@
+#ifndef AL_EFX_H
+#define AL_EFX_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ALC_EXT_EFX_NAME                         "ALC_EXT_EFX"
+
+#define ALC_EFX_MAJOR_VERSION                    0x20001
+#define ALC_EFX_MINOR_VERSION                    0x20002
+#define ALC_MAX_AUXILIARY_SENDS                  0x20003
+
+
+/* Listener properties. */
+#define AL_METERS_PER_UNIT                       0x20004
+
+/* Source properties. */
+#define AL_DIRECT_FILTER                         0x20005
+#define AL_AUXILIARY_SEND_FILTER                 0x20006
+#define AL_AIR_ABSORPTION_FACTOR                 0x20007
+#define AL_ROOM_ROLLOFF_FACTOR                   0x20008
+#define AL_CONE_OUTER_GAINHF                     0x20009
+#define AL_DIRECT_FILTER_GAINHF_AUTO             0x2000A
+#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO       0x2000B
+#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO     0x2000C
+
+
+/* Effect properties. */
+
+/* Reverb effect parameters */
+#define AL_REVERB_DENSITY                        0x0001
+#define AL_REVERB_DIFFUSION                      0x0002
+#define AL_REVERB_GAIN                           0x0003
+#define AL_REVERB_GAINHF                         0x0004
+#define AL_REVERB_DECAY_TIME                     0x0005
+#define AL_REVERB_DECAY_HFRATIO                  0x0006
+#define AL_REVERB_REFLECTIONS_GAIN               0x0007
+#define AL_REVERB_REFLECTIONS_DELAY              0x0008
+#define AL_REVERB_LATE_REVERB_GAIN               0x0009
+#define AL_REVERB_LATE_REVERB_DELAY              0x000A
+#define AL_REVERB_AIR_ABSORPTION_GAINHF          0x000B
+#define AL_REVERB_ROOM_ROLLOFF_FACTOR            0x000C
+#define AL_REVERB_DECAY_HFLIMIT                  0x000D
+
+/* EAX Reverb effect parameters */
+#define AL_EAXREVERB_DENSITY                     0x0001
+#define AL_EAXREVERB_DIFFUSION                   0x0002
+#define AL_EAXREVERB_GAIN                        0x0003
+#define AL_EAXREVERB_GAINHF                      0x0004
+#define AL_EAXREVERB_GAINLF                      0x0005
+#define AL_EAXREVERB_DECAY_TIME                  0x0006
+#define AL_EAXREVERB_DECAY_HFRATIO               0x0007
+#define AL_EAXREVERB_DECAY_LFRATIO               0x0008
+#define AL_EAXREVERB_REFLECTIONS_GAIN            0x0009
+#define AL_EAXREVERB_REFLECTIONS_DELAY           0x000A
+#define AL_EAXREVERB_REFLECTIONS_PAN             0x000B
+#define AL_EAXREVERB_LATE_REVERB_GAIN            0x000C
+#define AL_EAXREVERB_LATE_REVERB_DELAY           0x000D
+#define AL_EAXREVERB_LATE_REVERB_PAN             0x000E
+#define AL_EAXREVERB_ECHO_TIME                   0x000F
+#define AL_EAXREVERB_ECHO_DEPTH                  0x0010
+#define AL_EAXREVERB_MODULATION_TIME             0x0011
+#define AL_EAXREVERB_MODULATION_DEPTH            0x0012
+#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF       0x0013
+#define AL_EAXREVERB_HFREFERENCE                 0x0014
+#define AL_EAXREVERB_LFREFERENCE                 0x0015
+#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR         0x0016
+#define AL_EAXREVERB_DECAY_HFLIMIT               0x0017
+
+/* Chorus effect parameters */
+#define AL_CHORUS_WAVEFORM                       0x0001
+#define AL_CHORUS_PHASE                          0x0002
+#define AL_CHORUS_RATE                           0x0003
+#define AL_CHORUS_DEPTH                          0x0004
+#define AL_CHORUS_FEEDBACK                       0x0005
+#define AL_CHORUS_DELAY                          0x0006
+
+/* Distortion effect parameters */
+#define AL_DISTORTION_EDGE                       0x0001
+#define AL_DISTORTION_GAIN                       0x0002
+#define AL_DISTORTION_LOWPASS_CUTOFF             0x0003
+#define AL_DISTORTION_EQCENTER                   0x0004
+#define AL_DISTORTION_EQBANDWIDTH                0x0005
+
+/* Echo effect parameters */
+#define AL_ECHO_DELAY                            0x0001
+#define AL_ECHO_LRDELAY                          0x0002
+#define AL_ECHO_DAMPING                          0x0003
+#define AL_ECHO_FEEDBACK                         0x0004
+#define AL_ECHO_SPREAD                           0x0005
+
+/* Flanger effect parameters */
+#define AL_FLANGER_WAVEFORM                      0x0001
+#define AL_FLANGER_PHASE                         0x0002
+#define AL_FLANGER_RATE                          0x0003
+#define AL_FLANGER_DEPTH                         0x0004
+#define AL_FLANGER_FEEDBACK                      0x0005
+#define AL_FLANGER_DELAY                         0x0006
+
+/* Frequency shifter effect parameters */
+#define AL_FREQUENCY_SHIFTER_FREQUENCY           0x0001
+#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION      0x0002
+#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION     0x0003
+
+/* Vocal morpher effect parameters */
+#define AL_VOCAL_MORPHER_PHONEMEA                0x0001
+#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING  0x0002
+#define AL_VOCAL_MORPHER_PHONEMEB                0x0003
+#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING  0x0004
+#define AL_VOCAL_MORPHER_WAVEFORM                0x0005
+#define AL_VOCAL_MORPHER_RATE                    0x0006
+
+/* Pitchshifter effect parameters */
+#define AL_PITCH_SHIFTER_COARSE_TUNE             0x0001
+#define AL_PITCH_SHIFTER_FINE_TUNE               0x0002
+
+/* Ringmodulator effect parameters */
+#define AL_RING_MODULATOR_FREQUENCY              0x0001
+#define AL_RING_MODULATOR_HIGHPASS_CUTOFF        0x0002
+#define AL_RING_MODULATOR_WAVEFORM               0x0003
+
+/* Autowah effect parameters */
+#define AL_AUTOWAH_ATTACK_TIME                   0x0001
+#define AL_AUTOWAH_RELEASE_TIME                  0x0002
+#define AL_AUTOWAH_RESONANCE                     0x0003
+#define AL_AUTOWAH_PEAK_GAIN                     0x0004
+
+/* Compressor effect parameters */
+#define AL_COMPRESSOR_ONOFF                      0x0001
+
+/* Equalizer effect parameters */
+#define AL_EQUALIZER_LOW_GAIN                    0x0001
+#define AL_EQUALIZER_LOW_CUTOFF                  0x0002
+#define AL_EQUALIZER_MID1_GAIN                   0x0003
+#define AL_EQUALIZER_MID1_CENTER                 0x0004
+#define AL_EQUALIZER_MID1_WIDTH                  0x0005
+#define AL_EQUALIZER_MID2_GAIN                   0x0006
+#define AL_EQUALIZER_MID2_CENTER                 0x0007
+#define AL_EQUALIZER_MID2_WIDTH                  0x0008
+#define AL_EQUALIZER_HIGH_GAIN                   0x0009
+#define AL_EQUALIZER_HIGH_CUTOFF                 0x000A
+
+/* Effect type */
+#define AL_EFFECT_FIRST_PARAMETER                0x0000
+#define AL_EFFECT_LAST_PARAMETER                 0x8000
+#define AL_EFFECT_TYPE                           0x8001
+
+/* Effect types, used with the AL_EFFECT_TYPE property */
+#define AL_EFFECT_NULL                           0x0000
+#define AL_EFFECT_REVERB                         0x0001
+#define AL_EFFECT_CHORUS                         0x0002
+#define AL_EFFECT_DISTORTION                     0x0003
+#define AL_EFFECT_ECHO                           0x0004
+#define AL_EFFECT_FLANGER                        0x0005
+#define AL_EFFECT_FREQUENCY_SHIFTER              0x0006
+#define AL_EFFECT_VOCAL_MORPHER                  0x0007
+#define AL_EFFECT_PITCH_SHIFTER                  0x0008
+#define AL_EFFECT_RING_MODULATOR                 0x0009
+#define AL_EFFECT_AUTOWAH                        0x000A
+#define AL_EFFECT_COMPRESSOR                     0x000B
+#define AL_EFFECT_EQUALIZER                      0x000C
+#define AL_EFFECT_EAXREVERB                      0x8000
+
+/* Auxiliary Effect Slot properties. */
+#define AL_EFFECTSLOT_EFFECT                     0x0001
+#define AL_EFFECTSLOT_GAIN                       0x0002
+#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO        0x0003
+
+/* NULL Auxiliary Slot ID to disable a source send. */
+#define AL_EFFECTSLOT_NULL                       0x0000
+
+
+/* Filter properties. */
+
+/* Lowpass filter parameters */
+#define AL_LOWPASS_GAIN                          0x0001
+#define AL_LOWPASS_GAINHF                        0x0002
+
+/* Highpass filter parameters */
+#define AL_HIGHPASS_GAIN                         0x0001
+#define AL_HIGHPASS_GAINLF                       0x0002
+
+/* Bandpass filter parameters */
+#define AL_BANDPASS_GAIN                         0x0001
+#define AL_BANDPASS_GAINLF                       0x0002
+#define AL_BANDPASS_GAINHF                       0x0003
+
+/* Filter type */
+#define AL_FILTER_FIRST_PARAMETER                0x0000
+#define AL_FILTER_LAST_PARAMETER                 0x8000
+#define AL_FILTER_TYPE                           0x8001
+
+/* Filter types, used with the AL_FILTER_TYPE property */
+#define AL_FILTER_NULL                           0x0000
+#define AL_FILTER_LOWPASS                        0x0001
+#define AL_FILTER_HIGHPASS                       0x0002
+#define AL_FILTER_BANDPASS                       0x0003
+
+
+/* Effect object function types. */
+typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint);
+typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*);
+
+/* Filter object function types. */
+typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint);
+typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*);
+
+/* Auxiliary Effect Slot object function types. */
+typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*);
+typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat);
+typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*);
+typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*);
+
+#ifdef AL_ALEXT_PROTOTYPES
+AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects);
+AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects);
+AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect);
+AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues);
+
+AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters);
+AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters);
+AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter);
+AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues);
+
+AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
+AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots);
+AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue);
+AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue);
+AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues);
+#endif
+
+/* Filter ranges and defaults. */
+
+/* Lowpass filter */
+#define LOWPASS_MIN_GAIN                         (0.0f)
+#define LOWPASS_MAX_GAIN                         (1.0f)
+#define LOWPASS_DEFAULT_GAIN                     (1.0f)
+
+#define LOWPASS_MIN_GAINHF                       (0.0f)
+#define LOWPASS_MAX_GAINHF                       (1.0f)
+#define LOWPASS_DEFAULT_GAINHF                   (1.0f)
+
+/* Highpass filter */
+#define HIGHPASS_MIN_GAIN                        (0.0f)
+#define HIGHPASS_MAX_GAIN                        (1.0f)
+#define HIGHPASS_DEFAULT_GAIN                    (1.0f)
+
+#define HIGHPASS_MIN_GAINLF                      (0.0f)
+#define HIGHPASS_MAX_GAINLF                      (1.0f)
+#define HIGHPASS_DEFAULT_GAINLF                  (1.0f)
+
+/* Bandpass filter */
+#define BANDPASS_MIN_GAIN                        (0.0f)
+#define BANDPASS_MAX_GAIN                        (1.0f)
+#define BANDPASS_DEFAULT_GAIN                    (1.0f)
+
+#define BANDPASS_MIN_GAINHF                      (0.0f)
+#define BANDPASS_MAX_GAINHF                      (1.0f)
+#define BANDPASS_DEFAULT_GAINHF                  (1.0f)
+
+#define BANDPASS_MIN_GAINLF                      (0.0f)
+#define BANDPASS_MAX_GAINLF                      (1.0f)
+#define BANDPASS_DEFAULT_GAINLF                  (1.0f)
+
+
+/* Effect parameter ranges and defaults. */
+
+/* Standard reverb effect */
+#define AL_REVERB_MIN_DENSITY                    (0.0f)
+#define AL_REVERB_MAX_DENSITY                    (1.0f)
+#define AL_REVERB_DEFAULT_DENSITY                (1.0f)
+
+#define AL_REVERB_MIN_DIFFUSION                  (0.0f)
+#define AL_REVERB_MAX_DIFFUSION                  (1.0f)
+#define AL_REVERB_DEFAULT_DIFFUSION              (1.0f)
+
+#define AL_REVERB_MIN_GAIN                       (0.0f)
+#define AL_REVERB_MAX_GAIN                       (1.0f)
+#define AL_REVERB_DEFAULT_GAIN                   (0.32f)
+
+#define AL_REVERB_MIN_GAINHF                     (0.0f)
+#define AL_REVERB_MAX_GAINHF                     (1.0f)
+#define AL_REVERB_DEFAULT_GAINHF                 (0.89f)
+
+#define AL_REVERB_MIN_DECAY_TIME                 (0.1f)
+#define AL_REVERB_MAX_DECAY_TIME                 (20.0f)
+#define AL_REVERB_DEFAULT_DECAY_TIME             (1.49f)
+
+#define AL_REVERB_MIN_DECAY_HFRATIO              (0.1f)
+#define AL_REVERB_MAX_DECAY_HFRATIO              (2.0f)
+#define AL_REVERB_DEFAULT_DECAY_HFRATIO          (0.83f)
+
+#define AL_REVERB_MIN_REFLECTIONS_GAIN           (0.0f)
+#define AL_REVERB_MAX_REFLECTIONS_GAIN           (3.16f)
+#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN       (0.05f)
+
+#define AL_REVERB_MIN_REFLECTIONS_DELAY          (0.0f)
+#define AL_REVERB_MAX_REFLECTIONS_DELAY          (0.3f)
+#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY      (0.007f)
+
+#define AL_REVERB_MIN_LATE_REVERB_GAIN           (0.0f)
+#define AL_REVERB_MAX_LATE_REVERB_GAIN           (10.0f)
+#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN       (1.26f)
+
+#define AL_REVERB_MIN_LATE_REVERB_DELAY          (0.0f)
+#define AL_REVERB_MAX_LATE_REVERB_DELAY          (0.1f)
+#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY      (0.011f)
+
+#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF      (0.892f)
+#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF      (1.0f)
+#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF  (0.994f)
+
+#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR        (0.0f)
+#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR        (10.0f)
+#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR    (0.0f)
+
+#define AL_REVERB_MIN_DECAY_HFLIMIT              AL_FALSE
+#define AL_REVERB_MAX_DECAY_HFLIMIT              AL_TRUE
+#define AL_REVERB_DEFAULT_DECAY_HFLIMIT          AL_TRUE
+
+/* EAX reverb effect */
+#define AL_EAXREVERB_MIN_DENSITY                 (0.0f)
+#define AL_EAXREVERB_MAX_DENSITY                 (1.0f)
+#define AL_EAXREVERB_DEFAULT_DENSITY             (1.0f)
+
+#define AL_EAXREVERB_MIN_DIFFUSION               (0.0f)
+#define AL_EAXREVERB_MAX_DIFFUSION               (1.0f)
+#define AL_EAXREVERB_DEFAULT_DIFFUSION           (1.0f)
+
+#define AL_EAXREVERB_MIN_GAIN                    (0.0f)
+#define AL_EAXREVERB_MAX_GAIN                    (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAIN                (0.32f)
+
+#define AL_EAXREVERB_MIN_GAINHF                  (0.0f)
+#define AL_EAXREVERB_MAX_GAINHF                  (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAINHF              (0.89f)
+
+#define AL_EAXREVERB_MIN_GAINLF                  (0.0f)
+#define AL_EAXREVERB_MAX_GAINLF                  (1.0f)
+#define AL_EAXREVERB_DEFAULT_GAINLF              (1.0f)
+
+#define AL_EAXREVERB_MIN_DECAY_TIME              (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_TIME              (20.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_TIME          (1.49f)
+
+#define AL_EAXREVERB_MIN_DECAY_HFRATIO           (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_HFRATIO           (2.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO       (0.83f)
+
+#define AL_EAXREVERB_MIN_DECAY_LFRATIO           (0.1f)
+#define AL_EAXREVERB_MAX_DECAY_LFRATIO           (2.0f)
+#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO       (1.0f)
+
+#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN        (0.0f)
+#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN        (3.16f)
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN    (0.05f)
+
+#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY       (0.0f)
+#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY       (0.3f)
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY   (0.007f)
+
+#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f)
+
+#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN        (0.0f)
+#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN        (10.0f)
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN    (1.26f)
+
+#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY       (0.0f)
+#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY       (0.1f)
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY   (0.011f)
+
+#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f)
+
+#define AL_EAXREVERB_MIN_ECHO_TIME               (0.075f)
+#define AL_EAXREVERB_MAX_ECHO_TIME               (0.25f)
+#define AL_EAXREVERB_DEFAULT_ECHO_TIME           (0.25f)
+
+#define AL_EAXREVERB_MIN_ECHO_DEPTH              (0.0f)
+#define AL_EAXREVERB_MAX_ECHO_DEPTH              (1.0f)
+#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH          (0.0f)
+
+#define AL_EAXREVERB_MIN_MODULATION_TIME         (0.04f)
+#define AL_EAXREVERB_MAX_MODULATION_TIME         (4.0f)
+#define AL_EAXREVERB_DEFAULT_MODULATION_TIME     (0.25f)
+
+#define AL_EAXREVERB_MIN_MODULATION_DEPTH        (0.0f)
+#define AL_EAXREVERB_MAX_MODULATION_DEPTH        (1.0f)
+#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH    (0.0f)
+
+#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF   (0.892f)
+#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF   (1.0f)
+#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f)
+
+#define AL_EAXREVERB_MIN_HFREFERENCE             (1000.0f)
+#define AL_EAXREVERB_MAX_HFREFERENCE             (20000.0f)
+#define AL_EAXREVERB_DEFAULT_HFREFERENCE         (5000.0f)
+
+#define AL_EAXREVERB_MIN_LFREFERENCE             (20.0f)
+#define AL_EAXREVERB_MAX_LFREFERENCE             (1000.0f)
+#define AL_EAXREVERB_DEFAULT_LFREFERENCE         (250.0f)
+
+#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR     (0.0f)
+#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR     (10.0f)
+#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f)
+
+#define AL_EAXREVERB_MIN_DECAY_HFLIMIT           AL_FALSE
+#define AL_EAXREVERB_MAX_DECAY_HFLIMIT           AL_TRUE
+#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT       AL_TRUE
+
+/* Chorus effect */
+#define AL_CHORUS_WAVEFORM_SINUSOID              (0)
+#define AL_CHORUS_WAVEFORM_TRIANGLE              (1)
+
+#define AL_CHORUS_MIN_WAVEFORM                   (0)
+#define AL_CHORUS_MAX_WAVEFORM                   (1)
+#define AL_CHORUS_DEFAULT_WAVEFORM               (1)
+
+#define AL_CHORUS_MIN_PHASE                      (-180)
+#define AL_CHORUS_MAX_PHASE                      (180)
+#define AL_CHORUS_DEFAULT_PHASE                  (90)
+
+#define AL_CHORUS_MIN_RATE                       (0.0f)
+#define AL_CHORUS_MAX_RATE                       (10.0f)
+#define AL_CHORUS_DEFAULT_RATE                   (1.1f)
+
+#define AL_CHORUS_MIN_DEPTH                      (0.0f)
+#define AL_CHORUS_MAX_DEPTH                      (1.0f)
+#define AL_CHORUS_DEFAULT_DEPTH                  (0.1f)
+
+#define AL_CHORUS_MIN_FEEDBACK                   (-1.0f)
+#define AL_CHORUS_MAX_FEEDBACK                   (1.0f)
+#define AL_CHORUS_DEFAULT_FEEDBACK               (0.25f)
+
+#define AL_CHORUS_MIN_DELAY                      (0.0f)
+#define AL_CHORUS_MAX_DELAY                      (0.016f)
+#define AL_CHORUS_DEFAULT_DELAY                  (0.016f)
+
+/* Distortion effect */
+#define AL_DISTORTION_MIN_EDGE                   (0.0f)
+#define AL_DISTORTION_MAX_EDGE                   (1.0f)
+#define AL_DISTORTION_DEFAULT_EDGE               (0.2f)
+
+#define AL_DISTORTION_MIN_GAIN                   (0.01f)
+#define AL_DISTORTION_MAX_GAIN                   (1.0f)
+#define AL_DISTORTION_DEFAULT_GAIN               (0.05f)
+
+#define AL_DISTORTION_MIN_LOWPASS_CUTOFF         (80.0f)
+#define AL_DISTORTION_MAX_LOWPASS_CUTOFF         (24000.0f)
+#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF     (8000.0f)
+
+#define AL_DISTORTION_MIN_EQCENTER               (80.0f)
+#define AL_DISTORTION_MAX_EQCENTER               (24000.0f)
+#define AL_DISTORTION_DEFAULT_EQCENTER           (3600.0f)
+
+#define AL_DISTORTION_MIN_EQBANDWIDTH            (80.0f)
+#define AL_DISTORTION_MAX_EQBANDWIDTH            (24000.0f)
+#define AL_DISTORTION_DEFAULT_EQBANDWIDTH        (3600.0f)
+
+/* Echo effect */
+#define AL_ECHO_MIN_DELAY                        (0.0f)
+#define AL_ECHO_MAX_DELAY                        (0.207f)
+#define AL_ECHO_DEFAULT_DELAY                    (0.1f)
+
+#define AL_ECHO_MIN_LRDELAY                      (0.0f)
+#define AL_ECHO_MAX_LRDELAY                      (0.404f)
+#define AL_ECHO_DEFAULT_LRDELAY                  (0.1f)
+
+#define AL_ECHO_MIN_DAMPING                      (0.0f)
+#define AL_ECHO_MAX_DAMPING                      (0.99f)
+#define AL_ECHO_DEFAULT_DAMPING                  (0.5f)
+
+#define AL_ECHO_MIN_FEEDBACK                     (0.0f)
+#define AL_ECHO_MAX_FEEDBACK                     (1.0f)
+#define AL_ECHO_DEFAULT_FEEDBACK                 (0.5f)
+
+#define AL_ECHO_MIN_SPREAD                       (-1.0f)
+#define AL_ECHO_MAX_SPREAD                       (1.0f)
+#define AL_ECHO_DEFAULT_SPREAD                   (-1.0f)
+
+/* Flanger effect */
+#define AL_FLANGER_WAVEFORM_SINUSOID             (0)
+#define AL_FLANGER_WAVEFORM_TRIANGLE             (1)
+
+#define AL_FLANGER_MIN_WAVEFORM                  (0)
+#define AL_FLANGER_MAX_WAVEFORM                  (1)
+#define AL_FLANGER_DEFAULT_WAVEFORM              (1)
+
+#define AL_FLANGER_MIN_PHASE                     (-180)
+#define AL_FLANGER_MAX_PHASE                     (180)
+#define AL_FLANGER_DEFAULT_PHASE                 (0)
+
+#define AL_FLANGER_MIN_RATE                      (0.0f)
+#define AL_FLANGER_MAX_RATE                      (10.0f)
+#define AL_FLANGER_DEFAULT_RATE                  (0.27f)
+
+#define AL_FLANGER_MIN_DEPTH                     (0.0f)
+#define AL_FLANGER_MAX_DEPTH                     (1.0f)
+#define AL_FLANGER_DEFAULT_DEPTH                 (1.0f)
+
+#define AL_FLANGER_MIN_FEEDBACK                  (-1.0f)
+#define AL_FLANGER_MAX_FEEDBACK                  (1.0f)
+#define AL_FLANGER_DEFAULT_FEEDBACK              (-0.5f)
+
+#define AL_FLANGER_MIN_DELAY                     (0.0f)
+#define AL_FLANGER_MAX_DELAY                     (0.004f)
+#define AL_FLANGER_DEFAULT_DELAY                 (0.002f)
+
+/* Frequency shifter effect */
+#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY       (0.0f)
+#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY       (24000.0f)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY   (0.0f)
+
+#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION  (0)
+#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION  (2)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0)
+
+#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN      (0)
+#define AL_FREQUENCY_SHIFTER_DIRECTION_UP        (1)
+#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF       (2)
+
+#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0)
+#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2)
+#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0)
+
+/* Vocal morpher effect */
+#define AL_VOCAL_MORPHER_MIN_PHONEMEA            (0)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEA            (29)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA        (0)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEB            (0)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEB            (29)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB        (10)
+
+#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24)
+#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24)
+#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0)
+
+#define AL_VOCAL_MORPHER_PHONEME_A               (0)
+#define AL_VOCAL_MORPHER_PHONEME_E               (1)
+#define AL_VOCAL_MORPHER_PHONEME_I               (2)
+#define AL_VOCAL_MORPHER_PHONEME_O               (3)
+#define AL_VOCAL_MORPHER_PHONEME_U               (4)
+#define AL_VOCAL_MORPHER_PHONEME_AA              (5)
+#define AL_VOCAL_MORPHER_PHONEME_AE              (6)
+#define AL_VOCAL_MORPHER_PHONEME_AH              (7)
+#define AL_VOCAL_MORPHER_PHONEME_AO              (8)
+#define AL_VOCAL_MORPHER_PHONEME_EH              (9)
+#define AL_VOCAL_MORPHER_PHONEME_ER              (10)
+#define AL_VOCAL_MORPHER_PHONEME_IH              (11)
+#define AL_VOCAL_MORPHER_PHONEME_IY              (12)
+#define AL_VOCAL_MORPHER_PHONEME_UH              (13)
+#define AL_VOCAL_MORPHER_PHONEME_UW              (14)
+#define AL_VOCAL_MORPHER_PHONEME_B               (15)
+#define AL_VOCAL_MORPHER_PHONEME_D               (16)
+#define AL_VOCAL_MORPHER_PHONEME_F               (17)
+#define AL_VOCAL_MORPHER_PHONEME_G               (18)
+#define AL_VOCAL_MORPHER_PHONEME_J               (19)
+#define AL_VOCAL_MORPHER_PHONEME_K               (20)
+#define AL_VOCAL_MORPHER_PHONEME_L               (21)
+#define AL_VOCAL_MORPHER_PHONEME_M               (22)
+#define AL_VOCAL_MORPHER_PHONEME_N               (23)
+#define AL_VOCAL_MORPHER_PHONEME_P               (24)
+#define AL_VOCAL_MORPHER_PHONEME_R               (25)
+#define AL_VOCAL_MORPHER_PHONEME_S               (26)
+#define AL_VOCAL_MORPHER_PHONEME_T               (27)
+#define AL_VOCAL_MORPHER_PHONEME_V               (28)
+#define AL_VOCAL_MORPHER_PHONEME_Z               (29)
+
+#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID       (0)
+#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE       (1)
+#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH       (2)
+
+#define AL_VOCAL_MORPHER_MIN_WAVEFORM            (0)
+#define AL_VOCAL_MORPHER_MAX_WAVEFORM            (2)
+#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM        (0)
+
+#define AL_VOCAL_MORPHER_MIN_RATE                (0.0f)
+#define AL_VOCAL_MORPHER_MAX_RATE                (10.0f)
+#define AL_VOCAL_MORPHER_DEFAULT_RATE            (1.41f)
+
+/* Pitch shifter effect */
+#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE         (-12)
+#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE         (12)
+#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE     (12)
+
+#define AL_PITCH_SHIFTER_MIN_FINE_TUNE           (-50)
+#define AL_PITCH_SHIFTER_MAX_FINE_TUNE           (50)
+#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE       (0)
+
+/* Ring modulator effect */
+#define AL_RING_MODULATOR_MIN_FREQUENCY          (0.0f)
+#define AL_RING_MODULATOR_MAX_FREQUENCY          (8000.0f)
+#define AL_RING_MODULATOR_DEFAULT_FREQUENCY      (440.0f)
+
+#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF    (0.0f)
+#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF    (24000.0f)
+#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f)
+
+#define AL_RING_MODULATOR_SINUSOID               (0)
+#define AL_RING_MODULATOR_SAWTOOTH               (1)
+#define AL_RING_MODULATOR_SQUARE                 (2)
+
+#define AL_RING_MODULATOR_MIN_WAVEFORM           (0)
+#define AL_RING_MODULATOR_MAX_WAVEFORM           (2)
+#define AL_RING_MODULATOR_DEFAULT_WAVEFORM       (0)
+
+/* Autowah effect */
+#define AL_AUTOWAH_MIN_ATTACK_TIME               (0.0001f)
+#define AL_AUTOWAH_MAX_ATTACK_TIME               (1.0f)
+#define AL_AUTOWAH_DEFAULT_ATTACK_TIME           (0.06f)
+
+#define AL_AUTOWAH_MIN_RELEASE_TIME              (0.0001f)
+#define AL_AUTOWAH_MAX_RELEASE_TIME              (1.0f)
+#define AL_AUTOWAH_DEFAULT_RELEASE_TIME          (0.06f)
+
+#define AL_AUTOWAH_MIN_RESONANCE                 (2.0f)
+#define AL_AUTOWAH_MAX_RESONANCE                 (1000.0f)
+#define AL_AUTOWAH_DEFAULT_RESONANCE             (1000.0f)
+
+#define AL_AUTOWAH_MIN_PEAK_GAIN                 (0.00003f)
+#define AL_AUTOWAH_MAX_PEAK_GAIN                 (31621.0f)
+#define AL_AUTOWAH_DEFAULT_PEAK_GAIN             (11.22f)
+
+/* Compressor effect */
+#define AL_COMPRESSOR_MIN_ONOFF                  (0)
+#define AL_COMPRESSOR_MAX_ONOFF                  (1)
+#define AL_COMPRESSOR_DEFAULT_ONOFF              (1)
+
+/* Equalizer effect */
+#define AL_EQUALIZER_MIN_LOW_GAIN                (0.126f)
+#define AL_EQUALIZER_MAX_LOW_GAIN                (7.943f)
+#define AL_EQUALIZER_DEFAULT_LOW_GAIN            (1.0f)
+
+#define AL_EQUALIZER_MIN_LOW_CUTOFF              (50.0f)
+#define AL_EQUALIZER_MAX_LOW_CUTOFF              (800.0f)
+#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF          (200.0f)
+
+#define AL_EQUALIZER_MIN_MID1_GAIN               (0.126f)
+#define AL_EQUALIZER_MAX_MID1_GAIN               (7.943f)
+#define AL_EQUALIZER_DEFAULT_MID1_GAIN           (1.0f)
+
+#define AL_EQUALIZER_MIN_MID1_CENTER             (200.0f)
+#define AL_EQUALIZER_MAX_MID1_CENTER             (3000.0f)
+#define AL_EQUALIZER_DEFAULT_MID1_CENTER         (500.0f)
+
+#define AL_EQUALIZER_MIN_MID1_WIDTH              (0.01f)
+#define AL_EQUALIZER_MAX_MID1_WIDTH              (1.0f)
+#define AL_EQUALIZER_DEFAULT_MID1_WIDTH          (1.0f)
+
+#define AL_EQUALIZER_MIN_MID2_GAIN               (0.126f)
+#define AL_EQUALIZER_MAX_MID2_GAIN               (7.943f)
+#define AL_EQUALIZER_DEFAULT_MID2_GAIN           (1.0f)
+
+#define AL_EQUALIZER_MIN_MID2_CENTER             (1000.0f)
+#define AL_EQUALIZER_MAX_MID2_CENTER             (8000.0f)
+#define AL_EQUALIZER_DEFAULT_MID2_CENTER         (3000.0f)
+
+#define AL_EQUALIZER_MIN_MID2_WIDTH              (0.01f)
+#define AL_EQUALIZER_MAX_MID2_WIDTH              (1.0f)
+#define AL_EQUALIZER_DEFAULT_MID2_WIDTH          (1.0f)
+
+#define AL_EQUALIZER_MIN_HIGH_GAIN               (0.126f)
+#define AL_EQUALIZER_MAX_HIGH_GAIN               (7.943f)
+#define AL_EQUALIZER_DEFAULT_HIGH_GAIN           (1.0f)
+
+#define AL_EQUALIZER_MIN_HIGH_CUTOFF             (4000.0f)
+#define AL_EQUALIZER_MAX_HIGH_CUTOFF             (16000.0f)
+#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF         (6000.0f)
+
+
+/* Source parameter value ranges and defaults. */
+#define AL_MIN_AIR_ABSORPTION_FACTOR             (0.0f)
+#define AL_MAX_AIR_ABSORPTION_FACTOR             (10.0f)
+#define AL_DEFAULT_AIR_ABSORPTION_FACTOR         (0.0f)
+
+#define AL_MIN_ROOM_ROLLOFF_FACTOR               (0.0f)
+#define AL_MAX_ROOM_ROLLOFF_FACTOR               (10.0f)
+#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR           (0.0f)
+
+#define AL_MIN_CONE_OUTER_GAINHF                 (0.0f)
+#define AL_MAX_CONE_OUTER_GAINHF                 (1.0f)
+#define AL_DEFAULT_CONE_OUTER_GAINHF             (1.0f)
+
+#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO         AL_FALSE
+#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO         AL_TRUE
+#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO     AL_TRUE
+
+#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO   AL_FALSE
+#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO   AL_TRUE
+#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE
+
+#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE
+#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
+#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE
+
+
+/* Listener parameter value ranges and defaults. */
+#define AL_MIN_METERS_PER_UNIT                   FLT_MIN
+#define AL_MAX_METERS_PER_UNIT                   FLT_MAX
+#define AL_DEFAULT_METERS_PER_UNIT               (1.0f)
+
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif /* AL_EFX_H */
diff --git a/openal-soft.manifest b/openal-soft.manifest
new file mode 100755 (executable)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/openal.pc.in b/openal.pc.in
new file mode 100755 (executable)
index 0000000..eaa18e5
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: OpenAL
+Description: OpenAL is a cross-platform 3D audio API
+Requires: @PKG_CONFIG_REQUIRES@
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -l@LIBNAME@ @PKG_CONFIG_LIBS@
+Cflags: -I${includedir} @PKG_CONFIG_CFLAGS@
diff --git a/packaging/openal-soft.spec b/packaging/openal-soft.spec
new file mode 100755 (executable)
index 0000000..8637b42
--- /dev/null
@@ -0,0 +1,65 @@
+Name:       openal-soft
+Summary:    OpenAL library software implementation
+Version:    1.13
+Release:    6
+Group:      Multimedia/openal-soft
+License:    LGPLv2+ 
+Source0:    %{name}-%{version}.tar.gz
+BuildRequires: cmake
+BuildRequires: pkgconfig(avsysaudio)
+BuildRequires: pkgconfig(mm-session)
+BuildRequires: pkgconfig(audio-session-mgr)
+BuildRequires: pkgconfig(vconf)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+
+%description
+OpenAL library software implementation
+
+
+
+%package devel
+Summary:    OpenAL library software implementation (devel)
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+OpenAL library software implementation development package
+
+
+%prep
+%setup -q
+
+%build
+
+%ifarch %arm
+export CFLAGS+=" -DARM_ARCH -O3 -ftree-vectorize -ffast-math -fsingle-precision-constant -DUSE_DLOG "
+%else
+export CFLAGS+=" -DI386_ARCH "
+%endif
+
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+
+
+%files
+%manifest openal-soft.manifest
+%{_libdir}/*.so*
+%{_bindir}/*
+/etc/openal/alsoft.conf
+
+%files devel
+%{_includedir}/*
+%{_libdir}/pkgconfig/*
+
diff --git a/utils/openal-info.c b/utils/openal-info.c
new file mode 100644 (file)
index 0000000..586a1c7
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * OpenAL Info Utility
+ *
+ * Copyright (c) 2010 by Chris Robinson <chris.kcat@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "AL/alc.h"
+#include "AL/al.h"
+#include "AL/alext.h"
+
+#ifndef ALC_ENUMERATE_ALL_EXT
+#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER        0x1012
+#define ALC_ALL_DEVICES_SPECIFIER                0x1013
+#endif
+
+#ifndef ALC_EXT_EFX
+#define ALC_EFX_MAJOR_VERSION                    0x20001
+#define ALC_EFX_MINOR_VERSION                    0x20002
+#define ALC_MAX_AUXILIARY_SENDS                  0x20003
+#define AL_FILTER_TYPE                           0x8001
+#define AL_FILTER_NULL                           0x0000
+#define AL_FILTER_LOWPASS                        0x0001
+#define AL_FILTER_HIGHPASS                       0x0002
+#define AL_FILTER_BANDPASS                       0x0003
+#define AL_EFFECT_TYPE                           0x8001
+#define AL_EFFECT_NULL                           0x0000
+#define AL_EFFECT_EAXREVERB                      0x8000
+#define AL_EFFECT_REVERB                         0x0001
+#define AL_EFFECT_CHORUS                         0x0002
+#define AL_EFFECT_DISTORTION                     0x0003
+#define AL_EFFECT_ECHO                           0x0004
+#define AL_EFFECT_FLANGER                        0x0005
+#define AL_EFFECT_FREQUENCY_SHIFTER              0x0006
+#define AL_EFFECT_VOCAL_MORPHER                  0x0007
+#define AL_EFFECT_PITCH_SHIFTER                  0x0008
+#define AL_EFFECT_RING_MODULATOR                 0x0009
+#define AL_EFFECT_AUTOWAH                        0x000A
+#define AL_EFFECT_COMPRESSOR                     0x000B
+#define AL_EFFECT_EQUALIZER                      0x000C
+typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint);
+typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, ALuint*);
+typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint);
+#endif
+static LPALGENFILTERS    palGenFilters;
+static LPALDELETEFILTERS palDeleteFilters;
+static LPALFILTERI       palFilteri;
+static LPALGENEFFECTS    palGenEffects;
+static LPALDELETEEFFECTS palDeleteEffects;
+static LPALEFFECTI       palEffecti;
+
+
+#define MAX_WIDTH  80
+
+static void printList(const char *list, char separator)
+{
+    size_t col = MAX_WIDTH, len;
+    const char *indent = "    ";
+    const char *next;
+
+    if(!list || *list == '\0')
+    {
+        fprintf(stdout, "\n%s!!! none !!!\n", indent);
+        return;
+    }
+
+    do {
+        next = strchr(list, separator);
+        if(next)
+        {
+            len = next-list;
+            do {
+                next++;
+            } while(*next == separator);
+        }
+        else
+            len = strlen(list);
+
+        if(len + col + 2 >= MAX_WIDTH)
+        {
+            fprintf(stdout, "\n%s", indent);
+            col = strlen(indent);
+        }
+        else
+        {
+            fputc(' ', stdout);
+            col++;
+        }
+
+        len = fwrite(list, 1, len, stdout);
+        col += len;
+
+        if(!next || *next == '\0')
+            break;
+        fputc(',', stdout);
+        col++;
+
+        list = next;
+    } while(1);
+    fputc('\n', stdout);
+}
+
+static void printDeviceList(const char *list)
+{
+    if(!list || *list == '\0')
+        printf("    !!! none !!!\n");
+    else do {
+        printf("    %s\n", list);
+        list += strlen(list) + 1;
+    } while(*list != '\0');
+}
+
+
+static ALenum checkALErrors(int linenum)
+{
+    ALenum err = alGetError();
+    if(err != AL_NO_ERROR)
+        printf("OpenAL Error: %s (0x%x), @ %d\n", alGetString(err), err, linenum);
+    return err;
+}
+#define checkALErrors() checkALErrors(__LINE__)
+
+static ALCenum checkALCErrors(ALCdevice *device, int linenum)
+{
+    ALCenum err = alcGetError(device);
+    if(err != ALC_NO_ERROR)
+        printf("ALC Error: %s (0x%x), @ %d\n", alcGetString(device, err), err, linenum);
+    return err;
+}
+#define checkALCErrors(x) checkALCErrors((x),__LINE__)
+
+
+static void printALCInfo(ALCdevice *device)
+{
+    ALCint major, minor;
+
+    alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
+    alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
+    if(checkALCErrors(device) == ALC_NO_ERROR)
+        printf("ALC version: %d.%d\n", major, minor);
+    if(device)
+    {
+        printf("ALC extensions:");
+        printList(alcGetString(device, ALC_EXTENSIONS), ' ');
+        checkALCErrors(device);
+    }
+}
+
+static void printALInfo(void)
+{
+    printf("OpenAL vendor string: %s\n", alGetString(AL_VENDOR));
+    printf("OpenAL renderer string: %s\n", alGetString(AL_RENDERER));
+    printf("OpenAL version string: %s\n", alGetString(AL_VERSION));
+    printf("OpenAL extensions:");
+    printList(alGetString(AL_EXTENSIONS), ' ');
+    checkALErrors();
+}
+
+static void printEFXInfo(ALCdevice *device)
+{
+    ALCint major, minor, sends;
+    ALuint obj;
+    int i;
+    const ALenum filters[] = {
+        AL_FILTER_LOWPASS, AL_FILTER_HIGHPASS, AL_FILTER_BANDPASS,
+        AL_FILTER_NULL
+    };
+    char filterNames[] = "Low-pass,High-pass,Band-pass,";
+    const ALenum effects[] = {
+        AL_EFFECT_EAXREVERB, AL_EFFECT_REVERB, AL_EFFECT_CHORUS,
+        AL_EFFECT_DISTORTION, AL_EFFECT_ECHO, AL_EFFECT_FLANGER,
+        AL_EFFECT_FREQUENCY_SHIFTER, AL_EFFECT_VOCAL_MORPHER,
+        AL_EFFECT_PITCH_SHIFTER, AL_EFFECT_RING_MODULATOR, AL_EFFECT_AUTOWAH,
+        AL_EFFECT_COMPRESSOR, AL_EFFECT_EQUALIZER, AL_EFFECT_NULL
+    };
+    char effectNames[] = "EAX Reverb,Reverb,Chorus,Distortion,Echo,Flanger,"
+                         "Frequency Shifter,Vocal Morpher,Pitch Shifter,"
+                         "Ring Modulator,Autowah,Compressor,Equalizer,";
+    char *current;
+
+    if(alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_FALSE)
+    {
+        printf("EFX not available\n");
+        return;
+    }
+
+    alcGetIntegerv(device, ALC_EFX_MAJOR_VERSION, 1, &major);
+    alcGetIntegerv(device, ALC_EFX_MINOR_VERSION, 1, &minor);
+    if(checkALCErrors(device) == ALC_NO_ERROR)
+        printf("EFX version: %d.%d\n", major, minor);
+    alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &sends);
+    if(checkALCErrors(device) == ALC_NO_ERROR)
+        printf("Max auxiliary sends: %d\n", sends);
+
+    palGenFilters = alGetProcAddress("alGenFilters");
+    palDeleteFilters = alGetProcAddress("alDeleteFilters");
+    palFilteri = alGetProcAddress("alFilteri");
+    palGenEffects = alGetProcAddress("alGenEffects");
+    palDeleteEffects = alGetProcAddress("alDeleteEffects");
+    palEffecti = alGetProcAddress("alEffecti");
+    if(checkALErrors() != AL_NO_ERROR ||
+       !palGenFilters || !palDeleteFilters || !palFilteri ||
+       !palGenEffects || !palDeleteEffects || !palEffecti)
+    {
+        printf("!!! Missing EFX functions !!!\n");
+        return;
+    }
+
+    palGenFilters(1, &obj);
+    if(checkALErrors() == AL_NO_ERROR)
+    {
+        current = filterNames;
+        for(i = 0;filters[i] != AL_FILTER_NULL;i++)
+        {
+            char *next = strchr(current, ',');
+
+            palFilteri(obj, AL_FILTER_TYPE, filters[i]);
+            if(alGetError() == AL_NO_ERROR)
+                current = next+1;
+            else
+                memmove(current, next+1, strlen(next));
+        }
+        palDeleteFilters(1, &obj);
+        checkALErrors();
+
+        printf("Supported filters:");
+        printList(filterNames, ',');
+    }
+
+    palGenEffects(1, &obj);
+    if(checkALErrors() == AL_NO_ERROR)
+    {
+        current = effectNames;
+        for(i = 0;effects[i] != AL_EFFECT_NULL;i++)
+        {
+            char *next = strchr(current, ',');
+
+            palEffecti(obj, AL_EFFECT_TYPE, effects[i]);
+            if(alGetError() == AL_NO_ERROR)
+                current = next+1;
+            else
+                memmove(current, next+1, strlen(next));
+        }
+        palDeleteEffects(1, &obj);
+        checkALErrors();
+
+        printf("Supported effects:");
+        printList(effectNames, ',');
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    ALCdevice *device;
+    ALCcontext *context;
+
+    if(argc > 1 && (strcmp(argv[1], "--help") == 0 ||
+                    strcmp(argv[1], "-h") == 0))
+    {
+        printf("Usage: %s [playback device]\n", argv[0]);
+        return 0;
+    }
+
+    printf("Available playback devices:\n");
+    if(alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
+        printDeviceList(alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER));
+    else
+        printDeviceList(alcGetString(NULL, ALC_DEVICE_SPECIFIER));
+    printf("Available capture devices:\n");
+    printDeviceList(alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER));
+
+    printf("Default playback device: %s\n",
+           alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER));
+    printf("Default capture device: %s\n",
+           alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER));
+
+    printALCInfo(NULL);
+
+    device = alcOpenDevice((argc>1) ? argv[1] : NULL);
+    if(!device)
+    {
+        printf("\n!!! Failed to open %s !!!\n\n", ((argc>1) ? argv[1] : "default device"));
+        return 1;
+    }
+
+    printf("\n** Info for device \"%s\" **\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
+    printALCInfo(device);
+
+    context = alcCreateContext(device, NULL);
+    if(!context || alcMakeContextCurrent(context) == ALC_FALSE)
+    {
+        if(context)
+            alcDestroyContext(context);
+        alcCloseDevice(device);
+        printf("\n!!! Failed to set a context !!!\n\n");
+        return 1;
+    }
+
+    printALInfo();
+    printEFXInfo(device);
+
+    alcMakeContextCurrent(NULL);
+    alcDestroyContext(context);
+    alcCloseDevice(device);
+
+    return 0;
+}