Message
Type
Channel

How to Use DH_MIDIMunger

MIDI Message Conversion Module

Copyright © 2003-2006 David Haupt, all rights reserved

Munge: "An extensive rewrite of a routine, data structure or entire
computer program"
-Atomica
 

Description

DH_MIDIMunger.sem is a SynthEdit module that can "munge", or rewrite, MIDI messages on the fly. For example, it can divert selected messages to a different MIDI channel. It can transpose notes. You can use it to raise, lower, or compress velocity ranges. In fact, you can use it to change any Note Off, Note On, Polyphonic Key Pressure, Control Change, Program Change,  Channel Aftertouch, Pitch Bend message, or RPN/NRPN message sequence, to any other, substituting data according to rules that you specify.

 

Quick Index

Topics:

MIDI Message Structure
Rules Rule
Rule Field Descriptions
Input Ranges
Output Ranges & Data Interpolation
The Pass Message On Flag
Swapping Data1 and Data2
RPNs and NRPNs: Background
RPNs and NRPNs in SynthEdit
DH_MIDIMunger Support for RPNs and NRPNs
Known Limitations

FAQ:

What if I need more than 10 rules?
How can I make sure my rule file will be found after I've saved the project as a VST?
What happens if a rule isn't formatted correctly?
What licensing terms/usage restrictions apply to DH_MIDIMunger?
What if I find a bug, or have a question that isn't answered here?

 

 

Rule Examples:

Changing CC# and Channel
Split Keyboard
Velocity Compression
Reverse Keyboard
Octaver
CC to Note On
Changing NRPN
CC to RPN
 

 

Data Interpolation Tricks:

Inverting a range
Adding a constant
Multiplying by a constant
 

 

DH_MIDIMunger

MIDI Message Structure

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.

MIDI Message Structure

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 1.)
 

Top
Index
 
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)
   

In addition to these message types, DH_MIDIMunger also supports conversion to and from the multiple-message sequences used for Registered and Non-Registered Parameter Numbers (RPN and NRPN). This is discussed in more detail later in this document.

 
   

Rules Rule

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 first 6 fields, 1 - 6, let you specify criteria for selecting incoming messages for processing.
  • The 6 fields 8 - 13 are identical to the first 6, but they specify the actions to be applied to messages that match the rule's selection criteria. This is where you specify what you want changed.

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:

  • Channel
  • Message Type
  • Data1 (as a range: Min to Max)
  • Data2 (as a range: Min to Max)

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.
 

Top
Index
 

DH_MIDIMunger Rules: Field Descriptions

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
Optional Swap
Flags
Use incoming Data1 values to calculate outgoing Data2 byte >
Use incoming Data2 values to calculate outgoing Data1 byte <
Switch both Data1 and Data2  >,<
Top
Index
 

 

Here's a simple rule that selects Mod Wheel messages (Controller 1) coming in on channel 2 and changes them into Controller 10 messages on channel 1:

 

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.

 

 

Top
Index

 

Input Ranges

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.

 

Top
Index
 

Output Ranges & Data Interpolation

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.

Top
Index
 
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.

   
 

DH_MIDIMunger's interpolation capabilities can also be used in some not-so-obvious ways. These 2 rules reverse the keyboard by mapping the note number range 0 - 127 to the range 127 to 0:

Not that you'd want to do this to anyone ;-)

  ...but you may find other applications for inversely interpolating MIDI parameters.

 

 

Top
Index

 

The Pass Message On Flag

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.

Here's a simple Octaver that uses the Pass Message On flag:

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.

 
Top
Index
 

Swapping Data1 and Data2

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.
 

Top
Index
 
The following rules translate CC20 messages to Note Ons and Note Offs. This can be used with a knob or slider on an external controller to create a nice glissando effect. (Depending on the patch's dynamic envelope, the Note Off rule may be left out.)

 

Top
Index
 

RPNs and NRPNs: Background

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).  

  • The Most Significant Byte (MSB) of the NRPN is in the Data2 byte of the CC99 message
  • The Least Significant Byte (LSB) of the NRPN is in the Data2 byte of the CC98 message.
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:

  • Values that can range from 0 - 16,383 require 2 messages:
    • The MSB of the data is in the Data2 byte of a CC6 Data Entry message.
    • The LSB of the data is in the Data2 byte of a CC38 message.
  • Values that range from 0 - 127 can be sent in 1 message. It could be a CC6 or a CC38, depending on the manufacturer.
  • A CC96 Data Increment message can be sent. Its Data2 byte  holds a value
    (0 - 127) to be added to the current parameter value.
  • A CC97 Data Decrement message can be sent. Its Data2 byte holds a value
    (0 - 127) to be subtracted from the current parameter value.

So, a typical NRPN sequence would be

CC99 3      
CC98 116 
CC6   78
CC38 12

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:

CC98 117
CC6   45
CC38 32


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.

 

Top
Index

 

 

RPNs and NRPNs in SynthEdit

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.

 

Top
Index
 

DH_MIDIMunger Support for RPNs and NRPNs

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 ranges.

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

CC99 26
CC98 72
CC6   31
CC38 4

would become

CC99 0
CC98 100
CC6   31
CC38 4

The next rule converts CC1 (Mod Wheel) messages to RPN 150 messages:

There is a problem, however. This rule translates the message CC1 67 to the sequence

CC101 1
CC100 22
CC6     0
CC38   67

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

CC101 1
CC100 22
CC6     67
CC38   0

 

Top
Index
 

Known Limitations:

  1. The LSB and MSB fields of the Pitch Bend message are still treated as 2 separate fields with 0 - 127 value ranges. This was not an issue in previous versions of DH_MIDIMunger, because all of the message types to which a Pitch Bend could be converted used values in the range 0 - 127. With the addition of RPN/NRPN support, you should be aware that the rule

         1,PitchB,*,*,*,*,N,*,NRPN,15,15,*,* will translate Pitch Bend 3 25 to
     
    CC99 0
    CC98 15
    CC6   0
    CC38 25

    i.e., the MSB of the Pitch Bend message gets mapped to the sequence's Data Entry LSB, and the Pitch Bend's LSB is ignored. You can map the Pitch Bend's MSB field to the Data Entry MSB using data interpolation, but the Pitch Bend's LSB is still ignored. There is no way to combine the Pitch Bend's LSB and MSB to get a single number with a range of 0 - 16383.
     
  2. There is no way to specify rules for RPNs or NRPNs that use CC96 Data Increment or CC97 Data Decrement messages.
Top
Index
 

 

   

FAQ

  • What if I need more than 10 rules?
    • The recommended method would be to put your rules in a text file.
    • You can also chain multiple DH_MIDIMungers in series, with the MIDI Out of one connected to the MIDI In of the next. This is not recommended if you are using RPNs or NRPNs, or if you are using CC#98 - CC#101 individually, because a one CC message delay is sometimes needed to recognize an RPN or NRPN sequence, and this delay gets multiplied as it propagates through several DH_MIDIMungers.
  • How can I make sure my rule file will be found after I've saved the project as a VST?
    • Use just the file name -- no path -- for the module's File input.
    • Create the file in your SynthEdit directory. SynthEdit will find it there using just the file name.
    • When you save as VST, go to the Embedded Files tab, and add the file. If again, if it is in your SynthEdit directory, it will be saved without a path.
    • When the VST is run, the VST will create a directory into which it will unload your rule file, along with DH_MIDIMunger.sem and any other SDK modules. Because the file has been saved without a path, DH_MIDIMunger will look for it in the same directory as itself, and will find it there.
  • What happens if a rule isn't formatted correctly?
    • Incorrectly formatted rules are simply ignored, as are blank lines.
  • What licensing terms/usage restrictions apply to DH_MIDIMunger?
  • What if I find a bug, or have a question that isn't answered here?
    • To report problems, or to request technical assistance with using DH_MIDIMunger, email dave@dehaupt.com.

     

    DH_MIDIMunger © 2003-2006 David Haupt.  All rights reserved.

    SynthEdit © 2002, Jeff McClintock

Top
Index