OpenShot Audio Library | OpenShotAudio: juce_UMPMidi1ToBytestreamTranslator.h Source File

OpenShot Audio Library | OpenShotAudio 1.0.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
34 class Midi1ToBytestreamTranslator
35{
36public:
40 explicit Midi1ToBytestreamTranslator (int initialBufferSize)
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 {
127 case SysEx7::Kind::complete:
128 startSysExMessage (time);
129 pushBytes (packet);
130 terminateSysExMessage (callback);
131 break;
132
133 case SysEx7::Kind::begin:
134 startSysExMessage (time);
135 pushBytes (packet);
136 break;
137
138 case SysEx7::Kind::continuation:
139 if (pendingSysExData.empty())
140 break;
141
142 pushBytes (packet);
143 break;
144
145 case SysEx7::Kind::end:
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
juce::MidiMessage
Definition juce_MidiMessage.h:35
juce::MidiMessage::MidiMessage
MidiMessage() noexcept
Definition juce_MidiMessage.cpp:125
juce::MidiMessage::getMessageLengthFromFirstByte
static int getMessageLengthFromFirstByte(uint8 firstByte) noexcept
Definition juce_MidiMessage.cpp:104
juce::universal_midi_packets::Midi1ToBytestreamTranslator::Midi1ToBytestreamTranslator
Midi1ToBytestreamTranslator(int initialBufferSize)
Definition juce_UMPMidi1ToBytestreamTranslator.h:40
juce::universal_midi_packets::Midi1ToBytestreamTranslator::dispatch
void dispatch(const View &packet, double time, MessageCallback &&callback)
Definition juce_UMPMidi1ToBytestreamTranslator.h:61
juce::universal_midi_packets::Midi1ToBytestreamTranslator::fromUmp
static MidiMessage fromUmp(const PacketX1 &m, double time=0)
Definition juce_UMPMidi1ToBytestreamTranslator.h:107
juce::universal_midi_packets::Midi1ToBytestreamTranslator::reset
void reset()
Definition juce_UMPMidi1ToBytestreamTranslator.h:46
juce::universal_midi_packets::View
Definition juce_UMPView.h:44
juce::universal_midi_packets::View::size
uint32_t size() const noexcept
Definition juce_UMPView.cpp:26
juce::universal_midi_packets::View::data
const uint32_t * data() const noexcept
Definition juce_UMPView.h:55
juce::universal_midi_packets::BytestreamMidiView
Definition juce_UMPConversion.h:33
juce::universal_midi_packets::SysEx7::Kind
Kind
Definition juce_UMPSysEx7.h:47
juce::universal_midi_packets::SysEx7::Kind::end
@ end
Definition juce_UMPSysEx7.h:58
juce::universal_midi_packets::SysEx7::Kind::continuation
@ continuation
Definition juce_UMPSysEx7.h:55
juce::universal_midi_packets::SysEx7::Kind::begin
@ begin
Definition juce_UMPSysEx7.h:52
juce::universal_midi_packets::SysEx7::Kind::complete
@ complete
Definition juce_UMPSysEx7.h:49
juce::universal_midi_packets::SysEx7::getDataBytes
static PacketBytes getDataBytes(const PacketX2 &packet)
Definition juce_UMPSysEx7.cpp:32
juce::universal_midi_packets::Utils::getNumWordsForMessageType
static uint32_t getNumWordsForMessageType(uint32_t)
Definition juce_UMPUtils.cpp:26