MIDI Message Conversion
if I need more than 10 rules?
Data Interpolation Tricks:
To use DH_MIDIMunger effectively, you need to have a basic understanding of the various types of MIDI messages, their functions, and their structure. Each MIDI message consists of a Status byte, which may be followed by one or more Data bytes. The Status byte identifies the message type, and the MIDI Channel. Most of the message types the DH_MIDIMunger works on have 2 Data bytes, which we will refer to as Data1 and Data2. The meaning of the data in the Data1 and Data2 bytes varies, depending upon the message type.
The table below shows how the Data1 and Data2 bytes are used for the
message types supported by DH_MIDIMunger. Note that the values range only
from 0 to 127. This is because the first bit is always 0 to identify the
Data1 and Data2 bytes as Data bytes. (A Status byte's first bit is always
|Message Type||DH_MIDIMunger Abbreviation||Data1 (values 0 - 127)||Data2 (values 0 - 127)|
|Note Off||NoteOff||MIDI Note Number||Velocity|
|Note On||NoteOn||MIDI Note Number||Velocity|
|Polyphonic Key Pressure||KeyAft||MIDI Note Number||Pressure|
|Control Change||Ctrl||Controller Number||Data Value|
|Program Change||ProgChg||Program Number||Not Used|
|Channel Aftertouch||ChanAft||Pressure||Not Used|
|Pitch Bend||PitchB||Least Significant Byte (LSB)||Most Significant Byte (MSB)|
You use rules to tell DH_MIDIMunger which messages you want to change, and what changes you want to make. A rule is just a line of text containing 13 fields, separated by commas.
The 7th field has a special purpose that will be explained shortly. For
now, you can think of it as a convenient divider between the 6 Selection
fields and the 6 Action fields.
The 6 Selection fields correspond directly to the information in the incoming MIDI message:
You can put a specific value in to require an exact match on a field, or you can use an asterisk (*) as a wildcard to match all values for a field that's not a selection factor. You can match on a range of values for the Data1 and Data2 fields, or put the same value in both the Min and Max fields to require an exact match.
The 6 Action fields, 8 - 13 correspond to the outgoing MIDI message in
exactly the same way. An asterisk (*) in these fields means that the value
in the field is to be passed through from the incoming message unchanged.
If you enter specific values for a field, DH_MIDIMunger will change the
value of that field in the outgoing message, based on what you enter, for
all messages that match the rule.
|Field Position||Name||Possible Values|
|1||Channel In||Channel of incoming messages to match, 1-16, or * for all|
|2||Msg Type In||NoteOff, NoteOn, KeyAft, Ctrl, ProgChg, ChanAft, PitchB, RPN or NRPN (not case-sensitive)|
|3||Data1 Min In||Minimum value to match for Data1 byte, or * to match all|
|4||Data1 Max In||Maximum value to match for Data1 byte, or * to match all|
|5||Data2 Min In||Minimum value to match for Data2 byte, or * to match all|
|6||Data2 Max In||Maximum value to match for Data2 byte, or * to match all|
|7||Pass Message On Flag||Y or N (not case sensitive)|
|8||Channel Out||channel for the outgoing message, 1-16, * for no change|
|9||Msg Type Out||NoteOff, NoteOn, KeyAft, Ctrl, ProgChg, ChanAft, PitchB, RPN, NRPN, Discard, or * for no change. (not case sensitive)|
|10||Data1 Min Out||Minimum value for outgoing Data1 byte, or * for no change|
|11||Data1 Max Out||Maximum value for outgoing Data1 byte, or * for no change|
|12||Data2 Min Out||Minimum value for outgoing Data2 byte, or * for no change|
|13||Data2 Max Out||Maximum value for outgoing Data2 byte, or * for no change|
|Use incoming Data1 values to calculate outgoing Data2 byte||>|
|Use incoming Data2 values to calculate outgoing Data1 byte||<|
|Switch both Data1 and Data2||>,<|
On the selection side of the rule, we've specified that we only want to match channel 2 Control Change messages. We're only interested in Controller 1 messages. The Controller number is in the Data1 byte of a Control Change message, so we've put a 1 in both the Min and Max of the Data1 In range. Data2 is the value to be sent to the controller. We want all CC1 messages, regardless of value, so we've used asterisks for the Data2 In range.
On the action side, we've specified that the channel is to be changed to channel 1. It's still to be a Control Change message, but we put a 10 in both the Min and Max of the Data1 Out range to change it to CC10. We want the values coming in from the Mod Wheel to be passed through to CC10 unchanged, so asterisks go in the Data2 Out range.
You can limit the selection of messages to those that have a Data1 or Data2 value that falls within a specific range by entering the range's minimum and maximum values in the Data1 or Data2 Min In and Max In fields. The rules below use this feature to split the keyboard between MIDI channels 1 and 2.
In a Note On message, the MIDI note
number is in the Data1 byte, and the velocity is in the Data2 byte.
The rules select Note On and Note Off messages for channel 1 where the
note number is in the range 0 - 59, and change the channel to channel 2.
Wildcards are used in the Data2 range fields, because velocity is not a
factor in the selection, and we want the velocity information to be passed
through unchanged. Messages with note numbers 60 - 127 are not
affected, so they remain on channel 1.
If you specify a numeric range for the outgoing Data1 or Data2, DH_MIDIMunger will interpolate the new value within your specified range, based on the incoming value's relative position in the incoming range. For example, the following rule compresses the dynamic range of velocities:
The Rule uses wildcards for both the incoming and outgoing
Data1 ranges so that all notes will be selected, and the note numbers will
pass through unchanged. The Data2 fields map the range 1 - 127 to the
range 64 - 100, so that if the velocity in the incoming message were, say,
1/3 of the way from 1 to 127, the velocity in the outbound message would
be 1/3 of the way from 64 to 100.
|Tip: Some MIDI equipment uses Note On messages with a
velocity of 0 in place of
Note Off messages, so in practice, the range of Note On
velocities is 1 - 127.
In the above example, if we made the selection range for velocities 0 - 127, the rule would convert 0-velocity Note On messages, which were intended to function as Note Offs, into Note Ons with a velocity of 64, hardly the desired effect.
Not that you'd want to do this to anyone ;-)
...but you may find other applications for inversely interpolating MIDI parameters.
Normally, when a message matches a rule, we want the modified message to replace the incoming message. An N in the 7th field of a rule prevents further processing of the original incoming message. No attempt will be made to match it with other rules, and it will not be output.
In some situations, however, we may want an incoming message to generate more than one outgoing message. Or, we may want to keep the original incoming message in addition to any messages it generates by matching rules. In such cases, a Y in the 7th field of a rule tells DH_MIDIMunger to continue processing the original message.
The rules transpose by translating the note range 0 - 115 to the range 12 - 127. Since 12 has been added to both the Data1 Min In and Data1 Max In fields to get the corresponding output values, the rules add 12 to the note number in the Data1 byte of each message matched. The "Y"s in field 7 cause both the original (unmodified) and the modified messages to be output.
Sometimes, when converting from one message type to another, you need to set the value in Data1 of the outgoing message based on the Data2 value of the incoming message, or vice versa. For example, suppose you want to use Control Change messages to generate Note Ons, with the Control Change values (in the Data2 byte of the incoming messages) determining the note numbers (in the Data 1 byte of the outgoing Note On messages).
DH_MIDIMunger rules use Swap Flags of ">" and "<" for this purpose. They are added at the end of the 13 standard rule fields, separated from field 13 by the usual comma.
A Swap Flag of "<" will cause DH_MIDIMunger to set the value of the
outgoing Data1 byte based on the incoming Data2 value. Similarly, a Swap
Flag of ">" will cause the value of the outgoing Data2 byte to be set
based on the incoming Data1 value. To swap both fields, use both Swap
Flags, separated by a comma.
As synth designers and others apply MIDI control to more and more parameters, having to work within the bounds of the original 128 Controller numbers, many of which have standard pre-assigned uses, has become very limiting. Registered Parameter Numbers (RPNs) and Non-Registered Parameter Numbers (NRPNs) open up 32,768 additional numbers (16,384 RPNs and 16,384 NRPNs) for possible use in MIDI control.
The additional flexibility of RPNs and NRPNs comes at the price of
added complexity. Unlike standard Control Change messages, NRPNs use
multiple-message sequences. The topic DH_MIDIMunger Support for RPNs and NRPNs describes how
DH_MIDIMunger has been
designed to manage most of this complexity for you. It still helps to have
a basic understanding of how RPNs and NRPNs work, however.
RPNs and NRPNs work in essentially the same way, so to keep things as simple as possible, we'll focus first on NRPNs.
A NRPN serves the same purpose as a MIDI CC number. It takes 2 Control Change messages to identify a NRPN. Controller numbers 99 and 98 are reserved for this purpose. Two messages are required because NRPNs can be any of 16,384 possible values (0 - 16383), and the Data2 byte of each Control Change message can hold only 128 possible values (0 - 127).
|Tip: To calculate
the full number from its LSB and MSB, multiply the MSB by 128 and
add the LSB:|
N = MSB * 128 + LSB
Data values for NRPNs are sent in separate messages that follow immediately after the CC99 and CC98 messages. There are several alternatives:
So, a typical NRPN sequence would be
This sequence sends the value 9,996 ( 78 * 128 + 12 )
to NRPN 500 ( 3 * 128 + 116).
The MIDI standard provides that CC99 and CC98 messages need not be repeated unless they change. Therefore, once 3 is established as the current NRPN MSB with the above sequence, the following would be a valid sequence for NRPN 501:
RPNs function the same way as NRPNs, but use CC101 for the RPN MSB and CC100 for the RPN LSB. The same data messages are used.
You can assign RPNs and NRPNs to SynthEdit controls for MIDI Automation. In the screen shots below, NRPN 500 has been assigned to the Slider. Note that 98/99 - NRPN (or 100/101 - RPN) must be selected as the controller.
The MIDI Monitor displays the NRPN sequences that were generated by moving the slider. The NRPN MSB of 3 and the NRPN LSB of 116 add up to our NRPN of 500 (3 * 128 + 116) The slider will also respond to sequences like this, targeted to NRPN 500.
DH_MIDIMunger allows you to work with RPNs and NRPNs as if they were just 2 additional message types. You can change parameter numbers, convert RPNs or NRPNs to or from other message types, and interpolate data ranges without having to get involved with the underlying message sequences, MSBs and LSBs, and so on. All of this is taken care of automatically.
In a rule, you use a RPN or NRPN "message type" much like the Control Change message type. The Data1 range is used for the parameter number, and the Data2 range is used for the data value. The parameter numbers and data values can range from 0 - 16383, instead of just 0 - 127.
With a Message Type In of RPN or NRPN, the rule will match a RPN or
NRPN sequence. When such a sequence is detected in the input, the
parameter number and data value are calculated from the MSB and LSB fields
in its messages and matched against the rule's Data1 In and Data2 In
With a Message Type Out of RPN or NRPN, the rule will generate a RPN or NRPN sequence when it is matched. The rule's Data1 Out and Data2 Out range values are used to calculate the correct MSB and LSB fields in the outgoing sequence's messages.
The following rule will redirect NRPN sequences that are targeted to NRPN 3400 to NRPN 100:
For example, the sequence
There is a problem, however. This rule translates the message CC1 67 to the sequence
Note that the wildcard character
is used in the
Data2 ranges, so there is no change in the data value. Since the RPN data
range is 0 - 16,383, this puts the value 67 in the Data Entry LSB
(CC38). The result will be that although the mod wheel is positioned just
past the half-way mark (67/127), the RPN value is only 67/16383, or 0.4%
of the total.
To get the CC1 value into the Data Entry MSB (CC6), you could use DH_MIDIMunger's data interpolation capability to multiply the value by 128. ( 128 * 128 = 16,384 )
With this rule, CC1 67 translates to
DH_MIDIMunger © 2003-2006 David Haupt. All rights reserved.
SynthEdit © 2002, Jeff McClintock