summaryrefslogtreecommitdiffstats
path: root/src/audio/oal
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio/oal')
-rw-r--r--src/audio/oal/aldlist.cpp329
-rw-r--r--src/audio/oal/aldlist.h49
-rw-r--r--src/audio/oal/channel.cpp210
-rw-r--r--src/audio/oal/channel.h51
-rw-r--r--src/audio/oal/oal_utils.cpp169
-rw-r--r--src/audio/oal/oal_utils.h48
-rw-r--r--src/audio/oal/stream.cpp520
-rw-r--r--src/audio/oal/stream.h112
8 files changed, 1488 insertions, 0 deletions
diff --git a/src/audio/oal/aldlist.cpp b/src/audio/oal/aldlist.cpp
new file mode 100644
index 00000000..2c2f13a8
--- /dev/null
+++ b/src/audio/oal/aldlist.cpp
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2006, Creative Labs Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of conditions and
+ * the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
+ * promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "aldlist.h"
+#ifdef AUDIO_OAL
+/*
+ * Init call
+ */
+ALDeviceList::ALDeviceList()
+{
+ ALDEVICEINFO ALDeviceInfo;
+ char *devices;
+ int index;
+ const char *defaultDeviceName;
+ const char *actualDeviceName;
+
+ // DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support
+ vDeviceInfo.empty();
+ vDeviceInfo.reserve(10);
+
+ defaultDeviceIndex = 0;
+
+ if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) {
+ devices = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
+ defaultDeviceName = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
+
+ index = 0;
+ // go through device list (each device terminated with a single NULL, list terminated with double NULL)
+ while (*devices != NULL) {
+ if (strcmp(defaultDeviceName, devices) == 0) {
+ defaultDeviceIndex = index;
+ }
+ ALCdevice *device = alcOpenDevice(devices);
+ if (device) {
+ ALCcontext *context = alcCreateContext(device, NULL);
+ if (context) {
+ alcMakeContextCurrent(context);
+ // if new actual device name isn't already in the list, then add it...
+ actualDeviceName = alcGetString(device, ALC_DEVICE_SPECIFIER);
+ bool bNewName = true;
+ for (int i = 0; i < GetNumDevices(); i++) {
+ if (strcmp(GetDeviceName(i), actualDeviceName) == 0) {
+ bNewName = false;
+ }
+ }
+ if ((bNewName) && (actualDeviceName != NULL) && (strlen(actualDeviceName) > 0)) {
+ memset(&ALDeviceInfo, 0, sizeof(ALDEVICEINFO));
+ ALDeviceInfo.bSelected = true;
+ ALDeviceInfo.strDeviceName = std::string(actualDeviceName, strlen(actualDeviceName));
+ alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(int), &ALDeviceInfo.iMajorVersion);
+ alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(int), &ALDeviceInfo.iMinorVersion);
+
+ ALDeviceInfo.pvstrExtensions = new std::vector<std::string>;
+
+ // Check for ALC Extensions
+ if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_CAPTURE");
+ if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("ALC_EXT_EFX");
+
+ // Check for AL Extensions
+ if (alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_OFFSET");
+
+ if (alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_LINEAR_DISTANCE");
+ if (alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("AL_EXT_EXPONENT_DISTANCE");
+
+ if (alIsExtensionPresent("EAX2.0") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("EAX2.0");
+ if (alIsExtensionPresent("EAX3.0") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("EAX3.0");
+ if (alIsExtensionPresent("EAX4.0") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("EAX4.0");
+ if (alIsExtensionPresent("EAX5.0") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("EAX5.0");
+
+ if (alIsExtensionPresent("EAX-RAM") == AL_TRUE)
+ ALDeviceInfo.pvstrExtensions->push_back("EAX-RAM");
+
+ // Get Source Count
+ ALDeviceInfo.uiSourceCount = GetMaxNumSources();
+
+ vDeviceInfo.push_back(ALDeviceInfo);
+ }
+ alcMakeContextCurrent(NULL);
+ alcDestroyContext(context);
+ }
+ alcCloseDevice(device);
+ }
+ devices += strlen(devices) + 1;
+ index += 1;
+ }
+ }
+
+ ResetFilters();
+}
+
+/*
+ * Exit call
+ */
+ALDeviceList::~ALDeviceList()
+{
+ for (unsigned int i = 0; i < vDeviceInfo.size(); i++) {
+ if (vDeviceInfo[i].pvstrExtensions) {
+ vDeviceInfo[i].pvstrExtensions->empty();
+ delete vDeviceInfo[i].pvstrExtensions;
+ }
+ }
+
+ vDeviceInfo.empty();
+}
+
+/*
+ * Returns the number of devices in the complete device list
+ */
+int ALDeviceList::GetNumDevices()
+{
+ return (int)vDeviceInfo.size();
+}
+
+/*
+ * Returns the device name at an index in the complete device list
+ */
+char * ALDeviceList::GetDeviceName(int index)
+{
+ if (index < GetNumDevices())
+ return (char *)vDeviceInfo[index].strDeviceName.c_str();
+ else
+ return NULL;
+}
+
+/*
+ * Returns the major and minor version numbers for a device at a specified index in the complete list
+ */
+void ALDeviceList::GetDeviceVersion(int index, int *major, int *minor)
+{
+ if (index < GetNumDevices()) {
+ if (major)
+ *major = vDeviceInfo[index].iMajorVersion;
+ if (minor)
+ *minor = vDeviceInfo[index].iMinorVersion;
+ }
+ return;
+}
+
+/*
+ * Returns the maximum number of Sources that can be generate on the given device
+ */
+unsigned int ALDeviceList::GetMaxNumSources(int index)
+{
+ if (index < GetNumDevices())
+ return vDeviceInfo[index].uiSourceCount;
+ else
+ return 0;
+}
+
+/*
+ * Checks if the extension is supported on the given device
+ */
+bool ALDeviceList::IsExtensionSupported(int index, char *szExtName)
+{
+ bool bReturn = false;
+
+ if (index < GetNumDevices()) {
+ for (unsigned int i = 0; i < vDeviceInfo[index].pvstrExtensions->size(); i++) {
+ if (!_stricmp(vDeviceInfo[index].pvstrExtensions->at(i).c_str(), szExtName)) {
+ bReturn = true;
+ break;
+ }
+ }
+ }
+
+ return bReturn;
+}
+
+/*
+ * returns the index of the default device in the complete device list
+ */
+int ALDeviceList::GetDefaultDevice()
+{
+ return defaultDeviceIndex;
+}
+
+/*
+ * Deselects devices which don't have the specified minimum version
+ */
+void ALDeviceList::FilterDevicesMinVer(int major, int minor)
+{
+ int dMajor, dMinor;
+ for (unsigned int i = 0; i < vDeviceInfo.size(); i++) {
+ GetDeviceVersion(i, &dMajor, &dMinor);
+ if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) {
+ vDeviceInfo[i].bSelected = false;
+ }
+ }
+}
+
+/*
+ * Deselects devices which don't have the specified maximum version
+ */
+void ALDeviceList::FilterDevicesMaxVer(int major, int minor)
+{
+ int dMajor, dMinor;
+ for (unsigned int i = 0; i < vDeviceInfo.size(); i++) {
+ GetDeviceVersion(i, &dMajor, &dMinor);
+ if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) {
+ vDeviceInfo[i].bSelected = false;
+ }
+ }
+}
+
+/*
+ * Deselects device which don't support the given extension name
+ */
+void ALDeviceList::FilterDevicesExtension(char *szExtName)
+{
+ bool bFound;
+
+ for (unsigned int i = 0; i < vDeviceInfo.size(); i++) {
+ bFound = false;
+ for (unsigned int j = 0; j < vDeviceInfo[i].pvstrExtensions->size(); j++) {
+ if (!_stricmp(vDeviceInfo[i].pvstrExtensions->at(j).c_str(), szExtName)) {
+ bFound = true;
+ break;
+ }
+ }
+ if (!bFound)
+ vDeviceInfo[i].bSelected = false;
+ }
+}
+
+/*
+ * Resets all filtering, such that all devices are in the list
+ */
+void ALDeviceList::ResetFilters()
+{
+ for (int i = 0; i < GetNumDevices(); i++) {
+ vDeviceInfo[i].bSelected = true;
+ }
+ filterIndex = 0;
+}
+
+/*
+ * Gets index of first filtered device
+ */
+int ALDeviceList::GetFirstFilteredDevice()
+{
+ int i;
+
+ for (i = 0; i < GetNumDevices(); i++) {
+ if (vDeviceInfo[i].bSelected == true) {
+ break;
+ }
+ }
+ filterIndex = i + 1;
+ return i;
+}
+
+/*
+ * Gets index of next filtered device
+ */
+int ALDeviceList::GetNextFilteredDevice()
+{
+ int i;
+
+ for (i = filterIndex; i < GetNumDevices(); i++) {
+ if (vDeviceInfo[i].bSelected == true) {
+ break;
+ }
+ }
+ filterIndex = i + 1;
+ return i;
+}
+
+/*
+ * Internal function to detemine max number of Sources that can be generated
+ */
+unsigned int ALDeviceList::GetMaxNumSources()
+{
+ ALuint uiSources[256];
+ unsigned int iSourceCount = 0;
+
+ // Clear AL Error Code
+ alGetError();
+
+ // Generate up to 256 Sources, checking for any errors
+ for (iSourceCount = 0; iSourceCount < 256; iSourceCount++)
+ {
+ alGenSources(1, &uiSources[iSourceCount]);
+ if (alGetError() != AL_NO_ERROR)
+ break;
+ }
+
+ // Release the Sources
+ alDeleteSources(iSourceCount, uiSources);
+ if (alGetError() != AL_NO_ERROR)
+ {
+ for (unsigned int i = 0; i < 256; i++)
+ {
+ alDeleteSources(1, &uiSources[i]);
+ }
+ }
+
+ return iSourceCount;
+}
+#endif \ No newline at end of file
diff --git a/src/audio/oal/aldlist.h b/src/audio/oal/aldlist.h
new file mode 100644
index 00000000..b8f1b31a
--- /dev/null
+++ b/src/audio/oal/aldlist.h
@@ -0,0 +1,49 @@
+#ifndef ALDEVICELIST_H
+#define ALDEVICELIST_H
+
+#include "oal_utils.h"
+
+#ifdef AUDIO_OAL
+#pragma warning(disable: 4786) //disable warning "identifier was truncated to '255' characters in the browser information"
+#include <vector>
+#include <string>
+
+typedef struct
+{
+ std::string strDeviceName;
+ int iMajorVersion;
+ int iMinorVersion;
+ unsigned int uiSourceCount;
+ std::vector<std::string> *pvstrExtensions;
+ bool bSelected;
+} ALDEVICEINFO, *LPALDEVICEINFO;
+
+class ALDeviceList
+{
+private:
+ std::vector<ALDEVICEINFO> vDeviceInfo;
+ int defaultDeviceIndex;
+ int filterIndex;
+
+public:
+ ALDeviceList ();
+ ~ALDeviceList ();
+ int GetNumDevices();
+ char *GetDeviceName(int index);
+ void GetDeviceVersion(int index, int *major, int *minor);
+ unsigned int GetMaxNumSources(int index);
+ bool IsExtensionSupported(int index, char *szExtName);
+ int GetDefaultDevice();
+ void FilterDevicesMinVer(int major, int minor);
+ void FilterDevicesMaxVer(int major, int minor);
+ void FilterDevicesExtension(char *szExtName);
+ void ResetFilters();
+ int GetFirstFilteredDevice();
+ int GetNextFilteredDevice();
+
+private:
+ unsigned int GetMaxNumSources();
+};
+#endif
+
+#endif // ALDEVICELIST_H \ No newline at end of file
diff --git a/src/audio/oal/channel.cpp b/src/audio/oal/channel.cpp
new file mode 100644
index 00000000..7742a06a
--- /dev/null
+++ b/src/audio/oal/channel.cpp
@@ -0,0 +1,210 @@
+#include "channel.h"
+
+#ifdef AUDIO_OAL
+#include "common.h"
+#include "sampman.h"
+
+extern bool IsFXSupported();
+
+CChannel::CChannel()
+{
+ alSource = AL_NONE;
+ alFilter = AL_FILTER_NULL;
+ SetDefault();
+}
+
+void CChannel::SetDefault()
+{
+ alBuffer = AL_NONE;
+
+ Pitch = 1.0f;
+ Gain = 1.0f;
+ Mix = 0.0f;
+
+ Position[0] = 0.0f; Position[1] = 0.0f; Position[2] = 0.0f;
+ Distances[0] = 0.0f; Distances[1] = FLT_MAX;
+ LoopCount = 1;
+ LoopPoints[0] = 0; LoopPoints[1] = -1;
+
+ Frequency = MAX_FREQ;
+}
+
+void CChannel::Reset()
+{
+ ClearBuffer();
+ SetDefault();
+}
+
+void CChannel::Init(bool Is2D)
+{
+ ASSERT(!HasSource());
+ alGenSources(1, &alSource);
+ if ( HasSource() )
+ {
+ alSourcei(alSource, AL_SOURCE_RELATIVE, AL_TRUE);
+ if ( IsFXSupported() )
+ alSource3i(alSource, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
+
+ if ( Is2D )
+ {
+ alSource3f(alSource, AL_POSITION, 0.0f, 0.0f, 0.0f);
+ alSourcef (alSource, AL_GAIN, 1.0f);
+ }
+ else
+ {
+ if ( IsFXSupported() )
+ alGenFilters(1,&alFilter);
+ }
+ }
+}
+
+void CChannel::Term()
+{
+ Stop();
+ if ( HasSource() )
+ {
+ if ( IsFXSupported() )
+ {
+ alSource3i(alSource, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
+
+ if(alFilter != AL_FILTER_NULL)
+ alDeleteFilters(1,&alFilter);
+ }
+
+ alDeleteSources(1, &alSource);
+ }
+ alSource = AL_NONE;
+ alFilter = AL_FILTER_NULL;
+}
+
+void CChannel::Start()
+{
+ if ( !HasSource() ) return;
+
+ if ( LoopPoints[0] != 0 && LoopPoints[0] != -1 )
+ alBufferiv(alBuffer, AL_LOOP_POINTS_SOFT, LoopPoints);
+ alSourcei (alSource, AL_BUFFER, alBuffer);
+ alSourcePlay(alSource);
+}
+
+void CChannel::Stop()
+{
+ if ( HasSource() )
+ alSourceStop(alSource);
+
+ Reset();
+}
+
+bool CChannel::HasSource()
+{
+ return alSource != AL_NONE;
+}
+
+bool CChannel::IsUsed()
+{
+ if ( HasSource() )
+ {
+ ALint sourceState;
+ alGetSourcei(alSource, AL_SOURCE_STATE, &sourceState);
+ return sourceState == AL_PLAYING;
+ }
+ return false;
+}
+
+void CChannel::SetPitch(float pitch)
+{
+ if ( !HasSource() ) return;
+ alSourcef(alSource, AL_PITCH, pitch);
+}
+
+void CChannel::SetGain(float gain)
+{
+ if ( !HasSource() ) return;
+ alSourcef(alSource, AL_GAIN, gain);
+}
+
+void CChannel::SetVolume(int32 vol)
+{
+ SetGain(ALfloat(vol) / MAX_VOLUME);
+}
+
+void CChannel::SetSampleID(uint32 nSfx)
+{
+ Sample = nSfx;
+}
+
+void CChannel::SetFreq(int32 freq)
+{
+ Frequency = freq;
+}
+
+void CChannel::SetCurrentFreq(uint32 freq)
+{
+ SetPitch(ALfloat(freq) / Frequency);
+}
+
+void CChannel::SetLoopCount(int32 loopCount) // fake. TODO:
+{
+ if ( !HasSource() ) return;
+ alSourcei(alSource, AL_LOOPING, loopCount == 1 ? AL_FALSE : AL_TRUE);
+}
+
+void CChannel::SetLoopPoints(ALint start, ALint end)
+{
+ LoopPoints[0] = start;
+ LoopPoints[1] = end;
+}
+
+void CChannel::SetPosition(float x, float y, float z)
+{
+ if ( !HasSource() ) return;
+ alSource3f(alSource, AL_POSITION, x, y, z);
+}
+
+void CChannel::SetDistances(float max, float min)
+{
+ if ( !HasSource() ) return;
+ alSourcef (alSource, AL_MAX_DISTANCE, max);
+ alSourcef (alSource, AL_REFERENCE_DISTANCE, min);
+ alSourcef (alSource, AL_MAX_GAIN, 1.0f);
+ alSourcef (alSource, AL_ROLLOFF_FACTOR, 1.0f);
+}
+
+void CChannel::SetPan(uint32 pan)
+{
+ SetPosition((pan-63)/64.0f, 0.0f, Sqrt(1.0f-SQR((pan-63)/64.0f)));
+}
+
+void CChannel::SetBuffer(ALuint buffer)
+{
+ alBuffer = buffer;
+}
+
+void CChannel::ClearBuffer()
+{
+ if ( !HasSource() ) return;
+ SetBuffer(AL_NONE);
+ alSourcei(alSource, AL_BUFFER, AL_NONE);
+}
+
+void CChannel::SetReverbMix(ALuint slot, float mix)
+{
+ if ( !IsFXSupported() ) return;
+ if ( !HasSource() ) return;
+ if ( alFilter == AL_FILTER_NULL ) return;
+
+ Mix = mix;
+ EAX3_SetReverbMix(alFilter, mix);
+ alSource3i(alSource, AL_AUXILIARY_SEND_FILTER, slot, 0, alFilter);
+}
+
+void CChannel::UpdateReverb(ALuint slot)
+{
+ if ( !IsFXSupported() ) return;
+ if ( !HasSource() ) return;
+ if ( alFilter == AL_FILTER_NULL ) return;
+ EAX3_SetReverbMix(alFilter, Mix);
+ alSource3i(alSource, AL_AUXILIARY_SEND_FILTER, slot, 0, alFilter);
+}
+
+#endif \ No newline at end of file
diff --git a/src/audio/oal/channel.h b/src/audio/oal/channel.h
new file mode 100644
index 00000000..4dd09ca1
--- /dev/null
+++ b/src/audio/oal/channel.h
@@ -0,0 +1,51 @@
+#pragma once
+#include "common.h"
+
+#ifdef AUDIO_OAL
+#include "oal/oal_utils.h"
+#include <AL/al.h>
+#include <AL/alext.h>
+#include <AL/efx.h>
+
+
+class CChannel
+{
+ ALuint alSource;
+ ALuint alFilter;
+ ALuint alBuffer;
+ float Pitch, Gain;
+ float Mix;
+ int32 Frequency;
+ float Position[3];
+ float Distances[2];
+ int32 LoopCount;
+ ALint LoopPoints[2];
+ uint32 Sample;
+public:
+ CChannel();
+ void SetDefault();
+ void Reset();
+ void Init(bool Is2D = false);
+ void Term();
+ void Start();
+ void Stop();
+ bool HasSource();
+ bool IsUsed();
+ void SetPitch(float pitch);
+ void SetGain(float gain);
+ void SetVolume(int32 vol);
+ void SetSampleID(uint32 nSfx);
+ void SetFreq(int32 freq);
+ void SetCurrentFreq(uint32 freq);
+ void SetLoopCount(int32 loopCount); // fake
+ void SetLoopPoints(ALint start, ALint end);
+ void SetPosition(float x, float y, float z);
+ void SetDistances(float max, float min);
+ void SetPan(uint32 pan);
+ void SetBuffer(ALuint buffer);
+ void ClearBuffer();
+ void SetReverbMix(ALuint slot, float mix);
+ void UpdateReverb(ALuint slot);
+};
+
+#endif \ No newline at end of file
diff --git a/src/audio/oal/oal_utils.cpp b/src/audio/oal/oal_utils.cpp
new file mode 100644
index 00000000..4119672f
--- /dev/null
+++ b/src/audio/oal/oal_utils.cpp
@@ -0,0 +1,169 @@
+#include "oal_utils.h"
+
+#ifdef AUDIO_OAL
+
+LPALGENEFFECTS alGenEffects;
+LPALDELETEEFFECTS alDeleteEffects;
+LPALISEFFECT alIsEffect;
+LPALEFFECTI alEffecti;
+LPALEFFECTIV alEffectiv;
+LPALEFFECTF alEffectf;
+LPALEFFECTFV alEffectfv;
+LPALGETEFFECTI alGetEffecti;
+LPALGETEFFECTIV alGetEffectiv;
+LPALGETEFFECTF alGetEffectf;
+LPALGETEFFECTFV alGetEffectfv;
+LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
+LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
+LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
+LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
+LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
+LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
+LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
+LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
+LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
+LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
+LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
+LPALGENFILTERS alGenFilters;
+LPALDELETEFILTERS alDeleteFilters;
+LPALISFILTER alIsFilter;
+LPALFILTERI alFilteri;
+LPALFILTERIV alFilteriv;
+LPALFILTERF alFilterf;
+LPALFILTERFV alFilterfv;
+LPALGETFILTERI alGetFilteri;
+LPALGETFILTERIV alGetFilteriv;
+LPALGETFILTERF alGetFilterf;
+LPALGETFILTERFV alGetFilterfv;
+
+
+void EFXInit()
+{
+ /* Define a macro to help load the function pointers. */
+#define LOAD_PROC(T, x) ((x) = (T)alGetProcAddress(#x))
+ LOAD_PROC(LPALGENEFFECTS, alGenEffects);
+ LOAD_PROC(LPALDELETEEFFECTS, alDeleteEffects);
+ LOAD_PROC(LPALISEFFECT, alIsEffect);
+ LOAD_PROC(LPALEFFECTI, alEffecti);
+ LOAD_PROC(LPALEFFECTIV, alEffectiv);
+ LOAD_PROC(LPALEFFECTF, alEffectf);
+ LOAD_PROC(LPALEFFECTFV, alEffectfv);
+ LOAD_PROC(LPALGETEFFECTI, alGetEffecti);
+ LOAD_PROC(LPALGETEFFECTIV, alGetEffectiv);
+ LOAD_PROC(LPALGETEFFECTF, alGetEffectf);
+ LOAD_PROC(LPALGETEFFECTFV, alGetEffectfv);
+
+ LOAD_PROC(LPALGENFILTERS, alGenFilters);
+ LOAD_PROC(LPALDELETEFILTERS, alDeleteFilters);
+ LOAD_PROC(LPALISFILTER, alIsFilter);
+ LOAD_PROC(LPALFILTERI, alFilteri);
+ LOAD_PROC(LPALFILTERIV, alFilteriv);
+ LOAD_PROC(LPALFILTERF, alFilterf);
+ LOAD_PROC(LPALFILTERFV, alFilterfv);
+ LOAD_PROC(LPALGETFILTERI, alGetFilteri);
+ LOAD_PROC(LPALGETFILTERIV, alGetFilteriv);
+ LOAD_PROC(LPALGETFILTERF, alGetFilterf);
+ LOAD_PROC(LPALGETFILTERFV, alGetFilterfv);
+
+ LOAD_PROC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots);
+ LOAD_PROC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots);
+ LOAD_PROC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot);
+ LOAD_PROC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti);
+ LOAD_PROC(LPALAUXILIARYEFFECTSLOTIV, alAuxiliaryEffectSlotiv);
+ LOAD_PROC(LPALAUXILIARYEFFECTSLOTF, alAuxiliaryEffectSlotf);
+ LOAD_PROC(LPALAUXILIARYEFFECTSLOTFV, alAuxiliaryEffectSlotfv);
+ LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTI, alGetAuxiliaryEffectSloti);
+ LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTIV, alGetAuxiliaryEffectSlotiv);
+ LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf);
+ LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv);
+#undef LOAD_PROC
+}
+
+void SetEffectsLevel(ALuint uiFilter, float level)
+{
+ alFilteri(uiFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
+ alFilterf(uiFilter, AL_LOWPASS_GAIN, 1.0f);
+ alFilterf(uiFilter, AL_LOWPASS_GAINHF, level);
+}
+
+static inline float gain_to_mB(float gain)
+{
+ return (gain > 1e-5f) ? (float)(log10f(gain) * 2000.0f) : -10000l;
+}
+
+static inline float mB_to_gain(float millibels)
+{
+ return (millibels > -10000.0f) ? powf(10.0f, millibels/2000.0f) : 0.0f;
+}
+
+static inline float clampF(float val, float minval, float maxval)
+{
+ if(val >= maxval) return maxval;
+ if(val <= minval) return minval;
+ return val;
+}
+
+void EAX3_Set(ALuint effect, const EAXLISTENERPROPERTIES *props)
+{
+ alEffecti (effect, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
+ alEffectf (effect, AL_EAXREVERB_DENSITY, clampF(powf(props->flEnvironmentSize, 3.0f) / 16.0f, 0.0f, 1.0f));
+ alEffectf (effect, AL_EAXREVERB_DIFFUSION, props->flEnvironmentDiffusion);
+ alEffectf (effect, AL_EAXREVERB_GAIN, mB_to_gain((float)props->lRoom));
+ alEffectf (effect, AL_EAXREVERB_GAINHF, mB_to_gain((float)props->lRoomHF));
+ alEffectf (effect, AL_EAXREVERB_GAINLF, mB_to_gain((float)props->lRoomLF));
+ alEffectf (effect, AL_EAXREVERB_DECAY_TIME, props->flDecayTime);
+ alEffectf (effect, AL_EAXREVERB_DECAY_HFRATIO, props->flDecayHFRatio);
+ alEffectf (effect, AL_EAXREVERB_DECAY_LFRATIO, props->flDecayLFRatio);
+ alEffectf (effect, AL_EAXREVERB_REFLECTIONS_GAIN, clampF(mB_to_gain((float)props->lReflections), AL_EAXREVERB_MIN_REFLECTIONS_GAIN, AL_EAXREVERB_MAX_REFLECTIONS_GAIN));
+ alEffectf (effect, AL_EAXREVERB_REFLECTIONS_DELAY, props->flReflectionsDelay);
+ alEffectfv(effect, AL_EAXREVERB_REFLECTIONS_PAN, &props->vReflectionsPan.x);
+ alEffectf (effect, AL_EAXREVERB_LATE_REVERB_GAIN, clampF(mB_to_gain((float)props->lReverb), AL_EAXREVERB_MIN_LATE_REVERB_GAIN, AL_EAXREVERB_MAX_LATE_REVERB_GAIN));
+ alEffectf (effect, AL_EAXREVERB_LATE_REVERB_DELAY, props->flReverbDelay);
+ alEffectfv(effect, AL_EAXREVERB_LATE_REVERB_PAN, &props->vReverbPan.x);
+ alEffectf (effect, AL_EAXREVERB_ECHO_TIME, props->flEchoTime);
+ alEffectf (effect, AL_EAXREVERB_ECHO_DEPTH, props->flEchoDepth);
+ alEffectf (effect, AL_EAXREVERB_MODULATION_TIME, props->flModulationTime);
+ alEffectf (effect, AL_EAXREVERB_MODULATION_DEPTH, props->flModulationDepth);
+ alEffectf (effect, AL_EAXREVERB_AIR_ABSORPTION_GAINHF, clampF(mB_to_gain(props->flAirAbsorptionHF), AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF, AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF));
+ alEffectf (effect, AL_EAXREVERB_HFREFERENCE, props->flHFReference);
+ alEffectf (effect, AL_EAXREVERB_LFREFERENCE, props->flLFReference);
+ alEffectf (effect, AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, props->flRoomRolloffFactor);
+ alEffecti (effect, AL_EAXREVERB_DECAY_HFLIMIT, (props->ulFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ? AL_TRUE : AL_FALSE);
+}
+
+void EFX_Set(ALuint effect, const EAXLISTENERPROPERTIES *props)
+{
+ alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
+
+ alEffectf(effect, AL_REVERB_DENSITY, clampF(powf(props->flEnvironmentSize, 3.0f) / 16.0f, 0.0f, 1.0f));
+ alEffectf(effect, AL_REVERB_DIFFUSION, props->flEnvironmentDiffusion);
+ alEffectf(effect, AL_REVERB_GAIN, mB_to_gain((float)props->lRoom));
+ alEffectf(effect, AL_REVERB_GAINHF, mB_to_gain((float)props->lRoomHF));
+ alEffectf(effect, AL_REVERB_DECAY_TIME, props->flDecayTime);
+ alEffectf(effect, AL_REVERB_DECAY_HFRATIO, props->flDecayHFRatio);
+ alEffectf(effect, AL_REVERB_REFLECTIONS_GAIN, clampF(mB_to_gain((float)props->lReflections), AL_EAXREVERB_MIN_REFLECTIONS_GAIN, AL_EAXREVERB_MAX_REFLECTIONS_GAIN));
+ alEffectf(effect, AL_REVERB_REFLECTIONS_DELAY, props->flReflectionsDelay);
+ alEffectf(effect, AL_REVERB_LATE_REVERB_GAIN, clampF(mB_to_gain((float)props->lReverb), AL_EAXREVERB_MIN_LATE_REVERB_GAIN, AL_EAXREVERB_MAX_LATE_REVERB_GAIN));
+ alEffectf(effect, AL_REVERB_LATE_REVERB_DELAY, props->flReverbDelay);
+ alEffectf(effect, AL_REVERB_AIR_ABSORPTION_GAINHF, clampF(mB_to_gain(props->flAirAbsorptionHF), AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF, AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF));
+ alEffectf(effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, props->flRoomRolloffFactor);
+ alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, (props->ulFlags&EAXLISTENERFLAGS_DECAYHFLIMIT) ? AL_TRUE : AL_FALSE);
+}
+
+void EAX3_SetReverbMix(ALuint filter, float mix)
+{
+ //long vol=(long)linear_to_dB(mix);
+ //DSPROPERTY_EAXBUFFER_ROOMHF,
+ //DSPROPERTY_EAXBUFFER_ROOM,
+ //DSPROPERTY_EAXBUFFER_REVERBMIX,
+
+ long mbvol = gain_to_mB(mix);
+ float mb = mbvol;
+ float mbhf = mbvol;
+
+ alFilteri(filter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
+ alFilterf(filter, AL_LOWPASS_GAIN, mB_to_gain(Min(mb, 0.0f)));
+ alFilterf(filter, AL_LOWPASS_GAINHF, mB_to_gain(mbhf));
+}
+
+#endif \ No newline at end of file
diff --git a/src/audio/oal/oal_utils.h b/src/audio/oal/oal_utils.h
new file mode 100644
index 00000000..af45a944
--- /dev/null
+++ b/src/audio/oal/oal_utils.h
@@ -0,0 +1,48 @@
+#pragma once
+#include "common.h"
+
+#ifdef AUDIO_OAL
+#include "eax.h"
+#include "AL/efx.h"
+
+
+void EFXInit();
+void EAX3_Set(ALuint effect, const EAXLISTENERPROPERTIES *props);
+void EFX_Set(ALuint effect, const EAXLISTENERPROPERTIES *props);
+void EAX3_SetReverbMix(ALuint filter, float mix);
+void SetEffectsLevel(ALuint uiFilter, float level);
+
+extern LPALGENEFFECTS alGenEffects;
+extern LPALDELETEEFFECTS alDeleteEffects;
+extern LPALISEFFECT alIsEffect;
+extern LPALEFFECTI alEffecti;
+extern LPALEFFECTIV alEffectiv;
+extern LPALEFFECTF alEffectf;
+extern LPALEFFECTFV alEffectfv;
+extern LPALGETEFFECTI alGetEffecti;
+extern LPALGETEFFECTIV alGetEffectiv;
+extern LPALGETEFFECTF alGetEffectf;
+extern LPALGETEFFECTFV alGetEffectfv;
+extern LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
+extern LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
+extern LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
+extern LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
+extern LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
+extern LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
+extern LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
+extern LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
+extern LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
+extern LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
+extern LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
+extern LPALGENFILTERS alGenFilters;
+extern LPALDELETEFILTERS alDeleteFilters;
+extern LPALISFILTER alIsFilter;
+extern LPALFILTERI alFilteri;
+extern LPALFILTERIV alFilteriv;
+extern LPALFILTERF alFilterf;
+extern LPALFILTERFV alFilterfv;
+extern LPALGETFILTERI alGetFilteri;
+extern LPALGETFILTERIV alGetFilteriv;
+extern LPALGETFILTERF alGetFilterf;
+extern LPALGETFILTERFV alGetFilterfv;
+#endif
diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp
new file mode 100644
index 00000000..9bca0546
--- /dev/null
+++ b/src/audio/oal/stream.cpp
@@ -0,0 +1,520 @@
+#include "stream.h"
+
+#ifdef AUDIO_OAL
+#include "common.h"
+#include "sampman.h"
+
+typedef long ssize_t;
+
+#include <sndfile.h>
+#include <mpg123.h>
+
+#pragma comment( lib, "libsndfile-1.lib" )
+#pragma comment( lib, "libmpg123.lib" )
+
+class CSndFile : public IDecoder
+{
+ SNDFILE *m_pfSound;
+ SF_INFO m_soundInfo;
+public:
+ CSndFile(const char *path) :
+ m_pfSound(nil)
+ {
+ memset(&m_soundInfo, 0, sizeof(m_soundInfo));
+ m_pfSound = sf_open(path, SFM_READ, &m_soundInfo);
+ }
+
+ ~CSndFile()
+ {
+ if ( m_pfSound )
+ {
+ sf_close(m_pfSound);
+ m_pfSound = nil;
+ }
+ }
+
+ bool IsOpened()
+ {
+ return m_pfSound != nil;
+ }
+
+ uint32 GetSampleSize()
+ {
+ return sizeof(uint16);
+ }
+
+ uint32 GetSampleCount()
+ {
+ return m_soundInfo.frames;
+ }
+
+ uint32 GetSampleRate()
+ {
+ return m_soundInfo.samplerate;
+ }
+
+ uint32 GetChannels()
+ {
+ return m_soundInfo.channels;
+ }
+
+ void Seek(uint32 milliseconds)
+ {
+ if ( !IsOpened() ) return;
+ sf_seek(m_pfSound, ms2samples(milliseconds), SF_SEEK_SET);
+ }
+
+ uint32 Tell()
+ {
+ if ( !IsOpened() ) return 0;
+ return samples2ms(sf_seek(m_pfSound, 0, SF_SEEK_CUR));
+ }
+
+ uint32 Decode(void *buffer)
+ {
+ if ( !IsOpened() ) return 0;
+ return sf_read_short(m_pfSound, (short *)buffer, GetBufferSamples()) * GetSampleSize();
+ }
+};
+
+class CMP3File : public IDecoder
+{
+ mpg123_handle *m_pMH;
+ bool m_bOpened;
+ uint32 m_nRate;
+ uint32 m_nChannels;
+public:
+ CMP3File(const char *path) :
+ m_pMH(nil),
+ m_bOpened(false),
+ m_nRate(0),
+ m_nChannels(0)
+ {
+ m_pMH = mpg123_new(nil, nil);
+ if ( m_pMH )
+ {
+ long rate = 0;
+ int channels = 0;
+ int encoding = 0;
+
+ m_bOpened = mpg123_open(m_pMH, path) == MPG123_OK
+ && mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK;
+ m_nRate = rate;
+ m_nChannels = channels;
+
+ if ( IsOpened() )
+ {
+ mpg123_format_none(m_pMH);
+ mpg123_format(m_pMH, rate, channels, encoding);
+ }
+ }
+ }
+
+ ~CMP3File()
+ {
+ if ( m_pMH )
+ {
+ mpg123_close(m_pMH);
+ mpg123_delete(m_pMH);
+ m_pMH = nil;
+ }
+ }
+
+ bool IsOpened()
+ {
+ return m_bOpened;
+ }
+
+ uint32 GetSampleSize()
+ {
+ return sizeof(uint16);
+ }
+
+ uint32 GetSampleCount()
+ {
+ if ( !IsOpened() ) return 0;
+ return mpg123_length(m_pMH);
+ }
+
+ uint32 GetSampleRate()
+ {
+ return m_nRate;
+ }
+
+ uint32 GetChannels()
+ {
+ return m_nChannels;
+ }
+
+ void Seek(uint32 milliseconds)
+ {
+ if ( !IsOpened() ) return;
+ mpg123_seek(m_pMH, ms2samples(milliseconds)*GetSampleSize(), SEEK_SET);
+ }
+
+ uint32 Tell()
+ {
+ if ( !IsOpened() ) return 0;
+ return samples2ms(mpg123_tell(m_pMH)/GetSampleSize());
+ }
+
+ uint32 Decode(void *buffer)
+ {
+ if ( !IsOpened() ) return 0;
+
+ size_t size;
+ int err = mpg123_read(m_pMH, (unsigned char *)buffer, GetBufferSize(), &size);
+ if (err != MPG123_OK && err != MPG123_DONE) return 0;
+ return size;
+ }
+};
+
+void CStream::Initialise()
+{
+ mpg123_init();
+}
+
+void CStream::Terminate()
+{
+ mpg123_exit();
+}
+
+CStream::CStream(char *filename, ALuint &source, ALuint (&buffers)[NUM_STREAMBUFFERS]) :
+ m_alSource(source),
+ m_alBuffers(buffers),
+ m_pBuffer(nil),
+ m_bPaused(false),
+ m_bActive(false),
+ m_pSoundFile(nil),
+ m_bReset(false),
+ m_nVolume(0),
+ m_nPan(0),
+ m_nPosBeforeReset(0)
+
+{
+ strcpy(m_aFilename, filename);
+
+ DEV("Stream %s\n", m_aFilename);
+
+ if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3"))
+ m_pSoundFile = new CMP3File(m_aFilename);
+ else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav"))
+ m_pSoundFile = new CSndFile(m_aFilename);
+ else
+ m_pSoundFile = nil;
+ ASSERT(m_pSoundFile != nil);
+ if (m_pSoundFile && m_pSoundFile->IsOpened() )
+ {
+ m_pBuffer = malloc(m_pSoundFile->GetBufferSize());
+ ASSERT(m_pBuffer!=nil);
+
+ DEV("AvgSamplesPerSec: %d\n", m_pSoundFile->GetAvgSamplesPerSec());
+ DEV("SampleCount: %d\n", m_pSoundFile->GetSampleCount());
+ DEV("SampleRate: %d\n", m_pSoundFile->GetSampleRate());
+ DEV("Channels: %d\n", m_pSoundFile->GetChannels());
+ DEV("Buffer Samples: %d\n", m_pSoundFile->GetBufferSamples());
+ DEV("Buffer sec: %f\n", (float(m_pSoundFile->GetBufferSamples()) / float(m_pSoundFile->GetChannels())/ float(m_pSoundFile->GetSampleRate())));
+ DEV("Length MS: %02d:%02d\n", (m_pSoundFile->GetLength() / 1000) / 60, (m_pSoundFile->GetLength() / 1000) % 60);
+
+ return;
+ }
+}
+
+CStream::~CStream()
+{
+ Delete();
+}
+
+void CStream::Delete()
+{
+ Stop();
+ ClearBuffers();
+
+ if ( m_pSoundFile )
+ {
+ delete m_pSoundFile;
+ m_pSoundFile = nil;
+ }
+
+ if ( m_pBuffer )
+ {
+ free(m_pBuffer);
+ m_pBuffer = nil;
+ }
+}
+
+bool CStream::HasSource()
+{
+ return m_alSource != AL_NONE;
+}
+
+bool CStream::IsOpened()
+{
+ return m_pSoundFile->IsOpened();
+}
+
+bool CStream::IsPlaying()
+{
+ if ( !HasSource() || !IsOpened() ) return false;
+
+ if ( m_pSoundFile->IsOpened() && !m_bPaused )
+ {
+ ALint sourceState;
+ alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
+ if ( m_bActive || sourceState == AL_PLAYING )
+ return true;
+ }
+
+ return false;
+}
+
+void CStream::Pause()
+{
+ if ( !HasSource() ) return;
+ ALint sourceState = AL_PAUSED;
+ alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
+ if (sourceState != AL_PAUSED )
+ alSourcePause(m_alSource);
+}
+
+void CStream::SetPause(bool bPause)
+{
+ if ( !HasSource() ) return;
+ if ( bPause )
+ {
+ Pause();
+ m_bPaused = true;
+ }
+ else
+ {
+ if (m_bPaused)
+ SetPlay(true);
+ m_bPaused = false;
+ }
+}
+
+void CStream::SetPitch(float pitch)
+{
+ if ( !HasSource() ) return;
+ alSourcef(m_alSource, AL_PITCH, pitch);
+}
+
+void CStream::SetGain(float gain)
+{
+ if ( !HasSource() ) return;
+ alSourcef(m_alSource, AL_GAIN, gain);
+}
+
+void CStream::SetPosition(float x, float y, float z)
+{
+ if ( !HasSource() ) return;
+ alSource3f(m_alSource, AL_POSITION, x, y, z);
+}
+
+void CStream::SetVolume(uint32 nVol)
+{
+ m_nVolume = nVol;
+ SetGain(ALfloat(nVol) / MAX_VOLUME);
+}
+
+void CStream::SetPan(uint8 nPan)
+{
+ m_nPan = nPan;
+ SetPosition((nPan - 63)/64.0f, 0.0f, Sqrt(1.0f-SQR((nPan-63)/64.0f)));
+}
+
+void CStream::SetPosMS(uint32 nPos)
+{
+ if ( !m_pSoundFile->IsOpened() ) return;
+ m_pSoundFile->Seek(nPos);
+ ClearBuffers();
+}
+
+uint32 CStream::GetPosMS()
+{
+ if ( !HasSource() ) return 0;
+ if ( !m_pSoundFile->IsOpened() ) return 0;
+
+ ALint offset;
+ //alGetSourcei(m_alSource, AL_SAMPLE_OFFSET, &offset);
+ alGetSourcei(m_alSource, AL_BYTE_OFFSET, &offset);
+
+ return m_pSoundFile->Tell()
+ - m_pSoundFile->samples2ms(m_pSoundFile->GetBufferSamples() * (NUM_STREAMBUFFERS-1))
+ + m_pSoundFile->samples2ms(offset/m_pSoundFile->GetSampleSize());
+}
+
+uint32 CStream::GetLengthMS()
+{
+ if ( !m_pSoundFile->IsOpened() ) return 0;
+ return m_pSoundFile->GetLength();
+}
+
+bool CStream::FillBuffer(ALuint alBuffer)
+{
+ if ( !HasSource() )
+ return false;
+ if ( !m_pSoundFile->IsOpened() )
+ return false;
+ if ( !(alBuffer != AL_NONE && alIsBuffer(alBuffer)) )
+ return false;
+
+ uint32 size = m_pSoundFile->Decode(m_pBuffer);
+ if( size == 0 )
+ return false;
+
+ alBufferData(alBuffer, m_pSoundFile->GetChannels() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16,
+ m_pBuffer, size, m_pSoundFile->GetSampleRate());
+
+ return true;
+}
+
+int32 CStream::FillBuffers()
+{
+ int32 i = 0;
+ for ( i = 0; i < NUM_STREAMBUFFERS; i++ )
+ {
+ if ( !FillBuffer(m_alBuffers[i]) )
+ break;
+ alSourceQueueBuffers(m_alSource, 1, &m_alBuffers[i]);
+ }
+
+ return i;
+}
+
+void CStream::ClearBuffers()
+{
+ if ( !HasSource() ) return;
+
+ ALint buffersQueued;
+ alGetSourcei(m_alSource, AL_BUFFERS_QUEUED, &buffersQueued);
+
+ ALuint value;
+ while (buffersQueued--)
+ alSourceUnqueueBuffers(m_alSource, 1, &value);
+}
+
+bool CStream::Setup()
+{
+ if ( m_pSoundFile->IsOpened() )
+ {
+ m_pSoundFile->Seek(0);
+ alSourcei(m_alSource, AL_SOURCE_RELATIVE, AL_TRUE);
+ //SetPosition(0.0f, 0.0f, 0.0f);
+ SetPitch(1.0f);
+ //SetPan(m_nPan);
+ //SetVolume(100);
+ }
+
+ return IsOpened();
+}
+
+void CStream::SetPlay(bool state)
+{
+ if ( !HasSource() ) return;
+ if ( state )
+ {
+ ALint sourceState = AL_PLAYING;
+ alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
+ if (sourceState != AL_PLAYING )
+ alSourcePlay(m_alSource);
+ m_bActive = true;
+ }
+ else
+ {
+ ALint sourceState = AL_STOPPED;
+ alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
+ if (sourceState != AL_STOPPED )
+ alSourceStop(m_alSource);
+ m_bActive = false;
+ }
+}
+
+void CStream::Start()
+{
+ if ( !HasSource() ) return;
+ if ( FillBuffers() != 0 )
+ SetPlay(true);
+}
+
+void CStream::Stop()
+{
+ if ( !HasSource() ) return;
+ SetPlay(false);
+}
+
+void CStream::Update()
+{
+ if ( !IsOpened() )
+ return;
+
+ if ( !HasSource() )
+ return;
+
+ if ( m_bReset )
+ return;
+
+ if ( !m_bPaused )
+ {
+ ALint sourceState;
+ ALint buffersProcessed = 0;
+
+ alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
+ alGetSourcei(m_alSource, AL_BUFFERS_PROCESSED, &buffersProcessed);
+
+ ALint looping = AL_FALSE;
+ alGetSourcei(m_alSource, AL_LOOPING, &looping);
+
+ if ( looping == AL_TRUE )
+ {
+ TRACE("stream set looping");
+ alSourcei(m_alSource, AL_LOOPING, AL_TRUE);
+ }
+
+ while( buffersProcessed-- )
+ {
+ ALuint buffer;
+
+ alSourceUnqueueBuffers(m_alSource, 1, &buffer);
+
+ if ( m_bActive && FillBuffer(buffer) )
+ alSourceQueueBuffers(m_alSource, 1, &buffer);
+ }
+
+ if ( sourceState != AL_PLAYING )
+ {
+ alGetSourcei(m_alSource, AL_BUFFERS_PROCESSED, &buffersProcessed);
+ SetPlay(buffersProcessed!=0);
+ }
+ }
+}
+
+void CStream::ProviderInit()
+{
+ if ( m_bReset )
+ {
+ if ( Setup() )
+ {
+ SetPan(m_nPan);
+ SetVolume(m_nVolume);
+ SetPosMS(m_nPosBeforeReset);
+ if (m_bActive)
+ FillBuffers();
+ SetPlay(m_bActive);
+ if ( m_bPaused )
+ Pause();
+ }
+
+ m_bReset = false;
+ }
+}
+
+void CStream::ProviderTerm()
+{
+ m_bReset = true;
+ m_nPosBeforeReset = GetPosMS();
+
+ ClearBuffers();
+}
+
+#endif \ No newline at end of file
diff --git a/src/audio/oal/stream.h b/src/audio/oal/stream.h
new file mode 100644
index 00000000..f1e5f458
--- /dev/null
+++ b/src/audio/oal/stream.h
@@ -0,0 +1,112 @@
+#pragma once
+#include "common.h"
+
+#ifdef AUDIO_OAL
+#include <AL/al.h>
+
+#define NUM_STREAMBUFFERS 4
+
+class IDecoder
+{
+public:
+ virtual ~IDecoder() { }
+
+ virtual bool IsOpened() = 0;
+
+ virtual uint32 GetSampleSize() = 0;
+ virtual uint32 GetSampleCount() = 0;
+ virtual uint32 GetSampleRate() = 0;
+ virtual uint32 GetChannels() = 0;
+
+ uint32 GetAvgSamplesPerSec()
+ {
+ return GetChannels() * GetSampleRate();
+ }
+
+ uint32 ms2samples(uint32 ms)
+ {
+ return float(ms) / 1000.0f * float(GetChannels()) * float(GetSampleRate());
+ }
+
+ uint32 samples2ms(uint32 sm)
+ {
+ return float(sm) * 1000.0f / float(GetChannels()) / float(GetSampleRate());
+ }
+
+ uint32 GetBufferSamples()
+ {
+ //return (GetAvgSamplesPerSec() >> 2) - (GetSampleCount() % GetChannels());
+ return (GetAvgSamplesPerSec() / 4); // 250ms
+ }
+
+ uint32 GetBufferSize()
+ {
+ return GetBufferSamples() * GetSampleSize();
+ }
+
+ virtual void Seek(uint32 milliseconds) = 0;
+ virtual uint32 Tell() = 0;
+
+ uint32 GetLength()
+ {
+ return float(GetSampleCount()) * 1000.0f / float(GetSampleRate());
+ }
+
+ virtual uint32 Decode(void *buffer) = 0;
+};
+
+class CStream
+{
+ char m_aFilename[128];
+ ALuint &m_alSource;
+ ALuint (&m_alBuffers)[NUM_STREAMBUFFERS];
+
+ bool m_bPaused;
+ bool m_bActive;
+
+ void *m_pBuffer;
+
+ bool m_bReset;
+ uint32 m_nVolume;
+ uint8 m_nPan;
+ uint32 m_nPosBeforeReset;
+
+ IDecoder *m_pSoundFile;
+
+ bool HasSource();
+ void SetPosition(float x, float y, float z);
+ void SetPitch(float pitch);
+ void SetGain(float gain);
+ void Pause();
+ void SetPlay(bool state);
+
+ bool FillBuffer(ALuint alBuffer);
+ int32 FillBuffers();
+ void ClearBuffers();
+public:
+ static void Initialise();
+ static void Terminate();
+
+ CStream(char *filename, ALuint &source, ALuint (&buffers)[NUM_STREAMBUFFERS]);
+ ~CStream();
+ void Delete();
+
+ bool IsOpened();
+ bool IsPlaying();
+ void SetPause (bool bPause);
+ void SetVolume(uint32 nVol);
+ void SetPan (uint8 nPan);
+ void SetPosMS (uint32 nPos);
+ uint32 GetPosMS();
+ uint32 GetLengthMS();
+
+ bool Setup();
+ void Start();
+ void Stop();
+ void Update(void);
+
+ void ProviderInit();
+ void ProviderTerm();
+};
+
+#endif \ No newline at end of file