OpenShot Audio Library | OpenShotAudio 0.4.0
Loading...
Searching...
No Matches
juce_UMPMidi1ToBytestreamTranslator.h
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23#ifndef DOXYGEN
24
25namespace juce::universal_midi_packets
26{
27
35{
36public:
41 {
42 pendingSysExData.reserve (size_t (initialBufferSize));
43 }
44
46 void reset()
47 {
48 pendingSysExData.clear();
49 pendingSysExTime = 0.0;
50 }
51
60 template <typename MessageCallback>
61 void dispatch (const View& packet, double time, MessageCallback&& callback)
62 {
63 const auto firstWord = *packet.data();
64
65 if (! pendingSysExData.empty() && shouldPacketTerminateSysExEarly (firstWord))
66 pendingSysExData.clear();
67
68 switch (packet.size())
69 {
70 case 1:
71 {
72 // Utility messages don't translate to bytestream format
73 if (Utils::getMessageType (firstWord) != 0x00)
74 {
75 const auto message = fromUmp (PacketX1 { firstWord }, time);
76 callback (BytestreamMidiView (&message));
77 }
78
79 break;
80 }
81
82 case 2:
83 {
84 if (Utils::getMessageType (firstWord) == 0x3)
85 processSysEx (PacketX2 { packet[0], packet[1] }, time, callback);
86
87 break;
88 }
89
90 case 3: // no 3-word packets in the current spec
91 case 4: // no 4-word packets translate to bytestream format
92 default:
93 break;
94 }
95 }
96
107 static MidiMessage fromUmp (const PacketX1& m, double time = 0)
108 {
109 const auto word = m.front();
110 jassert (Utils::getNumWordsForMessageType (word) == 1);
111
112 const std::array<uint8_t, 3> bytes { { uint8_t ((word >> 0x10) & 0xff),
113 uint8_t ((word >> 0x08) & 0xff),
114 uint8_t ((word >> 0x00) & 0xff) } };
115 const auto numBytes = MidiMessage::getMessageLengthFromFirstByte (bytes.front());
116 return MidiMessage (bytes.data(), numBytes, time);
117 }
118
119private:
120 template <typename MessageCallback>
121 void processSysEx (const PacketX2& packet,
122 double time,
123 MessageCallback&& callback)
124 {
125 switch (getSysEx7Kind (packet[0]))
126 {
128 startSysExMessage (time);
129 pushBytes (packet);
130 terminateSysExMessage (callback);
131 break;
132
134 startSysExMessage (time);
135 pushBytes (packet);
136 break;
137
139 if (pendingSysExData.empty())
140 break;
141
142 pushBytes (packet);
143 break;
144
146 if (pendingSysExData.empty())
147 break;
148
149 pushBytes (packet);
150 terminateSysExMessage (callback);
151 break;
152 }
153 }
154
155 void pushBytes (const PacketX2& packet)
156 {
157 const auto bytes = SysEx7::getDataBytes (packet);
158 pendingSysExData.insert (pendingSysExData.end(),
159 bytes.data.begin(),
160 bytes.data.begin() + bytes.size);
161 }
162
163 void startSysExMessage (double time)
164 {
165 pendingSysExTime = time;
166 pendingSysExData.push_back (std::byte { 0xf0 });
167 }
168
169 template <typename MessageCallback>
170 void terminateSysExMessage (MessageCallback&& callback)
171 {
172 pendingSysExData.push_back (std::byte { 0xf7 });
173 callback (BytestreamMidiView (pendingSysExData, pendingSysExTime));
174 pendingSysExData.clear();
175 }
176
177 static bool shouldPacketTerminateSysExEarly (uint32_t firstWord)
178 {
179 return ! (isSysExContinuation (firstWord)
180 || isSystemRealTime (firstWord)
181 || isJROrNOP (firstWord));
182 }
183
184 static SysEx7::Kind getSysEx7Kind (uint32_t word)
185 {
186 return SysEx7::Kind ((word >> 0x14) & 0xf);
187 }
188
189 static bool isJROrNOP (uint32_t word)
190 {
191 return Utils::getMessageType (word) == 0x0;
192 }
193
194 static bool isSysExContinuation (uint32_t word)
195 {
196 if (Utils::getMessageType (word) != 0x3)
197 return false;
198
199 const auto kind = getSysEx7Kind (word);
200 return kind == SysEx7::Kind::continuation || kind == SysEx7::Kind::end;
201 }
202
203 static bool isSystemRealTime (uint32_t word)
204 {
205 return Utils::getMessageType (word) == 0x1 && ((word >> 0x10) & 0xff) >= 0xf8;
206 }
207
208 std::vector<std::byte> pendingSysExData;
209
210 double pendingSysExTime = 0.0;
211};
212
213} // namespace juce::universal_midi_packets
214
215#endif
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
void dispatch(const View &packet, double time, MessageCallback &&callback)
static PacketBytes getDataBytes(const PacketX2 &packet)
static uint32_t getNumWordsForMessageType(uint32_t)