/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ // Original file Copyright Crytek GMBH or its affiliates, used under license. #include #include #include #include #include #include #include #include #include #include #include #include namespace AudioControls { //-------------------------------------------------------------------------------------------// TImplControlType TagToType(const AZStd::string_view tag) { if (tag == Audio::WwiseXmlTags::WwiseEventTag) { return eWCT_WWISE_EVENT; } else if (tag == Audio::WwiseXmlTags::WwiseRtpcTag) { return eWCT_WWISE_RTPC; } else if (tag == Audio::WwiseXmlTags::WwiseAuxBusTag) { return eWCT_WWISE_AUX_BUS; } else if (tag == Audio::WwiseXmlTags::WwiseFileTag) { return eWCT_WWISE_SOUND_BANK; } else if (tag == Audio::WwiseXmlTags::WwiseSwitchTag) { return eWCT_WWISE_SWITCH_GROUP; } else if (tag == Audio::WwiseXmlTags::WwiseStateTag) { return eWCT_WWISE_GAME_STATE_GROUP; } return eWCT_INVALID; } //-------------------------------------------------------------------------------------------// const AZStd::string_view TypeToTag(const TImplControlType type) { switch (type) { case eWCT_WWISE_EVENT: return Audio::WwiseXmlTags::WwiseEventTag; case eWCT_WWISE_RTPC: return Audio::WwiseXmlTags::WwiseRtpcTag; case eWCT_WWISE_SWITCH: return Audio::WwiseXmlTags::WwiseValueTag; case eWCT_WWISE_AUX_BUS: return Audio::WwiseXmlTags::WwiseAuxBusTag; case eWCT_WWISE_SOUND_BANK: return Audio::WwiseXmlTags::WwiseFileTag; case eWCT_WWISE_GAME_STATE: return Audio::WwiseXmlTags::WwiseValueTag; case eWCT_WWISE_SWITCH_GROUP: return Audio::WwiseXmlTags::WwiseSwitchTag; case eWCT_WWISE_GAME_STATE_GROUP: return Audio::WwiseXmlTags::WwiseStateTag; } return ""; } //-------------------------------------------------------------------------------------------// void CAudioSystemEditor_wwise::Reload() { // set all the controls as placeholder as we don't know if // any of them have been removed but still have connections to them for (const auto& idControlPair : m_controls) { TControlPtr control = idControlPair.second; if (control) { control->SetPlaceholder(true); } } // reload data m_loader.Load(this); m_connectionsByID.clear(); UpdateConnectedStatus(); } //-------------------------------------------------------------------------------------------// IAudioSystemControl* CAudioSystemEditor_wwise::CreateControl(const SControlDef& controlDefinition) { AZStd::string fullName = controlDefinition.m_name; IAudioSystemControl* parent = controlDefinition.m_parentControl; if (parent) { AZ::StringFunc::Path::Join(controlDefinition.m_parentControl->GetName().c_str(), fullName.c_str(), fullName); } if (!controlDefinition.m_path.empty()) { AZ::StringFunc::Path::Join(controlDefinition.m_path.c_str(), fullName.c_str(), fullName); } CID id = GetID(fullName); IAudioSystemControl* control = GetControl(id); if (control) { if (control->IsPlaceholder()) { control->SetPlaceholder(false); if (parent && parent->IsPlaceholder()) { parent->SetPlaceholder(false); } } return control; } else { TControlPtr newControl = AZStd::make_shared(controlDefinition.m_name, id, controlDefinition.m_type); if (!parent) { parent = &m_rootControl; } parent->AddChild(newControl.get()); newControl->SetParent(parent); newControl->SetLocalized(controlDefinition.m_isLocalized); m_controls[id] = newControl; return newControl.get(); } } //-------------------------------------------------------------------------------------------// IAudioSystemControl* CAudioSystemEditor_wwise::GetControl(CID id) const { if (id != ACE_INVALID_CID) { auto it = m_controls.find(id); if (it != m_controls.end()) { return it->second.get(); } } return nullptr; } //-------------------------------------------------------------------------------------------// IAudioSystemControl* CAudioSystemEditor_wwise::GetControlByName(AZStd::string name, bool isLocalized, IAudioSystemControl* parent) const { if (parent) { AZ::StringFunc::Path::Join(parent->GetName().c_str(), name.c_str(), name); } if (isLocalized) { AZ::StringFunc::Path::Join(m_loader.GetLocalizationFolder().c_str(), name.c_str(), name); } return GetControl(GetID(name)); } //-------------------------------------------------------------------------------------------// TConnectionPtr CAudioSystemEditor_wwise::CreateConnectionToControl(EACEControlType atlControlType, IAudioSystemControl* middlewareControl) { if (middlewareControl) { middlewareControl->SetConnected(true); ++m_connectionsByID[middlewareControl->GetId()]; if (middlewareControl->GetType() == eWCT_WWISE_RTPC) { switch (atlControlType) { case EACEControlType::eACET_RTPC: { return AZStd::make_shared(middlewareControl->GetId()); } case EACEControlType::eACET_SWITCH_STATE: { return AZStd::make_shared(middlewareControl->GetId()); } } } return AZStd::make_shared(middlewareControl->GetId()); } return nullptr; } //-------------------------------------------------------------------------------------------// TConnectionPtr CAudioSystemEditor_wwise::CreateConnectionFromXMLNode(XmlNodeRef node, EACEControlType atlControlType) { if (node) { const AZStd::string tag(node->getTag()); TImplControlType type = TagToType(tag); if (type != AUDIO_IMPL_INVALID_TYPE) { AZStd::string name(node->getAttr(Audio::WwiseXmlTags::WwiseNameAttribute)); AZStd::string localized(node->getAttr(Audio::WwiseXmlTags::WwiseLocalizedAttribute)); // Legacy Preload support if (localized.empty()) { localized = node->getAttr(Audio::WwiseXmlTags::Legacy::WwiseLocalizedAttribute); } bool isLocalized = AZ::StringFunc::Equal(localized.c_str(), "true"); // If control not found, create a placeholder. // We want to keep that connection even if it's not in the middleware. // The user could be using the engine without the wwise project IAudioSystemControl* control = GetControlByName(name, isLocalized); if (!control) { control = CreateControl(SControlDef(name, type)); if (control) { control->SetPlaceholder(true); control->SetLocalized(isLocalized); } } // If it's a switch we actually connect to one of the states within the switch if (type == eWCT_WWISE_SWITCH_GROUP || type == eWCT_WWISE_GAME_STATE_GROUP) { if (node->getChildCount() == 1) { node = node->getChild(0); if (node) { AZStd::string childName(node->getAttr(Audio::WwiseXmlTags::WwiseNameAttribute)); IAudioSystemControl* childControl = GetControlByName(childName, false, control); if (!childControl) { childControl = CreateControl(SControlDef(childName, type == eWCT_WWISE_SWITCH_GROUP ? eWCT_WWISE_SWITCH : eWCT_WWISE_GAME_STATE, false, control)); } control = childControl; } } else { CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_ERROR, "Audio Controls Editor (Wwise): Error reading connection to Wwise control %s", name); } } if (control) { control->SetConnected(true); ++m_connectionsByID[control->GetId()]; if (type == eWCT_WWISE_RTPC) { switch (atlControlType) { case EACEControlType::eACET_RTPC: { TRtpcConnectionPtr connection = AZStd::make_shared(control->GetId()); float mult = 1.0f; float shift = 0.0f; if (node->haveAttr(Audio::WwiseXmlTags::WwiseMutiplierAttribute)) { const AZStd::string multProperty(node->getAttr(Audio::WwiseXmlTags::WwiseMutiplierAttribute)); mult = AZStd::stof(multProperty); } if (node->haveAttr(Audio::WwiseXmlTags::WwiseShiftAttribute)) { const AZStd::string shiftProperty(node->getAttr(Audio::WwiseXmlTags::WwiseShiftAttribute)); shift = AZStd::stof(shiftProperty); } connection->m_mult = mult; connection->m_shift = shift; return connection; } case EACEControlType::eACET_SWITCH_STATE: { TStateConnectionPtr connection = AZStd::make_shared(control->GetId()); float value = 0.0f; if (node->haveAttr(Audio::WwiseXmlTags::WwiseValueAttribute)) { const AZStd::string valueProperty(node->getAttr(Audio::WwiseXmlTags::WwiseValueAttribute)); value = AZStd::stof(valueProperty); } connection->m_value = value; return connection; } } } else { return AZStd::make_shared(control->GetId()); } } } } return nullptr; } //-------------------------------------------------------------------------------------------// XmlNodeRef CAudioSystemEditor_wwise::CreateXMLNodeFromConnection(const TConnectionPtr connection, const EACEControlType atlControlType) { const IAudioSystemControl* control = GetControl(connection->GetID()); if (control) { switch (control->GetType()) { case AudioControls::eWCT_WWISE_SWITCH: case AudioControls::eWCT_WWISE_SWITCH_GROUP: case AudioControls::eWCT_WWISE_GAME_STATE: case AudioControls::eWCT_WWISE_GAME_STATE_GROUP: { const IAudioSystemControl* parent = control->GetParent(); if (parent) { XmlNodeRef switchNode = GetISystem()->CreateXmlNode(TypeToTag(parent->GetType()).data()); switchNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, parent->GetName().c_str()); XmlNodeRef stateNode = switchNode->createNode(Audio::WwiseXmlTags::WwiseValueTag); stateNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str()); switchNode->addChild(stateNode); return switchNode; } break; } case AudioControls::eWCT_WWISE_RTPC: { XmlNodeRef connectionNode = GetISystem()->CreateXmlNode(TypeToTag(control->GetType()).data()); connectionNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str()); if (atlControlType == eACET_RTPC) { AZStd::shared_ptr rtpcConnection = AZStd::static_pointer_cast(connection); if (rtpcConnection->m_mult != 1.0f) { connectionNode->setAttr(Audio::WwiseXmlTags::WwiseMutiplierAttribute, rtpcConnection->m_mult); } if (rtpcConnection->m_shift != 0.0f) { connectionNode->setAttr(Audio::WwiseXmlTags::WwiseShiftAttribute, rtpcConnection->m_shift); } } else if (atlControlType == eACET_SWITCH_STATE) { AZStd::shared_ptr stateConnection = AZStd::static_pointer_cast(connection); connectionNode->setAttr(Audio::WwiseXmlTags::WwiseValueAttribute, stateConnection->m_value); } return connectionNode; } case AudioControls::eWCT_WWISE_EVENT: { XmlNodeRef connectionNode = GetISystem()->CreateXmlNode(TypeToTag(control->GetType()).data()); connectionNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str()); return connectionNode; } case AudioControls::eWCT_WWISE_AUX_BUS: { XmlNodeRef connectionNode = GetISystem()->CreateXmlNode(TypeToTag(control->GetType()).data()); connectionNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str()); return connectionNode; } case AudioControls::eWCT_WWISE_SOUND_BANK: { XmlNodeRef connectionNode = GetISystem()->CreateXmlNode(TypeToTag(control->GetType()).data()); connectionNode->setAttr(Audio::WwiseXmlTags::WwiseNameAttribute, control->GetName().c_str()); if (control->IsLocalized()) { connectionNode->setAttr(Audio::WwiseXmlTags::WwiseLocalizedAttribute, "true"); } return connectionNode; } } } return nullptr; } //-------------------------------------------------------------------------------------------// const AZStd::string_view CAudioSystemEditor_wwise::GetTypeIcon(TImplControlType type) const { switch (type) { case eWCT_WWISE_EVENT: return ":/Editor/WwiseIcons/event_nor.svg"; case eWCT_WWISE_RTPC: return ":/Editor/WwiseIcons/gameparameter_nor.svg"; case eWCT_WWISE_SWITCH: return ":/Editor/WwiseIcons/switch_nor.svg"; case eWCT_WWISE_AUX_BUS: return ":/Editor/WwiseIcons/auxbus_nor.svg"; case eWCT_WWISE_SOUND_BANK: return ":/Editor/WwiseIcons/soundbank_nor.svg"; case eWCT_WWISE_GAME_STATE: return ":/Editor/WwiseIcons/state_nor.svg"; case eWCT_WWISE_SWITCH_GROUP: return ":/Editor/WwiseIcons/switchgroup_nor.svg"; case eWCT_WWISE_GAME_STATE_GROUP: return ":/Editor/WwiseIcons/stategroup_nor.svg"; default: // should make a "default"/empty icon... return ":/Editor/WwiseIcons/switchgroup_nor.svg"; } } const AZStd::string_view CAudioSystemEditor_wwise::GetTypeIconSelected(TImplControlType type) const { switch (type) { case eWCT_WWISE_EVENT: return ":/Editor/WwiseIcons/event_nor_hover.svg"; case eWCT_WWISE_RTPC: return ":/Editor/WwiseIcons/gameparameter_nor_hover.svg"; case eWCT_WWISE_SWITCH: return ":/Editor/WwiseIcons/switch_nor_hover.svg"; case eWCT_WWISE_AUX_BUS: return ":/Editor/WwiseIcons/auxbus_nor_hover.svg"; case eWCT_WWISE_SOUND_BANK: return ":/Editor/WwiseIcons/soundbank_nor_hover.svg"; case eWCT_WWISE_GAME_STATE: return ":/Editor/WwiseIcons/state_nor_hover.svg"; case eWCT_WWISE_SWITCH_GROUP: return ":/Editor/WwiseIcons/switchgroup_nor_hover.svg"; case eWCT_WWISE_GAME_STATE_GROUP: return ":/Editor/WwiseIcons/stategroup_nor_hover.svg"; default: // should make a "default"/empty icon... return ":/Editor/WwiseIcons/switchgroup_nor_hover.svg"; } } //-------------------------------------------------------------------------------------------// EACEControlType CAudioSystemEditor_wwise::ImplTypeToATLType(TImplControlType type) const { switch (type) { case eWCT_WWISE_EVENT: return eACET_TRIGGER; case eWCT_WWISE_RTPC: return eACET_RTPC; case eWCT_WWISE_SWITCH: case eWCT_WWISE_GAME_STATE: return eACET_SWITCH_STATE; case eWCT_WWISE_AUX_BUS: return eACET_ENVIRONMENT; case eWCT_WWISE_SOUND_BANK: return eACET_PRELOAD; case eWCT_WWISE_GAME_STATE_GROUP: case eWCT_WWISE_SWITCH_GROUP: return eACET_SWITCH; } return eACET_NUM_TYPES; } //-------------------------------------------------------------------------------------------// TImplControlTypeMask CAudioSystemEditor_wwise::GetCompatibleTypes(EACEControlType atlControlType) const { switch (atlControlType) { case eACET_TRIGGER: return eWCT_WWISE_EVENT; case eACET_RTPC: return eWCT_WWISE_RTPC; case eACET_SWITCH: return AUDIO_IMPL_INVALID_TYPE; case eACET_SWITCH_STATE: return (eWCT_WWISE_SWITCH | eWCT_WWISE_GAME_STATE | eWCT_WWISE_RTPC); case eACET_ENVIRONMENT: return (eWCT_WWISE_AUX_BUS | eWCT_WWISE_SWITCH | eWCT_WWISE_GAME_STATE | eWCT_WWISE_RTPC); case eACET_PRELOAD: return eWCT_WWISE_SOUND_BANK; } return AUDIO_IMPL_INVALID_TYPE; } //-------------------------------------------------------------------------------------------// CID CAudioSystemEditor_wwise::GetID(const AZStd::string_view name) const { return Audio::AudioStringToID(name.data()); } //-------------------------------------------------------------------------------------------// AZStd::string CAudioSystemEditor_wwise::GetName() const { return "Wwise"; } //-------------------------------------------------------------------------------------------// void CAudioSystemEditor_wwise::UpdateConnectedStatus() { for (const auto& idCountPair : m_connectionsByID) { if (idCountPair.second > 0) { IAudioSystemControl* control = GetControl(idCountPair.first); if (control) { control->SetConnected(true); } } } } //-------------------------------------------------------------------------------------------// void CAudioSystemEditor_wwise::ConnectionRemoved(IAudioSystemControl* control) { int connectionCount = m_connectionsByID[control->GetId()] - 1; if (connectionCount <= 0) { connectionCount = 0; control->SetConnected(false); } m_connectionsByID[control->GetId()] = connectionCount; } //-------------------------------------------------------------------------------------------// AZStd::string CAudioSystemEditor_wwise::GetDataPath() const { AZStd::string path(Path::GetEditingGameDataFolder()); AZ::StringFunc::Path::Join(path.c_str(), "/sounds/wwise_project/", path); return path; } } // namespace AudioControls