Midimessage
Extensive library for MIDI constants, un-/packers, parser, cli and unified human-readable formatters/parser for MIDI Messages (embedded friendly)
Install / Use
/learn @tschiemer/MidimessageREADME
midimessage
https://github.com/tschiemer/midimessage
Extensive library for MIDI constants, un-/packers, parser, cli and unified human-readable formatters/parser for MIDI Messages.
Intended for usage with frameworks (such as https://github.com/thestk/rtmidi) that do not provide these basics.
No particular structures are enforced such that you can take from it what you want.
Features
- (many) MIDI Message constants + enumerations (see
include/midimessage.h) - structs and types help to create a unified interface and make handling easier
- Manufacturer Id list (see
include/midimessage/manufacturerids.h) - tool to generate up-to-date header, run
make manufacturerids(requires wget + php) - Standard/Common CC list (see
include/midimessage/commonccs.h) - DLS Proprietary Chunk ids (see
include/midimessage/dlsproprietarychunkids.h) - Basic note helpers (see
include/midimessage/notes.h) - packers construct the right byte sequence for a particular message ASSERTing valid parameters (see
include/midimessage/packers.h) - unpackers for a specific message type try to parse the given byte sequence thereby validating the byte sequence (could be used in any combination) (see
include/midimessage/packers.h) - packers and unpackers are always complementary and are available as literal-based and struct-based variants
- generic MIDI stream parser respecting Running Status and interleaved system real time messages (see
include/midimessage/parser.h) - stringifier struct to turn (binary) MIDI messages into a uniform human-readable format and vice versa (see
include/midimessage/stringifier.h; seesrc/cli.cppfor application) - Command line utility to turn human-readable commands into corresponding byte sequence and vice versa (see
src/cli.cppand below)
tt = to test
| Feature Set | Feature / Message | Message Family | Status* | |-----|-----|----|:-----:| | Channel Voice Message | Note On / Off | | tt | | | Polyphonic Key Pressure (Aftertouch) | | tt | | | Control Change | | tt | | | Program Change | | tt | | | Channel Pressure (Aftertouch) | | tt | | | Pitch Bend Change | | tt | | Channel Mode Messages | Specific Control Change (All Sound Off, Reset All Controllers, etc) | Control Change | tt | | System Common Messages | Song position pointer | | tt | | | Song select | | tt | | | Tune request | | tt | | | Quarter Frames -> MIDI Time Code | | | | System Real Time Messages | Timing clock | | tt | | | Start | | tt | | | Continue | | tt | | | Stop | | tt | | | Active Sensing | | tt | | | Reset | | tt | | MIDI Time Code (MTC) | Quarter Frames | System Common | tt | | | Full Message + User Bits| SysEx Real Time | tt | | | Real Time MTC Cueing | SysEx Real Time | tt | | | Non Real Time MTC Cueing | SysEx Non-Real Time | tt | | General SysEx NonRT Handshaking | wait, cancel, ack, nak, end of file | SysEx Non-Real Time | tt | | MIDI Machine Control (MMC) | | | work in progress | | MIDI Show Control (MSC) | All | SysEx Real Time | tt | | MIDI Visual Control (MVC)| Set Parameter Message (all) | SysEx Non-Real Time | tt | | MIDI Tuning Standard | | | TODO | | Experimental messages | | SysEx Experimental | tt | | Manufacturer messages (+ manufacturer ids)| | SysEx Manufacturer | tt | | General MIDI (GM) | System on/off | SysEx Non-Real Time | tt | | General Information | Identify request/reply | SysEx Non-Real Time | tt | | Device Control | Master volume, balance, coarse/fine tuning, global parameters | SysEx Real Time | tt | | Controller Destination Settings | Channel/Key pressure, control change | SysEx Real Time | tt | | Key-based Instrument Control | | SysEx Real Time | tt | | Sample Dump | (Extended) Header, Request, DataPacket, (Extended) Loop Point Request & Transmission, Name Request & Transmission | SysEx Non-Real Time | tt | | File Dump | Request, Header, DataPacket | Non-Real Time | tt | | Downloadable Sounds | | Non-Real Time | TODO | | Notation Information | Bar Number, Time Signature (delayed, immediate) | Real Time | tt | | Capability Inquiry (MIDI-CI) | | SysEx Non-Real Time | TODO | | Scalable Polyphony MIDI MIP (SP-MIDI MIP)| | SysEx Real Time | TODO | | Mobile Phone Control | on, off, reset, set level, set color, follow MIDI channels, manufacturer specific | SysEx Real Time | tt |
Requirements
midimessage-clirequires getopt and c-utils- target
manufactureridsrequires wget and php(-cli)
Building
git clone --recursive https://github.com/tschiemer/midimessage.git
cd midimessage
cmake .
make
make examples
make docs
make manufacturerids
To include as library in a cmake-based project (something like) the following in your CMakeLists.txt:
# path to root of midimessage
set(MIDIMESSAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/midimessage)
# midimessage include dir
# in your source files: #include <midimessage.h> or <midimessage/...>
set(MIDIMESSAGE_INCLUDES ${MIDIMESSAGE_DIR}/include)
# add the subproject
add_subdirectory(${MIDIMESSAGE_DIR} EXCLUDE_FROM_ALL)
# don't forget to add the include directory
target_include_directories(myTarget ${MIDIMESSAGE_INCLUDES})
# link library with your own target
target_link_libraries(myTarget midimsg)
Code Example
void receivedMidiMessageFromSomewhere( uint8_t * buf, int len ){
MidiMessage::Message_t msg, msg2;
uint8_t msgBuf[128], msgBuf2[128];
msg.Data.SysEx.ByteData = msgBuf;
msg2.Data.SysEx.ByteData = msgBuf2;
uint8_t buf2[256];
int len2;
static uint8_t pitch = 0;
if (!MidiMessage::unpack( buf, len, &msg )) {
std::cout << "Discarding invalid message" << std::endl;
return;
}
if (!MidiMessage::isChannelVoiceMessage(&msg)){
std::cout << "Discarding non-ChannelVoice message" << std::endl;
return;
}
// Struct based approach to create messages
// (the final message packaging is unified)
msg2.StatusClass = MidiMessage::StatusClassNoteOn;
msg2.Channel = msg.Channel;
msg2.Data.Note.Key = 40 + pitch;
msg2.Data.Note.Velocity = 100;
pitch = (pitch + 1) % 13;
len2 = MidiMessage::pack( buf2, &msg2 );
if (len2 > 0){
sendMidiMessageToSomewhere( buf2, len2 );
}
// direct approach
len2 = MidiMessage::packNoteOff( buf2, msg2.Channel, msg2.Data.Note.Key, 50 );
if (len2 > 0){
sendMidiMessageToSomewhere( buf2, len2 );
}
}
Command Line Utility
Usage:
midimessage-cli [-h?]
midimessage-cli [--running-status|-r] [--timed|-t[milli|micro]] (--parse|-p) [-d] [--nprn-filter]
midimessage-cli [--running-status|-r] [--timed|-t[milli|micro]] (--generate|-g) [-x0|-x1] [-v[N]] [--prefix=<prefix>] [--suffix=<suffix] [<cmd> ...]
midimessage-cli --convert=(nibblize|denibblize|sevenbitize|desevenbitize) [--hex] [<data xN>]
Options:
-h|-? show this help
--running-status|-r Accept (when parsing) or generate messages that rely on the running status (see MIDI specs)
--timed|-t[milli|micro] Enables the capture or playback of delta-time information (ie the time between messages). Optionally the time resolution (milliseconds or microseconds) can be specified (default = micro)
--parse|-p [<binary-data>] Enter parse mode and optionally pass as first argument (binary) message to be parsed. If no argument is provided starts reading binary stream from STDIN. Each successfully parsed message will be printed to STDOUT and terminated with a newline.
-d In parsing mode only, instead of silent discarding output any discarded data to STDERR.
--nrpn-filter In parsing mode only, assume CC-sequences 99-98-96 (increment), 99-98-97 (decrement), 99-98-6-38 (data entry) are NRPN sequences, thus these will be filtered even if impartial (!! ie, 99-98-6-2 will only output the message for 2; this is a convenience feature and can not be solved for the general case)
--generate|-g [<cmd> ...] Enter generation mode and optionally pass command to be generated. If no command is given, expects one command from STDIN per line. Generated (binary) messages are written to STDOUT.
--prefix=<prefix> Prefixes given string (max 32 bytes) before each binary sequence (only when in generation mode). A single %d can be given which will be replaced with the length of the following binary message (incompatible with running-status mode).
--suffix=<suffix> Suffixes given string (max 32 bytes) before each binary sequence (only when in generation mode).
-x0, -x1 In generation mode, exit on input error (-x1) or continue processing (-x0). Default := continue (-x0).
-v0, -v1 In generation mode, print command parsing result (on error only) to STDERR. Default := do NOT print (-v0).
--convert=.. Enter convertion mode, ie transform incoming STDIN using convertion method and write to STDOUT (raw bytes).
--hex In convertion mode (only), hex input/output
Fancy pants note: the parsing output format is identical to the generation command format ;)
Data types:
uN := N bit unsigned integer)
u4 (data nibble) < 15 (0x0F)
u7 <= 127 (0x7F)
u14 <= 16383 (0x3FFF)
u21 <= 2097151 (0x1FFFFF)
u28 <= 268435455 (0x0FFFFFFF)
u35 <= 34359738367 (0x7FFFFFFFF)
sN := N bit signed integer
strN ((max) N byte ascii string)
xN (N byte hex string <> 2Ns) (note: data bytes must be <= 0x7F)
Voice Commands:
note (on|off) <channel (u4)> <key (u7)> <velocity (u7)>
cc <channel (u4)> <controller (u7)> <value (u7)>
pc <channel (u4)> <program (u7)>
pressure <channel (u4)> <pressure (u7)>
pitch <channel (u4)> <pitch (u14)>
poly <channel (u4)> <key (u7)> <pressure (u7)>
System Commands:
start
stop
continue
reset
active-sensing
tune-request
timing-clock
quarter-frame <messageType (u3)> <nibble (u4)>
song-position <position (u14)>
song-select <songNumber (u7)>
(Basic) System Exclusives:
sysex experimental <data (xN)>
sysex manufacturer <manufacturer-id (x1..3)> <data
