axmol/thirdparty/openal/al/source.h

1052 lines
35 KiB
C++

#ifndef AL_SOURCE_H
#define AL_SOURCE_H
#include <array>
#include <atomic>
#include <cstddef>
#include <iterator>
#include <limits>
#include <deque>
#include "AL/al.h"
#include "AL/alc.h"
#include "alc/alu.h"
#include "alc/context.h"
#include "alc/inprogext.h"
#include "aldeque.h"
#include "almalloc.h"
#include "alnumeric.h"
#include "atomic.h"
#include "core/voice.h"
#include "vector.h"
#ifdef ALSOFT_EAX
#include "eax/call.h"
#include "eax/exception.h"
#include "eax/fx_slot_index.h"
#include "eax/utils.h"
#endif // ALSOFT_EAX
struct ALbuffer;
struct ALeffectslot;
enum class SourceStereo : bool {
Normal = AL_NORMAL_SOFT,
Enhanced = AL_SUPER_STEREO_SOFT
};
#define DEFAULT_SENDS 2
#define INVALID_VOICE_IDX static_cast<ALuint>(-1)
struct ALbufferQueueItem : public VoiceBufferItem {
ALbuffer *mBuffer{nullptr};
DISABLE_ALLOC()
};
#ifdef ALSOFT_EAX
class EaxSourceException : public EaxException {
public:
explicit EaxSourceException(const char* message)
: EaxException{"EAX_SOURCE", message}
{}
};
#endif // ALSOFT_EAX
struct ALsource {
/** Source properties. */
float Pitch{1.0f};
float Gain{1.0f};
float OuterGain{0.0f};
float MinGain{0.0f};
float MaxGain{1.0f};
float InnerAngle{360.0f};
float OuterAngle{360.0f};
float RefDistance{1.0f};
float MaxDistance{std::numeric_limits<float>::max()};
float RolloffFactor{1.0f};
#ifdef ALSOFT_EAX
// For EAXSOURCE_ROLLOFFFACTOR, which is distinct from and added to
// AL_ROLLOFF_FACTOR
float RolloffFactor2{0.0f};
#endif
std::array<float,3> Position{{0.0f, 0.0f, 0.0f}};
std::array<float,3> Velocity{{0.0f, 0.0f, 0.0f}};
std::array<float,3> Direction{{0.0f, 0.0f, 0.0f}};
std::array<float,3> OrientAt{{0.0f, 0.0f, -1.0f}};
std::array<float,3> OrientUp{{0.0f, 1.0f, 0.0f}};
bool HeadRelative{false};
bool Looping{false};
DistanceModel mDistanceModel{DistanceModel::Default};
Resampler mResampler{ResamplerDefault};
DirectMode DirectChannels{DirectMode::Off};
SpatializeMode mSpatialize{SpatializeMode::Auto};
SourceStereo mStereoMode{SourceStereo::Normal};
bool DryGainHFAuto{true};
bool WetGainAuto{true};
bool WetGainHFAuto{true};
float OuterGainHF{1.0f};
float AirAbsorptionFactor{0.0f};
float RoomRolloffFactor{0.0f};
float DopplerFactor{1.0f};
/* NOTE: Stereo pan angles are specified in radians, counter-clockwise
* rather than clockwise.
*/
std::array<float,2> StereoPan{{al::numbers::pi_v<float>/6.0f, -al::numbers::pi_v<float>/6.0f}};
float Radius{0.0f};
float EnhWidth{0.593f};
/** Direct filter and auxiliary send info. */
struct {
float Gain;
float GainHF;
float HFReference;
float GainLF;
float LFReference;
} Direct;
struct SendData {
ALeffectslot *Slot;
float Gain;
float GainHF;
float HFReference;
float GainLF;
float LFReference;
};
std::array<SendData,MAX_SENDS> Send;
/**
* Last user-specified offset, and the offset type (bytes, samples, or
* seconds).
*/
double Offset{0.0};
ALenum OffsetType{AL_NONE};
/** Source type (static, streaming, or undetermined) */
ALenum SourceType{AL_UNDETERMINED};
/** Source state (initial, playing, paused, or stopped) */
ALenum state{AL_INITIAL};
/** Source Buffer Queue head. */
al::deque<ALbufferQueueItem> mQueue;
bool mPropsDirty{true};
/* Index into the context's Voices array. Lazily updated, only checked and
* reset when looking up the voice.
*/
ALuint VoiceIdx{INVALID_VOICE_IDX};
/** Self ID */
ALuint id{0};
ALsource();
~ALsource();
ALsource(const ALsource&) = delete;
ALsource& operator=(const ALsource&) = delete;
DISABLE_ALLOC()
#ifdef ALSOFT_EAX
public:
void eax_initialize(ALCcontext *context) noexcept;
void eax_dispatch(const EaxCall& call);
void eax_commit() { eax_commit(EaxCommitType::normal); }
void eax_commit_and_update();
bool eax_is_initialized() const noexcept { return eax_al_context_ != nullptr; }
static ALsource* eax_lookup_source(ALCcontext& al_context, ALuint source_id) noexcept;
private:
using Exception = EaxSourceException;
enum class EaxCommitType {
normal,
forced,
};
static constexpr auto eax_max_speakers = 9;
using EaxFxSlotIds = const GUID* [EAX_MAX_FXSLOTS];
static constexpr const EaxFxSlotIds eax4_fx_slot_ids = {
&EAXPROPERTYID_EAX40_FXSlot0,
&EAXPROPERTYID_EAX40_FXSlot1,
&EAXPROPERTYID_EAX40_FXSlot2,
&EAXPROPERTYID_EAX40_FXSlot3,
};
static constexpr const EaxFxSlotIds eax5_fx_slot_ids = {
&EAXPROPERTYID_EAX50_FXSlot0,
&EAXPROPERTYID_EAX50_FXSlot1,
&EAXPROPERTYID_EAX50_FXSlot2,
&EAXPROPERTYID_EAX50_FXSlot3,
};
using EaxActiveFxSlots = std::array<bool, EAX_MAX_FXSLOTS>;
using EaxSpeakerLevels = std::array<EAXSPEAKERLEVELPROPERTIES, eax_max_speakers>;
using EaxSends = std::array<EAXSOURCEALLSENDPROPERTIES, EAX_MAX_FXSLOTS>;
using Eax1Props = EAXBUFFER_REVERBPROPERTIES;
struct Eax1State {
Eax1Props i; // Immediate.
Eax1Props d; // Deferred.
};
using Eax2Props = EAX20BUFFERPROPERTIES;
struct Eax2State {
Eax2Props i; // Immediate.
Eax2Props d; // Deferred.
};
using Eax3Props = EAX30SOURCEPROPERTIES;
struct Eax3State {
Eax3Props i; // Immediate.
Eax3Props d; // Deferred.
};
struct Eax4Props {
Eax3Props source;
EaxSends sends;
EAX40ACTIVEFXSLOTS active_fx_slots;
bool operator==(const Eax4Props& rhs) noexcept
{
return std::memcmp(this, &rhs, sizeof(Eax4Props)) == 0;
}
};
struct Eax4State {
Eax4Props i; // Immediate.
Eax4Props d; // Deferred.
};
struct Eax5Props {
EAX50SOURCEPROPERTIES source;
EaxSends sends;
EAX50ACTIVEFXSLOTS active_fx_slots;
EaxSpeakerLevels speaker_levels;
bool operator==(const Eax5Props& rhs) noexcept
{
return std::memcmp(this, &rhs, sizeof(Eax5Props)) == 0;
}
};
struct Eax5State {
Eax5Props i; // Immediate.
Eax5Props d; // Deferred.
};
ALCcontext* eax_al_context_{};
EaxFxSlotIndex eax_primary_fx_slot_id_{};
EaxActiveFxSlots eax_active_fx_slots_{};
int eax_version_{};
bool eax_changed_{};
Eax1State eax1_{};
Eax2State eax2_{};
Eax3State eax3_{};
Eax4State eax4_{};
Eax5State eax5_{};
Eax5Props eax_{};
// ----------------------------------------------------------------------
// Source validators
struct Eax1SourceReverbMixValidator {
void operator()(float reverb_mix) const
{
if (reverb_mix == EAX_REVERBMIX_USEDISTANCE)
return;
eax_validate_range<Exception>(
"Reverb Mix",
reverb_mix,
EAX_BUFFER_MINREVERBMIX,
EAX_BUFFER_MAXREVERBMIX);
}
};
struct Eax2SourceDirectValidator {
void operator()(long lDirect) const
{
eax_validate_range<Exception>(
"Direct",
lDirect,
EAXSOURCE_MINDIRECT,
EAXSOURCE_MAXDIRECT);
}
};
struct Eax2SourceDirectHfValidator {
void operator()(long lDirectHF) const
{
eax_validate_range<Exception>(
"Direct HF",
lDirectHF,
EAXSOURCE_MINDIRECTHF,
EAXSOURCE_MAXDIRECTHF);
}
};
struct Eax2SourceRoomValidator {
void operator()(long lRoom) const
{
eax_validate_range<Exception>(
"Room",
lRoom,
EAXSOURCE_MINROOM,
EAXSOURCE_MAXROOM);
}
};
struct Eax2SourceRoomHfValidator {
void operator()(long lRoomHF) const
{
eax_validate_range<Exception>(
"Room HF",
lRoomHF,
EAXSOURCE_MINROOMHF,
EAXSOURCE_MAXROOMHF);
}
};
struct Eax2SourceRoomRolloffFactorValidator {
void operator()(float flRoomRolloffFactor) const
{
eax_validate_range<Exception>(
"Room Rolloff Factor",
flRoomRolloffFactor,
EAXSOURCE_MINROOMROLLOFFFACTOR,
EAXSOURCE_MAXROOMROLLOFFFACTOR);
}
};
struct Eax2SourceObstructionValidator {
void operator()(long lObstruction) const
{
eax_validate_range<Exception>(
"Obstruction",
lObstruction,
EAXSOURCE_MINOBSTRUCTION,
EAXSOURCE_MAXOBSTRUCTION);
}
};
struct Eax2SourceObstructionLfRatioValidator {
void operator()(float flObstructionLFRatio) const
{
eax_validate_range<Exception>(
"Obstruction LF Ratio",
flObstructionLFRatio,
EAXSOURCE_MINOBSTRUCTIONLFRATIO,
EAXSOURCE_MAXOBSTRUCTIONLFRATIO);
}
};
struct Eax2SourceOcclusionValidator {
void operator()(long lOcclusion) const
{
eax_validate_range<Exception>(
"Occlusion",
lOcclusion,
EAXSOURCE_MINOCCLUSION,
EAXSOURCE_MAXOCCLUSION);
}
};
struct Eax2SourceOcclusionLfRatioValidator {
void operator()(float flOcclusionLFRatio) const
{
eax_validate_range<Exception>(
"Occlusion LF Ratio",
flOcclusionLFRatio,
EAXSOURCE_MINOCCLUSIONLFRATIO,
EAXSOURCE_MAXOCCLUSIONLFRATIO);
}
};
struct Eax2SourceOcclusionRoomRatioValidator {
void operator()(float flOcclusionRoomRatio) const
{
eax_validate_range<Exception>(
"Occlusion Room Ratio",
flOcclusionRoomRatio,
EAXSOURCE_MINOCCLUSIONROOMRATIO,
EAXSOURCE_MAXOCCLUSIONROOMRATIO);
}
};
struct Eax2SourceOutsideVolumeHfValidator {
void operator()(long lOutsideVolumeHF) const
{
eax_validate_range<Exception>(
"Outside Volume HF",
lOutsideVolumeHF,
EAXSOURCE_MINOUTSIDEVOLUMEHF,
EAXSOURCE_MAXOUTSIDEVOLUMEHF);
}
};
struct Eax2SourceAirAbsorptionFactorValidator {
void operator()(float flAirAbsorptionFactor) const
{
eax_validate_range<Exception>(
"Air Absorption Factor",
flAirAbsorptionFactor,
EAXSOURCE_MINAIRABSORPTIONFACTOR,
EAXSOURCE_MAXAIRABSORPTIONFACTOR);
}
};
struct Eax2SourceFlagsValidator {
void operator()(unsigned long dwFlags) const
{
eax_validate_range<Exception>(
"Flags",
dwFlags,
0UL,
~EAX20SOURCEFLAGS_RESERVED);
}
};
struct Eax3SourceOcclusionDirectRatioValidator {
void operator()(float flOcclusionDirectRatio) const
{
eax_validate_range<Exception>(
"Occlusion Direct Ratio",
flOcclusionDirectRatio,
EAXSOURCE_MINOCCLUSIONDIRECTRATIO,
EAXSOURCE_MAXOCCLUSIONDIRECTRATIO);
}
};
struct Eax3SourceExclusionValidator {
void operator()(long lExclusion) const
{
eax_validate_range<Exception>(
"Exclusion",
lExclusion,
EAXSOURCE_MINEXCLUSION,
EAXSOURCE_MAXEXCLUSION);
}
};
struct Eax3SourceExclusionLfRatioValidator {
void operator()(float flExclusionLFRatio) const
{
eax_validate_range<Exception>(
"Exclusion LF Ratio",
flExclusionLFRatio,
EAXSOURCE_MINEXCLUSIONLFRATIO,
EAXSOURCE_MAXEXCLUSIONLFRATIO);
}
};
struct Eax3SourceDopplerFactorValidator {
void operator()(float flDopplerFactor) const
{
eax_validate_range<Exception>(
"Doppler Factor",
flDopplerFactor,
EAXSOURCE_MINDOPPLERFACTOR,
EAXSOURCE_MAXDOPPLERFACTOR);
}
};
struct Eax3SourceRolloffFactorValidator {
void operator()(float flRolloffFactor) const
{
eax_validate_range<Exception>(
"Rolloff Factor",
flRolloffFactor,
EAXSOURCE_MINROLLOFFFACTOR,
EAXSOURCE_MAXROLLOFFFACTOR);
}
};
struct Eax5SourceMacroFXFactorValidator {
void operator()(float flMacroFXFactor) const
{
eax_validate_range<Exception>(
"Macro FX Factor",
flMacroFXFactor,
EAXSOURCE_MINMACROFXFACTOR,
EAXSOURCE_MAXMACROFXFACTOR);
}
};
struct Eax5SourceFlagsValidator {
void operator()(unsigned long dwFlags) const
{
eax_validate_range<Exception>(
"Flags",
dwFlags,
0UL,
~EAX50SOURCEFLAGS_RESERVED);
}
};
struct Eax1SourceAllValidator {
void operator()(const Eax1Props& props) const
{
Eax1SourceReverbMixValidator{}(props.fMix);
}
};
struct Eax2SourceAllValidator {
void operator()(const Eax2Props& props) const
{
Eax2SourceDirectValidator{}(props.lDirect);
Eax2SourceDirectHfValidator{}(props.lDirectHF);
Eax2SourceRoomValidator{}(props.lRoom);
Eax2SourceRoomHfValidator{}(props.lRoomHF);
Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
Eax2SourceObstructionValidator{}(props.lObstruction);
Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
Eax2SourceOcclusionValidator{}(props.lOcclusion);
Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
Eax2SourceFlagsValidator{}(props.dwFlags);
}
};
struct Eax3SourceAllValidator {
void operator()(const Eax3Props& props) const
{
Eax2SourceDirectValidator{}(props.lDirect);
Eax2SourceDirectHfValidator{}(props.lDirectHF);
Eax2SourceRoomValidator{}(props.lRoom);
Eax2SourceRoomHfValidator{}(props.lRoomHF);
Eax2SourceObstructionValidator{}(props.lObstruction);
Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
Eax2SourceOcclusionValidator{}(props.lOcclusion);
Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
Eax3SourceExclusionValidator{}(props.lExclusion);
Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
Eax2SourceOutsideVolumeHfValidator{}(props.lOutsideVolumeHF);
Eax3SourceDopplerFactorValidator{}(props.flDopplerFactor);
Eax3SourceRolloffFactorValidator{}(props.flRolloffFactor);
Eax2SourceRoomRolloffFactorValidator{}(props.flRoomRolloffFactor);
Eax2SourceAirAbsorptionFactorValidator{}(props.flAirAbsorptionFactor);
Eax2SourceFlagsValidator{}(props.ulFlags);
}
};
struct Eax5SourceAllValidator {
void operator()(const EAX50SOURCEPROPERTIES& props) const
{
Eax3SourceAllValidator{}(static_cast<const Eax3Props&>(props));
Eax5SourceMacroFXFactorValidator{}(props.flMacroFXFactor);
}
};
struct Eax5SourceAll2dValidator {
void operator()(const EAXSOURCE2DPROPERTIES& props) const
{
Eax2SourceDirectValidator{}(props.lDirect);
Eax2SourceDirectHfValidator{}(props.lDirectHF);
Eax2SourceRoomValidator{}(props.lRoom);
Eax2SourceRoomHfValidator{}(props.lRoomHF);
Eax5SourceFlagsValidator{}(props.ulFlags);
}
};
struct Eax4ObstructionValidator {
void operator()(const EAXOBSTRUCTIONPROPERTIES& props) const
{
Eax2SourceObstructionValidator{}(props.lObstruction);
Eax2SourceObstructionLfRatioValidator{}(props.flObstructionLFRatio);
}
};
struct Eax4OcclusionValidator {
void operator()(const EAXOCCLUSIONPROPERTIES& props) const
{
Eax2SourceOcclusionValidator{}(props.lOcclusion);
Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
}
};
struct Eax4ExclusionValidator {
void operator()(const EAXEXCLUSIONPROPERTIES& props) const
{
Eax3SourceExclusionValidator{}(props.lExclusion);
Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
}
};
// Source validators
// ----------------------------------------------------------------------
// Send validators
struct Eax4SendReceivingFxSlotIdValidator {
void operator()(const GUID& guidReceivingFXSlotID) const
{
if (guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot0 &&
guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot1 &&
guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot2 &&
guidReceivingFXSlotID != EAXPROPERTYID_EAX40_FXSlot3)
{
eax_fail_unknown_receiving_fx_slot_id();
}
}
};
struct Eax5SendReceivingFxSlotIdValidator {
void operator()(const GUID& guidReceivingFXSlotID) const
{
if (guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot0 &&
guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot1 &&
guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot2 &&
guidReceivingFXSlotID != EAXPROPERTYID_EAX50_FXSlot3)
{
eax_fail_unknown_receiving_fx_slot_id();
}
}
};
struct Eax4SendSendValidator {
void operator()(long lSend) const
{
eax_validate_range<Exception>(
"Send",
lSend,
EAXSOURCE_MINSEND,
EAXSOURCE_MAXSEND);
}
};
struct Eax4SendSendHfValidator {
void operator()(long lSendHF) const
{
eax_validate_range<Exception>(
"Send HF",
lSendHF,
EAXSOURCE_MINSENDHF,
EAXSOURCE_MAXSENDHF);
}
};
template<typename TIdValidator>
struct EaxSendValidator {
void operator()(const EAXSOURCESENDPROPERTIES& props) const
{
TIdValidator{}(props.guidReceivingFXSlotID);
Eax4SendSendValidator{}(props.lSend);
Eax4SendSendHfValidator{}(props.lSendHF);
}
};
struct Eax4SendValidator : EaxSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
struct Eax5SendValidator : EaxSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
template<typename TIdValidator>
struct EaxOcclusionSendValidator {
void operator()(const EAXSOURCEOCCLUSIONSENDPROPERTIES& props) const
{
TIdValidator{}(props.guidReceivingFXSlotID);
Eax2SourceOcclusionValidator{}(props.lOcclusion);
Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
}
};
struct Eax4OcclusionSendValidator : EaxOcclusionSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
struct Eax5OcclusionSendValidator : EaxOcclusionSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
template<typename TIdValidator>
struct EaxExclusionSendValidator {
void operator()(const EAXSOURCEEXCLUSIONSENDPROPERTIES& props) const
{
TIdValidator{}(props.guidReceivingFXSlotID);
Eax3SourceExclusionValidator{}(props.lExclusion);
Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
}
};
struct Eax4ExclusionSendValidator : EaxExclusionSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
struct Eax5ExclusionSendValidator : EaxExclusionSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
template<typename TIdValidator>
struct EaxAllSendValidator {
void operator()(const EAXSOURCEALLSENDPROPERTIES& props) const
{
TIdValidator{}(props.guidReceivingFXSlotID);
Eax4SendSendValidator{}(props.lSend);
Eax4SendSendHfValidator{}(props.lSendHF);
Eax2SourceOcclusionValidator{}(props.lOcclusion);
Eax2SourceOcclusionLfRatioValidator{}(props.flOcclusionLFRatio);
Eax2SourceOcclusionRoomRatioValidator{}(props.flOcclusionRoomRatio);
Eax3SourceOcclusionDirectRatioValidator{}(props.flOcclusionDirectRatio);
Eax3SourceExclusionValidator{}(props.lExclusion);
Eax3SourceExclusionLfRatioValidator{}(props.flExclusionLFRatio);
}
};
struct Eax4AllSendValidator : EaxAllSendValidator<Eax4SendReceivingFxSlotIdValidator> {};
struct Eax5AllSendValidator : EaxAllSendValidator<Eax5SendReceivingFxSlotIdValidator> {};
// Send validators
// ----------------------------------------------------------------------
// Active FX slot ID validators
struct Eax4ActiveFxSlotIdValidator {
void operator()(const GUID &guid) const
{
if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID
&& guid != EAXPROPERTYID_EAX40_FXSlot0 && guid != EAXPROPERTYID_EAX40_FXSlot1
&& guid != EAXPROPERTYID_EAX40_FXSlot2 && guid != EAXPROPERTYID_EAX40_FXSlot3)
{
eax_fail_unknown_active_fx_slot_id();
}
}
};
struct Eax5ActiveFxSlotIdValidator {
void operator()(const GUID &guid) const
{
if(guid != EAX_NULL_GUID && guid != EAX_PrimaryFXSlotID
&& guid != EAXPROPERTYID_EAX50_FXSlot0 && guid != EAXPROPERTYID_EAX50_FXSlot1
&& guid != EAXPROPERTYID_EAX50_FXSlot2 && guid != EAXPROPERTYID_EAX50_FXSlot3)
{
eax_fail_unknown_active_fx_slot_id();
}
}
};
// Active FX slot ID validators
// ----------------------------------------------------------------------
// Speaker level validators.
struct Eax5SpeakerIdValidator {
void operator()(long lSpeakerID) const
{
switch (lSpeakerID) {
case EAXSPEAKER_FRONT_LEFT:
case EAXSPEAKER_FRONT_CENTER:
case EAXSPEAKER_FRONT_RIGHT:
case EAXSPEAKER_SIDE_RIGHT:
case EAXSPEAKER_REAR_RIGHT:
case EAXSPEAKER_REAR_CENTER:
case EAXSPEAKER_REAR_LEFT:
case EAXSPEAKER_SIDE_LEFT:
case EAXSPEAKER_LOW_FREQUENCY:
break;
default:
eax_fail("Unknown speaker ID.");
}
}
};
struct Eax5SpeakerLevelValidator {
void operator()(long lLevel) const
{
// TODO Use a range when the feature will be implemented.
if (lLevel != EAXSOURCE_DEFAULTSPEAKERLEVEL)
eax_fail("Speaker level out of range.");
}
};
struct Eax5SpeakerAllValidator {
void operator()(const EAXSPEAKERLEVELPROPERTIES& all) const
{
Eax5SpeakerIdValidator{}(all.lSpeakerID);
Eax5SpeakerLevelValidator{}(all.lLevel);
}
};
// Speaker level validators.
// ----------------------------------------------------------------------
struct Eax4SendIndexGetter {
EaxFxSlotIndexValue operator()(const GUID &guid) const
{
if(guid == EAXPROPERTYID_EAX40_FXSlot0)
return 0;
if(guid == EAXPROPERTYID_EAX40_FXSlot1)
return 1;
if(guid == EAXPROPERTYID_EAX40_FXSlot2)
return 2;
if(guid == EAXPROPERTYID_EAX40_FXSlot3)
return 3;
eax_fail_unknown_receiving_fx_slot_id();
}
};
struct Eax5SendIndexGetter {
EaxFxSlotIndexValue operator()(const GUID &guid) const
{
if(guid == EAXPROPERTYID_EAX50_FXSlot0)
return 0;
if(guid == EAXPROPERTYID_EAX50_FXSlot1)
return 1;
if(guid == EAXPROPERTYID_EAX50_FXSlot2)
return 2;
if(guid == EAXPROPERTYID_EAX50_FXSlot3)
return 3;
eax_fail_unknown_receiving_fx_slot_id();
}
};
[[noreturn]] static void eax_fail(const char* message);
[[noreturn]] static void eax_fail_unknown_property_id();
[[noreturn]] static void eax_fail_unknown_version();
[[noreturn]] static void eax_fail_unknown_active_fx_slot_id();
[[noreturn]] static void eax_fail_unknown_receiving_fx_slot_id();
void eax_set_sends_defaults(EaxSends& sends, const EaxFxSlotIds& ids) noexcept;
void eax1_set_defaults(Eax1Props& props) noexcept;
void eax1_set_defaults() noexcept;
void eax2_set_defaults(Eax2Props& props) noexcept;
void eax2_set_defaults() noexcept;
void eax3_set_defaults(Eax3Props& props) noexcept;
void eax3_set_defaults() noexcept;
void eax4_set_sends_defaults(EaxSends& sends) noexcept;
void eax4_set_active_fx_slots_defaults(EAX40ACTIVEFXSLOTS& slots) noexcept;
void eax4_set_defaults() noexcept;
void eax5_set_source_defaults(EAX50SOURCEPROPERTIES& props) noexcept;
void eax5_set_sends_defaults(EaxSends& sends) noexcept;
void eax5_set_active_fx_slots_defaults(EAX50ACTIVEFXSLOTS& slots) noexcept;
void eax5_set_speaker_levels_defaults(EaxSpeakerLevels& speaker_levels) noexcept;
void eax5_set_defaults(Eax5Props& props) noexcept;
void eax5_set_defaults() noexcept;
void eax_set_defaults() noexcept;
void eax1_translate(const Eax1Props& src, Eax5Props& dst) noexcept;
void eax2_translate(const Eax2Props& src, Eax5Props& dst) noexcept;
void eax3_translate(const Eax3Props& src, Eax5Props& dst) noexcept;
void eax4_translate(const Eax4Props& src, Eax5Props& dst) noexcept;
static float eax_calculate_dst_occlusion_mb(
long src_occlusion_mb,
float path_ratio,
float lf_ratio) noexcept;
EaxAlLowPassParam eax_create_direct_filter_param() const noexcept;
EaxAlLowPassParam eax_create_room_filter_param(
const ALeffectslot& fx_slot,
const EAXSOURCEALLSENDPROPERTIES& send) const noexcept;
void eax_update_direct_filter();
void eax_update_room_filters();
void eax_commit_filters();
static void eax_copy_send_for_get(
const EAXSOURCEALLSENDPROPERTIES& src,
EAXSOURCESENDPROPERTIES& dst) noexcept
{
dst = reinterpret_cast<const EAXSOURCESENDPROPERTIES&>(src);
}
static void eax_copy_send_for_get(
const EAXSOURCEALLSENDPROPERTIES& src,
EAXSOURCEALLSENDPROPERTIES& dst) noexcept
{
dst = src;
}
static void eax_copy_send_for_get(
const EAXSOURCEALLSENDPROPERTIES& src,
EAXSOURCEOCCLUSIONSENDPROPERTIES& dst) noexcept
{
dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID;
dst.lOcclusion = src.lOcclusion;
dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
}
static void eax_copy_send_for_get(
const EAXSOURCEALLSENDPROPERTIES& src,
EAXSOURCEEXCLUSIONSENDPROPERTIES& dst) noexcept
{
dst.guidReceivingFXSlotID = src.guidReceivingFXSlotID;
dst.lExclusion = src.lExclusion;
dst.flExclusionLFRatio = src.flExclusionLFRatio;
}
template<typename TDstSend>
void eax_get_sends(const EaxCall& call, const EaxSends& src_sends)
{
const auto dst_sends = call.get_values<TDstSend>(EAX_MAX_FXSLOTS);
const auto count = dst_sends.size();
for (auto i = decltype(count){}; i < count; ++i) {
const auto& src_send = src_sends[i];
auto& dst_send = dst_sends[i];
eax_copy_send_for_get(src_send, dst_send);
}
}
void eax1_get(const EaxCall& call, const Eax1Props& props);
void eax2_get(const EaxCall& call, const Eax2Props& props);
void eax3_get_obstruction(const EaxCall& call, const Eax3Props& props);
void eax3_get_occlusion(const EaxCall& call, const Eax3Props& props);
void eax3_get_exclusion(const EaxCall& call, const Eax3Props& props);
void eax3_get(const EaxCall& call, const Eax3Props& props);
void eax4_get(const EaxCall& call, const Eax4Props& props);
void eax5_get_all_2d(const EaxCall& call, const EAX50SOURCEPROPERTIES& props);
void eax5_get_speaker_levels(const EaxCall& call, const EaxSpeakerLevels& props);
void eax5_get(const EaxCall& call, const Eax5Props& props);
void eax_get(const EaxCall& call);
static void eax_copy_send_for_set(
const EAXSOURCESENDPROPERTIES& src,
EAXSOURCEALLSENDPROPERTIES& dst) noexcept
{
dst.lSend = src.lSend;
dst.lSendHF = src.lSendHF;
}
static void eax_copy_send_for_set(
const EAXSOURCEALLSENDPROPERTIES& src,
EAXSOURCEALLSENDPROPERTIES& dst) noexcept
{
dst.lSend = src.lSend;
dst.lSendHF = src.lSendHF;
dst.lOcclusion = src.lOcclusion;
dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
dst.lExclusion = src.lExclusion;
dst.flExclusionLFRatio = src.flExclusionLFRatio;
}
static void eax_copy_send_for_set(
const EAXSOURCEOCCLUSIONSENDPROPERTIES& src,
EAXSOURCEALLSENDPROPERTIES& dst) noexcept
{
dst.lOcclusion = src.lOcclusion;
dst.flOcclusionLFRatio = src.flOcclusionLFRatio;
dst.flOcclusionRoomRatio = src.flOcclusionRoomRatio;
dst.flOcclusionDirectRatio = src.flOcclusionDirectRatio;
}
static void eax_copy_send_for_set(
const EAXSOURCEEXCLUSIONSENDPROPERTIES& src,
EAXSOURCEALLSENDPROPERTIES& dst) noexcept
{
dst.lExclusion = src.lExclusion;
dst.flExclusionLFRatio = src.flExclusionLFRatio;
}
template<typename TValidator, typename TIndexGetter, typename TSrcSend>
void eax_defer_sends(const EaxCall& call, EaxSends& dst_sends)
{
const auto src_sends = call.get_values<const TSrcSend>(EAX_MAX_FXSLOTS);
std::for_each(src_sends.cbegin(), src_sends.cend(), TValidator{});
const auto count = src_sends.size();
const auto index_getter = TIndexGetter{};
for (auto i = decltype(count){}; i < count; ++i) {
const auto& src_send = src_sends[i];
const auto dst_index = index_getter(src_send.guidReceivingFXSlotID);
auto& dst_send = dst_sends[dst_index];
eax_copy_send_for_set(src_send, dst_send);
}
}
template<typename TValidator, typename TSrcSend>
void eax4_defer_sends(const EaxCall& call, EaxSends& dst_sends)
{
eax_defer_sends<TValidator, Eax4SendIndexGetter, TSrcSend>(call, dst_sends);
}
template<typename TValidator, typename TSrcSend>
void eax5_defer_sends(const EaxCall& call, EaxSends& dst_sends)
{
eax_defer_sends<TValidator, Eax5SendIndexGetter, TSrcSend>(call, dst_sends);
}
template<typename TValidator, size_t TIdCount>
void eax_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
{
const auto src_ids = call.get_values<const GUID>(TIdCount);
std::for_each(src_ids.cbegin(), src_ids.cend(), TValidator{});
std::uninitialized_copy(src_ids.cbegin(), src_ids.cend(), dst_ids);
}
template<size_t TIdCount>
void eax4_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
{
eax_defer_active_fx_slot_id<Eax4ActiveFxSlotIdValidator>(call, dst_ids);
}
template<size_t TIdCount>
void eax5_defer_active_fx_slot_id(const EaxCall& call, GUID (&dst_ids)[TIdCount])
{
eax_defer_active_fx_slot_id<Eax5ActiveFxSlotIdValidator>(call, dst_ids);
}
template<typename TValidator, typename TProperty>
static void eax_defer(const EaxCall& call, TProperty& property)
{
const auto& value = call.get_value<Exception, const TProperty>();
TValidator{}(value);
property = value;
}
// Defers source's sub-properties (obstruction, occlusion, exclusion).
template<typename TValidator, typename TSubproperty, typename TProperty>
void eax_defer_sub(const EaxCall& call, TProperty& property)
{
const auto& src_props = call.get_value<Exception, const TSubproperty>();
TValidator{}(src_props);
auto& dst_props = reinterpret_cast<TSubproperty&>(property);
dst_props = src_props;
}
void eax_set_efx_outer_gain_hf();
void eax_set_efx_doppler_factor();
void eax_set_efx_rolloff_factor();
void eax_set_efx_room_rolloff_factor();
void eax_set_efx_air_absorption_factor();
void eax_set_efx_dry_gain_hf_auto();
void eax_set_efx_wet_gain_auto();
void eax_set_efx_wet_gain_hf_auto();
void eax1_set(const EaxCall& call, Eax1Props& props);
void eax2_set(const EaxCall& call, Eax2Props& props);
void eax3_set(const EaxCall& call, Eax3Props& props);
void eax4_set(const EaxCall& call, Eax4Props& props);
void eax5_defer_all_2d(const EaxCall& call, EAX50SOURCEPROPERTIES& props);
void eax5_defer_speaker_levels(const EaxCall& call, EaxSpeakerLevels& props);
void eax5_set(const EaxCall& call, Eax5Props& props);
void eax_set(const EaxCall& call);
// `alSource3i(source, AL_AUXILIARY_SEND_FILTER, ...)`
void eax_set_al_source_send(ALeffectslot *slot, size_t sendidx,
const EaxAlLowPassParam &filter);
void eax_commit_active_fx_slots();
void eax_commit(EaxCommitType commit_type);
#endif // ALSOFT_EAX
};
void UpdateAllSourceProps(ALCcontext *context);
#endif