Everything you wanted to know about Transform

…except maybe how to use it!

When a Midihub user asks a question like…

“how on earth do I get this [input] to give this [outcome]?”
… the answer will often involve Transform along the way.


See that…


…Transform works by…

…swapping MIDI data…


…around to create new messages!

Watch Animations…

…showing examples of Transform in action!


Then…

…see Transform in 3 sections:

… its ‘Type’

…its ‘Settings’

– giving it the ability to “make anything from anything”

…and its ‘Ranges’

– allowing you to focus precisely on which events to transform!



There’s more in the full list and map of contents, but…




…Let’s get started! :rocket:

1 Like

Preface: Transform is a bit special

Many Midihub pipes manipulate the data a MIDI message carries with it.

Some MIDI message types use three blocks of data called “bytes”


These examples describe a Control Change (#3) and a Note On (“middle C”):


(most others use just one or two “bytes” – only Sysex uses more)

Several of Midihub’s pipes use just one of these pieces of data to change messages of a certain type:


(all these pipes “stay in their column”, as it were)

The Transform pipe can also use information a message carries in its bytes to create a different message…

…but, instead of scaling or shifting the numbers, it does this by swapping data around (or using stored values) to make new messages…

…often of a completely different type:

Transform_vs_other_modifiers2

In addition, whereas other pipes can deal with just a few message types, Transform can handle nearly all of them (Sysex escapes its reach but not much else).




Before going into the details of this seriously powerful tool, let’s look at a few examples

1 Like

Some Animated Examples

All the messages Transform works with can be defined by (up to) three pieces of data.

These are known as the Status Byte, the 1st Data Byte & the 2nd Data Byte.

(The “Status Byte” always tells us what type of MIDI message to expect. With Channel messages it also tells us the channel)

This section shows a few examples of the different ways Transform can do this.

Many of the examples below transform a Note On into a CC message in various ways.

All the examples show Mode set to Replace (i.e. “one in”, “one out”) just to make the animations less fussy.

(plus I’ve stuck them all in disclosures to avoid distraction from several animations at once!)

viewing GIFs

People testing these animations have often wanted to let them run several times to get the ideas.

The Discord technology on this forum lets users on phones, tablets and PCs enlarge jpgs and pngs by clicking…
…but not GIFs it seems.

On a PC you can “Open in a separate Tab” to get a better view of an animation, but with phones and tablets, the only option seems to be going landscape and pinching. Hmm…


1. Transferring data bytes

In this first example we have the simplest Transform where nearly all the incoming data is re-used…

Transform 1

…in the same order as the original message…

0 Repl Id=Id val=vel simp 4_title fade

…the only thing that changes is the “message type” part of the Status Byte…

…changing the meaning of identical data when the message type changes

So a

type 2nd Byte 3rd Byte Ch
Note On C3 (#=60) velocity 87 Ch10
becomes
CC #60 value = 87 Ch10

(and so on for all the notes and velocities in the Transform’s ranges )


2. Swapping data bytes

The second Transform is similar:
all the data from the original message is re-used…
…but here the “data bytes” are swapped around…

Transform 2

So the velocity of the Note On becomes the CC id of the new message…

…and the Note number itself gives the CC value:

1 Repl Id=vel val=id simp 2title fade

:thought_balloon: it might be unusual to have a Transform exactly like this with unrestricted ranges, but when velocity is scaled to just a few values it can be very useful…

A more common use of a swapped property is shown later.


3. Discarding data bytes

Messages like Note On or CC need 3 bytes of data…
…so when we use them to create to a single byte message like Stop, all that extra data is just ignored.

Transform 3

5 Repl NoteOn>Stop

This use of Transform means several properties can be ignored

:game_die: try it yourself:

  • choose any What type from the top of the list (Note On to say Pitch Bend )…

  • then choose any Into type from one of the ‘simple’ types (Start ~ Stop and Tune Request ~ Reset)

    See how all of the Set...To properties become Unused

(this also means that all the Argument properties are also irrelevant - there’s nothing that can be set to them!)

puzzled by “Arguments”? Read on!


4. Providing data bytes

Using Transform the other way around –to make a more ‘complex’ message from a ‘simple’ one – means we’ve got to get that extra information from somewhere.

This is where Transform’s arguments become essential; we need them to fill in the gaps!

Transform 4

Here we’re using the values stored in the Arguments 1 & 2 to set the CC id and value…
…and the Channel Argument to set the Channel:

6 Repl Stop by CC

:pushpin: It is useful to think of Arguments as places for “stored values”, but they don’t have to be fixed
…see the section on arguments for more


5. Employing Arguments

We’ve seen above that you can use Transform without using arguments…
and we’ve seen that certain Transforms absolutely need to use all three arguments.

The next example shows a common usage where we choose to use arguments to get a job done:

Transform 5

Here we create a CC which carries as it’s value the Note Number of an incoming Note On

When we want that CC to be used for a mapping, for example, we often want to fix the CC id and Channel:

2 Repl Id=arg val=id simp 5

Now every note creates a Ch11 CC107 with its value holding the Note Number

:thought_balloon: Use this and Rescale to quickly set different values with a few keys on a keyboard

Or tweak this Transform to “fix” value to Arg 2 and use with a single key to send CC to change an external device…

…or change a channel or port within Midihub itself

:pushpin: we could use Argument 2 instead of Argument 1 above
Switching between the Channel Argument and Argument 1/2 is different as we’ll see next

…see also the section on arguments for more




The last two examples use the new Channel Argument feature.

Some users may prefer to return to these later…


6. Channel Number → Id/Value

Transform can also take a Channel Number and convert it into an “id” or “value”…

Transform 6

…but, to do this, the 16 Channel Numbers are “spread out” across the 128 value range:

3 Repl Id=arg val=inCh 7

the rule for this is “-1 then x 8”
more details in a separate entry


7. Id/Value → Channel Number

lastly, Transform can use an “id” or “value” and convert that to a Channel Number

Transform 7

So here, every Note On creates a CC107…

4 Repl ch=id Id=Arg1 val=inCh 8

…but the channel of CC107 is set by the Note Number itself:

  • the lowest 8 Notes → Channel 1
  • the next 8 Notes → Channel 2
  • the Notes 16-23 → Channel 3
  • etc

the calculation for this conversion could be written "divide by 8ignore the remainderthen +1"
…or maybe:

“what’s the next number in the 8 x table?”

So

  • this Note number is 27…

  • so “the next number in the 8 x table” is 32

  • that’s 4 x 8 so this Note is assigned to CC107 on channel 4

more details on this conversion in a separate entry

2 Likes

Intro & contents

The previous sections gave a rough sketch of what Transform does.
The rest of this topic aims to break things down a bit further and explain things in as non-technical a way as I can.

This tutorial takes it fairly gently using images where I though they might be helpful.
I’ve tried to follow some coherent order but have tried to write it so folks can jump around as they wish.

I’ve also tried to address some of the aspects I’ve seen users puzzled about over the time I’ve been following the forum.

I’ve decided to leave certain ideas for a separate topic called

“Using Transform”**

(some hints & recipes)

As well as reading, I’d encourage readers to keep an Editor open and try changing property parameters. Better still, start a new preset and do some testing of any new ideas before reading on (see Testing)

Here are the sections, written to encourage users to skip back and forth.



extra ideas:


If there’s a key issue for you that I’ve missed out,

please Message me...

…from one of the sections by clicking the icon/avatar at the start…

…I might have already covered that in materials I decided not to publish at this point.

Messaging me allows us to go to and fro to get the best graphics/clarification without cluttering up the flow of the tutorial.

1 Like

Transform has Three Sections

The full array of Transform’s properties can look at bit overwhelming at first…

…but we can break them into sections



We can think of Transform’s properties as falling into 3 sections:


Transform ‘Type’

This tells Transform

  • what incoming message-type it will handle

  • …where to place any new message in the message stream
    (or whether to just to discard – Drop – the incoming message without creating a new one at all)

  • …and –if a new event is being created– which message-type to create

See more detail in the next section

Transform ‘Settings’

Once you have decided what sort of message you want to make, it’s here where you define which values you’ll use to create it.

Transform gives you a lot of choice about this:

  • you can use some of the information contained in the incoming message…

  • …and/or you can use the data stored in the 3 Argument properties

We’ve already seen some animations showing examples of ‘Settings’ in practice :link:
See more detail in the Settings section

Transform ‘Ranges’

Transform has enormous scope, allowing you to focus on, say, just a particular Note On at velocity 127 in Channel 16 or a much wider range of possible messages within your chosen type.

Transforms Ranges are what make this possible.
The Midihub Ranges… section and Transform Ranges graphics will hopefully give you a better understanding of how Transforms Ranges work.



Settings are for Outgoing, Ranges for Incoming

It’s useful to remember that the ‘Ranges’ section decides which particular events ( of the chosen message-type) Transform should act on…

while the ‘Settings’ dictate how those messages which pass the test will be used to create the new event you need.

So, to sum up:

1 Like

The ‘Type’ of a Transform

We can think of Mode, What and Into as creating the “Type” of Transform we want, so…

“PC → CC Replace” or similar…

…would hopefully tell users what type of Transform we’re about to describe in detail

Transform changes MIDI messages into other MIDI messages…

…of a different message-type
Transform_iconEgs

… or maybe the same
Transform_CC_CC


Mode

tells Transform where to place the new message in relation to the incoming:


We can create a new message and Insert Before

Insert Before


…or Insert After the original message

Insert After

Alternatively, Transform can be set to Replace the incoming message…

Replace1


…and lastly, Transform can now be used to just remove certain messages from the MIDI stream…

..using 'Drop'

Drop1

:pushpin: A Drop Transform is like a very particular filter:

Drop will (almost always?) be used with Ranges…
…where, say, all the messages inside a range will be Transformed to a CC…
…but all those outside it will just Dropped

:calendar: As Drop was only introduced in late '23, you may find presets using (say) Replace by Active Sensing Transforms to do the same job that Drop now does
(see also :link:§§ about early versions of Transform)


Before or After?

When we’re using Transform to create a new event alongside the original message…
…it often won’t matter whether your new message is created before or after the original one.

Some times though it will, for example:

  • a CC for a velocity based effect might need to be Insert Before so the synth is tweaked before the the note itself gets played (.mhp :link: anyone?)
  • you might use a Program Change to create a Stop with Insert Before before and then a Continue with Insert After
    • (not sure if these are the best examples Message me with better!)

1 Like

the ‘Settings’ section of Transform

A message-type can carry up to 3 pieces of information with it.

For the message-types we use quite often, I use a shorthand of the ‘id’ and ‘value’ of the message (in addition to the Channel)…

…that tells me the ‘What’, ‘Where’, ‘Which’ and ‘How Much’ of certain MIDI events

for example
(type & Channel) ‘id’ ‘value’
Note On Channel Note Number Velocity
Note Off Channel Note Number Velocity
Control Change Channel CC Number Value
Poly Aftertouch Channel Note Number Pressure
Program Change Channel Program Number n/a
‘What’ ‘Where’ ‘Which’ ‘How Much’

this is very much not standard language, but it helps me to think a little more generally about MIDI messages without using formal language

This informal language will be used in the Ranges section


As hinted at earlier, we have a choice of using the information carried by the incoming message and/or the values stored as “Argument” :asterisk: properties.

This gives us a lot of options…

…which might be a bit overwhelming at first, but soon becomes familiar.

We’ll work through some examples in the “Using Transform” tutorial


Bear in mind that the diagrams show that you’ll always be ignoring some of the data available to you:

  • sometimes we might use none of the values stored in the “arguments”
  • for some uses we might use all three!


:asterisk: why this word “Argument”? see the note later


Most settings combinations in the diagrams above are straight swaps of numbers.

When Channel data is used for other settings –or vice versa– we need to do a little conversion.
We saw this in action in the animated examples

This is explained more here

1 Like

Midihub’s different ranges

Before looking in detail at the Input Ranges of the Transform pipe, it’s useful to consider
how ranges work in some other types of pipe…

…because they’re subtly different in important ways!



This diagram shows Rescale and the Remap-type pipes:


Both types ‘scale’ some aspect of the messages within their ranges…

…but…

See how Remap acts also acts as a Filter…
…messages outside its In-range are blocked

…whereas, with Rescale, every event gets through
(all the values outside are “clipped” – Try It!)


See also with both…
… every (relevant) event is changed in some way

(unless , of course, the Pipe is left with the default “Allow Everything” ranges!)




Transform’s Ranges are quite different:

Every event that falls outside its ranges passes through unchanged – it’s just ignored.

Every event inside the ranges is used to make a new event and –unless it’s Replaced or Dropped– it carries on unchanged.

In Drop mode...

Drop_TRANSFORM_flow
Now all messages within the range are destroyed…
…while those outside just pass through.

:pushpin: this can be very powerful; removing events in a very specific way that could otherwise make the message flow much more difficult




This is a key aspect of Transform’s versatility:

For example…
…one Transform might Replace notes within a velocity range…
…the next Replacing certain other velocity notes…
…with a third transforming only those remaining which are in the highest octaves.

Transform is perhaps the most selective of Midihub’s pipes!

(this wasn’t always so – early versions had no Ranges)


In the next section, we’ll look at how Transform’s ranges work separately and in combination.

1 Like

How Transform’s ranges work

Once you have told Transform What type of messages it will work on…
the Transform’s ranges gives a lot of control over…

…whether to create new messages from all of them –the default–

…or just a select few.



Let’s start with some message types that come with the most information :

Note On, Control Change and Poly Aftertouch


As well as the ‘id’ and ‘value’ carried in their 2nd & 3rd ‘bytes’…

(recall:)
(type & Channel) ‘id’ ‘value’
Note On Channel Note Number Velocity
Control Change Channel CC Number Value
Poly Aftertouch Channel Note Number Pressure
‘What’ ‘Where’ ‘Which’ ‘How Much’

…they all have a channel…

So we can think of the full range of their data as being like a three-dimensional grid

Channel x ‘id’ x ‘value’:


Transform’s ranges (and Channel) let you decide…

…the sections of the grid that you want to focus on.

(like telling it …Where , Which , How Much)

Let’s look at some of the Range properties.



Sticking with Notes, Control Changes and Poly Aftertouch:


The first pair of properties Work with ... in Range Low|High

…let you choose which Notes…
or CC#s…
or Poly Aftertouch Notes…

… Transform will act on:


depending on the message-type…

..the diagram might show:
  • only transforming the 7th octave (of Notes On/Off/On&Off)

  • or acting only on CC#104~111

  • or creating a new message for every Polyphonic Aftertouch event just in octave 7

Remember all the events that don’t fit the criteria just get ignored and pass through





Or, using the second pair of Work with ... in Range Low|High

… you could choose the ranges of velocities (or CC values or Aftertouch pressure values) to act on:


Now

...this diagram could show:
  • triggering a new event only when any note is played fortissimo

  • or transforming only for CC values 106~118

  • or creating a new message whenever Aftertouch Pressure is between 106 and 118




And, of course, these Ranges can be combined
…allowing you to be even more specific:

now…

...the diagram could represent:
  • transforming only the top notes when played at low velocities

  • or acting on only on CC#111~127 for values 0~20

  • or creating a new message whenever gentle Pressure is applied to the high notes



For even more refinement, we can add Work with Channel to our criteria:


Now even if an incoming message matches the type set by What and both Ranges…
…it will be ignored unless it matches the set Channel.

The above diagram could show a Transform which works on a couple of octaves of notes played on Channel 8 at middling velocities, for example.


Transform now has great scope

:thought_balloon:
It’s maybe worth taking a moment…
… to realise that Ranges (and Work with Channel) allow you:

to go from “Transform any message of this type”…

(say every CC# with any value in every channel ~ that’s over 250,000 distinct messages!)

… right down to
…“Transform only this (‘id’) when it has this single (‘value’) when the message is on this channel”


(so, from a huge drag-net to a pair of tweezers, if you like!)




To complete this section, it’s worth noting:

First, that we can

...'invert' ranges...

by selecting Use Value = Outside Range

As well as being useful when the ‘ids’ or ‘values’ we want are at both ends of the full range…

…it’s very handy when we have two Transforms that together cover the whole of the range

…and virtually essential if we want to map the Range settings of those two Transforms:


Second, that the same ideas apply to

messages with MSB and LSB...


…for Pitch Bend this shows messages being created for a bunch of ‘Fine’ values… …but only when the lever is over on the the Left (giving low ‘Coarse’ values)

…whereas with Song Position Pointer it could mean firing off a new event when a sequencer tells Midihub it’s at certain places in the song :


Third, that the first range…

...can be used for some other types:

like Program Change, Channel Pressure and Song Select

(You’ll notice that the properties for the 2nd Range change to (Unused) when What is set to these types – see “Transform’s Properties Change with Message Type” )

And, finally, that the ‘simplest’ message types:
Start, Continue, Tune Request, Clock, Active Sense, Reset…
don’t have any ranges to restrict!

1 Like

That completes the main flow of this tutorial topic

In a nutshell…

…we have seen that Transform takes messages of one data type …

...

… or a subset of those messages …

(the full range of the messages of the chosen type can be narrowed by restricting the Ranges or the Channel that the Transform acts on)

…and can create new messages

...

…either replacing the original message or by creating one before or after…

by swapping their data bytes or replacing them

...

…with a choice of those stored as Transform‘s three Argument parameters

Or by using Drop, Transform can simply remove those particular events from the message stream

see next…

for a few FAQs and some background information,

1 Like

What’s the Argument?

Some users have been puzzled by the terms Argument 1, Argument 2 (and now Channel Argument)

Like a lot of English words, “Argument” has several distinct meanings

here are three

  1. A heated discussion
    “They got into a big argument about his drinking”

  2. Reasoning offered as proof or persuasion
    “Give me your arguments for & against investing in stocks & shares”

  3. a quantity used by a mathematical or computing function
    "if we make the arguments of rectangleArea(l,w) equal, we get the area of a square"

Midihub’s Transform uses the third meaning, so in our context we can think “Argument” = “stored value”

PS

As a native English speaker, I’ve never really known why mathematicians started using the word in this sense.

Poring over early refs –all the ways back to Chaucer– I have hunch that “argument” had an early sense of a container which sort of fits with meanings 2 & 3.

Most native English speakers, IMO, associate “argument” with conflict - very much not the Transform meaning!

1 Like

Note On & Off

There is no MIDI message called Note On & Off

“Note On & Off” is useful when converting Notes to another message type:

If you used Note On…

…you would need a second Transform for the Note Off messages

So Note On & Off saves time and pipes!

NB. Into set to Note On & Off does not create two events at the same time!


Prioritize Real-Time?

MIDI system real-time messages are messages that are not specific to a MIDI channel but prompt all devices on the MIDI system to respond and to do so in real time.

as suggested by the MIDI 1.0 specification:

To help ensure accurate timing, System Real Time messages are given priority over other messages, and these single-byte messages may occur anywhere in the data stream (a Real Time message may appear between the status byte and data byte of some other MIDI message).

So normally, the Real Time MIDI messages get pushed right at the front of the MIDI message queue, so they get in front of the remaining non-realtime data, such as Note On, CC, etc… Disabling Prioritize Real-Time will actually place the produced real-time messages not at the front, but the back of the queue, so whatever Transformation you’re working on, stays in that order.
An example where this was needed was discussed here

One of those things to bear in mind when the order of events like Transport controls might be critical


Channel Number conversions

Transform has always been able to take an “id” and create a “value” from it

for example,

  • Note On #64 (say, velocity 37) → CC#3 value = 64

    or vice versa

  • CC#3 value = 64 → Note On #64 (say, velocity 127)

Now (from version 1.15), Transform can use an “id” or “value” to also set Channel data…

...but it's not just a straight swap!

Channel Number → Id/Value

Transform has to allocate all 128 "id"s or values to just 16 channels, so it does the same as when a controller knob is mapped to a channel property
(eg. the In|Out Low|High properties of Channel Remap) …

so, for example…

  • values 0-7 → Channel 1
  • values 32-39 → Channel 5
  • values 120-127 → Channel 16

Animation 7 shows an example for this :link:

Id/Value → Channel Number

Transform can also use Channel data to set an “id” or “value”

to set an id/value from the channel, Transform simply chooses the first value from its corresponding set…

…eg:

  • Channel 1 → value 0
  • Channel 5 → value 32
  • Channel 16 → value 120

This type of conversion is shown in Animation 6

1 Like

Transform is now bigger and better…

Earlier versions of Transform were much more limited:

TRFM_1.11.10

At first, Transform didn’t have the power of Ranges or Work with Channel .

This meant

  • “early” Transform would work on (say) every Note On at every Velocity regardless of Channel

  • which meant that often the only option was to use separate pipelines with filters to do the kinds of selection we saw in the Ranges section

Ranges were introduced in 2022 and made a

huge difference


(2020 preset with Note On → CC Insert Before Transforms)

Even if the incoming Note#'s or the outgoing CC#'s had no pattern, 2022 Transform could do all this in one line

Happily in this case, the Notes → CCs followed the pattern [60…69] → [40…49], so…

…the 10 Transforms could all be replaced by just one Transform followed by a CC Remap

This is something to be alert to when using older presets from this forum or patchstorage; the approach might have been the best possible then – now the same result might be achieved more simply and directly.

We’ll go into this in more detail in the forthcoming “Using Transform” Topic :smile:

1 Like

Testing Transform

You may have read through the sections above…

…without Midihub connected…

…maybe looking at the Editor…

… or just reading on a 'phone or tablet.

Transform starts to make real sense when using it in practice…
…sending messages through versions of Transform pipes

This can done by creating a patch just to test Transform’s settings themselves…

…and Monitoring the output as messages are sent in.

(no need to overwrite any of your precious stored presets, just save it file)




Try creating this:

There are already enough hints in the 3 diagrams to figure out what the blue Transform settings and ranges are…

…but we’ll return to this in the “Using Transform” tutorial

Try it! (Remember the mapping must come from Virtual-A to use the newly-scaled values ) :smile:



Meantime, the next section covers what this Transform Test shows…

1 Like

Transform’s Properties Change with Message Type

We saw right at the start that Transform works by swapping data around

Transform_vs_other_modifiers2
and saw some animated examples to show this swapping in action.

In the very first version of Transform, the (generalised) structure of MIDI data was more obvious…

TRFM_1.11.3

…but the meaning of the data-bytes of each message type wasn’t made explicit…


Blokas soon decided to make Transform show those values as we see them…

  • Note#, Velocity

  • CC#, Value

  • Pitch Bend LSB (fine), Pitch Bend MSB (fine)

  • etc

…giving us Transform Properties that…

...Change with Message Type

SettingContextMac2m

See how changing Into changes the meaning of the outgoing message’s data.

Make the testing patch hinted at in Testing Transform to see this idea live for yourself!

So changing the What and Into properties will change words you see elsewhere in Transform:

Try yourself to see how changing the What will change the wording of 6 properties at the bottom of the pane.

:eye_in_speech_bubble: Sometimes property labels will appear as Unused if that property isn’t possible with your choice of What & Into


Table of MIDI message types used by Transform…

...and their other data

note

As well as formal MIDI terms ‘Status Byte’, ‘2nd Byte’, ‘3rd Byte’…
… the columns include looser terms ‘id’ and ‘value’

… and the ‘everyday’ terms ‘What’, ‘What’, ‘Which’ & ‘How Much’

I find these useful to ‘ground’ the meaning of what I’m doing…
…others may not!

Status 2nd Byte 3rd Byte Channel ‘nibble’
3-byte messages
type ‘id’ ‘value’ channel
‘What’ ‘Which’ ‘How Much’ ‘Where’
Note On Note Number Velocity yes
Note Off Note Number Velocity yes
“Note On & Note Off” Note Number Velocity yes
Control Change CC Number Value yes
Poly Aftertouch Note Number Pressure yes
Program Change Program Number n/a yes
Song Select Song n/a n/a
3-byte messages (High Res Values)
‘What’ ‘How Much (Fine)’ ‘How Much (Coarse)’
Pitch Bend Pitch Bend LSB Pitch Bend MSB yes
Song Position Pointer Song Pos LSB Song Pos MSB n/a
2-byte messages
‘How Much’!
Channel Pressure Pressure n/a yes
~
1-byte messages
‘What’ Everywhere!
Start n/a n/a n/a
Continue n/a n/a n/a
Tune Request n/a n/a n/a
Clock n/a n/a n/a
Active Sense n/a n/a n/a
Reset n/a n/a n/a
1 Like

this section has information that some users might want to turn to


Appendix 1

A summary of MIDI data bytes for Transform message types

A grouped summary of MIDI data bytes:
Status Bytes Meaning 2nd Byte 3rd Byte
80 - 8F Note off + Ch. Note Number (0-127) Note Velocity (0-127)
90 - 9F Note on + Ch. Note Number (0-127) Note Velocity (0-127)
A0 - AF Poly Aftertouch + Ch. Note Number (0-127) Pressure (0-127)
B0 - BF Control Change + Ch. CC Number (0-127) CC Value (0-127)
C0 - CF Program Change + Ch. Program Number (0-127) none
D0 - DF Channel Aftertouch + Ch. Pressure (0-127) none
E0 - EF Pitch Bend Change + Ch. Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
F2 Song Position Pointer LSB MSB
F3 Song Select Song Number (0-127) none
F6 Tune request none none
F8 Timing clock none none
FA Start none none
FB Continue none none
FC Stop none none
FE Active Sensing none none
FF System Reset none none

(there are few Status Byte values that Transform doesn’t work with. These rows have been removed)

This summary based the “Expanded MIDI 1.0 Messages List (Status Bytes)” from midi org

This is no longer available on their site as of 2024 - it is archived here

Nowadays Google Drive versions can be found here


Appendix 2

A summary of data bytes for all MIDI message types

Including Hex codes...

Hex codes are useful when using the MIDI Monitor pane in its Raw Display

Notice how, for the first types (starting 8, 9, A, …, D ), the Status Byte also holds the Channel Information.

The Status Byte is given in hex with the decimal value in brackets

Status Byte Meaning 2nd Byte 3rd Byte
80 (=128) Ch.1 Note off Note Number (0-127) Note Velocity (0-127)
81 (=129) Ch.2 Note off Note Number (0-127) Note Velocity (0-127)
82 (=130) Ch.3 Note off Note Number (0-127) Note Velocity (0-127)
83 (=131) Ch.4 Note off Note Number (0-127) Note Velocity (0-127)
84 (=132) Ch.5 Note off Note Number (0-127) Note Velocity (0-127)
85 (=133) Ch.6 Note off Note Number (0-127) Note Velocity (0-127)
86 (=134) Ch.7 Note off Note Number (0-127) Note Velocity (0-127)
87 (=135) Ch.8 Note off Note Number (0-127) Note Velocity (0-127)
88 (=136) Ch.9 Note off Note Number (0-127) Note Velocity (0-127)
89 (=137) Ch.10 Note off Note Number (0-127) Note Velocity (0-127)
8A (=138) Ch.11 Note off Note Number (0-127) Note Velocity (0-127)
8B (=139) Ch.12 Note off Note Number (0-127) Note Velocity (0-127)
8C (=140) Ch.13 Note off Note Number (0-127) Note Velocity (0-127)
8D (=141) Ch.14 Note off Note Number (0-127) Note Velocity (0-127)
8E (=142) Ch.15 Note off Note Number (0-127) Note Velocity (0-127)
8F (=143) Ch.16 Note off Note Number (0-127) Note Velocity (0-127)
90 (=144) Ch.1 Note on Note Number (0-127) Note Velocity (0-127)
91 (=145) Ch.2 Note on Note Number (0-127) Note Velocity (0-127)
92 (=146) Ch.3 Note on Note Number (0-127) Note Velocity (0-127)
93 (=147) Ch.4 Note on Note Number (0-127) Note Velocity (0-127)
94 (=148) Ch.5 Note on Note Number (0-127) Note Velocity (0-127)
95 (=149) Ch.6 Note on Note Number (0-127) Note Velocity (0-127)
96 (=150) Ch.7 Note on Note Number (0-127) Note Velocity (0-127)
97 (=151) Ch.8 Note on Note Number (0-127) Note Velocity (0-127)
98 (=152) Ch.9 Note on Note Number (0-127) Note Velocity (0-127)
99 (=153) Ch.10 Note on Note Number (0-127) Note Velocity (0-127)
9A (=154) Ch.11 Note on Note Number (0-127) Note Velocity (0-127)
9B (=155) Ch.12 Note on Note Number (0-127) Note Velocity (0-127)
9C (=156) Ch.13 Note on Note Number (0-127) Note Velocity (0-127)
9D (=157) Ch.14 Note on Note Number (0-127) Note Velocity (0-127)
9E (=158) Ch.15 Note on Note Number (0-127) Note Velocity (0-127)
9F (=159) Ch.16 Note on Note Number (0-127) Note Velocity (0-127)
A0 (=160) Ch.1 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A1 (=161) Ch.2 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A2 (=162) Ch.3 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A3 (=163) Ch.4 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A4 (=164) Ch.5 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A5 (=165) Ch.6 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A6 (=166) Ch.7 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A7 (=167) Ch.8 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A8 (=168) Ch.9 Poly Aftertouch Note Number (0-127) Pressure (0-127)
A9 (=169) Ch.10 Poly Aftertouch Note Number (0-127) Pressure (0-127)
AA (=170) Ch.11 Poly Aftertouch Note Number (0-127) Pressure (0-127)
AB (=171) Ch.12 Poly Aftertouch Note Number (0-127) Pressure (0-127)
AC (=172) Ch.13 Poly Aftertouch Note Number (0-127) Pressure (0-127)
AD (=173) Ch.14 Poly Aftertouch Note Number (0-127) Pressure (0-127)
AE (=174) Ch.15 Poly Aftertouch Note Number (0-127) Pressure (0-127)
AF (=175) Ch.16 Poly Aftertouch Note Number (0-127) Pressure (0-127)
B0 (=176) Ch.1 Control Change CC Number (0-127) CC Value (0-127)
B1 (=177) Ch.2 Control Change CC Number (0-127) CC Value (0-127)
B2 (=178) Ch.3 Control Change CC Number (0-127) CC Value (0-127)
B3 (=179) Ch.4 Control Change CC Number (0-127) CC Value (0-127)
B4 (=180) Ch.5 Control Change CC Number (0-127) CC Value (0-127)
B5 (=181) Ch.6 Control Change CC Number (0-127) CC Value (0-127)
B6 (=182) Ch.7 Control Change CC Number (0-127) CC Value (0-127)
B7 (=183) Ch.8 Control Change CC Number (0-127) CC Value (0-127)
B8 (=184) Ch.9 Control Change CC Number (0-127) CC Value (0-127)
B9 (=185) Ch.10 Control Change CC Number (0-127) CC Value (0-127)
BA (=186) Ch.11 Control Change CC Number (0-127) CC Value (0-127)
BB (=187) Ch.12 Control Change CC Number (0-127) CC Value (0-127)
BC (=188) Ch.13 Control Change CC Number (0-127) CC Value (0-127)
BD (=189) Ch.14 Control Change CC Number (0-127) CC Value (0-127)
BE (=190) Ch.15 Control Change CC Number (0-127) CC Value (0-127)
BF (=191) Ch.16 Control Change CC Number (0-127) CC Value (0-127)
C0 (=192) Ch.1 Program Change Program # (0-127) none
C1 (=193) Ch.2 Program Change Program # (0-127) none
C2 (=194) Ch.3 Program Change Program # (0-127) none
C3 (=195) Ch.4 Program Change Program # (0-127) none
C4 (=196) Ch.5 Program Change Program # (0-127) none
C5 (=197) Ch.6 Program Change Program # (0-127) none
C6 (=198) Ch.7 Program Change Program # (0-127) none
C7 (=199) Ch.8 Program Change Program # (0-127) none
C8 (=200) Ch.9 Program Change Program # (0-127) none
C9 (=201) Ch.10 Program Change Program # (0-127) none
CA (=202) Ch.11 Program Change Program # (0-127) none
CB (=203) Ch.12 Program Change Program # (0-127) none
CC (=204) Ch.13 Program Change Program # (0-127) none
CD (=205) Ch.14 Program Change Program # (0-127) none
CE (=206) Ch.15 Program Change Program # (0-127) none
CF (=207) Ch.16 Program Change Program # (0-127) none
D0 (=208) Ch.1 Channel Aftertouch Pressure (0-127) none
D1 (=209) Ch.2 Channel Aftertouch Pressure (0-127) none
D2 (=210) Ch.3 Channel Aftertouch Pressure (0-127) none
D3 (=211) Ch.4 Channel Aftertouch Pressure (0-127) none
D4 (=212) Ch.5 Channel Aftertouch Pressure (0-127) none
D5 (=213) Ch.6 Channel Aftertouch Pressure (0-127) none
D6 (=214) Ch.7 Channel Aftertouch Pressure (0-127) none
D7 (=215) Ch.8 Channel Aftertouch Pressure (0-127) none
D8 (=216) Ch.9 Channel Aftertouch Pressure (0-127) none
D9 (=217) Ch.10 Channel Aftertouch Pressure (0-127) none
DA (=218) Ch.11 Channel Aftertouch Pressure (0-127) none
DB (=219) Ch.12 Channel Aftertouch Pressure (0-127) none
DC (=220) Ch.13 Channel Aftertouch Pressure (0-127) none
DD (=221) Ch.14 Channel Aftertouch Pressure (0-127) none
DE (=222) Ch.15 Channel Aftertouch Pressure (0-127) none
DF (=223) Ch.16 Channel Aftertouch Pressure (0-127) none
E0 (=224) Ch.1 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E1 (=225) Ch.2 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E2 (=226) Ch.3 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E3 (=227) Ch.4 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E4 (=228) Ch.5 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E5 (=229) Ch.6 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E6 (=230) Ch.7 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E7 (=231) Ch.8 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E8 (=232) Ch.9 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
E9 (=233) Ch.10 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
EA (=234) Ch.11 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
EB (=235) Ch.12 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
EC (=236) Ch.13 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
ED (=237) Ch.14 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
EE (=238) Ch.15 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
EF (=239) Ch.16 Pitch Bend Change Pitch Bend LSB (0-127) Pitch Bend MSB (0-127)
F0 (=240) System Exclusive ** **
F1 (=241) MIDI Time Code Qtr. Frame -see spec- -see spec-
F2 (=242) Song Position Pointer LSB MSB
F3 (=243) Song Select Song Number (0-127) none
F4 (=244) Undefined (Reserved)
F5 (=245) Undefined (Reserved)
F6 (=246) Tune request none none
F7 (=247) End of SysEx (EOX) none none
F8 (=248) Timing clock none none
F9 (=249) Undefined (Reserved)
FA (=250) Start none none
FB (=251) Continue none none
FC (=252) Stop none none
FD (=253) Undefined (Reserved)
FE (=254) Active Sensing none none
FF (=255) System Reset none none

Appendix 3

Hex Codes: a brief note

Raw Display

if you switch from the “normal” MIDI Monitor display to Settings → Raw Display you’ll noticed the codes in the Raw Display don’t often match the “normal” numbers

Let’s put the two display styles side-by side:

The raw data is shown in “hexadecimal” numbers…
…where we count in 16’s

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 1 2 3 4 5 6 7 8 9 a b c d e f

Using ‘28’ in ‘hex’… as an example:

  • it’s pronounced “two - eight”…

  • …and means 2 x 16 + 8

  • which equals 40 in decimal.

Let’s look down the list
(For now we’re going to ignore the “Status Byte” on the left of the 3 codes)

  • Note Off 4 8 → 80 04 08
    the 04 08 matches with Note 4, velocity 8

  • Note On 4 16 → 90 04 10
    the 10 is code for 1 x 16 + 0 so matches with velocity 10

  • CC 4 24 → b0 04 18
    the 18 is code for 1 x 16 + 8 so matches with value 24

  • Aftertouch 4 40 → a0 04 28
    the 24 is code for 2 x 16 + 8 so matches with value 40

(The other thing that can confuse is that MIDI counts channels from 0-15 so channel 0 in raw data = channel 1 in human terms! )

End of Transform Tutorial Part One

2 Likes