Initial commit

This commit is contained in:
Shinovon 2026-04-22 07:30:27 +05:00
commit 77cdaaf97e
827 changed files with 418745 additions and 0 deletions

291
src/audio/oal/aldlist.cpp Normal file
View file

@ -0,0 +1,291 @@
/*
* 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()
{
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
nNumOfDevices = 0;
defaultDeviceIndex = 0;
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) {
devices = (char *)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
defaultDeviceName = (char *)alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
index = 0;
// go through device list (each device terminated with a single NULL, list terminated with double NULL)
while (*devices != '\0') {
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_ALL_DEVICES_SPECIFIER);
if ((actualDeviceName != NULL) && (strlen(actualDeviceName) > 0)) {
ALDEVICEINFO &ALDeviceInfo = aDeviceInfo[nNumOfDevices++];
ALDeviceInfo.bSelected = true;
ALDeviceInfo.SetName(actualDeviceName);
alcGetIntegerv(device, ALC_MAJOR_VERSION, sizeof(int), &ALDeviceInfo.iMajorVersion);
alcGetIntegerv(device, ALC_MINOR_VERSION, sizeof(int), &ALDeviceInfo.iMinorVersion);
// Check for ALC Extensions
if (alcIsExtensionPresent(device, "ALC_EXT_CAPTURE") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EXT_CAPTURE;
if (alcIsExtensionPresent(device, "ALC_EXT_EFX") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EXT_EFX;
// Check for AL Extensions
if (alIsExtensionPresent("AL_EXT_OFFSET") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EXT_OFFSET;
if (alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EXT_LINEAR_DISTANCE;
if (alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EXT_EXPONENT_DISTANCE;
if (alIsExtensionPresent("EAX2.0") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EAX2;
if (alIsExtensionPresent("EAX3.0") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EAX3;
if (alIsExtensionPresent("EAX4.0") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EAX4;
if (alIsExtensionPresent("EAX5.0") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EAX5;
if (alIsExtensionPresent("EAX-RAM") == AL_TRUE)
ALDeviceInfo.Extensions |= ADEXT_EAX_RAM;
// Get Source Count
ALDeviceInfo.uiSourceCount = GetMaxNumSources();
}
alcMakeContextCurrent(NULL);
alcDestroyContext(context);
}
alcCloseDevice(device);
}
devices += strlen(devices) + 1;
index += 1;
}
}
ResetFilters();
}
/*
* Exit call
*/
ALDeviceList::~ALDeviceList()
{
}
/*
* Returns the number of devices in the complete device list
*/
unsigned int ALDeviceList::GetNumDevices()
{
return nNumOfDevices;
}
/*
* Returns the device name at an index in the complete device list
*/
const char * ALDeviceList::GetDeviceName(unsigned int index)
{
if (index < GetNumDevices())
return aDeviceInfo[index].strDeviceName;
else
return NULL;
}
/*
* Returns the major and minor version numbers for a device at a specified index in the complete list
*/
void ALDeviceList::GetDeviceVersion(unsigned int index, int *major, int *minor)
{
if (index < GetNumDevices()) {
if (major)
*major = aDeviceInfo[index].iMajorVersion;
if (minor)
*minor = aDeviceInfo[index].iMinorVersion;
}
return;
}
/*
* Returns the maximum number of Sources that can be generate on the given device
*/
unsigned int ALDeviceList::GetMaxNumSources(unsigned int index)
{
if (index < GetNumDevices())
return aDeviceInfo[index].uiSourceCount;
else
return 0;
}
/*
* Checks if the extension is supported on the given device
*/
bool ALDeviceList::IsExtensionSupported(int index, unsigned short ext)
{
return !!(aDeviceInfo[index].Extensions & ext);
}
/*
* 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 < nNumOfDevices; i++) {
GetDeviceVersion(i, &dMajor, &dMinor);
if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) {
aDeviceInfo[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 < nNumOfDevices; i++) {
GetDeviceVersion(i, &dMajor, &dMinor);
if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) {
aDeviceInfo[i].bSelected = false;
}
}
}
/*
* Deselects device which don't support the given extension name
*/
void
ALDeviceList::FilterDevicesExtension(unsigned short ext)
{
for (unsigned int i = 0; i < nNumOfDevices; i++) {
if (!IsExtensionSupported(i, ext))
aDeviceInfo[i].bSelected = false;
}
}
/*
* Resets all filtering, such that all devices are in the list
*/
void ALDeviceList::ResetFilters()
{
for (unsigned int i = 0; i < GetNumDevices(); i++) {
aDeviceInfo[i].bSelected = true;
}
filterIndex = 0;
}
/*
* Gets index of first filtered device
*/
int ALDeviceList::GetFirstFilteredDevice()
{
unsigned int i;
for (i = 0; i < GetNumDevices(); i++) {
if (aDeviceInfo[i].bSelected == true) {
break;
}
}
filterIndex = i + 1;
return i;
}
/*
* Gets index of next filtered device
*/
int ALDeviceList::GetNextFilteredDevice()
{
unsigned int i;
for (i = filterIndex; i < GetNumDevices(); i++) {
if (aDeviceInfo[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

82
src/audio/oal/aldlist.h Normal file
View file

@ -0,0 +1,82 @@
#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"
enum
{
ADEXT_EXT_CAPTURE = (1 << 0),
ADEXT_EXT_EFX = (1 << 1),
ADEXT_EXT_OFFSET = (1 << 2),
ADEXT_EXT_LINEAR_DISTANCE = (1 << 3),
ADEXT_EXT_EXPONENT_DISTANCE = (1 << 4),
ADEXT_EAX2 = (1 << 5),
ADEXT_EAX3 = (1 << 6),
ADEXT_EAX4 = (1 << 7),
ADEXT_EAX5 = (1 << 8),
ADEXT_EAX_RAM = (1 << 9),
};
struct ALDEVICEINFO {
char *strDeviceName;
int iMajorVersion;
int iMinorVersion;
unsigned int uiSourceCount;
unsigned short Extensions;
bool bSelected;
ALDEVICEINFO() : iMajorVersion(0), iMinorVersion(0), uiSourceCount(0), bSelected(false)
{
strDeviceName = NULL;
Extensions = 0;
}
~ALDEVICEINFO()
{
delete[] strDeviceName;
strDeviceName = NULL;
}
void SetName(const char *name)
{
if(strDeviceName) delete[] strDeviceName;
strDeviceName = new char[strlen(name) + 1];
strcpy(strDeviceName, name);
}
};
typedef ALDEVICEINFO *LPALDEVICEINFO;
class ALDeviceList
{
private:
ALDEVICEINFO aDeviceInfo[64];
unsigned int nNumOfDevices;
int defaultDeviceIndex;
int filterIndex;
public:
ALDeviceList ();
~ALDeviceList ();
unsigned int GetNumDevices();
const char *GetDeviceName(unsigned int index);
void GetDeviceVersion(unsigned int index, int *major, int *minor);
unsigned int GetMaxNumSources(unsigned int index);
bool IsExtensionSupported(int index, unsigned short ext);
int GetDefaultDevice();
void FilterDevicesMinVer(int major, int minor);
void FilterDevicesMaxVer(int major, int minor);
void FilterDevicesExtension(unsigned short ext);
void ResetFilters();
int GetFirstFilteredDevice();
int GetNextFilteredDevice();
private:
unsigned int GetMaxNumSources();
};
#endif
#endif // ALDEVICELIST_H

295
src/audio/oal/channel.cpp Normal file
View file

@ -0,0 +1,295 @@
#include "common.h"
#ifdef AUDIO_OAL
#include "channel.h"
#include "sampman.h"
#ifndef _WIN32
#include <float.h>
#endif
extern bool IsFXSupported();
ALuint alSources[NUM_CHANNELS];
ALuint alFilters[NUM_CHANNELS];
ALuint alBuffers[NUM_CHANNELS];
bool bChannelsCreated = false;
int32 CChannel::channelsThatNeedService = 0;
uint8 tempStereoBuffer[PED_BLOCKSIZE * 2];
void
CChannel::InitChannels()
{
alGenSources(NUM_CHANNELS, alSources);
alGenBuffers(NUM_CHANNELS, alBuffers);
if (IsFXSupported())
alGenFilters(NUM_CHANNELS, alFilters);
bChannelsCreated = true;
}
void
CChannel::DestroyChannels()
{
if (bChannelsCreated)
{
alDeleteSources(NUM_CHANNELS, alSources);
memset(alSources, 0, sizeof(alSources));
alDeleteBuffers(NUM_CHANNELS, alBuffers);
memset(alBuffers, 0, sizeof(alBuffers));
if (IsFXSupported())
{
alDeleteFilters(NUM_CHANNELS, alFilters);
memset(alFilters, 0, sizeof(alFilters));
}
bChannelsCreated = false;
}
}
CChannel::CChannel()
{
Data = nil;
DataSize = 0;
bIs2D = false;
SetDefault();
}
void CChannel::SetDefault()
{
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;
LastProcessedOffset = UINT32_MAX;
LoopPoints[0] = 0; LoopPoints[1] = -1;
Frequency = MAX_FREQ;
}
void CChannel::Reset()
{
// Here is safe because ctor don't call this
if (LoopCount > 1)
channelsThatNeedService--;
ClearBuffer();
SetDefault();
}
void CChannel::Init(uint32 _id, bool Is2D)
{
id = _id;
if ( HasSource() )
{
alSourcei(alSources[id], AL_SOURCE_RELATIVE, AL_TRUE);
if ( IsFXSupported() )
alSource3i(alSources[id], AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
if ( Is2D )
{
bIs2D = true;
alSource3f(alSources[id], AL_POSITION, 0.0f, 0.0f, 0.0f);
alSourcef(alSources[id], AL_GAIN, 1.0f);
}
}
}
void CChannel::Term()
{
Stop();
if ( HasSource() )
{
if ( IsFXSupported() )
{
alSource3i(alSources[id], AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
}
}
}
void CChannel::Start()
{
if ( !HasSource() ) return;
if ( !Data ) return;
if ( bIs2D )
{
// convert mono data to stereo
int16 *monoData = (int16*)Data;
int16 *stereoData = (int16*)tempStereoBuffer;
for (size_t i = 0; i < DataSize / 2; i++)
{
*(stereoData++) = *monoData;
*(stereoData++) = *(monoData++);
}
alBufferData(alBuffers[id], AL_FORMAT_STEREO16, tempStereoBuffer, DataSize * 2, Frequency);
}
else
alBufferData(alBuffers[id], AL_FORMAT_MONO16, Data, DataSize, Frequency);
if ( LoopPoints[0] != 0 && LoopPoints[0] != -1 )
alBufferiv(alBuffers[id], AL_LOOP_POINTS_SOFT, LoopPoints);
alSourcei(alSources[id], AL_BUFFER, alBuffers[id]);
alSourcePlay(alSources[id]);
}
void CChannel::Stop()
{
if ( HasSource() )
alSourceStop(alSources[id]);
Reset();
}
bool CChannel::HasSource()
{
return alSources[id] != AL_NONE;
}
bool CChannel::IsUsed()
{
if ( HasSource() )
{
ALint sourceState;
alGetSourcei(alSources[id], AL_SOURCE_STATE, &sourceState);
return sourceState == AL_PLAYING;
}
return false;
}
void CChannel::SetPitch(float pitch)
{
if ( !HasSource() ) return;
alSourcef(alSources[id], AL_PITCH, pitch);
}
void CChannel::SetGain(float gain)
{
if ( !HasSource() ) return;
alSourcef(alSources[id], AL_GAIN, gain);
}
void CChannel::SetVolume(int32 vol)
{
SetGain(ALfloat(vol) / MAX_VOLUME);
}
void CChannel::SetSampleData(void *_data, size_t _DataSize, int32 freq)
{
Data = _data;
DataSize = _DataSize;
Frequency = freq;
}
void CChannel::SetCurrentFreq(uint32 freq)
{
SetPitch(ALfloat(freq) / Frequency);
}
void CChannel::SetLoopCount(int32 count)
{
if ( !HasSource() ) return;
// 0: loop indefinitely, 1: play one time, 2: play two times etc...
// only > 1 needs manual processing
if (LoopCount > 1 && count < 2)
channelsThatNeedService--;
else if (LoopCount < 2 && count > 1)
channelsThatNeedService++;
alSourcei(alSources[id], AL_LOOPING, count == 1 ? AL_FALSE : AL_TRUE);
LoopCount = count;
}
bool CChannel::Update()
{
if (!HasSource()) return false;
if (LoopCount < 2) return false;
ALint state;
alGetSourcei(alSources[id], AL_SOURCE_STATE, &state);
if (state == AL_STOPPED) {
debug("Looping channels(%d in this case) shouldn't report AL_STOPPED, but nvm\n", id);
SetLoopCount(1);
return true;
}
assert(channelsThatNeedService > 0 && "Ref counting is broken");
ALint offset;
alGetSourcei(alSources[id], AL_SAMPLE_OFFSET, &offset);
// Rewound
if (offset < LastProcessedOffset) {
LoopCount--;
if (LoopCount == 1) {
// Playing last tune...
channelsThatNeedService--;
alSourcei(alSources[id], AL_LOOPING, AL_FALSE);
}
}
LastProcessedOffset = offset;
return 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(alSources[id], AL_POSITION, x, y, z);
}
void CChannel::SetDistances(float max, float min)
{
if ( !HasSource() ) return;
alSourcef (alSources[id], AL_MAX_DISTANCE, max);
alSourcef (alSources[id], AL_REFERENCE_DISTANCE, min);
alSourcef (alSources[id], AL_MAX_GAIN, 1.0f);
alSourcef (alSources[id], AL_ROLLOFF_FACTOR, 1.0f);
}
void CChannel::SetPan(int32 pan)
{
SetPosition((pan-63)/64.0f, 0.0f, Sqrt(1.0f-SQR((pan-63)/64.0f)));
}
void CChannel::ClearBuffer()
{
if ( !HasSource() ) return;
alSourcei(alSources[id], AL_LOOPING, AL_FALSE);
alSourcei(alSources[id], AL_BUFFER, AL_NONE);
Data = nil;
DataSize = 0;
}
void CChannel::SetReverbMix(ALuint slot, float mix)
{
if ( !IsFXSupported() ) return;
if ( !HasSource() ) return;
if ( alFilters[id] == AL_FILTER_NULL ) return;
Mix = mix;
EAX3_SetReverbMix(alFilters[id], mix);
alSource3i(alSources[id], AL_AUXILIARY_SEND_FILTER, slot, 0, alFilters[id]);
}
void CChannel::UpdateReverb(ALuint slot)
{
if ( !IsFXSupported() ) return;
if ( !HasSource() ) return;
if ( alFilters[id] == AL_FILTER_NULL ) return;
EAX3_SetReverbMix(alFilters[id], Mix);
alSource3i(alSources[id], AL_AUXILIARY_SEND_FILTER, slot, 0, alFilters[id]);
}
#endif

55
src/audio/oal/channel.h Normal file
View file

@ -0,0 +1,55 @@
#pragma once
#ifdef AUDIO_OAL
#include "oal/oal_utils.h"
#include <AL/al.h>
#include <AL/alext.h>
#include <AL/efx.h>
class CChannel
{
uint32 id;
float Pitch, Gain;
float Mix;
void *Data;
size_t DataSize;
int32 Frequency;
float Position[3];
float Distances[2];
int32 LoopCount;
ALint LoopPoints[2];
ALint LastProcessedOffset;
bool bIs2D;
public:
static int32 channelsThatNeedService;
static void InitChannels();
static void DestroyChannels();
CChannel();
void SetDefault();
void Reset();
void Init(uint32 _id, 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 SetSampleData(void *_data, size_t _DataSize, int32 freq);
void SetCurrentFreq(uint32 freq);
void SetLoopCount(int32 count);
void SetLoopPoints(ALint start, ALint end);
void SetPosition(float x, float y, float z);
void SetDistances(float max, float min);
void SetPan(int32 pan);
void ClearBuffer();
void SetReverbMix(ALuint slot, float mix);
void UpdateReverb(ALuint slot);
bool Update();
};
#endif

181
src/audio/oal/oal_utils.cpp Normal file
View file

@ -0,0 +1,181 @@
#include "common.h"
#include "oal_utils.h"
#ifdef AUDIO_OAL
/*
* When linking to a static openal-soft library,
* the extension function inside the openal library conflict with the variables here.
* Therefore declare these re3 owned symbols in a private namespace.
*/
namespace re3_openal {
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;
}
using namespace re3_openal;
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

54
src/audio/oal/oal_utils.h Normal file
View file

@ -0,0 +1,54 @@
#pragma once
#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);
namespace re3_openal {
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;
}
using namespace re3_openal;
#endif

1759
src/audio/oal/stream.cpp Normal file

File diff suppressed because it is too large Load diff

192
src/audio/oal/stream.h Normal file
View file

@ -0,0 +1,192 @@
#pragma once
#ifdef AUDIO_OAL
#include <AL/al.h>
#define NUM_STREAMBUFFERS 8
class IDecoder
{
public:
virtual ~IDecoder() { }
virtual bool IsOpened() = 0;
virtual void FileOpen() = 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(GetSampleRate());
}
uint32 samples2ms(uint32 sm)
{
return float(sm) * 1000.0f / 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()
{
FileOpen(); // abort deferred init, we need length now - game has to cache audio file sizes
return float(GetSampleCount()) * 1000.0f / float(GetSampleRate());
}
virtual uint32 Decode(void *buffer) = 0;
};
#ifdef MULTITHREADED_AUDIO
template <typename T> class tsQueue
{
public:
tsQueue() : count(0) { }
void push(const T &value)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_queue.push(value);
count++;
}
bool peekPop(T *retVal)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (count == 0)
return false;
*retVal = m_queue.front();
m_queue.pop();
count--;
return true;
}
void swapNts(tsQueue<T> &replaceWith)
{
m_queue.swap(replaceWith.m_queue);
replaceWith.count = count;
}
/*
void swapTs(tsQueue<T> &replaceWith)
{
std::lock_guard<std::mutex> lock(m_mutex);
std::lock_guard<std::mutex> lock2(replaceWith.m_mutex);
swapNts(replaceWith);
}
*/
bool emptyNts()
{
return count == 0;
}
/*
bool emptyTs()
{
std::lock_guard<std::mutex> lock(m_mutex);
return emptyNts();
}
*/
std::queue<T> m_queue;
int count;
mutable std::mutex m_mutex;
};
#endif
class CStream
{
char m_aFilename[128];
ALuint *m_pAlSources;
ALuint (&m_alBuffers)[NUM_STREAMBUFFERS];
bool m_bPaused;
bool m_bActive;
public:
#ifdef MULTITHREADED_AUDIO
std::mutex m_mutex;
std::queue<std::pair<ALuint, ALuint>> m_fillBuffers; // left and right buffer
tsQueue<std::pair<ALuint, ALuint>> m_queueBuffers;
// std::condition_variable m_closeCv;
bool m_bDoSeek;
uint32 m_SeekPos;
bool m_bIExist;
#endif
void *m_pBuffer;
bool m_bReset;
uint32 m_nVolume;
uint8 m_nPan;
uint32 m_nPosBeforeReset;
int32 m_nLoopCount;
IDecoder *m_pSoundFile;
void BuffersShouldBeFilled(); // all
bool BufferShouldBeFilledAndQueued(std::pair<ALuint, ALuint>*); // two (left-right)
#ifdef MULTITHREADED_AUDIO
void FlagAsToBeProcessed(bool close = false);
bool QueueBuffers();
#endif
bool HasSource();
void SetPosition(int i, 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(ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]);
~CStream();
void Delete();
bool Open(const char *filename, uint32 overrideSampleRate = 32000);
void Close();
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(bool imSureQueueIsEmpty = false, bool lock = true);
void Start();
void Stop();
void Update(void);
void SetLoopCount(int32);
void ProviderInit();
void ProviderTerm();
};
#endif