#include "config.h" #include "call.h" #include "exception.h" namespace { constexpr auto deferred_flag = 0x80000000U; class EaxCallException : public EaxException { public: explicit EaxCallException(const char* message) : EaxException{"EAX_CALL", message} {} }; // EaxCallException } // namespace EaxCall::EaxCall( EaxCallType type, const GUID& property_set_guid, ALuint property_id, ALuint property_source_id, ALvoid* property_buffer, ALuint property_size) : type_{type}, version_{0}, property_set_id_{EaxCallPropertySetId::none} , is_deferred_{(property_id & deferred_flag) != 0} , property_id_{property_id & ~deferred_flag}, property_source_id_{property_source_id} , property_buffer_{property_buffer}, property_size_{property_size} { switch (type_) { case EaxCallType::get: case EaxCallType::set: break; default: fail("Invalid type."); } if (false) { } else if (property_set_guid == EAXPROPERTYID_EAX40_Context) { version_ = 4; property_set_id_ = EaxCallPropertySetId::context; } else if (property_set_guid == EAXPROPERTYID_EAX50_Context) { version_ = 5; property_set_id_ = EaxCallPropertySetId::context; } else if (property_set_guid == DSPROPSETID_EAX20_ListenerProperties) { version_ = 2; fx_slot_index_ = 0u; property_set_id_ = EaxCallPropertySetId::fx_slot_effect; } else if (property_set_guid == DSPROPSETID_EAX30_ListenerProperties) { version_ = 3; fx_slot_index_ = 0u; property_set_id_ = EaxCallPropertySetId::fx_slot_effect; } else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot0) { version_ = 4; fx_slot_index_ = 0u; property_set_id_ = EaxCallPropertySetId::fx_slot; } else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot0) { version_ = 5; fx_slot_index_ = 0u; property_set_id_ = EaxCallPropertySetId::fx_slot; } else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot1) { version_ = 4; fx_slot_index_ = 1u; property_set_id_ = EaxCallPropertySetId::fx_slot; } else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot1) { version_ = 5; fx_slot_index_ = 1u; property_set_id_ = EaxCallPropertySetId::fx_slot; } else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot2) { version_ = 4; fx_slot_index_ = 2u; property_set_id_ = EaxCallPropertySetId::fx_slot; } else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot2) { version_ = 5; fx_slot_index_ = 2u; property_set_id_ = EaxCallPropertySetId::fx_slot; } else if (property_set_guid == EAXPROPERTYID_EAX40_FXSlot3) { version_ = 4; fx_slot_index_ = 3u; property_set_id_ = EaxCallPropertySetId::fx_slot; } else if (property_set_guid == EAXPROPERTYID_EAX50_FXSlot3) { version_ = 5; fx_slot_index_ = 3u; property_set_id_ = EaxCallPropertySetId::fx_slot; } else if (property_set_guid == DSPROPSETID_EAX20_BufferProperties) { version_ = 2; property_set_id_ = EaxCallPropertySetId::source; } else if (property_set_guid == DSPROPSETID_EAX30_BufferProperties) { version_ = 3; property_set_id_ = EaxCallPropertySetId::source; } else if (property_set_guid == EAXPROPERTYID_EAX40_Source) { version_ = 4; property_set_id_ = EaxCallPropertySetId::source; } else if (property_set_guid == EAXPROPERTYID_EAX50_Source) { version_ = 5; property_set_id_ = EaxCallPropertySetId::source; } else if (property_set_guid == DSPROPSETID_EAX_ReverbProperties) { version_ = 1; fx_slot_index_ = 0u; property_set_id_ = EaxCallPropertySetId::fx_slot_effect; } else if (property_set_guid == DSPROPSETID_EAXBUFFER_ReverbProperties) { version_ = 1; property_set_id_ = EaxCallPropertySetId::source; } else { fail("Unsupported property set id."); } if (version_ < 1 || version_ > 5) { fail("EAX version out of range."); } switch(property_id) { case EAXCONTEXT_LASTERROR: case EAXCONTEXT_SPEAKERCONFIG: case EAXCONTEXT_EAXSESSION: case EAXFXSLOT_NONE: case EAXFXSLOT_ALLPARAMETERS: case EAXFXSLOT_LOADEFFECT: case EAXFXSLOT_VOLUME: case EAXFXSLOT_LOCK: case EAXFXSLOT_FLAGS: case EAXFXSLOT_OCCLUSION: case EAXFXSLOT_OCCLUSIONLFRATIO: // EAX allow to set "defer" flag on immediate-only properties. // If we don't clear our flag then "applyAllUpdates" in EAX context won't be called. is_deferred_ = false; break; default: break; } if(!is_deferred_) { if(property_set_id_ != EaxCallPropertySetId::fx_slot && property_id_ != 0) { if (property_buffer == nullptr) { fail("Null property buffer."); } if (property_size == 0) { fail("Empty property."); } } } if(property_set_id_ == EaxCallPropertySetId::source && property_source_id_ == 0) { fail("Null AL source id."); } if (property_set_id_ == EaxCallPropertySetId::fx_slot) { if (property_id_ < EAXFXSLOT_NONE) { property_set_id_ = EaxCallPropertySetId::fx_slot_effect; } } } [[noreturn]] void EaxCall::fail(const char* message) { throw EaxCallException{message}; } [[noreturn]] void EaxCall::fail_too_small() { fail("Property buffer too small."); } EaxCall create_eax_call( EaxCallType type, const GUID* property_set_id, ALuint property_id, ALuint property_source_id, ALvoid* property_buffer, ALuint property_size) { if(!property_set_id) throw EaxCallException{"Null property set ID."}; return EaxCall{ type, *property_set_id, property_id, property_source_id, property_buffer, property_size }; }