diff --git a/Development/nmos/channels.cpp b/Development/nmos/channels.cpp index 611e22f3d..e9f596099 100644 --- a/Development/nmos/channels.cpp +++ b/Development/nmos/channels.cpp @@ -155,4 +155,52 @@ namespace nmos return channel_order.str(); } + + // See SMPTE ST 2110-30:2017 Section 6.2.2 Channel Order Convention + std::vector parse_fmtp_channel_order(const utility::string_t& channel_order) + { + std::vector channels; + + const auto first = channel_order.data(); + const auto last = first + channel_order.size(); + auto it = first; + + // check prefix + + static const auto prefix = U("SMPTE2110.("); + auto pit = &prefix[0]; + while (it != last && *pit != U('\0') && *it == *pit) ++it, ++pit; + if (*pit != U('\0')) return {}; + + // parse comma-separated channel group symbols + + while (true) + { + const auto git = it; + while (it != last && *it != U(')') && *it != U(',')) ++it; + if (it == last) return {}; + + const channel_group_symbol symbol(utility::string_t(git, it)); + + // hm, does not handle 22.2 Surround ('222'), SDI audio group ('SGRP') or Undefined ('U01' to 'U64') + auto group = std::find_if(details::channel_groups.begin(), details::channel_groups.end(), + [&](const std::pair, channel_group_symbol>& group) + { + return symbol == group.second; + }); + if (details::channel_groups.end() == group) return {}; + channels.insert(channels.end(), group->first.begin(), group->first.end()); + + if (*it == U(')')) break; + ++it; + } + + // check suffix + + if (it == last) return {}; + ++it; + if (it != last) return {}; + + return channels; + } } diff --git a/Development/nmos/channels.h b/Development/nmos/channels.h index 77e12a945..df0522b12 100644 --- a/Development/nmos/channels.h +++ b/Development/nmos/channels.h @@ -113,6 +113,7 @@ namespace nmos // See SMPTE ST 2110-30:2017 Section 6.2.2 Channel Order Convention utility::string_t make_fmtp_channel_order(const std::vector& channels); + std::vector parse_fmtp_channel_order(const utility::string_t& channel_order); } #endif diff --git a/Development/nmos/test/channels_test.cpp b/Development/nmos/test/channels_test.cpp index 1868ee853..ce316e592 100644 --- a/Development/nmos/test/channels_test.cpp +++ b/Development/nmos/test/channels_test.cpp @@ -28,3 +28,40 @@ BST_TEST_CASE(testMakeFmtpChannelOrder) const std::vector example_3{ M1, M1, M1, M1, L, R, C, LFE }; BST_REQUIRE_EQUAL(U("SMPTE2110.(M,M,M,M,ST,U02)"), nmos::make_fmtp_channel_order(example_3)); } + +//////////////////////////////////////////////////////////////////////////////////////////// +BST_TEST_CASE(testParseFmtpChannelOrder) +{ + using namespace nmos::channel_symbols; + + // two simple examples + + const std::vector stereo{ L, R }; + BST_REQUIRE_EQUAL(stereo, nmos::parse_fmtp_channel_order(U("SMPTE2110.(ST)"))); + + const std::vector dual_mono{ M1, M2 }; + BST_REQUIRE_EQUAL(dual_mono, nmos::parse_fmtp_channel_order(U("SMPTE2110.(DM)"))); + + // two examples from ST 2110-30:2017 Section 6.2.2 Channel Order Convention + + const std::vector example_1{ L, R, C, LFE, Ls, Rs, L, R }; + BST_REQUIRE_EQUAL(example_1, nmos::parse_fmtp_channel_order(U("SMPTE2110.(51,ST)"))); + + //const std::vector example_2{ M1, M1, M1, M1, L, R, Undefined(1), Undefined(2) }; + //BST_REQUIRE_EQUAL(example_2, nmos::parse_fmtp_channel_order(U("SMPTE2110.(M,M,M,M,ST,U02)"))); + + // bad examples + + const std::vector empty; + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110.(51,ST)BAD"))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110.(51,ST,)"))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110.(51,,ST)"))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110.(51,BAD)"))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110.(51,ST"))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110.(51,"))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110.(51"))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110.("))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("SMPTE2110."))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U("BAD"))); + BST_REQUIRE_EQUAL(empty, nmos::parse_fmtp_channel_order(U(""))); +}