From b7cb32c6e8f71ae12522d291fa4e07a8c893405e Mon Sep 17 00:00:00 2001 From: Lawrence Pardoe Date: Wed, 26 May 2021 12:49:59 +0100 Subject: [PATCH 1/9] support multiple loudnessMetadata elements --- CHANGELOG.md | 1 + include/adm/elements/audio_content.hpp | 34 +++++++++++++++------- include/adm/elements/audio_programme.hpp | 26 ++++++++++++----- include/adm/elements/loudness_metadata.hpp | 19 +++++++++++- include/adm/private/rapidxml_formatter.hpp | 2 ++ include/adm/private/xml_parser.hpp | 1 + src/elements/audio_content.cpp | 25 +++++++--------- src/elements/audio_programme.cpp | 18 ++---------- src/elements/loudness_metadata.cpp | 13 ++++++++- src/private/rapidxml_formatter.cpp | 12 ++++++-- src/private/xml_parser.cpp | 13 +++++++-- tests/audio_content_tests.cpp | 8 ++--- tests/audio_programme_tests.cpp | 8 ++--- tests/xml_parser_audio_content_tests.cpp | 2 +- tests/xml_parser_audio_programme_tests.cpp | 4 +-- tests/xml_writer_audio_content_tests.cpp | 2 +- tests/xml_writer_audio_programme_tests.cpp | 2 +- 17 files changed, 121 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf287022..dcd76bd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - fixed erroneous test acceptance data - updated required C++ standard from C++11 to C++14 - implemented fractional time format from BS.2076-2 +- audioProgramme and audioContent may now have multiple loudnessMetadata elements, as per BS.2076-2 ### Fixed - updateBlockFormatDurations now throws an exception when given an audioChannelFormat with no audioBlockFormats, rather than segfaulting diff --git a/include/adm/elements/audio_content.hpp b/include/adm/elements/audio_content.hpp index bc53f028..1528a1ec 100644 --- a/include/adm/elements/audio_content.hpp +++ b/include/adm/elements/audio_content.hpp @@ -12,6 +12,7 @@ #include "adm/helper/element_range.hpp" #include "adm/detail/named_option_helper.hpp" #include "adm/export.h" +#include "adm/detail/auto_base.hpp" namespace adm { @@ -30,12 +31,18 @@ namespace adm { /// @brief Tag for AudioContent struct AudioContentTag {}; + + namespace detail { + using AudioContentBase = HasParameters>; + } // namespace detail + /** * @brief Class representation of the audioContent ADM element * * @headerfile audio_content.hpp */ - class AudioContent : public std::enable_shared_from_this { + class AudioContent : public std::enable_shared_from_this, + private detail::AudioContentBase { public: typedef AudioContentTag tag; /// Type that holds the id for this element; @@ -101,8 +108,6 @@ namespace adm { ADM_EXPORT void set(AudioContentName name); /// @brief AudioContentLanguage setter ADM_EXPORT void set(AudioContentLanguage language); - /// @brief LoudnessMetadata setter - ADM_EXPORT void set(LoudnessMetadata loudnessMetadata); ///@{ /** @@ -180,17 +185,26 @@ namespace adm { /** * @brief Print overview to ostream */ - ADM_EXPORT void print(std::ostream &os) const; + ADM_EXPORT void print(std::ostream& os) const; /// Get adm::Document this element belongs to ADM_EXPORT std::weak_ptr getParent() const; + using detail::AudioContentBase::add; + using detail::AudioContentBase::remove; + using detail::AudioContentBase::set; + private: friend class AudioContentAttorney; ADM_EXPORT AudioContent(AudioContentName name); - ADM_EXPORT AudioContent(const AudioContent &) = default; - ADM_EXPORT AudioContent(AudioContent &&) = default; + ADM_EXPORT AudioContent(const AudioContent&) = default; + ADM_EXPORT AudioContent(AudioContent&&) = default; + + using detail::AudioContentBase::get; + using detail::AudioContentBase::has; + using detail::AudioContentBase::isDefault; + using detail::AudioContentBase::unset; ADM_EXPORT AudioContentId get(detail::ParameterTraits::tag) const; @@ -198,8 +212,6 @@ namespace adm { get(detail::ParameterTraits::tag) const; ADM_EXPORT AudioContentLanguage get(detail::ParameterTraits::tag) const; - ADM_EXPORT LoudnessMetadata - get(detail::ParameterTraits::tag) const; ADM_EXPORT DialogueId get(detail::ParameterTraits::tag) const; ADM_EXPORT ContentKind get(detail::ParameterTraits::tag) const; ADM_EXPORT NonDialogueContentKind @@ -213,7 +225,6 @@ namespace adm { ADM_EXPORT bool has(detail::ParameterTraits::tag) const; ADM_EXPORT bool has( detail::ParameterTraits::tag) const; - ADM_EXPORT bool has(detail::ParameterTraits::tag) const; ADM_EXPORT bool has(detail::ParameterTraits::tag) const; ADM_EXPORT bool has(detail::ParameterTraits::tag) const; ADM_EXPORT bool has( @@ -228,7 +239,6 @@ namespace adm { } ADM_EXPORT void unset(detail::ParameterTraits::tag); - ADM_EXPORT void unset(detail::ParameterTraits::tag); ADM_EXPORT void unset(detail::ParameterTraits::tag); ADM_EXPORT void unset(detail::ParameterTraits::tag); ADM_EXPORT void unset(detail::ParameterTraits::tag); @@ -252,13 +262,15 @@ namespace adm { AudioContentName name_; boost::optional language_; std::vector> audioObjects_; - boost::optional loudnessMetadata_; boost::optional dialogueId_; boost::optional nonDialogueContentKind_; boost::optional dialogueContentKind_; boost::optional mixedContentKind_; }; + std::ostream& operator<<(std::ostream& stream, + const LoudnessMetadatas& loudnessMetaDatas); + // ---- Implementation ---- // template diff --git a/include/adm/elements/audio_programme.hpp b/include/adm/elements/audio_programme.hpp index c8dd7615..cd5debd6 100644 --- a/include/adm/elements/audio_programme.hpp +++ b/include/adm/elements/audio_programme.hpp @@ -14,6 +14,7 @@ #include "adm/detail/named_option_helper.hpp" #include "adm/detail/named_type.hpp" #include "adm/export.h" +#include "adm/detail/auto_base.hpp" namespace adm { @@ -42,6 +43,12 @@ namespace adm { /// @brief Tag for AudioProgramme struct AudioProgrammeTag {}; + + namespace detail { + using AudioProgrammeBase = + HasParameters>; + } // namespace detail + /** * @brief Class representation of the audioProgramme ADM element * @@ -50,7 +57,8 @@ namespace adm { * * @headerfile audio_programme.hpp */ - class AudioProgramme : public std::enable_shared_from_this { + class AudioProgramme : public std::enable_shared_from_this, + private detail::AudioProgrammeBase { public: typedef AudioProgrammeTag tag; /// @brief Type that holds the id for this element; @@ -116,8 +124,6 @@ namespace adm { ADM_EXPORT void set(Start start); /// @brief End setter ADM_EXPORT void set(End end); - /// @brief LoudnessMetadata setter - ADM_EXPORT void set(LoudnessMetadata loudnessMetadata); /// @brief MaxDuckingDepth setter ADM_EXPORT void set(MaxDuckingDepth depth); /// @brief AudioProgrammeReferenceScreen setter @@ -177,6 +183,10 @@ namespace adm { /// Get adm::Document this element belongs to ADM_EXPORT std::weak_ptr getParent() const; + using detail::AudioProgrammeBase::add; + using detail::AudioProgrammeBase::remove; + using detail::AudioProgrammeBase::set; + private: friend class AudioProgrammeAttorney; @@ -184,6 +194,11 @@ namespace adm { ADM_EXPORT AudioProgramme(const AudioProgramme &) = default; ADM_EXPORT AudioProgramme(AudioProgramme &&) = default; + using detail::AudioProgrammeBase::get; + using detail::AudioProgrammeBase::has; + using detail::AudioProgrammeBase::isDefault; + using detail::AudioProgrammeBase::unset; + ADM_EXPORT AudioProgrammeId get(detail::ParameterTraits::tag) const; ADM_EXPORT AudioProgrammeName @@ -192,8 +207,6 @@ namespace adm { get(detail::ParameterTraits::tag) const; ADM_EXPORT Start get(detail::ParameterTraits::tag) const; ADM_EXPORT End get(detail::ParameterTraits::tag) const; - ADM_EXPORT LoudnessMetadata - get(detail::ParameterTraits::tag) const; ADM_EXPORT MaxDuckingDepth get(detail::ParameterTraits::tag) const; ADM_EXPORT AudioProgrammeReferenceScreen @@ -205,7 +218,6 @@ namespace adm { detail::ParameterTraits::tag) const; ADM_EXPORT bool has(detail::ParameterTraits::tag) const; ADM_EXPORT bool has(detail::ParameterTraits::tag) const; - ADM_EXPORT bool has(detail::ParameterTraits::tag) const; ADM_EXPORT bool has(detail::ParameterTraits::tag) const; ADM_EXPORT bool has( detail::ParameterTraits::tag) const; @@ -220,7 +232,6 @@ namespace adm { ADM_EXPORT void unset(detail::ParameterTraits::tag); ADM_EXPORT void unset(detail::ParameterTraits::tag); ADM_EXPORT void unset(detail::ParameterTraits::tag); - ADM_EXPORT void unset(detail::ParameterTraits::tag); ADM_EXPORT void unset(detail::ParameterTraits::tag); ADM_EXPORT void unset( detail::ParameterTraits::tag); @@ -244,7 +255,6 @@ namespace adm { boost::optional start_; boost::optional end_; std::vector> audioContents_; - boost::optional loudnessMetadata_; boost::optional maxDuckingDepth_; boost::optional refScreen_; }; diff --git a/include/adm/elements/loudness_metadata.hpp b/include/adm/elements/loudness_metadata.hpp index 4992363c..ffcabf0e 100644 --- a/include/adm/elements/loudness_metadata.hpp +++ b/include/adm/elements/loudness_metadata.hpp @@ -1,10 +1,12 @@ #pragma once #include "adm/detail/named_option_helper.hpp" #include "adm/detail/named_type.hpp" +#include "adm/detail/auto_base.hpp" #include "adm/export.h" #include #include #include +#include namespace adm { @@ -50,6 +52,14 @@ namespace adm { /// @brief Tag for LoudnessMetadata class struct LoudnessMetadataTag {}; + using LoudnessMetadatas = std::vector; + ADD_TRAIT(LoudnessMetadatas, LoudnessMetadatasTag); + + namespace detail { + extern template class ADM_EXPORT_TEMPLATE_METHODS + VectorParameter; + } + class LoudnessMetadata { public: typedef LoudnessMetadataTag tag; @@ -120,10 +130,17 @@ namespace adm { template void unset(); + /** + * @brief Operator overload + * + * Compares each loudnessMetadata parameter + */ + ADM_EXPORT bool operator==(const LoudnessMetadata& other) const; + /** * @brief Print overview to ostream */ - ADM_EXPORT void print(std::ostream &os) const; + ADM_EXPORT void print(std::ostream& os) const; private: ADM_EXPORT LoudnessMethod diff --git a/include/adm/private/rapidxml_formatter.hpp b/include/adm/private/rapidxml_formatter.hpp index 1476d45d..bb0f23be 100644 --- a/include/adm/private/rapidxml_formatter.hpp +++ b/include/adm/private/rapidxml_formatter.hpp @@ -11,6 +11,8 @@ namespace adm { XmlNode &node, const std::shared_ptr programme); void formatLoudnessMetadata(XmlNode &node, const LoudnessMetadata loudnessMetadata); + void formatLoudnessMetadatas(XmlNode &node, const std::string &name, + const LoudnessMetadatas &loudnessMetadatas); void formatNonDialogueContentKind(XmlNode &node, const NonDialogueContentKind contentKind); void formatDialogueContentKind(XmlNode &node, diff --git a/include/adm/private/xml_parser.hpp b/include/adm/private/xml_parser.hpp index 84104835..5c579d08 100644 --- a/include/adm/private/xml_parser.hpp +++ b/include/adm/private/xml_parser.hpp @@ -36,6 +36,7 @@ namespace adm { SphericalPosition parseSphericalPosition(std::vector nodes); CartesianPosition parseCartesianPosition(std::vector nodes); LoudnessMetadata parseLoudnessMetadata(NodePtr node); + LoudnessMetadatas parseLoudnessMetadatas(const std::vector& nodes); AudioProgrammeReferenceScreen parseAudioProgrammeReferenceScreen( NodePtr node); AudioBlockFormatObjects parseAudioBlockFormatObjects(NodePtr node); diff --git a/src/elements/audio_content.cpp b/src/elements/audio_content.cpp index b1599139..5c2558e8 100644 --- a/src/elements/audio_content.cpp +++ b/src/elements/audio_content.cpp @@ -23,10 +23,6 @@ namespace adm { detail::ParameterTraits::tag) const { return language_.get(); } - LoudnessMetadata AudioContent::get( - detail::ParameterTraits::tag) const { - return loudnessMetadata_.get(); - } DialogueId AudioContent::get(detail::ParameterTraits::tag) const { return dialogueId_.get(); } @@ -64,9 +60,6 @@ namespace adm { detail::ParameterTraits::tag) const { return language_ != boost::none; } - bool AudioContent::has(detail::ParameterTraits::tag) const { - return loudnessMetadata_ != boost::none; - } bool AudioContent::has(detail::ParameterTraits::tag) const { return dialogueId_ != boost::none; } @@ -102,9 +95,6 @@ namespace adm { void AudioContent::set(AudioContentLanguage language) { language_ = language; } - void AudioContent::set(LoudnessMetadata loudnessMetadata) { - loudnessMetadata_ = loudnessMetadata; - } void AudioContent::set(DialogueId id) { if (dialogueId_ && dialogueId_.get() == id) { return; @@ -148,9 +138,6 @@ namespace adm { void AudioContent::unset(detail::ParameterTraits::tag) { language_ = boost::none; } - void AudioContent::unset(detail::ParameterTraits::tag) { - loudnessMetadata_ = boost::none; - } void AudioContent::unset(detail::ParameterTraits::tag) { dialogueId_ = boost::none; nonDialogueContentKind_ = boost::none; @@ -199,6 +186,14 @@ namespace adm { return audioObjects_.clear(); } + std::ostream& operator<<(std::ostream& stream, + const LoudnessMetadatas& loudnessMetaDatas) { + // Iterate over loudnessMetaDatas + for (auto i = loudnessMetaDatas.begin(); i != loudnessMetaDatas.end(); ++i) + stream << *i << ' '; + return stream; + } + // ---- Common ---- // void AudioContent::print(std::ostream& os) const { os << get(); @@ -207,8 +202,8 @@ namespace adm { if (has()) { os << ", audioContentLanguage=" << get(); } - if (has()) { - os << ", loudnessMetadata=" << get(); + if (has()) { + os << ", loudnessMetadata=" << get(); } if (has()) { os << ", dialogueId=" << get(); diff --git a/src/elements/audio_programme.cpp b/src/elements/audio_programme.cpp index d7b11f35..2ab9365e 100644 --- a/src/elements/audio_programme.cpp +++ b/src/elements/audio_programme.cpp @@ -37,10 +37,6 @@ namespace adm { End AudioProgramme::get(detail::ParameterTraits::tag) const { return end_.get(); } - LoudnessMetadata AudioProgramme::get( - detail::ParameterTraits::tag) const { - return loudnessMetadata_.get(); - } MaxDuckingDepth AudioProgramme::get( detail::ParameterTraits::tag) const { return maxDuckingDepth_.get(); @@ -69,10 +65,6 @@ namespace adm { bool AudioProgramme::has(detail::ParameterTraits::tag) const { return end_ != boost::none; } - bool AudioProgramme::has( - detail::ParameterTraits::tag) const { - return loudnessMetadata_ != boost::none; - } bool AudioProgramme::has( detail::ParameterTraits::tag) const { return maxDuckingDepth_ != boost::none; @@ -105,9 +97,6 @@ namespace adm { } void AudioProgramme::set(Start start) { start_ = start; } void AudioProgramme::set(End end) { end_ = end; } - void AudioProgramme::set(LoudnessMetadata loudnessMetadata) { - loudnessMetadata_ = loudnessMetadata; - } void AudioProgramme::set(MaxDuckingDepth depth) { maxDuckingDepth_ = depth; } void AudioProgramme::set(AudioProgrammeReferenceScreen refScreen) { refScreen_ = refScreen; @@ -124,9 +113,6 @@ namespace adm { void AudioProgramme::unset(detail::ParameterTraits::tag) { end_ = boost::none; } - void AudioProgramme::unset(detail::ParameterTraits::tag) { - loudnessMetadata_ = boost::none; - } void AudioProgramme::unset(detail::ParameterTraits::tag) { maxDuckingDepth_ = boost::none; } @@ -182,8 +168,8 @@ namespace adm { if (has()) { os << ", end=" << formatTimecode(get().get()); } - if (has()) { - os << ", loudnessMetadata=" << get(); + if (has()) { + os << ", loudnessMetadata=" << get(); } if (has()) { os << ", maxDuckingDepth=" << get(); diff --git a/src/elements/loudness_metadata.cpp b/src/elements/loudness_metadata.cpp index e49012cb..30f414fe 100644 --- a/src/elements/loudness_metadata.cpp +++ b/src/elements/loudness_metadata.cpp @@ -4,6 +4,10 @@ namespace adm { + namespace detail { + template class VectorParameter; + } + // ---- Getter ---- // LoudnessMethod LoudnessMetadata::get( detail::ParameterTraits::tag) const { @@ -137,7 +141,14 @@ namespace adm { dialogueLoudness_ = boost::none; } - void LoudnessMetadata::print(std::ostream &os) const { + // ---- Operators ---- // + bool LoudnessMetadata::operator==(const LoudnessMetadata& other) const { + return get() == other.get() && + get() == other.get() && + get() == other.get(); + } + + void LoudnessMetadata::print(std::ostream& os) const { os << "("; if (has()) { os << "loudnessMethod=" << get() << ", "; diff --git a/src/private/rapidxml_formatter.cpp b/src/private/rapidxml_formatter.cpp index b416f97c..d7312b18 100644 --- a/src/private/rapidxml_formatter.cpp +++ b/src/private/rapidxml_formatter.cpp @@ -56,7 +56,7 @@ namespace adm { node.addOptionalAttribute(programme, "end"); node.addOptionalAttribute(programme, "maxDuckingDepth"); node.addReferences(programme, "audioContentIDRef"); - node.addOptionalElement(programme, "loudnessMetadata", &formatLoudnessMetadata); + node.addOptionalMultiElement(programme, "loudnessMetadata", &formatLoudnessMetadatas); // clang-format on } @@ -79,6 +79,14 @@ namespace adm { "dialogueLoudness"); } + void formatLoudnessMetadatas(XmlNode &node, const std::string &name, + const LoudnessMetadatas &loudnessMetadatas) { + for (const auto &loudnessMetadata : loudnessMetadatas) { + auto loudnessMetadataNode = node.addNode(name); + formatLoudnessMetadata(loudnessMetadataNode, loudnessMetadata); + } + } + void formatAudioContent(XmlNode &node, std::shared_ptr content) { // clang-format off @@ -86,7 +94,7 @@ namespace adm { node.addOptionalAttribute(content, "audioContentName"); node.addOptionalAttribute(content, "audioContentLanguage"); node.addReferences(content, "audioObjectIDRef"); - node.addOptionalElement(content, "loudnessMetadata", &formatLoudnessMetadata); + node.addOptionalMultiElement(content, "loudnessMetadata", &formatLoudnessMetadatas); node.addOptionalElement(content, "dialogue", &formatNonDialogueContentKind); node.addOptionalElement(content, "dialogue", &formatDialogueContentKind); node.addOptionalElement(content, "dialogue", &formatMixedContentKind); diff --git a/src/private/xml_parser.cpp b/src/private/xml_parser.cpp index 5ca190ae..358eae57 100644 --- a/src/private/xml_parser.cpp +++ b/src/private/xml_parser.cpp @@ -147,7 +147,7 @@ namespace adm { setOptionalAttribute(node, "end", audioProgramme, &parseTimecode); setOptionalAttribute(node, "maxDuckingDepth", audioProgramme); - setOptionalElement(node, "loudnessMetadata", audioProgramme, &parseLoudnessMetadata); + setOptionalMultiElement(node, "loudnessMetadata", audioProgramme, &parseLoudnessMetadatas); setOptionalElement(node, "audioProgrammeReferenceScreen", audioProgramme, &parseAudioProgrammeReferenceScreen); addOptionalReferences(node, "audioContentIDRef", audioProgramme, programmeContentRefs_, &parseAudioContentId); @@ -166,7 +166,7 @@ namespace adm { setOptionalAttribute(node, "audioContentLanguage", audioContent); - setOptionalElement(node, "loudnessMetadata", audioContent, &parseLoudnessMetadata); + setOptionalMultiElement(node, "loudnessMetadata", audioContent, &parseLoudnessMetadatas); setOptionalElement(node, "dialogue", audioContent, &parseContentKind); addOptionalReferences(node, "audioObjectIDRef", audioContent, contentObjectRefs_, &parseAudioObjectId); @@ -732,6 +732,15 @@ namespace adm { return loudnessMetadata; } + LoudnessMetadatas parseLoudnessMetadatas(std::vector const& nodes) { + LoudnessMetadatas loudnessMetatatas; + for (auto& element : nodes) { + auto loudnessMetadata = parseLoudnessMetadata(element); + loudnessMetatatas.push_back(loudnessMetadata); + } + return loudnessMetatatas; + } + DialogueId parseDialogueId(NodePtr node) { return DialogueId(std::stoi(node->value())); } diff --git a/tests/audio_content_tests.cpp b/tests/audio_content_tests.cpp index a331015e..fb2dff5a 100644 --- a/tests/audio_content_tests.cpp +++ b/tests/audio_content_tests.cpp @@ -10,13 +10,13 @@ TEST_CASE("audio_content") { audioContent->set(AudioContentId(AudioContentIdValue(1))); audioContent->set(AudioContentName("MyNewContent")); audioContent->set(AudioContentLanguage("de")); - audioContent->set(LoudnessMetadata()); + audioContent->add(LoudnessMetadata()); audioContent->set(Dialogue::NON_DIALOGUE); REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); - REQUIRE(audioContent->has() == true); + REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == false); @@ -29,11 +29,11 @@ TEST_CASE("audio_content") { REQUIRE(audioContent->get() == Dialogue::NON_DIALOGUE); audioContent->unset(); - audioContent->unset(); + audioContent->unset(); audioContent->unset(); REQUIRE(audioContent->has() == false); - REQUIRE(audioContent->has() == false); + REQUIRE(audioContent->has() == false); REQUIRE(audioContent->has() == false); REQUIRE(audioContent->has() == false); REQUIRE(audioContent->has() == false); diff --git a/tests/audio_programme_tests.cpp b/tests/audio_programme_tests.cpp index ed15209b..00588ad9 100644 --- a/tests/audio_programme_tests.cpp +++ b/tests/audio_programme_tests.cpp @@ -12,7 +12,7 @@ TEST_CASE("audio_programme") { audioProgramme->set(AudioProgrammeLanguage("de")); audioProgramme->set(Start(std::chrono::seconds(0))); audioProgramme->set(End(std::chrono::seconds(10))); - audioProgramme->set(LoudnessMetadata()); + audioProgramme->add(LoudnessMetadata()); audioProgramme->set(MaxDuckingDepth(-30)); // NOTE: AudioProgrammeReferenceScreen is not yet implemented. // audioProgramme->set(AudioProgrammeReferenceScreen()); @@ -22,7 +22,7 @@ TEST_CASE("audio_programme") { REQUIRE(audioProgramme->has()); REQUIRE(audioProgramme->has()); REQUIRE(audioProgramme->has()); - REQUIRE(audioProgramme->has()); + REQUIRE(audioProgramme->has()); REQUIRE(audioProgramme->has()); // NOTE: AudioProgrammeReferenceScreen is not yet implemented. // REQUIRE(audioProgramme->has()); @@ -41,7 +41,7 @@ TEST_CASE("audio_programme") { audioProgramme->unset(); audioProgramme->unset(); audioProgramme->unset(); - audioProgramme->unset(); + audioProgramme->unset(); audioProgramme->unset(); // NOTE: AudioProgrammeReferenceScreen is not yet implemented. // audioProgramme->unset(); @@ -49,7 +49,7 @@ TEST_CASE("audio_programme") { REQUIRE(!audioProgramme->has()); REQUIRE(audioProgramme->has()); REQUIRE(!audioProgramme->has()); - REQUIRE(!audioProgramme->has()); + REQUIRE(!audioProgramme->has()); REQUIRE(!audioProgramme->has()); // NOTE: AudioProgrammeReferenceScreen is not yet implemented. // REQUIRE(!audioProgramme->has()); diff --git a/tests/xml_parser_audio_content_tests.cpp b/tests/xml_parser_audio_content_tests.cpp index 3ae57676..05a4ebd6 100644 --- a/tests/xml_parser_audio_content_tests.cpp +++ b/tests/xml_parser_audio_content_tests.cpp @@ -13,7 +13,7 @@ TEST_CASE("xml_parser/audio_content") { REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); - REQUIRE(audioContent->has() == true); + REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); REQUIRE(audioContent->get() == "MyContent"); diff --git a/tests/xml_parser_audio_programme_tests.cpp b/tests/xml_parser_audio_programme_tests.cpp index 8dcae725..578643d6 100644 --- a/tests/xml_parser_audio_programme_tests.cpp +++ b/tests/xml_parser_audio_programme_tests.cpp @@ -17,7 +17,7 @@ TEST_CASE("xml_parser/audio_programme") { REQUIRE(audioProgramme->has() == true); REQUIRE(audioProgramme->has() == true); REQUIRE(audioProgramme->has() == true); - REQUIRE(audioProgramme->has() == true); + REQUIRE(audioProgramme->has() == true); REQUIRE(audioProgramme->has() == false); REQUIRE(audioProgramme->get() == "MyProgramme"); @@ -28,7 +28,7 @@ TEST_CASE("xml_parser/audio_programme") { REQUIRE(audioProgramme->get().get() == std::chrono::seconds(0)); REQUIRE(audioProgramme->get().get() == std::chrono::seconds(10)); REQUIRE(audioProgramme->get() == -15); - auto loudnessMetadata = audioProgramme->get(); + auto loudnessMetadata = audioProgramme->get().at(0); REQUIRE(loudnessMetadata.get() == "ITU-R BS.1770"); REQUIRE(loudnessMetadata.get() == "EBU R128"); REQUIRE(loudnessMetadata.get() == "File-based"); diff --git a/tests/xml_writer_audio_content_tests.cpp b/tests/xml_writer_audio_content_tests.cpp index 44f7b132..4d380439 100644 --- a/tests/xml_writer_audio_content_tests.cpp +++ b/tests/xml_writer_audio_content_tests.cpp @@ -12,7 +12,7 @@ TEST_CASE("write_audio_object_interaction") { auto audioContent = AudioContent::create(AudioContentName("MyContent")); audioContent->set(AudioContentId(AudioContentIdValue(0x1001))); audioContent->set(AudioContentLanguage("de")); - audioContent->set(LoudnessMetadata( + audioContent->add(LoudnessMetadata( LoudnessMethod("ITU-R BS.1770"), LoudnessRecType("EBU R128"), LoudnessCorrectionType("File-based"), IntegratedLoudness(-23.f), LoudnessRange(10.f), MaxTruePeak(-2.3f), MaxMomentary(-19.f), diff --git a/tests/xml_writer_audio_programme_tests.cpp b/tests/xml_writer_audio_programme_tests.cpp index 783aa7fe..e9cffe23 100644 --- a/tests/xml_writer_audio_programme_tests.cpp +++ b/tests/xml_writer_audio_programme_tests.cpp @@ -15,7 +15,7 @@ TEST_CASE("write_audio_object_interaction") { audioProgramme->set(AudioProgrammeLanguage("de")); audioProgramme->set(Start(std::chrono::seconds(0))); audioProgramme->set(End(std::chrono::seconds(10))); - audioProgramme->set(LoudnessMetadata( + audioProgramme->add(LoudnessMetadata( LoudnessMethod("ITU-R BS.1770"), LoudnessRecType("EBU R128"), LoudnessCorrectionType("File-based"), IntegratedLoudness(-23.f), LoudnessRange(10.f), MaxTruePeak(-2.3f), MaxMomentary(-19.f), From e3835320d49fe1cbd43ffe825c56b444df727e65 Mon Sep 17 00:00:00 2001 From: Tom Nixon Date: Thu, 27 May 2021 12:47:00 +0100 Subject: [PATCH 2/9] consolidate loudnessMetadata tests and test loudnessMetadatas only test xml loudnessMetadata in one place --- tests/CMakeLists.txt | 1 + .../test_data/loudness_metadata.accepted.xml | 47 +++++++++++++++++++ .../write_audio_content.accepted.xml | 8 ---- .../write_audio_programme.accepted.xml | 11 +---- tests/test_data/xml_parser/audio_content.xml | 8 ---- .../test_data/xml_parser/audio_programme.xml | 8 ---- .../xml_parser/loudness_metadata.xml | 46 ++++++++++++++++++ tests/xml_loudness_metadata_tests.cpp | 47 +++++++++++++++++++ tests/xml_parser_audio_content_tests.cpp | 1 - tests/xml_parser_audio_programme_tests.cpp | 11 ----- tests/xml_writer_audio_content_tests.cpp | 5 -- tests/xml_writer_audio_programme_tests.cpp | 5 -- 12 files changed, 142 insertions(+), 56 deletions(-) create mode 100644 tests/test_data/loudness_metadata.accepted.xml create mode 100644 tests/test_data/xml_parser/loudness_metadata.xml create mode 100644 tests/xml_loudness_metadata_tests.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 61ad7c0e..b54e5af1 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -66,6 +66,7 @@ add_adm_test("screen_edge_lock_tests") add_adm_test("speaker_position_tests") add_adm_test("type_descriptor_tests") add_adm_test("xml_audio_block_format_objects_tests") +add_adm_test("xml_loudness_metadata_tests") add_adm_test("xml_parser_audio_block_format_direct_speakers_tests") add_adm_test("xml_parser_audio_block_format_hoa_tests") add_adm_test("xml_parser_audio_channel_format_tests") diff --git a/tests/test_data/loudness_metadata.accepted.xml b/tests/test_data/loudness_metadata.accepted.xml new file mode 100644 index 00000000..b8c509e6 --- /dev/null +++ b/tests/test_data/loudness_metadata.accepted.xml @@ -0,0 +1,47 @@ + + + + + + + + -23.000000 + 10.000000 + -2.300000 + -19.000000 + -21.200001 + -24.000000 + + + -23.000000 + 10.000000 + -2.300000 + -19.000000 + -21.200001 + -24.000000 + + + + + -23.000000 + 10.000000 + -2.300000 + -19.000000 + -21.200001 + -24.000000 + + + -23.000000 + 10.000000 + -2.300000 + -19.000000 + -21.200001 + -24.000000 + + 1 + + + + + + diff --git a/tests/test_data/write_audio_content.accepted.xml b/tests/test_data/write_audio_content.accepted.xml index e57cbffd..6a41f2a4 100644 --- a/tests/test_data/write_audio_content.accepted.xml +++ b/tests/test_data/write_audio_content.accepted.xml @@ -4,14 +4,6 @@ - - -23.000000 - 10.000000 - -2.300000 - -19.000000 - -21.200001 - -24.000000 - 1 diff --git a/tests/test_data/write_audio_programme.accepted.xml b/tests/test_data/write_audio_programme.accepted.xml index 37797833..4a11370a 100644 --- a/tests/test_data/write_audio_programme.accepted.xml +++ b/tests/test_data/write_audio_programme.accepted.xml @@ -3,16 +3,7 @@ - - - -23.000000 - 10.000000 - -2.300000 - -19.000000 - -21.200001 - -24.000000 - - + diff --git a/tests/test_data/xml_parser/audio_content.xml b/tests/test_data/xml_parser/audio_content.xml index 166dfc11..f1592a3c 100644 --- a/tests/test_data/xml_parser/audio_content.xml +++ b/tests/test_data/xml_parser/audio_content.xml @@ -5,14 +5,6 @@ 1 - - -23.0 - 10.0 - -2.3 - -19.0 - -21.2 - -24.0 - diff --git a/tests/test_data/xml_parser/audio_programme.xml b/tests/test_data/xml_parser/audio_programme.xml index 92205429..0e81ce84 100644 --- a/tests/test_data/xml_parser/audio_programme.xml +++ b/tests/test_data/xml_parser/audio_programme.xml @@ -4,14 +4,6 @@ - - -23.0 - 10.0 - -2.3 - -19.0 - -21.2 - -24.0 - diff --git a/tests/test_data/xml_parser/loudness_metadata.xml b/tests/test_data/xml_parser/loudness_metadata.xml new file mode 100644 index 00000000..1c12d93a --- /dev/null +++ b/tests/test_data/xml_parser/loudness_metadata.xml @@ -0,0 +1,46 @@ + + + + + + + + -23.0 + 10.0 + -2.3 + -19.0 + -21.2 + -24.0 + + + -23.0 + 10.0 + -2.3 + -19.0 + -21.2 + -24.0 + + + + 1 + + -23.0 + 10.0 + -2.3 + -19.0 + -21.2 + -24.0 + + + -23.0 + 10.0 + -2.3 + -19.0 + -21.2 + -24.0 + + + + + + diff --git a/tests/xml_loudness_metadata_tests.cpp b/tests/xml_loudness_metadata_tests.cpp new file mode 100644 index 00000000..57ce6e83 --- /dev/null +++ b/tests/xml_loudness_metadata_tests.cpp @@ -0,0 +1,47 @@ +#include +#include +#include "adm/document.hpp" +#include "adm/elements/audio_content.hpp" +#include "adm/parse.hpp" +#include "adm/write.hpp" +#include "adm/errors.hpp" +#include "helper/file_comparator.hpp" + +using namespace adm; + +void check_loudnessMetadata(const LoudnessMetadata &lm, + const std::string &method) { + REQUIRE(lm.get() == method); + REQUIRE(lm.get() == "EBU R128"); + REQUIRE(lm.get() == "File-based"); + REQUIRE(lm.get() == Approx(-23.f)); + REQUIRE(lm.get() == Approx(10.f)); + REQUIRE(lm.get() == Approx(-2.3f)); + REQUIRE(lm.get() == Approx(-19.f)); + REQUIRE(lm.get() == Approx(-21.2f)); + REQUIRE(lm.get() == Approx(-24.f)); +} + +template +void check_loudnessMetadatas(const Element &element) { + REQUIRE(element->template has()); + LoudnessMetadatas lm = element->template get(); + REQUIRE(lm.size() == 2); + check_loudnessMetadata(lm.at(0), "ITU-R BS.1770"); + check_loudnessMetadata(lm.at(1), "proprietary"); +} + +TEST_CASE("xml/loudness_metadata") { + auto document = parseXml("xml_parser/loudness_metadata.xml"); + + auto audioContent = document->lookup(parseAudioContentId("ACO_1001")); + check_loudnessMetadatas(audioContent); + + auto audioProgramme = document->lookup(parseAudioProgrammeId("APR_1001")); + check_loudnessMetadatas(audioProgramme); + + std::stringstream xml; + writeXml(xml, document); + + CHECK_THAT(xml.str(), EqualsXmlFile("loudness_metadata")); +} diff --git a/tests/xml_parser_audio_content_tests.cpp b/tests/xml_parser_audio_content_tests.cpp index 05a4ebd6..0c96d999 100644 --- a/tests/xml_parser_audio_content_tests.cpp +++ b/tests/xml_parser_audio_content_tests.cpp @@ -13,7 +13,6 @@ TEST_CASE("xml_parser/audio_content") { REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); - REQUIRE(audioContent->has() == true); REQUIRE(audioContent->has() == true); REQUIRE(audioContent->get() == "MyContent"); diff --git a/tests/xml_parser_audio_programme_tests.cpp b/tests/xml_parser_audio_programme_tests.cpp index 578643d6..b3aa3e20 100644 --- a/tests/xml_parser_audio_programme_tests.cpp +++ b/tests/xml_parser_audio_programme_tests.cpp @@ -17,7 +17,6 @@ TEST_CASE("xml_parser/audio_programme") { REQUIRE(audioProgramme->has() == true); REQUIRE(audioProgramme->has() == true); REQUIRE(audioProgramme->has() == true); - REQUIRE(audioProgramme->has() == true); REQUIRE(audioProgramme->has() == false); REQUIRE(audioProgramme->get() == "MyProgramme"); @@ -28,16 +27,6 @@ TEST_CASE("xml_parser/audio_programme") { REQUIRE(audioProgramme->get().get() == std::chrono::seconds(0)); REQUIRE(audioProgramme->get().get() == std::chrono::seconds(10)); REQUIRE(audioProgramme->get() == -15); - auto loudnessMetadata = audioProgramme->get().at(0); - REQUIRE(loudnessMetadata.get() == "ITU-R BS.1770"); - REQUIRE(loudnessMetadata.get() == "EBU R128"); - REQUIRE(loudnessMetadata.get() == "File-based"); - REQUIRE(loudnessMetadata.get() == Approx(-23.f)); - REQUIRE(loudnessMetadata.get() == Approx(10.0f)); - REQUIRE(loudnessMetadata.get() == Approx(-2.3f)); - REQUIRE(loudnessMetadata.get() == Approx(-19.0f)); - REQUIRE(loudnessMetadata.get() == Approx(-21.2f)); - REQUIRE(loudnessMetadata.get() == Approx(-24.0f)); } } diff --git a/tests/xml_writer_audio_content_tests.cpp b/tests/xml_writer_audio_content_tests.cpp index 4d380439..a3bfb484 100644 --- a/tests/xml_writer_audio_content_tests.cpp +++ b/tests/xml_writer_audio_content_tests.cpp @@ -12,11 +12,6 @@ TEST_CASE("write_audio_object_interaction") { auto audioContent = AudioContent::create(AudioContentName("MyContent")); audioContent->set(AudioContentId(AudioContentIdValue(0x1001))); audioContent->set(AudioContentLanguage("de")); - audioContent->add(LoudnessMetadata( - LoudnessMethod("ITU-R BS.1770"), LoudnessRecType("EBU R128"), - LoudnessCorrectionType("File-based"), IntegratedLoudness(-23.f), - LoudnessRange(10.f), MaxTruePeak(-2.3f), MaxMomentary(-19.f), - MaxShortTerm(-21.2), DialogueLoudness(-24.f))); audioContent->set(DialogueContent::AUDIO_DESCRIPTION); auto document = Document::create(); diff --git a/tests/xml_writer_audio_programme_tests.cpp b/tests/xml_writer_audio_programme_tests.cpp index e9cffe23..d38edf0a 100644 --- a/tests/xml_writer_audio_programme_tests.cpp +++ b/tests/xml_writer_audio_programme_tests.cpp @@ -15,11 +15,6 @@ TEST_CASE("write_audio_object_interaction") { audioProgramme->set(AudioProgrammeLanguage("de")); audioProgramme->set(Start(std::chrono::seconds(0))); audioProgramme->set(End(std::chrono::seconds(10))); - audioProgramme->add(LoudnessMetadata( - LoudnessMethod("ITU-R BS.1770"), LoudnessRecType("EBU R128"), - LoudnessCorrectionType("File-based"), IntegratedLoudness(-23.f), - LoudnessRange(10.f), MaxTruePeak(-2.3f), MaxMomentary(-19.f), - MaxShortTerm(-21.2), DialogueLoudness(-24.f))); audioProgramme->set(MaxDuckingDepth(-30)); auto document = Document::create(); From d27b93c715d362254383fbfcd1f2bdd10de5bcfb Mon Sep 17 00:00:00 2001 From: Richard Bailey Date: Tue, 29 Jun 2021 10:23:11 +0100 Subject: [PATCH 3/9] Use ParameterCompare for VectorParameter element uniqueness --- include/adm/detail/auto_base.hpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/include/adm/detail/auto_base.hpp b/include/adm/detail/auto_base.hpp index b751a00a..cf555aad 100644 --- a/include/adm/detail/auto_base.hpp +++ b/include/adm/detail/auto_base.hpp @@ -190,6 +190,11 @@ namespace adm { boost::optional value_; }; + template + struct ParameterCompare { + static bool compare(T const& lhs, T const& rhs) { return lhs == rhs; } + }; + /// base class for storage of multiple elements in a std::vector. /// T should be a std::vector, as this is what the tag is /// associated with. @@ -210,7 +215,7 @@ namespace adm { ADM_BASE_EXPORT void unset(Tag) { value_.clear(); } ADM_BASE_EXPORT bool add(Value item) { - auto it = std::find(value_.begin(), value_.end(), item); + auto it = find_item(item); if (it == value_.end()) { value_.push_back(item); return true; @@ -220,13 +225,18 @@ namespace adm { } ADM_BASE_EXPORT void remove(Value item) { - auto it = std::find(value_.begin(), value_.end(), item); + auto it = find_item(item); if (it != value_.end()) value_.erase(it); } private: T value_; + ADM_BASE_EXPORT typename T::iterator find_item(Value const& item) { + return std::find_if( + value_.begin(), value_.end(), [&item, this](Value const& val) { + return ParameterCompare::compare(item, val); + }); + } }; - } // namespace detail } // namespace adm From 98c86eb0132dc373586238c4285b5f9fa733e2fd Mon Sep 17 00:00:00 2001 From: Richard Bailey Date: Tue, 29 Jun 2021 10:33:44 +0100 Subject: [PATCH 4/9] Return false from VectorParameter::isDefault to match OptionalParameter --- include/adm/detail/auto_base.hpp | 2 +- tests/auto_base_tests.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/adm/detail/auto_base.hpp b/include/adm/detail/auto_base.hpp index cf555aad..b616c5af 100644 --- a/include/adm/detail/auto_base.hpp +++ b/include/adm/detail/auto_base.hpp @@ -211,7 +211,7 @@ namespace adm { ADM_BASE_EXPORT T get(Tag) const { return value_; } ADM_BASE_EXPORT void set(T value) { value_ = value; } ADM_BASE_EXPORT bool has(Tag) const { return value_.size() > 0; } - ADM_BASE_EXPORT bool isDefault(Tag) const { return value_.size() == 0; } + ADM_BASE_EXPORT bool isDefault(Tag) const { return false; } ADM_BASE_EXPORT void unset(Tag) { value_.clear(); } ADM_BASE_EXPORT bool add(Value item) { diff --git a/tests/auto_base_tests.cpp b/tests/auto_base_tests.cpp index cda486f2..3978d263 100644 --- a/tests/auto_base_tests.cpp +++ b/tests/auto_base_tests.cpp @@ -145,7 +145,7 @@ TEST_CASE("vector") { TestElement e; REQUIRE(!e.has()); REQUIRE(e.get() == Vectors{}); - REQUIRE(e.isDefault()); + REQUIRE(!e.isDefault()); e.set(Vectors{{Vector{5}}}); REQUIRE(e.has()); @@ -165,5 +165,5 @@ TEST_CASE("vector") { e.unset(); REQUIRE(!e.has()); REQUIRE(e.get() == Vectors{}); - REQUIRE(e.isDefault()); + REQUIRE(!e.isDefault()); } From 6bde4a1b81220526bfc514fdc36cd0b96097bd7f Mon Sep 17 00:00:00 2001 From: Richard Bailey Date: Tue, 29 Jun 2021 10:37:23 +0100 Subject: [PATCH 5/9] Provide ParameterCompare instead of == overload --- include/adm/detail/optional_comparison.hpp | 40 ++++++++++++++++++++++ include/adm/elements/loudness_metadata.hpp | 21 +++++++----- src/elements/loudness_metadata.cpp | 7 ---- 3 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 include/adm/detail/optional_comparison.hpp diff --git a/include/adm/detail/optional_comparison.hpp b/include/adm/detail/optional_comparison.hpp new file mode 100644 index 00000000..511c71fa --- /dev/null +++ b/include/adm/detail/optional_comparison.hpp @@ -0,0 +1,40 @@ +#pragma once +namespace adm { + namespace detail { + namespace comparison { + template + bool compareOptionalParameter(ElementT const& lhs, ElementT const& rhs) { + // if one has the parameter and the other doesn't they're not equal + if (lhs.template has() != rhs.template has()) { + return false; + } + // either both have it or neither does. If neither, they're equal. + if (!lhs.template has()) { + return true; + } + // otherwise both have the parameter, so compare. + return lhs.template get() == rhs.template get(); + } + + template + struct OptionalComparator { + template + static bool compareAll(ElementT const& lhs, ElementT const& rhs) { + return (compareOptionalParameter(lhs, rhs) && + OptionalComparator::compareAll(lhs, rhs)); + } + }; + template + struct OptionalComparator { + template + static bool compareAll(ElementT const& lhs, ElementT const& rhs) { + return compareOptionalParameter(lhs, rhs); + } + }; + } // namespace comparison + template + bool compareOptionals(ElementT const& lhs, ElementT const& rhs) { + return comparison::OptionalComparator::compareAll(lhs, rhs); + } + } // namespace detail +} // namespace adm diff --git a/include/adm/elements/loudness_metadata.hpp b/include/adm/elements/loudness_metadata.hpp index ffcabf0e..50ec2bff 100644 --- a/include/adm/elements/loudness_metadata.hpp +++ b/include/adm/elements/loudness_metadata.hpp @@ -2,6 +2,7 @@ #include "adm/detail/named_option_helper.hpp" #include "adm/detail/named_type.hpp" #include "adm/detail/auto_base.hpp" +#include "adm/detail/optional_comparison.hpp" #include "adm/export.h" #include #include @@ -71,7 +72,7 @@ namespace adm { * in random order after the mandatory ADM parameters. */ template - LoudnessMetadata(Parameters... optionalNamedArgs); + explicit LoudnessMetadata(Parameters... optionalNamedArgs); /** * @brief ADM parameter getter template @@ -130,13 +131,6 @@ namespace adm { template void unset(); - /** - * @brief Operator overload - * - * Compares each loudnessMetadata parameter - */ - ADM_EXPORT bool operator==(const LoudnessMetadata& other) const; - /** * @brief Print overview to ostream */ @@ -229,4 +223,15 @@ namespace adm { typedef typename detail::ParameterTraits::tag Tag; return unset(Tag()); } + + namespace detail { + template <> + struct ParameterCompare { + static bool compare(LoudnessMetadata const& lhs, + LoudnessMetadata const& rhs) { + return compareOptionals(lhs, rhs); + } + }; + } // namespace detail } // namespace adm diff --git a/src/elements/loudness_metadata.cpp b/src/elements/loudness_metadata.cpp index 30f414fe..c441b939 100644 --- a/src/elements/loudness_metadata.cpp +++ b/src/elements/loudness_metadata.cpp @@ -141,13 +141,6 @@ namespace adm { dialogueLoudness_ = boost::none; } - // ---- Operators ---- // - bool LoudnessMetadata::operator==(const LoudnessMetadata& other) const { - return get() == other.get() && - get() == other.get() && - get() == other.get(); - } - void LoudnessMetadata::print(std::ostream& os) const { os << "("; if (has()) { From 2c8f01cf983ee61473c6916719408b7837c21631 Mon Sep 17 00:00:00 2001 From: Richard Bailey Date: Tue, 29 Jun 2021 10:39:54 +0100 Subject: [PATCH 6/9] Provide missing AudioContent::unset definition. --- src/elements/audio_content.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/elements/audio_content.cpp b/src/elements/audio_content.cpp index 5c2558e8..2b453177 100644 --- a/src/elements/audio_content.cpp +++ b/src/elements/audio_content.cpp @@ -144,6 +144,11 @@ namespace adm { dialogueContentKind_ = boost::none; mixedContentKind_ = boost::none; } + void AudioContent::unset(detail::ParameterTraits::tag) { + unset(); + unset(); + unset(); + } void AudioContent::unset( detail::ParameterTraits::tag) { unset(); From 3cc4032adfe5e6c7761edef055003f287c5bb1c9 Mon Sep 17 00:00:00 2001 From: Richard Bailey Date: Tue, 29 Jun 2021 10:41:07 +0100 Subject: [PATCH 7/9] Export operator<< from AudioConent for shared lib use outside library --- include/adm/elements/audio_content.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/adm/elements/audio_content.hpp b/include/adm/elements/audio_content.hpp index 1528a1ec..99d8ff7c 100644 --- a/include/adm/elements/audio_content.hpp +++ b/include/adm/elements/audio_content.hpp @@ -268,8 +268,8 @@ namespace adm { boost::optional mixedContentKind_; }; - std::ostream& operator<<(std::ostream& stream, - const LoudnessMetadatas& loudnessMetaDatas); + ADM_EXPORT std::ostream& operator<<( + std::ostream& stream, const LoudnessMetadatas& loudnessMetaDatas); // ---- Implementation ---- // From 189679173aca53faa8f9680d96ab45b04902adcc Mon Sep 17 00:00:00 2001 From: Richard Bailey Date: Tue, 29 Jun 2021 10:49:02 +0100 Subject: [PATCH 8/9] Update test helpers to add generic vectorparameter checks and comparisor ops --- tests/helper/parameter_checks.hpp | 35 +++++++++++++++++ tests/helper/parameter_comparators.hpp | 54 +++++++------------------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/tests/helper/parameter_checks.hpp b/tests/helper/parameter_checks.hpp index 7c9b4ce2..25c0b5e5 100644 --- a/tests/helper/parameter_checks.hpp +++ b/tests/helper/parameter_checks.hpp @@ -73,6 +73,34 @@ namespace adm_test { } } + template + void check_vector_impl(ElementT& element, VectorT parameter_vector) { + SECTION("test should be supplied with non-empty vector") { + using ValueT = typename VectorT::value_type; + // if it's an optional vector, set to empty vector + if (!element.template has()) { + element.set(VectorT{}); + } + } + SECTION("Check add & remove") { + auto items = element.template get(); + REQUIRE(items.empty()); + for (auto const& i : parameter_vector) { + element.add(i); + } + items = element.template get(); + REQUIRE(items.size() == parameter_vector.size()); + for (auto i = 0u; i != items.size(); ++i) { + REQUIRE(items[i] == parameter_vector[i]); + } + for (auto i = 0u; i != items.size(); ++i) { + element.remove(items[i]); + } + items = element.template get(); + REQUIRE(items.empty()); + } + } + template class HasDefaultOf { public: @@ -127,6 +155,13 @@ namespace adm_test { modifiedVal.get()); } + template + void check_vector_param(std::shared_ptr element, + detail::CanBeSetTo modifiedVal) { + detail::check_vector_impl(detail::get_from_shared(element), + modifiedVal.get()); + } + template detail::HasDefaultOf hasDefaultOf(T value) { return detail::HasDefaultOf(value); diff --git a/tests/helper/parameter_comparators.hpp b/tests/helper/parameter_comparators.hpp index 212f812c..1b7d8553 100644 --- a/tests/helper/parameter_comparators.hpp +++ b/tests/helper/parameter_comparators.hpp @@ -1,59 +1,33 @@ #pragma once - -namespace detail { - template - bool compareOptionalParameter(ElementT const& lhs, ElementT const& rhs) { - // if one has the parameter and the other doesn't they're not equal - if (lhs.template has() != rhs.template has()) { - return false; - } - // either both have it or neither does. If neither, they're equal. - if (!lhs.template has()) { - return true; - } - // otherwise both have the parameter, so compare. - return lhs.template get() == rhs.template get(); - } - - template - struct Comparator { - template - static bool compareAll(ElementT const& lhs, ElementT const& rhs) { - return (compareOptionalParameter(lhs, rhs) && - Comparator::compareAll(lhs, rhs)); - } - }; - template - struct Comparator { - template - static bool compareAll(ElementT const& lhs, ElementT const& rhs) { - return compareOptionalParameter(lhs, rhs); - } - }; - template - bool compareOptionals(ElementT const& lhs, ElementT const& rhs) { - return Comparator::compareAll(lhs, rhs); - } -} // namespace detail +#include +#include +#include namespace adm { bool operator==(ChannelLock const& lhs, ChannelLock const& rhs) { - using ::detail::compareOptionals; + using detail::compareOptionals; return compareOptionals(lhs, rhs); } bool operator==(ObjectDivergence const& lhs, ObjectDivergence const& rhs) { - using ::detail::compareOptionals; + using detail::compareOptionals; return compareOptionals(lhs, rhs); } bool operator==(JumpPosition const& lhs, JumpPosition const& rhs) { - using ::detail::compareOptionals; + using detail::compareOptionals; return compareOptionals(lhs, rhs); } bool operator==(HeadphoneVirtualise const& lhs, HeadphoneVirtualise const& rhs) { - using ::detail::compareOptionals; + using detail::compareOptionals; return compareOptionals(lhs, rhs); } + bool operator==(LoudnessMetadata const& lhs, LoudnessMetadata const& rhs) { + using detail::compareOptionals; + return compareOptionals(lhs, rhs); + } bool operator==(Gain const& lhs, Gain const& rhs) { if (lhs.isDb() != rhs.isDb()) { return false; From daeef33348e14af8985f22871fa54ed6528b3b2a Mon Sep 17 00:00:00 2001 From: Richard Bailey Date: Tue, 29 Jun 2021 10:50:26 +0100 Subject: [PATCH 9/9] Update AudioContent and AudioProgramme to use generic parameter checks --- tests/audio_content_tests.cpp | 59 ++++++++++++++- tests/audio_programme_tests.cpp | 129 +++++++++++++++----------------- 2 files changed, 117 insertions(+), 71 deletions(-) diff --git a/tests/audio_content_tests.cpp b/tests/audio_content_tests.cpp index fb2dff5a..f6c09cf5 100644 --- a/tests/audio_content_tests.cpp +++ b/tests/audio_content_tests.cpp @@ -2,9 +2,64 @@ #include #include "adm/elements/audio_content.hpp" #include "adm/elements/audio_object.hpp" +#include "helper/parameter_checks.hpp" +#include "adm/utilities/element_io.hpp" + +using namespace adm; +TEST_CASE("audio_content parameters") { + using namespace adm_test; + auto contentName = AudioContentName("MyContent"); + auto audioContent = AudioContent::create(AudioContentName(contentName)); + SECTION("AudioContentName") { + check_required_param( + audioContent, hasDefaultOf(contentName), + canBeSetTo(AudioContentName("SomethingElse"))); + } + SECTION("AudioContentId") { + check_required_param( + audioContent, hasDefaultOf(AudioContentId{}), + canBeSetTo(AudioContentId(AudioContentIdValue(2)))); + } + SECTION("AudioContentLanguage") { + check_optional_param( + audioContent, canBeSetTo(AudioContentLanguage("de"))); + } + SECTION("DialogId") { + check_optional_param(audioContent, + canBeSetTo(Dialogue::NON_DIALOGUE)); + } + SECTION("ContentKind") { + check_optional_param( + audioContent, canBeSetTo(ContentKind{MixedContentKind{}})); + } + SECTION("ContentKind variants") { + SECTION("Dialog") { + check_optional_param( + audioContent, canBeSetTo(DialogueContent::COMMENTARY)); + } + SECTION("NonDialog") { + check_optional_param( + audioContent, canBeSetTo(NonDialogueContent::EFFECT)); + } + SECTION("Mixed") { + check_optional_param( + audioContent, canBeSetTo(MixedContent::HEARING_IMPAIRED)); + } + } + SECTION("LoudnessMetadatas") { + LoudnessMetadatas loudness = LoudnessMetadatas{ + LoudnessMetadata{}, LoudnessMetadata{LoudnessMethod{"Guess"}}}; + SECTION("check get/set") { + check_optional_param(audioContent, + canBeSetTo(loudness)); + } + SECTION("add/remove") { + check_vector_param(audioContent, canBeSetTo(loudness)); + } + } +} TEST_CASE("audio_content") { - using namespace adm; { auto audioContent = AudioContent::create(AudioContentName("MyContent")); audioContent->set(AudioContentId(AudioContentIdValue(1))); @@ -63,8 +118,6 @@ TEST_CASE("audio_content") { } TEST_CASE("audio_content_dialogue_interdependencies") { - using namespace adm; - auto audioContent = AudioContent::create(AudioContentName("MyContent")); audioContent->set(DialogueContent::VOICEOVER); diff --git a/tests/audio_programme_tests.cpp b/tests/audio_programme_tests.cpp index 00588ad9..e991f57a 100644 --- a/tests/audio_programme_tests.cpp +++ b/tests/audio_programme_tests.cpp @@ -1,79 +1,72 @@ #define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER #include #include "adm/elements/audio_programme.hpp" +#include "helper/parameter_checks.hpp" +#include "helper/ostream_operators.hpp" -TEST_CASE("audio_programme") { - using namespace adm; - // Attributes / Elements - { - auto audioProgramme = - AudioProgramme::create(AudioProgrammeName("MyProgramme")); - audioProgramme->set(AudioProgrammeId(AudioProgrammeIdValue(1))); - audioProgramme->set(AudioProgrammeLanguage("de")); - audioProgramme->set(Start(std::chrono::seconds(0))); - audioProgramme->set(End(std::chrono::seconds(10))); - audioProgramme->add(LoudnessMetadata()); - audioProgramme->set(MaxDuckingDepth(-30)); - // NOTE: AudioProgrammeReferenceScreen is not yet implemented. - // audioProgramme->set(AudioProgrammeReferenceScreen()); +using namespace adm; +using namespace adm_test; - REQUIRE(audioProgramme->has()); - REQUIRE(audioProgramme->has()); - REQUIRE(audioProgramme->has()); - REQUIRE(audioProgramme->has()); - REQUIRE(audioProgramme->has()); - REQUIRE(audioProgramme->has()); - REQUIRE(audioProgramme->has()); - // NOTE: AudioProgrammeReferenceScreen is not yet implemented. - // REQUIRE(audioProgramme->has()); - - REQUIRE( - audioProgramme->get().get() == - 1u); - REQUIRE(audioProgramme->get() == "MyProgramme"); - REQUIRE(audioProgramme->get() == "de"); - REQUIRE(audioProgramme->get().get() == std::chrono::seconds(0)); - REQUIRE(audioProgramme->get().get() == std::chrono::seconds(10)); - REQUIRE(audioProgramme->get() == -30); - // NOTE: AudioProgrammeReferenceScreen is not yet implemented. - // REQUIRE(audioProgramme->get() == ???); - - audioProgramme->unset(); - audioProgramme->unset(); - audioProgramme->unset(); - audioProgramme->unset(); - audioProgramme->unset(); - // NOTE: AudioProgrammeReferenceScreen is not yet implemented. - // audioProgramme->unset(); - - REQUIRE(!audioProgramme->has()); - REQUIRE(audioProgramme->has()); - REQUIRE(!audioProgramme->has()); - REQUIRE(!audioProgramme->has()); - REQUIRE(!audioProgramme->has()); - // NOTE: AudioProgrammeReferenceScreen is not yet implemented. - // REQUIRE(!audioProgramme->has()); +TEST_CASE("audio_programme parameters") { + using std::chrono::seconds; + auto audioProgramme = + AudioProgramme::create(AudioProgrammeName("MyProgramme")); + SECTION("AudioProgrammeName") { + check_required_param(audioProgramme, + hasDefaultOf("MyProgramme"), + canBeSetTo("SomethingElse")); + } + SECTION("AudioProgrammeId") { + check_required_param( + audioProgramme, hasDefaultOf(AudioProgrammeIdValue{}), + canBeSetTo(AudioProgrammeIdValue(2u))); + } + SECTION("AudioProgrammeLanguage") { + check_optional_param(audioProgramme, + canBeSetTo("fr")); + } + SECTION("Start") { + check_defaulted_param(audioProgramme, hasDefaultOf(seconds{0}), + canBeSetTo(seconds{1})); } - // References - { - auto audioProgramme = - AudioProgramme::create(AudioProgrammeName("MyProgramme")); + SECTION("End") { + check_optional_param(audioProgramme, canBeSetTo(seconds(10))); + } + SECTION("LoudnessMetadatas") { + LoudnessMetadatas loudness = LoudnessMetadatas{ + LoudnessMetadata{}, LoudnessMetadata{LoudnessMethod{"Guess"}}}; + SECTION("check get/set") { + check_optional_param(audioProgramme, + canBeSetTo(loudness)); + } + SECTION("add/remove") { + check_vector_param(audioProgramme, + canBeSetTo(loudness)); + } + } + SECTION("MaxDuckingDepth") { + check_optional_param(audioProgramme, canBeSetTo(-30.0)); + } +} - auto referencedAudioContent = - AudioContent::create(AudioContentName("MyContent")); +TEST_CASE("audio_programme references") { + auto audioProgramme = + AudioProgramme::create(AudioProgrammeName("MyProgramme")); - // add references - audioProgramme->addReference(referencedAudioContent); - audioProgramme->addReference(referencedAudioContent); - REQUIRE(audioProgramme->getReferences().size() == 1); + auto referencedAudioContent = + AudioContent::create(AudioContentName("MyContent")); - // remove references - audioProgramme->removeReference(referencedAudioContent); - REQUIRE(audioProgramme->getReferences().size() == 0); + // add references + audioProgramme->addReference(referencedAudioContent); + audioProgramme->addReference(referencedAudioContent); + REQUIRE(audioProgramme->getReferences().size() == 1); - // clear references - audioProgramme->addReference(referencedAudioContent); - audioProgramme->clearReferences(); - REQUIRE(audioProgramme->getReferences().size() == 0); - } + // remove references + audioProgramme->removeReference(referencedAudioContent); + REQUIRE(audioProgramme->getReferences().size() == 0); + + // clear references + audioProgramme->addReference(referencedAudioContent); + audioProgramme->clearReferences(); + REQUIRE(audioProgramme->getReferences().size() == 0); }