diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a1794fc2..d970af226 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +Version 1.1.0 + +* Support for 128 channels when using REAPER >=v7.0 [#244](https://github.com/ebu/ear-production-suite/issues/244) [#254](https://github.com/ebu/ear-production-suite/pull/254) [#267](https://github.com/ebu/ear-production-suite/pull/267) +* Improve import support from third-party tools [#259](https://github.com/ebu/ear-production-suite/pull/259) +* Support HRTF switching in Binaural Monitoring plugin [#266](https://github.com/ebu/ear-production-suite/pull/266) +* Fix monitoring plugins not properly supporting shared inputs [#257](https://github.com/ebu/ear-production-suite/issues/257) [#258](https://github.com/ebu/ear-production-suite/pull/258) +* Apply "version" attribute to ADM as required by ITU-R BS.2076-2 [#248](https://github.com/ebu/ear-production-suite/issues/248) [#255](https://github.com/ebu/ear-production-suite/pull/255) +* Performance fix for envelope creation [#252](https://github.com/ebu/ear-production-suite/pull/252) +* Update BW64 lib for performance fixes [#260](https://github.com/ebu/ear-production-suite/issues/260) +* Allow user to opt-out of update-checking during setup [#256](https://github.com/ebu/ear-production-suite/pull/256) +* Warn user of impending FB360 and VISR support deprecation since these plugin suites are no longer maintained [#265](https://github.com/ebu/ear-production-suite/pull/265) + Version 1.0.0 * Setup Application included diff --git a/CMakeLists.txt b/CMakeLists.txt index ba7fb2276..e5e00ab8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.14) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/COPYRIGHT.TXT b/COPYRIGHT.TXT index 643e5067c..6e8c5ea3e 100644 --- a/COPYRIGHT.TXT +++ b/COPYRIGHT.TXT @@ -1,6 +1,6 @@ The content of this repository is -Copyright (C) 2019-2023 British Broadcasting Corporation (BBC) +Copyright (C) 2019-2024 British Broadcasting Corporation (BBC) Copyright (C) 2020-2021 European Broadcasting Union (EBU) Copyright (C) 2019-2021 Institut für Rundfunktechnik GmbH (IRT) diff --git a/ear-production-suite-plugins/lib/CMakeLists.txt b/ear-production-suite-plugins/lib/CMakeLists.txt index 0bd54d044..165256565 100644 --- a/ear-production-suite-plugins/lib/CMakeLists.txt +++ b/ear-production-suite-plugins/lib/CMakeLists.txt @@ -52,7 +52,8 @@ set(EAR_BASE_SOURCES src/communication/metadata_thread.cpp src/pending_store.cpp src/auto_mode_controller.cpp - ${EPS_SHARED_DIR}/helper/common_definition_helper.cpp + ${EPS_SHARED_DIR}/helper/adm_preset_definitions_helper.cpp + ${EPS_SHARED_DIR}/helper/cartesianspeakerlayouts.cpp ${EAR_PROTO_SRC} src/restored_pending_store.cpp ) @@ -133,6 +134,7 @@ set(EAR_BASE_HEADERS include/auto_mode_controller.hpp include/reaper_integration.hpp include/reaper_vst3_interfaces.h + ${EPS_SHARED_DIR}/helper/adm_preset_definitions_helper.h ${EPS_SHARED_DIR}/helper/container_helpers.hpp ${EPS_SHARED_DIR}/speaker_setups.hpp ) diff --git a/ear-production-suite-plugins/lib/include/binaural_monitoring_audio_processor.hpp b/ear-production-suite-plugins/lib/include/binaural_monitoring_audio_processor.hpp index 3817499b8..aa830ab50 100644 --- a/ear-production-suite-plugins/lib/include/binaural_monitoring_audio_processor.hpp +++ b/ear-production-suite-plugins/lib/include/binaural_monitoring_audio_processor.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include <../src/dynamic_renderer.hpp> #include "variable_block_adapter.hpp" #include @@ -9,6 +10,20 @@ namespace ear { namespace plugin { +enum BearStatusStates { + NOT_ATTEMPTED = 0, + FAILED, + SUCCEEDED +}; + +struct BearStatus { + bear::Config startupConfig; + BearStatusStates startupSuccess{NOT_ATTEMPTED}; + std::string startupErrorDesc; + BearStatusStates listenerDataSetSuccess{NOT_ATTEMPTED}; + std::string listenerDataSetErrorDesc; +}; + /** * @brief Binaural monitoring plugin dsp implementation * @@ -47,6 +62,8 @@ class BinauralMonitoringAudioProcessor { BinauralMonitoringAudioProcessor& operator=( BinauralMonitoringAudioProcessor&&) = delete; + BearStatus getBearStatus() { return bearStatus; } + template void process(const InBuffer& in, OutBuffer& out) { using InTraits = BufferTraits; @@ -67,7 +84,7 @@ class BinauralMonitoringAudioProcessor { void setListenerOrientation(float quatW, float quatX, float quatY, float quatZ); - bool rendererError() { return !bearRenderer; } + bool rendererStarted() { return bearRenderer && bearStatus.startupSuccess == SUCCEEDED; } void setIsPlaying(bool state) { isPlaying = state; } bool getIsPlaying() { return isPlaying; } @@ -84,6 +101,7 @@ class BinauralMonitoringAudioProcessor { std::shared_ptr bearRenderer; // TODO - why shared? std::mutex bearListenerMutex_; bear::Listener bearListener; + BearStatus bearStatus; bool listenerQuatsDirty{false}; std::array listenerQuats{1.0, 0.0, 0.0, 0.0}; diff --git a/ear-production-suite-plugins/lib/include/binaural_monitoring_backend.hpp b/ear-production-suite-plugins/lib/include/binaural_monitoring_backend.hpp index ea6cf3156..6a6295ee8 100644 --- a/ear-production-suite-plugins/lib/include/binaural_monitoring_backend.hpp +++ b/ear-production-suite-plugins/lib/include/binaural_monitoring_backend.hpp @@ -6,7 +6,6 @@ #include "ear-plugin-base/export.h" #include "scene_gains_calculator.hpp" #include "listener_orientation.hpp" -#include "helper/common_definition_helper.h" #include #include @@ -103,9 +102,6 @@ class BinauralMonitoringBackend { std::unique_ptr metadataReceiver_; communication::MonitoringControlConnection controlConnection_; - std::mutex commonDefinitionHelperMutex_; - AdmCommonDefinitionHelper commonDefinitionHelper{}; - bool isExporting_{ false }; }; diff --git a/ear-production-suite-plugins/lib/include/communication/direct_speakers_metadata_sender.hpp b/ear-production-suite-plugins/lib/include/communication/direct_speakers_metadata_sender.hpp index 71e65f20b..f0487248a 100644 --- a/ear-production-suite-plugins/lib/include/communication/direct_speakers_metadata_sender.hpp +++ b/ear-production-suite-plugins/lib/include/communication/direct_speakers_metadata_sender.hpp @@ -23,7 +23,7 @@ class DirectSpeakersMetadataSender { void name(const std::string& value); void inputInstanceId(int value); void colour(int value); - void speakerSetupIndex(int value); + void packFormatIdValue(int value); ConnectionId getConnectionId() { return sender_.connectionId(); } diff --git a/ear-production-suite-plugins/lib/include/helper/eps_to_ear_metadata_converter.hpp b/ear-production-suite-plugins/lib/include/helper/eps_to_ear_metadata_converter.hpp index fe710c4ff..8c705fc62 100644 --- a/ear-production-suite-plugins/lib/include/helper/eps_to_ear_metadata_converter.hpp +++ b/ear-production-suite-plugins/lib/include/helper/eps_to_ear_metadata_converter.hpp @@ -1,7 +1,10 @@ #pragma once #include "helper/protobuf_utilities.hpp" -#include "helper/common_definition_helper.h" +#include "helper/adm_preset_definitions_helper.h" +#include +#include +#include namespace ear { namespace plugin { @@ -26,12 +29,16 @@ struct EpsToEarMetadataConverter { static std::vector convert( const proto::DirectSpeakersTypeMetadata &epsMetadata) { - auto packFormatId = - proto::SpeakerLayoutTranslator::proto2ear(epsMetadata.layout()); + + adm::AudioPackFormatId audioPackFormatID( + adm::TypeDefinition::DIRECT_SPEAKERS, + adm::AudioPackFormatIdValue(epsMetadata.packformatidvalue())); + auto audioPackFormatIDstr = adm::formatId(audioPackFormatID); + std::vector earMetadata; for (auto epsSpeaker : epsMetadata.speakers()) { ear::DirectSpeakersTypeMetadata earSpeaker; - earSpeaker.audioPackFormatID = packFormatId; + earSpeaker.audioPackFormatID = audioPackFormatIDstr; earSpeaker.position = ear::PolarSpeakerPosition( epsSpeaker.position().azimuth(), epsSpeaker.position().elevation(), epsSpeaker.position().distance()); @@ -48,11 +55,9 @@ struct EpsToEarMetadataConverter { return earMetadata; } static ear::HOATypeMetadata convert( - const proto::HoaTypeMetadata &epsMetadata, - AdmCommonDefinitionHelper &commonDefinitionHelper) { - auto pfData = commonDefinitionHelper.getPackFormatData( + const proto::HoaTypeMetadata &epsMetadata) { + auto pfData = AdmPresetDefinitionsHelper::getSingleton().getPackFormatData( 4, epsMetadata.packformatidvalue()); - ear::HOATypeMetadata earMetadata; if (pfData) { diff --git a/ear-production-suite-plugins/lib/include/helper/protobuf_utilities.hpp b/ear-production-suite-plugins/lib/include/helper/protobuf_utilities.hpp index 37c47df16..dde7aa511 100644 --- a/ear-production-suite-plugins/lib/include/helper/protobuf_utilities.hpp +++ b/ear-production-suite-plugins/lib/include/helper/protobuf_utilities.hpp @@ -1,37 +1,13 @@ #pragma once -#include #include "type_metadata.pb.h" -#include namespace ear { namespace plugin { namespace proto { -class SpeakerLayoutTranslator { - public: - static std::string proto2ear(const SpeakerLayout& layout); - static SpeakerLayout ear2proto(const std::string& layout); - - private: - static std::map SpeakerLayoutProtoToEarLUT_; - static std::map SpeakerLayoutEarToProtoLUT_; -}; - -inline proto::DirectSpeakersTypeMetadata* convertSpeakerSetupToEpsMetadata( - int setupIndex) { - auto ds_metadata = new proto::DirectSpeakersTypeMetadata(); - - ds_metadata->set_layout(proto::SpeakerLayout(setupIndex)); - for (auto speaker : speakerSetupByIndex(setupIndex).speakers) { - auto newSpeaker = ds_metadata->add_speakers(); - newSpeaker->set_is_lfe(speaker.isLfe); - newSpeaker->add_labels(speaker.label); - newSpeaker->mutable_position()->set_azimuth(speaker.azimuth); - newSpeaker->mutable_position()->set_elevation(speaker.elevation); - } - return ds_metadata; -} +proto::DirectSpeakersTypeMetadata* convertPackFormatToEpsMetadata( + int packFormatIdValue); } // namespace proto } // namespace plugin diff --git a/ear-production-suite-plugins/lib/include/programme_store_adm_serializer.hpp b/ear-production-suite-plugins/lib/include/programme_store_adm_serializer.hpp index b213b7ca0..011abc6cd 100644 --- a/ear-production-suite-plugins/lib/include/programme_store_adm_serializer.hpp +++ b/ear-production-suite-plugins/lib/include/programme_store_adm_serializer.hpp @@ -7,7 +7,6 @@ #include #include #include -#include namespace ear { namespace plugin { @@ -49,8 +48,6 @@ class ProgrammeStoreAdmSerializer { void setInteractivity(adm::AudioObject& object, const proto::Object& object1); void setImportance(adm::AudioObject& object, const proto::Object& object1); bool isSerializedWithDifferentObjectSettings(const proto::Object& object); - - AdmCommonDefinitionHelper admCommonDefinitionHelper; }; } // namespace plugin diff --git a/ear-production-suite-plugins/lib/include/scene_gains_calculator.hpp b/ear-production-suite-plugins/lib/include/scene_gains_calculator.hpp index d9233c00c..0a61a2610 100644 --- a/ear-production-suite-plugins/lib/include/scene_gains_calculator.hpp +++ b/ear-production-suite-plugins/lib/include/scene_gains_calculator.hpp @@ -9,7 +9,6 @@ #include #include #include -#include "helper/common_definition_helper.h" namespace ear { namespace plugin { @@ -44,9 +43,6 @@ class SceneGainsCalculator { ear::GainCalculatorHOA hoaCalculator_; std::map routingCache_; - - std::mutex commonDefinitionHelperMutex_; - AdmCommonDefinitionHelper commonDefinitionHelper_{}; }; } // namespace plugin diff --git a/ear-production-suite-plugins/lib/messages/type_metadata.proto b/ear-production-suite-plugins/lib/messages/type_metadata.proto index 4e3c7a528..d4b94df80 100644 --- a/ear-production-suite-plugins/lib/messages/type_metadata.proto +++ b/ear-production-suite-plugins/lib/messages/type_metadata.proto @@ -4,33 +4,6 @@ package ear.plugin.proto; import "common_types.proto"; -// XXX: the numbers directly correspond to the indicies in the speaker layout combobox -enum SpeakerLayout { - ITU_BS_2051_UNKNOWN = -1; - ITU_BS_2051_0_1_0 = 0; - ITU_BS_2051_0_2_0 = 1; - ITU_BS_755_0_3_0 = 2; - ITU_BS_755_0_4_0 = 3; - ITU_BS_2051_0_5_0_NO_LFE = 4; - ITU_BS_2051_0_5_0 = 5; - ITU_BS_2051_0_6_0 = 6; - ITU_BS_2094_0_7_0_FRONT = 7; - ITU_BS_2051_0_7_0_BACK = 8; - ITU_BS_2051_2_5_0 = 9; - ITU_BS_2094_0_7_0_SIDE = 10; - ITU_BS_2094_2_5_0 = 11; - ITU_BS_2094_2_7_0_SCREEN = 12; - ITU_BS_2094_2_7_0 = 13; - ITU_BS_2051_4_5_0 = 14; - ITU_BS_2051_4_5_1 = 15; - ITU_BS_2051_3_7_0 = 16; - ITU_BS_2094_4_7_0 = 17; - ITU_BS_2051_4_7_0 = 18; - ITU_BS_2051_4_9_0 = 19; - ITU_BS_2051_9_10_3 = 20; - ITU_BS_2094_9_9_0 = 21; -} - message Speaker { optional int32 id = 1 [default = 0]; repeated string labels = 2; @@ -40,7 +13,7 @@ message Speaker { } message DirectSpeakersTypeMetadata { - optional SpeakerLayout layout = 1 [default = ITU_BS_2051_UNKNOWN]; + optional int32 packFormatIdValue = 1 [default = 0]; repeated Speaker speakers = 2; } diff --git a/ear-production-suite-plugins/lib/src/binaural_monitoring_audio_processor.cpp b/ear-production-suite-plugins/lib/src/binaural_monitoring_audio_processor.cpp index 9b5384ffe..e9909371b 100644 --- a/ear-production-suite-plugins/lib/src/binaural_monitoring_audio_processor.cpp +++ b/ear-production-suite-plugins/lib/src/binaural_monitoring_audio_processor.cpp @@ -37,19 +37,25 @@ BinauralMonitoringAudioProcessor::BinauralMonitoringAudioProcessor( bearListener.set_position_cart(std::array{0.0, 0.0, 0.0}); + bearStatus.startupConfig = bearConfig; try { bearRenderer = std::make_shared( blockSize, std::max(std::max(maxObjChannels, maxDsChannels), maxHoaChannels)); + bearRenderer->set_config_blocking(bearConfig); + bearStatus.startupSuccess = BearStatusStates::SUCCEEDED; try { bearRenderer->set_listener(bearListener); + bearStatus.listenerDataSetSuccess = BearStatusStates::SUCCEEDED; } catch (std::exception &e) { + bearStatus.listenerDataSetSuccess = BearStatusStates::FAILED; + bearStatus.listenerDataSetErrorDesc = e.what(); bearRenderer.reset(); - assert(false); } } catch (std::exception &e) { + bearStatus.startupSuccess = BearStatusStates::FAILED; + bearStatus.startupErrorDesc = e.what(); bearRenderer.reset(); - assert(false); } } @@ -218,6 +224,7 @@ bool BinauralMonitoringAudioProcessor::updateChannelCounts( // Do immediate update bearRenderer->set_config_blocking(bearConfig); } + return true; } } // namespace plugin diff --git a/ear-production-suite-plugins/lib/src/binaural_monitoring_backend.cpp b/ear-production-suite-plugins/lib/src/binaural_monitoring_backend.cpp index edce8dbce..2defd6d82 100644 --- a/ear-production-suite-plugins/lib/src/binaural_monitoring_backend.cpp +++ b/ear-production-suite-plugins/lib/src/binaural_monitoring_backend.cpp @@ -38,9 +38,6 @@ BinauralMonitoringBackend::BinauralMonitoringBackend( activeObjectIds.reserve(inputChannelCount); activeHoaIds.reserve(inputChannelCount); - commonDefinitionHelper - .getElementRelationships(); // Save doing it later in time-critical calls - allActiveIds.reserve(inputChannelCount); controlConnection_.logger(logger_); @@ -153,15 +150,12 @@ BinauralMonitoringBackend::getLatestHoaTypeMetadata(ConnId id) { if (!epsMD || !epsMD->has_hoa_metadata()) { return std::optional(); } - { - std::lock_guard lock(commonDefinitionHelperMutex_); - setInMap( - latestHoaTypeMetadata, id, - HoaEarMetadataAndRouting{ - epsMD->has_routing() ? epsMD->routing() : -1, - EpsToEarMetadataConverter::convert(epsMD->hoa_metadata(), - commonDefinitionHelper)}); - } + + setInMap( + latestHoaTypeMetadata, id, + HoaEarMetadataAndRouting{ + epsMD->has_routing() ? epsMD->routing() : -1, + EpsToEarMetadataConverter::convert(epsMD->hoa_metadata())}); earMD = getValuePointerFromMap( latestHoaTypeMetadata, id); @@ -229,15 +223,14 @@ void BinauralMonitoringBackend::onSceneReceived(proto::SceneStore store) { } if (item.has_hoa_metadata()) { auto hoaId = item.hoa_metadata().packformatidvalue(); - { - std::lock_guard lock(commonDefinitionHelperMutex_); - // TODO: May need to revisit later - - // this is a high-frequency call but may be slow to to execute - auto pfData = commonDefinitionHelper.getPackFormatData(4, hoaId); - if (pfData) { - auto cfCount = pfData->relatedChannelFormats.size(); - totalHoaChannels += cfCount; - } + // TODO: May need to revisit later - + // this is a high-frequency call but may be slow to to execute + auto pfData = + AdmPresetDefinitionsHelper::getSingleton().getPackFormatData(4, + hoaId); + if (pfData) { + auto cfCount = pfData->relatedChannelFormats.size(); + totalHoaChannels += cfCount; } } } diff --git a/ear-production-suite-plugins/lib/src/communication/direct_speakers_metadata_sender.cpp b/ear-production-suite-plugins/lib/src/communication/direct_speakers_metadata_sender.cpp index 60a33f409..c6fd377c1 100644 --- a/ear-production-suite-plugins/lib/src/communication/direct_speakers_metadata_sender.cpp +++ b/ear-production-suite-plugins/lib/src/communication/direct_speakers_metadata_sender.cpp @@ -39,10 +39,10 @@ void DirectSpeakersMetadataSender::inputInstanceId(int value) void DirectSpeakersMetadataSender::colour(int value) { setData([value](auto data) { data->set_colour(value); }); } -void DirectSpeakersMetadataSender::speakerSetupIndex(int value) { +void DirectSpeakersMetadataSender::packFormatIdValue(int value) { setData([value](auto data) { data->set_allocated_ds_metadata( - proto::convertSpeakerSetupToEpsMetadata(value)); + proto::convertPackFormatToEpsMetadata(value)); }); } diff --git a/ear-production-suite-plugins/lib/src/direct_speakers_backend.cpp b/ear-production-suite-plugins/lib/src/direct_speakers_backend.cpp index bb28786b0..d15c8a352 100644 --- a/ear-production-suite-plugins/lib/src/direct_speakers_backend.cpp +++ b/ear-production-suite-plugins/lib/src/direct_speakers_backend.cpp @@ -93,7 +93,7 @@ void DirectSpeakersBackend::onParameterChanged( } else if (parameter == ParameterId::PACKFORMAT_ID_VALUE) { auto extractedValue = boost::get(value); EAR_LOGGER_DEBUG(logger_, "PackFormat ID Value -> {}", extractedValue); - metadataSender_.speakerSetupIndex(getIndexFromPackFormatIdValue(extractedValue)); + metadataSender_.packFormatIdValue(extractedValue); } else if(parameter == ParameterId::INPUT_INSTANCE_ID) { auto extractedValue = boost::get(value); EAR_LOGGER_DEBUG(logger_, "Input Instance ID -> {}", extractedValue); diff --git a/ear-production-suite-plugins/lib/src/helper/protobuf_utilities.cpp b/ear-production-suite-plugins/lib/src/helper/protobuf_utilities.cpp index e622c34f7..abb0ee02a 100644 --- a/ear-production-suite-plugins/lib/src/helper/protobuf_utilities.cpp +++ b/ear-production-suite-plugins/lib/src/helper/protobuf_utilities.cpp @@ -1,83 +1,33 @@ #include "helper/protobuf_utilities.hpp" -#include -#include +#include namespace ear { namespace plugin { namespace proto { -std::map - SpeakerLayoutTranslator::SpeakerLayoutProtoToEarLUT_ = { - {SpeakerLayout::ITU_BS_2051_0_1_0, std::string("AP_00010001")}, - {SpeakerLayout::ITU_BS_2051_0_2_0, std::string("AP_00010002")}, - {SpeakerLayout::ITU_BS_755_0_3_0, std::string("AP_0001000a")}, - {SpeakerLayout::ITU_BS_755_0_4_0, std::string("AP_0001000b")}, - {SpeakerLayout::ITU_BS_2051_0_5_0_NO_LFE, std::string("AP_0001000c")}, - {SpeakerLayout::ITU_BS_2051_0_5_0, std::string("AP_00010003")}, - {SpeakerLayout::ITU_BS_2051_0_6_0, std::string("AP_0001000d")}, - {SpeakerLayout::ITU_BS_2094_0_7_0_FRONT, std::string("AP_0001000e")}, - {SpeakerLayout::ITU_BS_2051_0_7_0_BACK, std::string("AP_0001000f")}, - {SpeakerLayout::ITU_BS_2051_2_5_0, std::string("AP_00010004")}, - {SpeakerLayout::ITU_BS_2094_0_7_0_SIDE, std::string("AP_00010012")}, - {SpeakerLayout::ITU_BS_2094_2_5_0, std::string("AP_00010013")}, - {SpeakerLayout::ITU_BS_2094_2_7_0_SCREEN, std::string("AP_00010014")}, - {SpeakerLayout::ITU_BS_2094_2_7_0, std::string("AP_00010016")}, - {SpeakerLayout::ITU_BS_2051_4_5_0, std::string("AP_00010005")}, - {SpeakerLayout::ITU_BS_2051_4_5_1, std::string("AP_00010010")}, - {SpeakerLayout::ITU_BS_2051_3_7_0, std::string("AP_00010007")}, - {SpeakerLayout::ITU_BS_2094_4_7_0, std::string("AP_00010015")}, - {SpeakerLayout::ITU_BS_2051_4_7_0, std::string("AP_00010017")}, - {SpeakerLayout::ITU_BS_2051_4_9_0, std::string("AP_00010008")}, - {SpeakerLayout::ITU_BS_2051_9_10_3, std::string("AP_00010009")}, - {SpeakerLayout::ITU_BS_2094_9_9_0, std::string("AP_00010011")} -}; - -std::map - SpeakerLayoutTranslator::SpeakerLayoutEarToProtoLUT_ = { - {std::string("AP_00010001"), SpeakerLayout::ITU_BS_2051_0_1_0}, - {std::string("AP_00010002"), SpeakerLayout::ITU_BS_2051_0_2_0}, - {std::string("AP_0001000a"), SpeakerLayout::ITU_BS_755_0_3_0}, - {std::string("AP_0001000b"), SpeakerLayout::ITU_BS_755_0_4_0}, - {std::string("AP_0001000c"), SpeakerLayout::ITU_BS_2051_0_5_0_NO_LFE}, - {std::string("AP_00010003"), SpeakerLayout::ITU_BS_2051_0_5_0}, - {std::string("AP_0001000d"), SpeakerLayout::ITU_BS_2051_0_6_0}, - {std::string("AP_0001000e"), SpeakerLayout::ITU_BS_2094_0_7_0_FRONT}, - {std::string("AP_0001000f"), SpeakerLayout::ITU_BS_2051_0_7_0_BACK}, - {std::string("AP_00010004"), SpeakerLayout::ITU_BS_2051_2_5_0}, - {std::string("AP_00010012"), SpeakerLayout::ITU_BS_2094_0_7_0_SIDE}, - {std::string("AP_00010013"), SpeakerLayout::ITU_BS_2094_2_5_0}, - {std::string("AP_00010014"), SpeakerLayout::ITU_BS_2094_2_7_0_SCREEN}, - {std::string("AP_00010016"), SpeakerLayout::ITU_BS_2094_2_7_0}, - {std::string("AP_00010005"), SpeakerLayout::ITU_BS_2051_4_5_0}, - {std::string("AP_00010010"), SpeakerLayout::ITU_BS_2051_4_5_1}, - {std::string("AP_00010007"), SpeakerLayout::ITU_BS_2051_3_7_0}, - {std::string("AP_00010015"), SpeakerLayout::ITU_BS_2094_4_7_0}, - {std::string("AP_00010017"), SpeakerLayout::ITU_BS_2051_4_7_0}, - {std::string("AP_00010008"), SpeakerLayout::ITU_BS_2051_4_9_0}, - {std::string("AP_00010009"), SpeakerLayout::ITU_BS_2051_9_10_3}, - {std::string("AP_00010011"), SpeakerLayout::ITU_BS_2094_9_9_0} -}; - -std::string SpeakerLayoutTranslator::proto2ear(const SpeakerLayout& layout) { - auto it = SpeakerLayoutProtoToEarLUT_.find(layout); - - if (it != SpeakerLayoutProtoToEarLUT_.end()) { - return it->second; - } else { - return std::string(); - } -}; - -SpeakerLayout SpeakerLayoutTranslator::ear2proto(const std::string& layout) { - auto it = SpeakerLayoutEarToProtoLUT_.find(layout); - - if (it != SpeakerLayoutEarToProtoLUT_.end()) { - return it->second; - } else { - return SpeakerLayout::ITU_BS_2051_UNKNOWN; +proto::DirectSpeakersTypeMetadata* convertPackFormatToEpsMetadata( + int packFormatIdValue) { + auto ds_metadata = new proto::DirectSpeakersTypeMetadata(); + ds_metadata->set_packformatidvalue(packFormatIdValue); + + auto pfData = AdmPresetDefinitionsHelper::getSingleton().getPackFormatData( + 1, packFormatIdValue); + if (pfData) { + for (auto const& cfData : pfData->relatedChannelFormats) { + auto newSpeaker = ds_metadata->add_speakers(); + newSpeaker->set_id(cfData->idValue); + newSpeaker->set_is_lfe(cfData->isLfe); + for (auto const& speakerLabel : cfData->speakerLabels) { + newSpeaker->add_labels(speakerLabel); + } + newSpeaker->mutable_position()->set_azimuth(cfData->azimuth); + newSpeaker->mutable_position()->set_elevation(cfData->elevation); + } } + return ds_metadata; } + } // namespace proto } // namespace plugin } // namespace ear diff --git a/ear-production-suite-plugins/lib/src/programme_store_adm_serializer.cpp b/ear-production-suite-plugins/lib/src/programme_store_adm_serializer.cpp index 0067ae14a..3a1186c46 100644 --- a/ear-production-suite-plugins/lib/src/programme_store_adm_serializer.cpp +++ b/ear-production-suite-plugins/lib/src/programme_store_adm_serializer.cpp @@ -4,21 +4,18 @@ #include #include #include +#include +#include #include #include #include +#include +#include using namespace ear::plugin; namespace { -template -std::string int_to_hex(T i, size_t size) { - std::stringstream stream; - stream << std::setfill('0') << std::setw(size) << std::hex << i; - return stream.str(); -} - constexpr auto const ADM_DEFAULT_AZ = 0.0f; constexpr auto const ADM_DEFAULT_EL = 0.0f; // constexpr auto const ADM_DEFAULT_D = 0.f; @@ -216,44 +213,6 @@ adm::SimpleObjectHolder add2076v2SimpleObjectTo(std::shared_ptr d return holder; } -adm::SimpleCommonDefinitionsObjectHolder add2076v2TailoredCommonDefinitionsObjectTo( - std::shared_ptr document, const std::string& name, - const adm::AudioPackFormatId packFormatId, - const std::vector& channelFormatIds, - const std::vector& speakerLabels) { - adm::SimpleCommonDefinitionsObjectHolder holder; - holder.audioObject = adm::AudioObject::create(adm::AudioObjectName(name)); - auto packFormat = document->lookup(packFormatId); - if (!packFormat) { - std::stringstream ss; - ss << "AudioPackFormatId \"" << adm::formatId(packFormatId) - << "\" not found. Are the common definitions added to the document?"; - throw adm::error::AdmException(ss.str()); - } - holder.audioObject->addReference(packFormat); - if (channelFormatIds.size() != speakerLabels.size()) { - throw adm::error::AdmException( - "Sizes of channelFormatIds and speakerLabels arguments do not match."); - } - for (size_t i = 0; i < channelFormatIds.size(); i++) { - auto cf = document->lookup(channelFormatIds.at(i)); - if (!cf) { - std::stringstream ss; - ss << "AudioTrackFormatId \"" << adm::formatId(channelFormatIds.at(i)) - << "\" not found. Id might be invalid."; - throw adm::error::AdmException(ss.str()); - } - auto uid = adm::AudioTrackUid::create(); - uid->setReference(packFormat); - uid->setReference(cf); - holder.audioObject->addReference(uid); - holder.audioTrackUids[speakerLabels.at(i)] = uid; - } - document->add(holder.audioObject); - return holder; -} - - } // namespace bool ProgrammeStoreAdmSerializer::isAlreadySerialized( @@ -278,6 +237,7 @@ ProgrammeStoreAdmSerializer::serialize(std::pair for (auto& programme : programmes_.programme()) { serializeProgramme(*doc, programme); } + adm::reassignIds(doc); // ADM elms in pluginMap are shared_ptr so will also have the updated ID's return {doc, pluginMap}; } @@ -411,81 +371,38 @@ void ProgrammeStoreAdmSerializer::createTopLevelObject( serializedObjects[connectionId] = objectHolder.audioObject; pluginMap.push_back({ metadata.input_instance_id(), metadata.routing(), objectHolder.audioObject, objectHolder.audioTrackUid }); - } else if (metadata.has_hoa_metadata()) { - // get the pack format Id from the metadata and from that create the full - // pack format string This can be used to look up channel information using - // the common definitions helper - int packFormatIdValue = metadata.hoa_metadata().packformatidvalue(); - int packFormatId = 0x00040000 | packFormatIdValue; - std::string packFormatIdStr = - std::string("AP_") + int_to_hex(packFormatId, 8); - auto packFormat = - doc->lookup(adm::parseAudioPackFormatId(packFormatIdStr)); - - if(packFormat) { - auto hoaAudioObject = - adm::AudioObject::create(adm::AudioObjectName(metadata.name())); - hoaAudioObject->addReference(packFormat); - content.addReference(hoaAudioObject); - setInteractivity(*hoaAudioObject, object); - setImportance(*hoaAudioObject, object); - - auto channelFormats = - admCommonDefinitionHelper.getPackFormatData(4, packFormatIdValue) - ->relatedChannelFormats; - // The AudioTrackIUD needs to reference the track format - // To get the correct track format we go through all track formats and - // find the one that references the correct channel format - auto allTrackFormats = doc->getElements(); - - // For each channel format create a AudioTrackUid that references the pack - // format. The audio object also needs to reference the channel format. - for(int i(0); i < channelFormats.size(); ++i) { - auto audioTrackUid = adm::AudioTrackUid::create(); - hoaAudioObject->addReference(audioTrackUid); - audioTrackUid->setReference(packFormat); - - // We need the channel format from our document, - // not the document admCommonDefinitionHelper is using! - auto channelFormatId = adm::AudioChannelFormatId( + } + else if (metadata.has_hoa_metadata() || metadata.has_ds_metadata()) { + + adm::AudioPackFormatId audioPackFormatID; + if (metadata.has_ds_metadata()) { + // DS + audioPackFormatID = adm::AudioPackFormatId( + adm::TypeDefinition::DIRECT_SPEAKERS, + adm::AudioPackFormatIdValue( + metadata.ds_metadata().packformatidvalue())); + } else { + // HOA + audioPackFormatID = adm::AudioPackFormatId( adm::TypeDefinition::HOA, - adm::AudioChannelFormatIdValue(channelFormats[i]->id)); - auto channelFormat = doc->lookup(channelFormatId); - assert(channelFormat); - - audioTrackUid->setReference(channelFormat); - pluginMap.push_back({ metadata.input_instance_id(), metadata.routing() + i, hoaAudioObject, audioTrackUid }); - } - serializedObjects[connectionId] = hoaAudioObject; + adm::AudioPackFormatIdValue( + metadata.hoa_metadata().packformatidvalue())); } - } else if (metadata.has_ds_metadata()) { - auto layoutIndex = metadata.ds_metadata().layout(); - if (layoutIndex >= 0 && layoutIndex < SPEAKER_SETUPS.size()) { - std::vector speakerLabels; - std::vector channelFormatIds; - auto& speakerSetup = SPEAKER_SETUPS.at(layoutIndex); - - for (auto& speaker : speakerSetup.speakers) { - speakerLabels.push_back(speaker.label); - auto channelFormatId = speaker.channelFormatId; - channelFormatIds.push_back(adm::parseAudioChannelFormatId(channelFormatId)); - } - auto objectHolder = add2076v2TailoredCommonDefinitionsObjectTo( - doc, metadata.name(), - adm::parseAudioPackFormatId(speakerSetup.packFormatId), - channelFormatIds, speakerLabels); - - setInteractivity(*objectHolder.audioObject, object); - setImportance(*objectHolder.audioObject, object); - content.addReference(objectHolder.audioObject); - for (int i(0); i < objectHolder.audioTrackUids.size(); ++i) { - auto speakerLabel = speakerLabels.at(i); - pluginMap.push_back({ metadata.input_instance_id(), metadata.routing() + i, objectHolder.audioObject, objectHolder.audioTrackUids.at(speakerLabel) }); - } - serializedObjects[connectionId] = objectHolder.audioObject; + auto objectHolder = AdmPresetDefinitionsHelper::getSingleton() + .addPresetDefinitionObjectTo( + doc, metadata.name(), audioPackFormatID); + setInteractivity(*objectHolder.audioObject, object); + setImportance(*objectHolder.audioObject, object); + content.addReference(objectHolder.audioObject); + for (int i(0); i < objectHolder.channels.size(); ++i) { + pluginMap.push_back({metadata.input_instance_id(), + metadata.routing() + i, objectHolder.audioObject, + objectHolder.channels[i].audioTrackUid}); } - } + serializedObjects[connectionId] = objectHolder.audioObject; + + } } } diff --git a/ear-production-suite-plugins/lib/src/scene_gains_calculator.cpp b/ear-production-suite-plugins/lib/src/scene_gains_calculator.cpp index 1ec71fe5e..958910ad2 100644 --- a/ear-production-suite-plugins/lib/src/scene_gains_calculator.cpp +++ b/ear-production-suite-plugins/lib/src/scene_gains_calculator.cpp @@ -51,9 +51,7 @@ SceneGainsCalculator::SceneGainsCalculator(ear::Layout outputLayout, directSpeakersCalculator_{outputLayout}, hoaCalculator_{outputLayout}, totalOutputChannels{static_cast(outputLayout.channels().size())}, - totalInputChannels{inputChannelCount} { - commonDefinitionHelper_.getElementRelationships(); -} + totalInputChannels{inputChannelCount} {} bool SceneGainsCalculator::update(proto::SceneStore store) { // Called by NNG callback on thread with small stack. @@ -153,10 +151,7 @@ void SceneGainsCalculator::addOrUpdateItem(const proto::MonitoringItemMetadata & if(item.has_hoa_metadata()) { ear::HOATypeMetadata earMetadata; - { - std::lock_guard lock(commonDefinitionHelperMutex_); - earMetadata = EpsToEarMetadataConverter::convert(item.hoa_metadata(), commonDefinitionHelper_); - } + earMetadata = EpsToEarMetadataConverter::convert(item.hoa_metadata()); routing->inputStartingChannel = item.routing(); int inputChannelCount = static_cast(earMetadata.degrees.size()); resizeGainTables(*routing, inputChannelCount, totalOutputChannels); diff --git a/ear-production-suite-plugins/plugins/binaural_monitoring/CMakeLists.txt b/ear-production-suite-plugins/plugins/binaural_monitoring/CMakeLists.txt index cbc415d01..6579d42dd 100644 --- a/ear-production-suite-plugins/plugins/binaural_monitoring/CMakeLists.txt +++ b/ear-production-suite-plugins/plugins/binaural_monitoring/CMakeLists.txt @@ -1,16 +1,14 @@ -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - set(SOURCES_BINAURAL_MONITORING - ${EPS_SHARED_DIR}/binary_data.cpp - ${EPS_SHARED_DIR}/components/look_and_feel/slider.cpp - ${EPS_SHARED_DIR}/components/ear_header.cpp - ${EPS_SHARED_DIR}/components/ear_slider_label.cpp - ${EPS_SHARED_DIR}/components/level_meter_calculator.cpp + ${EPS_SHARED_DIR}/binary_data.cpp + ${EPS_SHARED_DIR}/components/look_and_feel/slider.cpp + ${EPS_SHARED_DIR}/components/ear_combo_box.cpp + ${EPS_SHARED_DIR}/components/ear_header.cpp + ${EPS_SHARED_DIR}/components/ear_slider_label.cpp + ${EPS_SHARED_DIR}/components/level_meter_calculator.cpp src/binaural_monitoring_frontend_connector.cpp - src/binaural_monitoring_plugin_editor.cpp - src/binaural_monitoring_plugin_processor.cpp + src/binaural_monitoring_plugin_editor.cpp + src/binaural_monitoring_plugin_processor.cpp + src/bear_data_files.cpp src/orientation_osc.cpp ) @@ -25,6 +23,7 @@ set(HEADERS_BINAURAL_MONITORING ${EPS_SHARED_DIR}/binary_data.hpp ${EPS_SHARED_DIR}/components/ear_button.hpp + ${EPS_SHARED_DIR}/components/ear_combo_box.hpp ${EPS_SHARED_DIR}/components/ear_header.hpp ${EPS_SHARED_DIR}/components/ear_inverted_slider.hpp ${EPS_SHARED_DIR}/components/ear_slider.hpp @@ -47,10 +46,11 @@ set(HEADERS_BINAURAL_MONITORING src/binaural_monitoring_frontend_connector.hpp src/binaural_monitoring_plugin_editor.hpp src/binaural_monitoring_plugin_processor.hpp - src/error_overlay.hpp + src/bear_data_files.hpp src/headphone_channel_meter.hpp src/headphone_channel_meter_box.hpp src/orientation_osc.hpp + src/value_box_data_file.hpp src/value_box_orientation.hpp src/value_box_osc.hpp ) @@ -60,7 +60,7 @@ source_group("Header Files" FILES ${HEADERS_BINAURAL_MONITORING}) add_juce_vst3_plugin( ear_binaural_monitoring SOURCES ${SOURCES_BINAURAL_MONITORING} ${HEADERS_BINAURAL_MONITORING} - IDE_FOLDER ${IDE_FOLDER_PLUGINS} + IDE_FOLDER ${IDE_FOLDER_PLUGINS} CODE_SUFFIX "F0" # Speaker Monitoring suffixes start from A0 and increment. For bin, lets use F0 (Note FF is scene) DISPLAY_NAME "EAR Binaural Monitoring" DESCRIPTION "The binaural monitoring plugin" @@ -81,7 +81,7 @@ if(APPLE) add_custom_command(TARGET ear_binaural_monitoring_VST3 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${TENSORFILE_FULLPATH} "$/../Resources/${TENSORFILE_FILENAME}" ) - install(FILES ${TENSORFILE_FULLPATH} DESTINATION "${EPS_PLUGIN_INSTALL_PREFIX}ear-production-suite/EAR Binaural Monitoring.vst3/Contents/Resources") + install(FILES ${TENSORFILE_FULLPATH} DESTINATION "${EPS_PLUGIN_INSTALL_PREFIX}ear-production-suite/EAR Binaural Monitoring.vst3/Contents/Resources") else() add_custom_command(TARGET ear_binaural_monitoring_VST3 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${TENSORFILE_FULLPATH} "$/${TENSORFILE_FILENAME}" diff --git a/ear-production-suite-plugins/plugins/binaural_monitoring/src/bear_data_files.cpp b/ear-production-suite-plugins/plugins/binaural_monitoring/src/bear_data_files.cpp new file mode 100644 index 000000000..6f1d52da0 --- /dev/null +++ b/ear-production-suite-plugins/plugins/binaural_monitoring/src/bear_data_files.cpp @@ -0,0 +1,181 @@ +#include "bear_data_files.hpp" +#include + +namespace { +juce::File getBearDataFileDirectory() { + auto vstPath = juce::File::getSpecialLocation( + juce::File::SpecialLocationType::currentExecutableFile); + vstPath = vstPath.getParentDirectory(); +#ifdef __APPLE__ + vstPath = vstPath.getParentDirectory(); + vstPath = vstPath.getChildFile("Resources"); +#endif + return vstPath; +}; + +juce::File getCustomDataFileDirectory() { + auto vstPath = juce::File::getSpecialLocation( + juce::File::SpecialLocationType::currentExecutableFile); + vstPath = vstPath.getParentDirectory(); +#ifdef __APPLE__ + // vstPath is `EAR Binaural Monitoring.vst3/Contents/MacOS` - traverse up x3 to get to dir containing vst3 bundle + vstPath = vstPath.getParentDirectory(); + vstPath = vstPath.getParentDirectory(); + vstPath = vstPath.getParentDirectory(); +#endif + return vstPath; +}; + +} + +namespace ear { +namespace plugin { +DataFileManager::DataFileManager() { + bearReleaseFiles_.add( + getBearDataFileDirectory().getChildFile(BEAR_DATA_FILE)); + updateAvailableFiles(); +} + +namespace { +void setFromMetadata(DataFileManager::DataFile& dataFile) { + try { + auto md = bear::DataFileMetadata::read_from_file( + dataFile.fullPath.getFullPathName().toStdString()); + if (md.has_metadata()) { + dataFile.label = md.get_label(); + dataFile.description = md.get_description(); + dataFile.isBearRelease = md.is_released(); + } + } + catch(std::exception const&) { + /* + `read_from_file` could throw if; + - the file does not exist, or otherwise unreadable + - the file is not a valid tensorfile + - the metadata within the file is not of the expected structure + In all these cases, and any other, silently skip metadata extraction + + Note that a file with bad metadata may still be a usable filter set + so we don't want to strike it off yet, nor is it worth doing deeper + checks here... the user can still select it as the processor will + catch unusable files (unreadable/invalid/corrupt etc) anyway when + it tries to start BEAR with it, and will report the actual error. + */ + } +} + +void updateFile(juce::File const& file, DataFileManager::FileMap& file_map, + bool mustBeRelease) { + DataFileManager::DataFile df{.filename = file.getFileName(), + .fullPath = file}; + setFromMetadata(df); + if (!mustBeRelease || df.isBearRelease) { + file_map.insert({file, std::move(df)}); + } +} +} // namespace + +bool DataFileManager::onlyContainsDefault() const { + return customDataFiles.empty() && releasedDataFiles.size() == 1u; +} + +bool DataFileManager::defaultIsSelected() const { + return selectedDataFile_.has_value() && + releasedDataFiles.contains(selectedDataFile_->fullPath); +} + +void DataFileManager::updateAvailableFiles() { + releasedDataFiles.clear(); + customDataFiles.clear(); + + // add our expected released files + for (auto const& file : bearReleaseFiles_) { + if (file.existsAsFile()) { + updateFile(file, releasedDataFiles, true); + } + } + + auto custom_files = getCustomDataFileDirectory().findChildFiles( + juce::File::TypesOfFileToFind::findFiles, false, "*.tf"); + for (const auto& file : custom_files) { + if (!releasedDataFiles.contains(file)) { // on windows the custom / release + // dirs are the same + updateFile(file, customDataFiles, false); + } + } +} + +std::optional +DataFileManager::getSelectedDataFileInfo() const { + return selectedDataFile_; +} + +std::vector +DataFileManager::getAvailableDataFiles() const { + std::vector files; + files.reserve(getAvailableDataFilesCount()); + auto fileExtractor = [](auto const& file) { return file.second; }; + std::transform(releasedDataFiles.begin(), releasedDataFiles.end(), std::back_inserter(files), fileExtractor); + std::transform(customDataFiles.begin(), customDataFiles.end(), std::back_inserter(files), fileExtractor); + return files; +} + +std::size_t DataFileManager::getAvailableDataFilesCount() const { + return releasedDataFiles.size() + customDataFiles.size(); +} + +void DataFileManager::setSelectedDataFile(DataFile const& file) { + if(!selectedDataFile_ || file != *selectedDataFile_) { + selectedDataFile_ = file; + selectedDataFileChangeCallback_(file); + } +} + +bool DataFileManager::setSelectedDataFile(const juce::String& fullPath) { + return setSelectedDataFile(juce::File(fullPath)); +} + +bool DataFileManager::setSelectedDataFile(const juce::File& fullPath) { + auto const found = getDataFileInfo(fullPath); + if (found) { + setSelectedDataFile(*found); + } + return static_cast(found); +} + +bool DataFileManager::setSelectedDataFileDefault() { + updateAvailableFiles(); + auto found = false; + if(!releasedDataFiles.empty()) { + setSelectedDataFile(releasedDataFiles.begin()->second); + found = true; + } + return found; +} + +namespace { + std::optional getDataFile(DataFileManager::FileMap const& map, juce::File const& file) { + std::optional dataFile; + if(auto it = map.find(file); it != map.end()) { + dataFile = it->second; + } + return dataFile; + } +} + +std::optional DataFileManager::getDataFileInfo( + const juce::File& fullPath) const { + auto file = getDataFile(releasedDataFiles, fullPath); + if(!file) { + file = getDataFile(customDataFiles, fullPath); + } + return file; +} + +void DataFileManager::onSelectedDataFileChange( + std::function callback) { + selectedDataFileChangeCallback_ = std::move(callback); +} + +} // namespace plugin +} // namespace ear diff --git a/ear-production-suite-plugins/plugins/binaural_monitoring/src/bear_data_files.hpp b/ear-production-suite-plugins/plugins/binaural_monitoring/src/bear_data_files.hpp new file mode 100644 index 000000000..6b67a8bf1 --- /dev/null +++ b/ear-production-suite-plugins/plugins/binaural_monitoring/src/bear_data_files.hpp @@ -0,0 +1,58 @@ +#pragma once +#include "JuceHeader.h" +#include +#include +#include +#include + +namespace ear { +namespace plugin { + +class DataFileManager { + public: + DataFileManager(); + + struct DataFile { + juce::String filename; + juce::File fullPath; + juce::String label; + juce::String description; + bool isBearRelease{false}; + friend bool operator<(DataFile const& lhs, DataFile const& rhs){ + return lhs.fullPath.getFileName().compareIgnoreCase(rhs.fullPath.getFileName()) < 0; + } + friend bool operator==(DataFile const& lhs, DataFile const& rhs) { + return lhs.fullPath.getFileName().compareIgnoreCase(rhs.fullPath.getFileName()) == 0; + } + friend bool operator!=(DataFile const& lhs, DataFile const& rhs) { + return !(lhs == rhs); + } + }; + + bool onlyContainsDefault() const; + bool defaultIsSelected() const; + void updateAvailableFiles(); + std::optional getSelectedDataFileInfo() const; + std::vector getAvailableDataFiles() const; + bool setSelectedDataFile(const juce::String& fullPath); + bool setSelectedDataFileDefault(); + void onSelectedDataFileChange( + std::function callback); + using FileMap = boost::container::flat_map; + + private: + void setSelectedDataFile(DataFile const& file); + std::size_t getAvailableDataFilesCount() const; + bool setSelectedDataFile(const juce::File& fullPath); + std::optional getDataFileInfo(const juce::File& fullPath) const; + juce::Array bearReleaseFiles_; + std::optional selectedDataFile_; + FileMap releasedDataFiles; + FileMap customDataFiles; + + std::function selectedDataFileChangeCallback_; +}; + +} // namespace plugin +} + diff --git a/ear-production-suite-plugins/plugins/binaural_monitoring/src/binaural_monitoring_frontend_connector.cpp b/ear-production-suite-plugins/plugins/binaural_monitoring/src/binaural_monitoring_frontend_connector.cpp index 662f835a8..401a6eb56 100644 --- a/ear-production-suite-plugins/plugins/binaural_monitoring/src/binaural_monitoring_frontend_connector.cpp +++ b/ear-production-suite-plugins/plugins/binaural_monitoring/src/binaural_monitoring_frontend_connector.cpp @@ -4,6 +4,18 @@ #include "components/ear_inverted_slider.hpp" #include "detail/weak_ptr_helpers.hpp" +#include +#include + +namespace { +void removePath(std::string& filePath) { + // Find the last occurrence of forward slash or backslash + size_t lastSlash = filePath.find_last_of("/\\"); + if (lastSlash != std::string::npos) { + filePath = filePath.substr(lastSlash + 1); + } +} +} namespace ear { namespace plugin { @@ -172,6 +184,70 @@ void BinauralMonitoringJuceFrontendConnector::setOscInvertQuatZButton( setOscInvertQuatZ(cachedOscInvertQuatZ_); } +void BinauralMonitoringJuceFrontendConnector::setDataFileComponent( + std::shared_ptr comp) { + dataFileComponent_ = comp; + p_->dataFileManager.updateAvailableFiles(); + if (p_->dataFileManager.onlyContainsDefault() && + p_->dataFileManager.defaultIsSelected()) { + comp->setVisible(false); + } else { + comp->setVisible(true); + } +} + +namespace { + juce::String getDataFileLabelText(DataFileManager::DataFile const& file) { + juce::String txt; + if (!file.isBearRelease) { + txt = "[CUSTOM] "; + } + if (file.label.isEmpty()) { + // use filename - will be an unusual case in future + txt += file.filename; + } else { + txt += file.label; + txt += " (" + file.filename + ")"; + } + return txt; + } + + juce::StringArray getDataFileLabelSubText(DataFileManager::DataFile const& file) { + juce::StringArray subtexts; + if (!file.description.isEmpty()) { + subtexts.add(file.description); + } + subtexts.add(juce::String(file.fullPath.getFullPathName())); + return subtexts; + } +} + +void BinauralMonitoringJuceFrontendConnector::setDataFileComboBox( + std::shared_ptr comboBox) { + comboBox->addListener(this); + dataFileComboBox_ = comboBox; + p_->dataFileManager.updateAvailableFiles(); + comboBox->clearEntries(); + auto dfs = p_->dataFileManager.getAvailableDataFiles(); + for (const auto& df : dfs) { + auto entry = comboBox->addTextWithSubtextEntry( + getDataFileLabelText(df), + getDataFileLabelSubText(df), + df.fullPath.getFullPathName()); + entry->setLightFont(!df.isBearRelease); + } + if (auto df = p_->dataFileManager.getSelectedDataFileInfo()) { + comboBox->setSelectedId(df->fullPath.getFullPathName(), + juce::NotificationType::dontSendNotification); + } +} + +void BinauralMonitoringJuceFrontendConnector::setRendererStatusLabel( + std::shared_ptr