OpenShot Audio Library | OpenShotAudio 0.4.0
juce_UMPMidi1ToMidi2DefaultTranslator.cpp
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
23namespace juce::universal_midi_packets
24{
25
26PacketX2 Midi1ToMidi2DefaultTranslator::processNoteOnOrOff (const HelperValues helpers)
27{
28 const auto velocity = helpers.byte2;
29 const auto needsConversion = (helpers.byte0 & std::byte { 0xf0 }) == std::byte { 0x90 } && velocity == std::byte { 0 };
30 const auto firstByte = needsConversion ? (std::byte { 0x80 } | (helpers.byte0 & std::byte { 0xf }))
31 : helpers.byte0;
32
33 return PacketX2
34 {
35 Utils::bytesToWord (helpers.typeAndGroup, firstByte, helpers.byte1, std::byte { 0 }),
36 (uint32_t) (Conversion::scaleTo16 (uint8_t (velocity)) << 0x10)
37 };
38}
39
40PacketX2 Midi1ToMidi2DefaultTranslator::processPolyPressure (const HelperValues helpers)
41{
42 return PacketX2
43 {
44 Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, helpers.byte1, std::byte { 0 }),
45 Conversion::scaleTo32 (uint8_t (helpers.byte2))
46 };
47}
48
49bool Midi1ToMidi2DefaultTranslator::processControlChange (const HelperValues helpers,
50 PacketX2& packet)
51{
52 const auto statusAndChannel = helpers.byte0;
53 const auto cc = uint8_t (helpers.byte1);
54
55 const auto shouldAccumulate = [&]
56 {
57 switch (cc)
58 {
59 case 6:
60 case 38:
61 case 98:
62 case 99:
63 case 100:
64 case 101:
65 return true;
66 }
67
68 return false;
69 }();
70
71 const auto group = (uint8_t) (helpers.typeAndGroup & std::byte { 0xf });
72 const auto channel = (uint8_t) (statusAndChannel & std::byte { 0xf });
73 const auto byte = helpers.byte2;
74
75 if (shouldAccumulate)
76 {
77 auto& accumulator = groupAccumulators[group][channel];
78
79 if (accumulator.addByte (cc, byte))
80 {
81 const auto& bytes = accumulator.getBytes();
82 const auto bank = bytes[0];
83 const auto index = bytes[1];
84 const auto msb = bytes[2];
85 const auto lsb = bytes[3];
86
87 const auto value = uint16_t ((uint16_t (msb & std::byte { 0x7f }) << 7) | uint16_t (lsb & std::byte { 0x7f }));
88
89 const auto newStatus = (uint8_t) (accumulator.getKind() == PnKind::nrpn ? 0x3 : 0x2);
90
91 packet = PacketX2
92 {
93 Utils::bytesToWord (helpers.typeAndGroup, std::byte ((newStatus << 0x4) | channel), bank, index),
95 };
96 return true;
97 }
98
99 return false;
100 }
101
102 if (cc == 0)
103 {
104 groupBanks[group][channel].setMsb (uint8_t (byte));
105 return false;
106 }
107
108 if (cc == 32)
109 {
110 groupBanks[group][channel].setLsb (uint8_t (byte));
111 return false;
112 }
113
114 packet = PacketX2
115 {
116 Utils::bytesToWord (helpers.typeAndGroup, statusAndChannel, std::byte { cc }, std::byte { 0 }),
117 Conversion::scaleTo32 (uint8_t (helpers.byte2))
118 };
119 return true;
120}
121
122PacketX2 Midi1ToMidi2DefaultTranslator::processProgramChange (const HelperValues helpers) const
123{
124 const auto group = (uint8_t) (helpers.typeAndGroup & std::byte { 0xf });
125 const auto channel = (uint8_t) (helpers.byte0 & std::byte { 0xf });
126 const auto bank = groupBanks[group][channel];
127 const auto valid = bank.isValid();
128
129 return PacketX2
130 {
131 Utils::bytesToWord (helpers.typeAndGroup,
132 helpers.byte0,
133 std::byte { 0 },
134 valid ? std::byte { 1 } : std::byte { 0 }),
135 Utils::bytesToWord (helpers.byte1,
136 std::byte { 0 },
137 valid ? std::byte { bank.getMsb() } : std::byte { 0 },
138 valid ? std::byte { bank.getLsb() } : std::byte { 0 })
139 };
140}
141
142PacketX2 Midi1ToMidi2DefaultTranslator::processChannelPressure (const HelperValues helpers)
143{
144 return PacketX2
145 {
146 Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, std::byte { 0 }, std::byte { 0 }),
147 Conversion::scaleTo32 (uint8_t (helpers.byte1))
148 };
149}
150
151PacketX2 Midi1ToMidi2DefaultTranslator::processPitchBend (const HelperValues helpers)
152{
153 const auto lsb = helpers.byte1;
154 const auto msb = helpers.byte2;
155 const auto value = uint16_t (uint16_t (msb) << 7 | uint16_t (lsb));
156
157 return PacketX2
158 {
159 Utils::bytesToWord (helpers.typeAndGroup, helpers.byte0, std::byte { 0 }, std::byte { 0 }),
160 Conversion::scaleTo32 (value)
161 };
162}
163
164bool Midi1ToMidi2DefaultTranslator::PnAccumulator::addByte (uint8_t cc, std::byte byte)
165{
166 const auto isStart = cc == 99 || cc == 101;
167
168 if (isStart)
169 {
170 kind = cc == 99 ? PnKind::nrpn : PnKind::rpn;
171 index = 0;
172 }
173
174 bytes[index] = byte;
175
176 const auto shouldContinue = [&]
177 {
178 switch (index)
179 {
180 case 0: return isStart;
181 case 1: return kind == PnKind::nrpn ? cc == 98 : cc == 100;
182 case 2: return cc == 6;
183 case 3: return cc == 38;
184 }
185
186 return false;
187 }();
188
189 index = shouldContinue ? index + 1 : 0;
190
191 if (index != bytes.size())
192 return false;
193
194 index = 0;
195 return true;
196}
197
198} // namespace juce::universal_midi_packets
static uint32_t scaleTo32(uint8_t word7Bit)
static uint16_t scaleTo16(uint8_t word7Bit)
static constexpr uint32_t bytesToWord(std::byte a, std::byte b, std::byte c, std::byte d)
Definition: juce_UMPUtils.h:36