Skip to content

Commit ed858d1

Browse files
committed
More midi2 work
1 parent 7d6d638 commit ed858d1

16 files changed

+2382
-2
lines changed

modules/yup_audio_basics/midi/ump/yup_UMPUniversalPacket.h

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121

2222
#ifndef DOXYGEN
2323

24+
#include <iomanip>
25+
#include <ios>
26+
#include <istream>
27+
#include <ostream>
28+
2429
namespace yup::ump
2530
{
2631

@@ -127,8 +132,8 @@ enum class StreamProtocol : Protocol
127132

128133
enum class StreamExtensions : Extensions
129134
{
130-
jitter_reduction_transmit = 0x1,
131-
jitter_reduction_receive = 0x2
135+
jitterReductionTransmit = 0x1,
136+
jitterReductionReceive = 0x2
132137
};
133138

134139
enum class StreamStatus : Status
@@ -370,6 +375,56 @@ struct UniversalPacket
370375
}
371376
};
372377

378+
namespace detail
379+
{
380+
struct IosBaseFlagsRestorer
381+
{
382+
explicit IosBaseFlagsRestorer (std::ios_base& stream)
383+
: strm (stream)
384+
, flags (stream.flags())
385+
{
386+
}
387+
388+
~IosBaseFlagsRestorer() { strm.flags (flags); }
389+
390+
std::ios_base& strm;
391+
std::ios_base::fmtflags flags;
392+
};
393+
} // namespace detail
394+
395+
inline std::ostream& operator<< (std::ostream& out, const UniversalPacket& p)
396+
{
397+
detail::IosBaseFlagsRestorer flagRestorer (out);
398+
399+
for (size_t word = 0; word < p.getSize(); ++word)
400+
{
401+
if (word != 0)
402+
out << ' ';
403+
out << std::hex << std::setfill ('0') << std::setw (8) << p.data[word];
404+
}
405+
406+
return out;
407+
}
408+
409+
inline std::istream& operator>> (std::istream& in, UniversalPacket& p)
410+
{
411+
detail::IosBaseFlagsRestorer flagRestorer (in);
412+
in >> std::hex >> p.data[0];
413+
414+
if (in.good())
415+
{
416+
const auto words = p.getSize();
417+
for (size_t word = 1; word < words; ++word)
418+
{
419+
in >> std::hex >> p.data[word];
420+
if (! in.good())
421+
break;
422+
}
423+
}
424+
425+
return in;
426+
}
427+
373428
} // namespace yup::ump
374429

375430
#endif
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
==============================================================================
3+
4+
This file is part of the YUP library.
5+
Copyright (c) 2025 - [email protected]
6+
7+
YUP is an open source library subject to open-source licensing.
8+
9+
The code included in this file is provided under the terms of the ISC license
10+
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
11+
to use, copy, modify, and/or distribute this software for any purpose with or
12+
without fee is hereby granted provided that the above copyright notice and
13+
this permission notice appear in all copies.
14+
15+
YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
16+
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
17+
DISCLAIMED.
18+
19+
==============================================================================
20+
*/
21+
22+
#include <yup_audio_basics/yup_audio_basics.h>
23+
24+
#include <gtest/gtest.h>
25+
#include <string>
26+
#include <string_view>
27+
28+
using namespace yup;
29+
using namespace yup::ump;
30+
using namespace yup::ump::ci;
31+
32+
TEST (UMPCapabilityInquiryProfileTests, ProfileIdEquality)
33+
{
34+
ProfileId a;
35+
EXPECT_EQ (a.byte1, 0x7e);
36+
EXPECT_EQ (a.byte2, 0x00);
37+
EXPECT_EQ (a.byte3, 0x00);
38+
EXPECT_EQ (a.byte4, 0x00);
39+
EXPECT_EQ (a.byte5, 0x00);
40+
41+
ProfileId b { 0x7e, 0x02, 0x03, 0x04, 0x05 };
42+
ProfileId c { 0x00, 0x21, 0x09, 0x7f, 0x01 };
43+
ProfileId d { b };
44+
45+
EXPECT_TRUE (a == a);
46+
EXPECT_FALSE (a == b);
47+
EXPECT_FALSE (a == c);
48+
EXPECT_FALSE (a == d);
49+
50+
EXPECT_FALSE (b == a);
51+
EXPECT_TRUE (b == b);
52+
EXPECT_FALSE (b == c);
53+
EXPECT_TRUE (b == d);
54+
55+
EXPECT_FALSE (c == a);
56+
EXPECT_FALSE (c == b);
57+
EXPECT_TRUE (c == c);
58+
EXPECT_FALSE (c == d);
59+
60+
EXPECT_FALSE (d == a);
61+
EXPECT_TRUE (d == b);
62+
EXPECT_FALSE (d == c);
63+
EXPECT_TRUE (d == d);
64+
}
65+
66+
TEST (UMPCapabilityInquiryProfileTests, ProfileInquiryViewAndMessage)
67+
{
68+
SysEx7 sx { Manufacturer::universalNonRealtime,
69+
{ 0x7f, 0x0d, Subtype::profileInquiry, 0x02, 0x78, 0x56, 0x34, 0x12, 0x77, 0x55, 0x33, 0x11 } };
70+
71+
EXPECT_TRUE (ProfileInquiryView::validate (sx));
72+
EXPECT_TRUE (isCapabilityInquiryMessage (sx));
73+
74+
auto mut = makeProfileInquiryMessage (0x7665544, 0x24d2b78, 0x08);
75+
EXPECT_TRUE (ProfileInquiryView::validate (mut));
76+
EXPECT_EQ (mut.data.size(), 12u);
77+
}
78+
79+
TEST (UMPCapabilityInquiryProfileTests, ProfileInquiryReplyProfiles)
80+
{
81+
SysEx7 sx { Manufacturer::universalNonRealtime,
82+
{ 0x7f, 0x0d, Subtype::profileInquiryReply, 0x00, 0x78, 0x56, 0x34, 0x12, 0x44, 0x33, 0x22, 0x11, 0x02, 0x00, 0x00, 0x21, 0x09, 42, 7, 0x7e, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x7e, 0x01, 0x02, 0x03, 0x04, 0x00, 0x00 } };
83+
84+
EXPECT_TRUE (ProfileInquiryReplyView::validate (sx));
85+
86+
const auto view = ProfileInquiryReplyView { sx };
87+
const auto enabled = view.getEnabledProfiles();
88+
const auto disabled = view.getDisabledProfiles();
89+
90+
ASSERT_EQ (enabled.size(), 2u);
91+
EXPECT_EQ (enabled[0].byte1, 0x00);
92+
EXPECT_EQ (enabled[0].byte2, 0x21);
93+
EXPECT_EQ (enabled[0].byte3, 0x09);
94+
EXPECT_EQ (enabled[0].byte4, 42);
95+
EXPECT_EQ (enabled[0].byte5, 7);
96+
97+
ASSERT_EQ (disabled.size(), 1u);
98+
EXPECT_EQ (disabled[0].byte1, 0x7e);
99+
EXPECT_EQ (disabled[0].byte2, 0x01);
100+
EXPECT_EQ (disabled[0].byte3, 0x02);
101+
EXPECT_EQ (disabled[0].byte4, 0x03);
102+
EXPECT_EQ (disabled[0].byte5, 0x04);
103+
}
104+
105+
TEST (UMPCapabilityInquiryProfileTests, ProfileInquiryReplyBuilder)
106+
{
107+
const std::vector<ProfileId> enabled { { 0x7e, 0x02, 0x03, 0x04, 0x05 } };
108+
const std::vector<ProfileId> disabled { { 0x00, 0x21, 0x09, 0x7f, 0x01 } };
109+
110+
auto sx = makeProfileInquiryReply (0x7665544, 0x4711, enabled, disabled, 0x08);
111+
EXPECT_TRUE (ProfileInquiryReplyView::validate (sx));
112+
113+
const auto view = ProfileInquiryReplyView { sx };
114+
EXPECT_EQ (view.getNumEnabledProfiles(), 1u);
115+
EXPECT_EQ (view.getNumDisabledProfiles(), 1u);
116+
}
117+
118+
TEST (UMPCapabilityInquiryProcessTests, ProcessInquiryCapabilities)
119+
{
120+
auto inquiry = makeProcessInquiryCapabilitiesInquiry (0x7665544, 0x24d2b78, 0x08);
121+
EXPECT_TRUE (CapabilityInquiryView::validate (inquiry));
122+
EXPECT_EQ (inquiry.data.size(), 12u);
123+
124+
auto reply = makeProcessInquiryCapabilitiesReply (0x7665544, 0x24d2b78, 19, 0x08);
125+
EXPECT_TRUE (ProcessInquiryCapabilitiesReplyView::validate (reply));
126+
EXPECT_EQ (reply.data.size(), 13u);
127+
128+
const auto view = ProcessInquiryCapabilitiesReplyView { reply };
129+
EXPECT_EQ (view.getSupportedFeatures(), 19);
130+
}
131+
132+
TEST (UMPCapabilityInquiryProcessTests, MidiMessageReportMessages)
133+
{
134+
auto inquiry = makeMidiMessageReportInquiry (0x7665544, 0x24d2b78, 0x12, 0x34, 0x56, 0x78, 0x04);
135+
EXPECT_TRUE (MidiMessageReportInquiryView::validate (inquiry));
136+
EXPECT_EQ (inquiry.data.size(), 16u);
137+
138+
auto reply = makeMidiMessageReportReply (0x7665544, 0x76, 0x54, 0x32, 0x0a);
139+
EXPECT_TRUE (MidiMessageReportReplyView::validate (reply));
140+
EXPECT_EQ (reply.data.size(), 15u);
141+
142+
auto end = makeMidiMessageReportEnd (0x7665544, 0x03);
143+
EXPECT_TRUE (CapabilityInquiryView::validate (end));
144+
EXPECT_EQ (end.data.size(), 12u);
145+
}
146+
147+
TEST (UMPCapabilityInquiryPropertyExchangeTests, CapabilitiesView)
148+
{
149+
SysEx7 sx { Manufacturer::universalNonRealtime,
150+
{ 0x7f, 0x0d, Subtype::propertyExchangeCapabilitiesInquiry, 0x01, 0x78, 0x56, 0x34, 0x12, 0x77, 0x55, 0x33, 0x11, 2 } };
151+
152+
EXPECT_TRUE (PropertyExchangeCapabilitiesView::validate (sx));
153+
const auto view = PropertyExchangeCapabilitiesView { sx };
154+
EXPECT_EQ (view.getMaximumNumberOfRequests(), 2);
155+
EXPECT_EQ (view.getMajorVersion(), 0);
156+
EXPECT_EQ (view.getMinorVersion(), 0);
157+
158+
SysEx7 missingVersion { Manufacturer::universalNonRealtime,
159+
{ 0x7f, 0x0d, Subtype::propertyExchangeCapabilitiesReply, 0x02, 0x78, 0x56, 0x34, 0x12, 0x77, 0x55, 0x33, 0x11, 2 } };
160+
EXPECT_FALSE (PropertyExchangeCapabilitiesView::validate (missingVersion));
161+
}
162+
163+
TEST (UMPCapabilityInquiryPropertyExchangeTests, PropertyDataMessageValidation)
164+
{
165+
const auto headerJson = propertyExchange::makeRjson (propertyExchange::Tags::resource,
166+
"ResourceList");
167+
const auto header = propertyExchange::Header { std::string_view { headerJson } };
168+
const auto chunk = propertyExchange::Chunk { std::string_view { "ABC" } };
169+
170+
auto sx = propertyExchange::makePropertyDataMessage (Subtype::getPropertyDataInquiry,
171+
0x1234567,
172+
0x4332211,
173+
header,
174+
1,
175+
1,
176+
chunk,
177+
0x11,
178+
0x0a);
179+
EXPECT_TRUE (propertyExchange::PropertyDataMessageView::validate (sx));
180+
EXPECT_TRUE (GetPropertyDataView::validate (sx));
181+
182+
SysEx7 invalid { Manufacturer::universalNonRealtime,
183+
{ 0x7f, 0x0d, Subtype::getPropertyDataInquiry, 0x02, 0x78, 0x56, 0x34, 0x12, 0x77, 0x55, 0x33, 0x11, 0x01, 0x7f, 0x7f } };
184+
EXPECT_FALSE (propertyExchange::PropertyDataMessageView::validate (invalid));
185+
186+
SysEx7 invalidChunk { Manufacturer::universalNonRealtime,
187+
{ 0x7f, 0x0d, Subtype::getPropertyDataInquiry, 0x02, 0x78, 0x56, 0x34, 0x12, 0x77, 0x55, 0x33, 0x11, 0x01, 0x01, 0x00, 0x7f, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00 } };
188+
EXPECT_FALSE (propertyExchange::PropertyDataMessageView::validate (invalidChunk));
189+
}

0 commit comments

Comments
 (0)