diff --git a/modules/juce_audio_basics/juce_audio_basics.cpp b/modules/juce_audio_basics/juce_audio_basics.cpp index 20a2e17088..4357374c26 100644 --- a/modules/juce_audio_basics/juce_audio_basics.cpp +++ b/modules/juce_audio_basics/juce_audio_basics.cpp @@ -101,14 +101,14 @@ #include "sources/juce_PositionableAudioSource.cpp" #include "synthesisers/juce_Synthesiser.cpp" #include "audio_play_head/juce_AudioPlayHead.cpp" -#include "midi/juce_MidiDataConcatenator.h" -#include "midi/ump/juce_UMP.h" +#include "utilities/juce_AudioWorkgroup.cpp" + #include "midi/ump/juce_UMPUtils.cpp" #include "midi/ump/juce_UMPView.cpp" #include "midi/ump/juce_UMPSysEx7.cpp" #include "midi/ump/juce_UMPMidi1ToMidi2DefaultTranslator.cpp" #include "midi/ump/juce_UMPIterator.cpp" -#include "utilities/juce_AudioWorkgroup.cpp" +#include "midi/ump/juce_UMPStringUtils.cpp" #if JUCE_UNIT_TESTS #include "utilities/juce_ADSR_test.cpp" diff --git a/modules/juce_audio_basics/juce_audio_basics.h b/modules/juce_audio_basics/juce_audio_basics.h index de9fd28aef..e035f1a47e 100644 --- a/modules/juce_audio_basics/juce_audio_basics.h +++ b/modules/juce_audio_basics/juce_audio_basics.h @@ -134,6 +134,7 @@ JUCE_END_IGNORE_WARNINGS_MSVC #include "utilities/juce_AudioWorkgroup.h" #include "midi/ump/juce_UMPBytesOnGroup.h" #include "midi/ump/juce_UMPDeviceInfo.h" +#include "midi/ump/juce_UMP.h" namespace juce { diff --git a/modules/juce_audio_basics/midi/ump/juce_UMP.h b/modules/juce_audio_basics/midi/ump/juce_UMP.h index eae2f8ccdb..88abe5cfc6 100644 --- a/modules/juce_audio_basics/midi/ump/juce_UMP.h +++ b/modules/juce_audio_basics/midi/ump/juce_UMP.h @@ -45,6 +45,7 @@ #include "juce_UMPMidi1ToMidi2DefaultTranslator.h" #include "juce_UMPConverters.h" #include "juce_UMPDispatcher.h" +#include "juce_UMPStringUtils.h" /** @cond */ namespace juce diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPStringUtils.cpp b/modules/juce_audio_basics/midi/ump/juce_UMPStringUtils.cpp new file mode 100644 index 0000000000..739e17fe9e --- /dev/null +++ b/modules/juce_audio_basics/midi/ump/juce_UMPStringUtils.cpp @@ -0,0 +1,248 @@ +/* + ============================================================================== + + This file is part of the JUCE framework. + Copyright (c) Raw Material Software Limited + + JUCE is an open source framework subject to commercial or open source + licensing. + + By downloading, installing, or using the JUCE framework, or combining the + JUCE framework with any other source code, object code, content or any other + copyrightable work, you agree to the terms of the JUCE End User Licence + Agreement, and all incorporated terms including the JUCE Privacy Policy and + the JUCE Website Terms of Service, as applicable, which will bind you. If you + do not agree to the terms of these agreements, we will not license the JUCE + framework to you, and you must discontinue the installation or download + process and cease use of the JUCE framework. + + JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/ + JUCE Privacy Policy: https://juce.com/juce-privacy-policy + JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/ + + Or: + + You may also use this code under the terms of the AGPLv3: + https://www.gnu.org/licenses/agpl-3.0.en.html + + THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL + WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + + ============================================================================== +*/ + +namespace juce::universal_midi_packets +{ + +String StringUtils::getHexString (const View& view) +{ + auto result = String::toHexString (*view.data()); + + std::for_each (std::next (view.begin()), view.end(), [&] (uint32_t word) + { + result << ' ' << String::toHexString (word); + }); + + return result; +} + +static String getUtilityMessageDescription (const PacketX1& p) +{ + const auto word = p.front(); + + switch ((uint8_t) Utils::getStatus (word)) + { + case 0x0: return "NOOP"; + case 0x1: return "JR Clock " + String::toHexString ((word >> 0x10) & 0xff); + case 0x2: return "JR Timestamp " + String::toHexString ((word >> 0x10) & 0xff); + } + + jassertfalse; + return {}; +} + +static String getPacketDescription (const PacketX1& p) +{ + switch (Utils::getMessageType (p.front())) + { + case Utils::MessageKind::utility: return "Utility: " + getUtilityMessageDescription (p); + case Utils::MessageKind::commonRealtime: return "System: " + SingleGroupMidi1ToBytestreamExtractor::fromUmp (p).getDescription(); + case Utils::MessageKind::channelVoice1: return "MIDI 1.0 Channel Voice: " + SingleGroupMidi1ToBytestreamExtractor::fromUmp (p).getDescription(); + + case Utils::MessageKind::channelVoice2: + case Utils::MessageKind::sysex7: + case Utils::MessageKind::sysex8: + case Utils::MessageKind::stream: + break; + } + + jassertfalse; + return {}; +} + +static String getData64MessageDescription (const PacketX2& p) +{ + const auto bytes = SysEx7::getDataBytes (p); + + String byteString; + + std::for_each (bytes.data.data(), bytes.data.data() + bytes.size, [&] (std::byte byte) + { + byteString << String::toHexString ((uint8_t) byte); + }); + + switch (SysEx7::Kind (Utils::getStatus (p.front()))) + { + case SysEx7::Kind::complete: return "Full: " + byteString; + case SysEx7::Kind::begin: return "Start: " + byteString; + case SysEx7::Kind::continuation: return "Continue: " + byteString; + case SysEx7::Kind::end: return "End: " + byteString; + } + + jassertfalse; + return {}; +} + +static String getMidi2ChannelVoiceDescription (const PacketX2& p) +{ + const auto getNoteName = [&] { return MidiMessage::getMidiNoteName ((p[0] >> 0x8) & 0xff, true, true, 3); }; + const auto getByte3 = [&] { return String::toHexString ((p[0] >> 0x8) & 0xff); }; + const auto getByte4 = [&] { return String::toHexString ((p[0] >> 0x0) & 0xff); }; + + const auto getVelocity = [&] { return String::toHexString ((p[1] >> 0x10) & 0xffff); }; + const auto getAttribute = [&] { return String::toHexString ((p[1] >> 0x00) & 0xffff); }; + + const auto getChannel = [&] { return String::toHexString (p.getChannel()); }; + + switch ((uint8_t) Utils::getStatus (p[0])) + { + case 0x0: return "Registered Per-Note Controller " + getByte4() + + " Channel " + getChannel() + + " Note " + getNoteName() + + " Data " + String::toHexString (p[1]); + case 0x1: return "Assignable Per-Note Controller " + getByte4() + + " Channel " + getChannel() + + " Note " + getNoteName() + + " Data " + String::toHexString (p[1]); + case 0x2: return "Registered Controller Bank " + getByte3() + + " Channel " + getChannel() + + " Index " + getByte4() + + " Data " + String::toHexString (p[1]); + case 0x3: return "Assignable Controller Bank " + getByte3() + + " Channel " + getChannel() + + " Index " + getByte4() + + " Data " + String::toHexString (p[1]); + case 0x4: return "Relative Registered Controller Bank " + getByte3() + + " Channel " + getChannel() + + " Index " + getByte4() + + " Data " + String::toHexString (p[1]); + case 0x5: return "Relative Assignable Controller Bank " + getByte3() + + " Channel " + getChannel() + + " Index " + getByte4() + + " Data " + String::toHexString (p[1]); + case 0x6: return "Per-Note Pitch Bend Note " + getNoteName() + + " Channel " + getChannel() + + " Data " + String::toHexString (p[1]); + case 0x8: return "Note Off " + getNoteName() + + " Channel " + getChannel() + + " Attribute Type " + getByte4() + + " Velocity " + getVelocity() + + " Attribute Data " + getAttribute(); + case 0x9: return "Note On " + getNoteName() + + " Channel " + getChannel() + + " Attribute Type " + getByte4() + + " Velocity " + getVelocity() + + " Attribute Data " + getAttribute(); + case 0xa: return "Poly Pressure Note " + getNoteName() + + " Channel " + getChannel() + + " Data " + String::toHexString (p[1]); + case 0xb: return "Control Change " + getByte3() + + " Channel " + getChannel() + + " Data " + String::toHexString (p[1]); + case 0xc: return "Program Change Options " + getByte4() + + " Channel " + getChannel() + + " Program " + String::toHexString ((p[1] >> 0x18) & 0xff) + + " Bank MSB " + String::toHexString ((p[1] >> 0x08) & 0xff) + + " Bank LSB " + String::toHexString ((p[1] >> 0x00) & 0xff); + case 0xd: return "Channel Pressure " + String::toHexString (p[1]) + + " Channel " + getChannel(); + case 0xe: return "Pitch Bend " + String::toHexString (p[1]) + + " Channel " + getChannel(); + case 0xf: return "Per-Note Management Note " + getNoteName() + + " Channel " + getChannel() + + " Options " + getByte4(); + } + + jassertfalse; + return {}; +} + +static String getPacketDescription (const PacketX2& p) +{ + switch (Utils::getMessageType (p.front())) + { + case Utils::MessageKind::sysex7: return "Data 64-Bit: " + getData64MessageDescription (p); + case Utils::MessageKind::channelVoice2: return "MIDI 2.0 Channel Voice: " + getMidi2ChannelVoiceDescription (p); + + case Utils::MessageKind::utility: + case Utils::MessageKind::channelVoice1: + case Utils::MessageKind::sysex8: + case Utils::MessageKind::commonRealtime: + case Utils::MessageKind::stream: + break; + } + + jassertfalse; + return {}; +} + +static String getPacketDescription (const PacketX3&) +{ + jassertfalse; + return {}; +} + +static String getPacketDescription (const PacketX4& p) +{ + switch (Utils::getMessageType (p[0])) + { + case Utils::MessageKind::sysex8: return "Data 128 Bit"; // TODO + case Utils::MessageKind::stream: return "Stream Configuration"; // TODO + + case Utils::MessageKind::utility: + case Utils::MessageKind::sysex7: + case Utils::MessageKind::channelVoice1: + case Utils::MessageKind::channelVoice2: + case Utils::MessageKind::commonRealtime: + break; + } + + jassertfalse; + return {}; +} + +String StringUtils::getDescription (const View& v) +{ + const auto group = (String ("Group ") + String (Utils::getGroup (*v.data()))) + ' '; + + switch (v.size()) + { + case 1: + return group + getPacketDescription (PacketX1 { v[0] }); + + case 2: + return group + getPacketDescription (PacketX2 { v[0], v[1] }); + + case 3: + return group + getPacketDescription (PacketX3 { v[0], v[1], v[2] }); + + case 4: + return group + getPacketDescription (PacketX4 { v[0], v[1], v[2], v[3] }); + } + + jassertfalse; + return {}; +} + +} // namespace juce::universal_midi_packets diff --git a/modules/juce_audio_basics/midi/ump/juce_UMPStringUtils.h b/modules/juce_audio_basics/midi/ump/juce_UMPStringUtils.h new file mode 100644 index 0000000000..ed38411827 --- /dev/null +++ b/modules/juce_audio_basics/midi/ump/juce_UMPStringUtils.h @@ -0,0 +1,54 @@ +/* + ============================================================================== + + This file is part of the JUCE framework. + Copyright (c) Raw Material Software Limited + + JUCE is an open source framework subject to commercial or open source + licensing. + + By downloading, installing, or using the JUCE framework, or combining the + JUCE framework with any other source code, object code, content or any other + copyrightable work, you agree to the terms of the JUCE End User Licence + Agreement, and all incorporated terms including the JUCE Privacy Policy and + the JUCE Website Terms of Service, as applicable, which will bind you. If you + do not agree to the terms of these agreements, we will not license the JUCE + framework to you, and you must discontinue the installation or download + process and cease use of the JUCE framework. + + JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/ + JUCE Privacy Policy: https://juce.com/juce-privacy-policy + JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/ + + Or: + + You may also use this code under the terms of the AGPLv3: + https://www.gnu.org/licenses/agpl-3.0.en.html + + THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL + WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + + ============================================================================== +*/ + +namespace juce::universal_midi_packets +{ + +/** + Holds utility functions for extracting textual representations of Universal + MIDI Packets. +*/ +struct StringUtils +{ + /** Return a textual description of this packet. */ + static String getHexString (const View&); + + /** Return a textual description of this packet. */ + static String getDescription (const View&); + +private: + StringUtils() = default; +}; + +} // namespace juce::universal_midi_packets