Skip to content

Commit 32cc745

Browse files
committed
implement profileList
1 parent 795cda7 commit 32cc745

14 files changed

+290
-1
lines changed

include/adm/document.hpp

+19-1
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,25 @@
44
#include <memory>
55
#include <vector>
66
#include "adm/elements.hpp"
7+
#include "adm/detail/auto_base.hpp"
78
#include "adm/detail/id_assigner.hpp"
89
#include "adm/export.h"
910

1011
namespace adm {
1112

13+
namespace detail {
14+
using DocumentBase = HasParameters<OptionalParameter<ProfileList>>;
15+
}
16+
1217
/**
1318
* @ingroup main
1419
* @brief Class representation of a whole ADM document
1520
* @headerfile document.hpp <adm/document.hpp>
1621
*
1722
*/
18-
class Document : public std::enable_shared_from_this<Document> {
23+
class Document : public std::enable_shared_from_this<Document>,
24+
private detail::DocumentBase,
25+
public detail::AddWrapperMethods<Document> {
1926
public:
2027
/**
2128
* @brief Static helper function to create an Document
@@ -202,6 +209,12 @@ namespace adm {
202209
const AudioTrackUidId &trackUidId) const;
203210
///@}
204211

212+
using detail::DocumentBase::set;
213+
using detail::AddWrapperMethods<Document>::get;
214+
using detail::AddWrapperMethods<Document>::has;
215+
using detail::AddWrapperMethods<Document>::isDefault;
216+
using detail::AddWrapperMethods<Document>::unset;
217+
205218
private:
206219
ADM_EXPORT Document();
207220
ADM_EXPORT Document(const Document &) = default;
@@ -251,6 +264,11 @@ namespace adm {
251264
template <typename Element>
252265
bool checkParent(const std::shared_ptr<Element> &element, const char *type);
253266

267+
using detail::DocumentBase::get;
268+
using detail::DocumentBase::has;
269+
270+
friend class detail::AddWrapperMethods<Document>;
271+
254272
std::vector<std::shared_ptr<AudioProgramme>> audioProgrammes_;
255273
std::vector<std::shared_ptr<AudioContent>> audioContents_;
256274
std::vector<std::shared_ptr<AudioObject>> audioObjects_;

include/adm/elements.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "adm/elements/audio_track_format.hpp"
2727
#include "adm/elements/audio_stream_format.hpp"
2828
#include "adm/elements/audio_track_uid.hpp"
29+
#include "adm/elements/profile_list.hpp"
2930

3031
#include "adm/elements/audio_block_format_direct_speakers.hpp"
3132
#include "adm/elements/audio_block_format_matrix.hpp"

include/adm/elements/profile_list.hpp

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#pragma once
2+
#include <vector>
3+
#include "adm/detail/auto_base.hpp"
4+
#include "adm/detail/named_option_helper.hpp"
5+
#include "adm/detail/optional_comparison.hpp"
6+
7+
namespace adm {
8+
struct ProfileValueTag {};
9+
using ProfileValue = detail::NamedType<std::string, ProfileValueTag>;
10+
11+
struct ProfileNameTag {};
12+
using ProfileName = detail::NamedType<std::string, ProfileNameTag>;
13+
14+
struct ProfileVersionTag {};
15+
using ProfileVersion = detail::NamedType<std::string, ProfileVersionTag>;
16+
17+
struct ProfileLevelTag {};
18+
using ProfileLevel = detail::NamedType<std::string, ProfileLevelTag>;
19+
20+
struct ProfileTag {};
21+
22+
namespace detail {
23+
extern template class ADM_EXPORT_TEMPLATE_METHODS
24+
RequiredParameter<ProfileValue>;
25+
extern template class ADM_EXPORT_TEMPLATE_METHODS
26+
RequiredParameter<ProfileName>;
27+
extern template class ADM_EXPORT_TEMPLATE_METHODS
28+
RequiredParameter<ProfileVersion>;
29+
extern template class ADM_EXPORT_TEMPLATE_METHODS
30+
RequiredParameter<ProfileLevel>;
31+
32+
using ProfileBase = HasParameters<
33+
RequiredParameter<ProfileValue>, RequiredParameter<ProfileName>,
34+
RequiredParameter<ProfileVersion>, RequiredParameter<ProfileLevel>>;
35+
} // namespace detail
36+
37+
class Profile : private detail::ProfileBase,
38+
public detail::AddWrapperMethods<Profile> {
39+
public:
40+
using tag = ProfileTag;
41+
42+
template <typename... Parameters>
43+
explicit Profile(Parameters... namedArgs) {
44+
detail::setNamedOptionHelper(this, std::move(namedArgs)...);
45+
static_assert(detail::optionInList<ProfileValue, Parameters...>(),
46+
"ProfileValue must be specified");
47+
static_assert(detail::optionInList<ProfileName, Parameters...>(),
48+
"ProfileName must be specified");
49+
static_assert(detail::optionInList<ProfileVersion, Parameters...>(),
50+
"ProfileVersion must be specified");
51+
static_assert(detail::optionInList<ProfileLevel, Parameters...>(),
52+
"ProfileLevel must be specified");
53+
}
54+
55+
using detail::ProfileBase::set;
56+
using detail::AddWrapperMethods<Profile>::get;
57+
using detail::AddWrapperMethods<Profile>::has;
58+
using detail::AddWrapperMethods<Profile>::isDefault;
59+
using detail::AddWrapperMethods<Profile>::unset;
60+
61+
private:
62+
using detail::ProfileBase::get;
63+
using detail::ProfileBase::has;
64+
65+
friend class detail::AddWrapperMethods<Profile>;
66+
};
67+
68+
inline bool operator==(const Profile &a, const Profile &b) {
69+
return detail::optionalsEqual<ProfileValue, ProfileName, ProfileVersion,
70+
ProfileLevel>(a, b);
71+
}
72+
73+
inline bool operator!=(const Profile &a, const Profile &b) {
74+
return !(a == b);
75+
}
76+
77+
struct ProfilesTag {};
78+
79+
using Profiles = std::vector<Profile>;
80+
ADD_TRAIT(Profiles, ProfilesTag);
81+
82+
namespace detail {
83+
extern template class ADM_EXPORT_TEMPLATE_METHODS VectorParameter<Profiles>;
84+
85+
using ProfileListBase = HasParameters<VectorParameter<Profiles>>;
86+
} // namespace detail
87+
88+
struct ProfileceListTag {};
89+
90+
class ProfileList : private detail::ProfileListBase,
91+
public detail::AddWrapperMethods<ProfileList> {
92+
public:
93+
using tag = ProfileceListTag;
94+
95+
template <typename... Parameters>
96+
explicit ProfileList(Parameters... namedArgs) {
97+
detail::setNamedOptionHelper(this, std::move(namedArgs)...);
98+
}
99+
100+
using detail::ProfileListBase::set;
101+
using detail::AddWrapperMethods<ProfileList>::get;
102+
using detail::AddWrapperMethods<ProfileList>::has;
103+
using detail::AddWrapperMethods<ProfileList>::isDefault;
104+
using detail::AddWrapperMethods<ProfileList>::unset;
105+
using detail::ProfileListBase::add;
106+
using detail::ProfileListBase::remove;
107+
108+
private:
109+
using detail::ProfileListBase::get;
110+
using detail::ProfileListBase::has;
111+
using detail::ProfileListBase::isDefault;
112+
using detail::ProfileListBase::unset;
113+
114+
friend class detail::AddWrapperMethods<ProfileList>;
115+
};
116+
} // namespace adm

include/adm/private/rapidxml_formatter.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ namespace adm {
4747
const std::shared_ptr<const AudioTrackFormat> trackFormat);
4848
void formatAudioTrackUid(
4949
XmlNode &node, const std::shared_ptr<const AudioTrackUid> trackUid);
50+
void formatProfileList(XmlNode &node, const ProfileList &profileList);
51+
void formatProfile(XmlNode &node, const Profile &profile);
5052

5153
void formatBlockFormatDirectSpeakers(
5254
XmlNode &node, const AudioBlockFormatDirectSpeakers &audioBlock);

include/adm/private/xml_parser.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ namespace adm {
6464
HeadphoneVirtualise parseHeadphoneVirtualise(NodePtr node);
6565
AudioBlockFormatHoa parseAudioBlockFormatHoa(NodePtr node);
6666
AudioBlockFormatBinaural parseAudioBlockFormatBinaural(NodePtr node);
67+
Profile parseProfile(NodePtr node);
6768

6869
NodePtr findAudioFormatExtendedNodeEbuCore(NodePtr root);
6970
NodePtr findAudioFormatExtendedNodeFullRecursive(NodePtr root);
@@ -94,6 +95,7 @@ namespace adm {
9495
std::shared_ptr<AudioPackFormat> parseAudioPackFormat(NodePtr node);
9596
std::shared_ptr<AudioTrackUid> parseAudioTrackUid(NodePtr node);
9697
std::shared_ptr<AudioChannelFormat> parseAudioChannelFormat(NodePtr node);
98+
ProfileList parseProfileList(NodePtr node);
9799

98100
rapidxml::file<> xmlFile_;
99101
ParserOptions options_;

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ add_library(adm
4848
elements/position.cpp
4949
elements/position_offset.cpp
5050
elements/position_interaction_range.cpp
51+
elements/profile_list.cpp
5152
elements/screen_edge_lock.cpp
5253
elements/speaker_position.cpp
5354
elements/type_descriptor.cpp

src/elements/profile_list.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include "adm/elements/profile_list.hpp"
2+
3+
namespace adm {
4+
namespace detail {
5+
template class RequiredParameter<ProfileValue>;
6+
template class RequiredParameter<ProfileName>;
7+
template class RequiredParameter<ProfileVersion>;
8+
template class RequiredParameter<ProfileLevel>;
9+
template class VectorParameter<Profiles>;
10+
} // namespace detail
11+
} // namespace adm

src/private/rapidxml_formatter.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -672,5 +672,16 @@ namespace adm {
672672
trackUid, "audioPackFormatIDRef");
673673
}
674674

675+
void formatProfileList(XmlNode &node, const ProfileList &profileList) {
676+
node.addVectorElements<Profiles>(&profileList, "profile", &formatProfile);
677+
}
678+
679+
void formatProfile(XmlNode &node, const Profile &profile) {
680+
node.setValue(profile.get<ProfileValue>());
681+
node.addElement<ProfileName>(&profile, "profileName");
682+
node.addElement<ProfileVersion>(&profile, "profileVersion");
683+
node.addElement<ProfileLevel>(&profile, "profileLevel");
684+
}
685+
675686
} // namespace xml
676687
} // namespace adm

src/private/xml_parser.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ namespace adm {
7676
add(parseAudioStreamFormat(node));
7777
} else if (nodeName == "audioTrackFormat") {
7878
add(parseAudioTrackFormat(node));
79+
} else if (nodeName == "profileList") {
80+
if (document_->has<ProfileList>())
81+
throw error::XmlParsingError(
82+
"found more than one profileList element");
83+
document_->set(parseProfileList(node));
7984
}
8085
}
8186
resolveReferences(programmeContentRefs_);
@@ -445,6 +450,23 @@ namespace adm {
445450
return audioTrackUid;
446451
}
447452

453+
ProfileList XmlParser::parseProfileList(NodePtr node) {
454+
ProfileList profileList;
455+
456+
addOptionalElements<Profile>(node, "profile", profileList, &parseProfile);
457+
458+
return profileList;
459+
}
460+
461+
Profile parseProfile(NodePtr node) {
462+
auto value = parseValue<ProfileValue>(node);
463+
auto name = parseAttribute<ProfileName>(node, "profileName");
464+
auto version = parseAttribute<ProfileVersion>(node, "profileVersion");
465+
auto level = parseAttribute<ProfileLevel>(node, "profileLevel");
466+
467+
return Profile{value, name, version, level};
468+
}
469+
448470
AudioBlockFormatDirectSpeakers parseAudioBlockFormatDirectSpeakers(
449471
NodePtr node) {
450472
AudioBlockFormatDirectSpeakers audioBlockFormat;

src/private/xml_writer.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace adm {
4646
root.addBaseElements<AudioStreamFormat, AudioStreamFormatId>(document, "audioStreamFormat", &formatAudioStreamFormat);
4747
root.addBaseElements<AudioTrackFormat, AudioTrackFormatId>(document, "audioTrackFormat", &formatAudioTrackFormat);
4848
root.addBaseElements<AudioTrackUid, AudioTrackUidId>(document, "audioTrackUID", &formatAudioTrackUid);
49+
root.addOptionalElement<ProfileList>(document, "profileList", &formatProfileList);
4950
// clang-format on
5051
return stream << xmlDocument;
5152
}

tests/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ add_adm_test("object_divergence_tests")
6464
add_adm_test("position_interaction_range_tests")
6565
add_adm_test("position_tests")
6666
add_adm_test("position_offset_tests")
67+
add_adm_test("profile_list_tests")
6768
add_adm_test("route_tracer_tests")
6869
add_adm_test("screen_edge_lock_tests")
6970
add_adm_test("speaker_position_tests")

tests/profile_list_tests.cpp

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include <catch2/catch.hpp>
2+
#include "adm/elements/profile_list.hpp"
3+
#include "helper/parameter_checks.hpp"
4+
#include "adm/document.hpp"
5+
#include "adm/parse.hpp"
6+
#include "adm/write.hpp"
7+
#include "helper/file_comparator.hpp"
8+
9+
using namespace adm;
10+
using namespace adm_test;
11+
12+
TEST_CASE("Profile parameters") {
13+
Profile profile{
14+
ProfileValue{"value"},
15+
ProfileName{"name"},
16+
ProfileVersion{"version"},
17+
ProfileLevel{"level"},
18+
};
19+
20+
check_required_param<ProfileValue>(profile,
21+
hasDefaultOf(ProfileValue{"value"}),
22+
canBeSetTo(ProfileValue{"value2"}));
23+
check_required_param<ProfileName>(profile, hasDefaultOf(ProfileName{"name"}),
24+
canBeSetTo(ProfileName{"name2"}));
25+
check_required_param<ProfileVersion>(profile,
26+
hasDefaultOf(ProfileVersion{"version"}),
27+
canBeSetTo(ProfileVersion{"version2"}));
28+
check_required_param<ProfileLevel>(profile,
29+
hasDefaultOf(ProfileLevel{"level"}),
30+
canBeSetTo(ProfileLevel{"level2"}));
31+
}
32+
33+
TEST_CASE("ProfileList parameters") {
34+
ProfileList profileList;
35+
36+
Profile profile{
37+
ProfileValue{"value"},
38+
ProfileName{"name"},
39+
ProfileVersion{"version"},
40+
ProfileLevel{"level"},
41+
};
42+
43+
check_vector_param<Profiles>(profileList, canBeSetTo(Profiles{profile}));
44+
}
45+
46+
TEST_CASE("xml/profileList") {
47+
auto document = parseXml("xml_parser/profile_list.xml");
48+
49+
REQUIRE(document->has<ProfileList>());
50+
auto profileList = document->get<ProfileList>();
51+
auto profiles = profileList.get<Profiles>();
52+
REQUIRE(profiles.size() == 2);
53+
54+
CHECK(profiles.at(0).get<ProfileValue>() == "value1");
55+
CHECK(profiles.at(0).get<ProfileName>() == "name1");
56+
CHECK(profiles.at(0).get<ProfileVersion>() == "version1");
57+
CHECK(profiles.at(0).get<ProfileLevel>() == "level1");
58+
59+
CHECK(profiles.at(1).get<ProfileValue>() == "value2");
60+
CHECK(profiles.at(1).get<ProfileName>() == "name2");
61+
CHECK(profiles.at(1).get<ProfileVersion>() == "version2");
62+
CHECK(profiles.at(1).get<ProfileLevel>() == "level2");
63+
64+
std::stringstream xml;
65+
writeXml(xml, document);
66+
67+
CHECK_THAT(xml.str(), EqualsXmlFile("profile_list"));
68+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<ebuCoreMain xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="urn:ebu:metadata-schema:ebuCore_2014" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schema="EBU_CORE_20140201.xsd" xml:lang="en">
3+
<coreMetadata>
4+
<format>
5+
<audioFormatExtended>
6+
<profileList>
7+
<profile>
8+
<profileName>name1</profileName>
9+
<profileVersion>version1</profileVersion>
10+
<profileLevel>level1</profileLevel>
11+
</profile>
12+
<profile>
13+
<profileName>name2</profileName>
14+
<profileVersion>version2</profileVersion>
15+
<profileLevel>level2</profileLevel>
16+
</profile>
17+
</profileList>
18+
</audioFormatExtended>
19+
</format>
20+
</coreMetadata>
21+
</ebuCoreMain>
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<ebuCoreMain>
3+
<coreMetadata>
4+
<format>
5+
<audioFormatExtended>
6+
<profileList>
7+
<profile profileName="name1" profileVersion="version1" profileLevel="level1">value1</profile>
8+
<profile profileName="name2" profileVersion="version2" profileLevel="level2">value2</profile>
9+
</profileList>
10+
</audioFormatExtended>
11+
</format>
12+
</coreMetadata>
13+
</ebuCoreMain>

0 commit comments

Comments
 (0)