Missing MIDI Manual

   2135   0   2
User Avatar
Member
28 posts
Joined: March 2014
Offline
I have been exploring MIDI inside of Houdini. This involves digging into CHOPs which has always intimidated me. The documentation is pretty thin, and I had hard time finding simple examples. The good news is that with a few leaps of understanding, working with MIDI inside of Houdini is pretty easy. My goal in documenting my explorations here is to that I might be able to find in when in the future, and hopefully to help shorten the learning curve for other folks.

This isn't really going to be a comprehensive manual, but an example walk-through that should get folks started.

Also note that this first example is based on the one and only MIDI-in example that comes with Houdini. While I made many changes to simplify their example, I can's say I thought up the cool trick they do with the channel indexes in the primitive node.

One thing before we get started, the word "channel" is used a lot in MIDI and a lot in Houdini. Since this post is about the intersection of the two, we need to keep things clear. So I will use "MIDI channel" to talk about the 16 MIDI channels that each MIDI port on a synthesizer or DAW can read/write. And "Houdini channel" to talk about how information is passed from one node to another, not necessarily directly connected, node.

For folks coming from a music background using DAW (Digital Audio Workstation) this is how they are used to working with MIDI:



This is a typical MIDI piano roll. Time is on the X axis, note number in on the Y axis. The piano keys on the left are a guide to which notes are being played.

This can be saved in a MIDI file (*.mid) which is compressed and requires a MIDI fluent program to read. If one dumps a simple MIDI file, it looks like this:

TIMESTAMP IN PORT STATUS DATA1 DATA2 CHAN NOTE EVENT
0000E4EC 2 3 90 48 3B 1 C 5 Note On
0000E5C6 2 3 80 48 40 1 C 5 Note Off
0000E6E2 2 3 90 4A 45 1 D 5 Note On
0000E7A9 2 3 80 4A 40 1 D 5 Note Off
0000E8D1 2 3 90 4C 40 1 E 5 Note On
0000E972 2 3 80 4C 40 1 E 5 Note Off
0000EAD4 2 3 90 4D 32 1 F 5 Note On
0000EB82 2 3 80 4D 40 1 F 5 Note Off
0000ECC4 2 3 90 4F 3B 1 G 5 Note On
0000ED75 2 3 80 4F 40 1 G 5 Note Off
0000EEAB 2 3 90 51 2C 1 A 5 Note On
0000EF5B 2 3 80 51 40 1 A 5 Note Off
0000F08F 2 3 90 53 2D 1 B 5 Note On
0000F14E 2 3 80 53 40 1 B 5 Note Off
0000F290 2 3 90 54 54 1 C 6 Note On
0000F64F 2 3 80 54 40 1 C 6 Note Off

It's basically a list of events, in this case "Note On" and "Note Off", and the time when they happen. There's also a note number which is being turned on or off. Also in this list is which MIDI channel the note is being sent on (in this example, channel 1). Also for each note there is a "velocity" parameter. This corresponds to how hard a key is hit on a keyboard (I'll get to this later). MIDI can get a lot more complicated than this, but let's start simple.

To read MIDI into Houdini, you need to create a CHOP network (usually inside a geo node or other obj level node)



Dive inside this and add a "MIDI In" node. Let's look at the important parameters, first the "Source" tab.



Set the parameters as shown above. Make sure to set the "MIDI File" to the actual location of your file. I have attached a super simple file to this post. I would suggest using this file just to make this walk through easier.

The MIDI Channels parameter sets which of this incoming channels should be fed forward. To keep things simple, set it to just the channels used in your file. For the attached MIDI file, set it to 1.

Next is "Channel Prefix", this an important key in the interface between MIDI channels and Houdini channels. I would suggest for now leave it at its default "ch".

If you check "Echo Messages to Textport" you get something that looks like this:

MIDI Event: 0 : Note On : channel 1 : 72 : 88
MIDI Event: 500000 : Note Off : channel 1 : 72 : 64
MIDI Event: 500000 : Note On : channel 1 : 74 : 79
MIDI Event: 500000 : Note Off : channel 1 : 74 : 64
MIDI Event: 500000 : Note On : channel 1 : 76 : 50
MIDI Event: 500000 : Note Off : channel 1 : 76 : 64
MIDI Event: 500000 : Note On : channel 1 : 77 : 44
MIDI Event: 500000 : Note Off : channel 1 : 77 : 64
MIDI Event: 500000 : Note On : channel 1 : 79 : 45
MIDI Event: 500000 : Note Off : channel 1 : 79 : 64
MIDI Event: 500000 : Note On : channel 1 : 81 : 45

You can see the data is there, the time seems to be messed up, but everything seems to work. I would ignore this output unless you really need it.

Next look at the "Note" tab:



Here the important parameters are the "Note Name" . This the second key in the MIDI channel to Houdini channel translator. Again, suggest keeping it as "n".

The parameter "Note Scope" controls the range of MIDI notes that are passed forward. The default 1-88 passes all the notes from an 88 key keyboard. MIDI can support more notes, they don't have to come from keyboards. But for now leave it at its default.

The "Note Output" parameter is also important. This determines if you are going to have one Houdini channel for all the notes in the incoming MIDI channel, or multiple Houdini channels, one for each note on the keyboard. To get the former, set this parameter to "One Multiplexed Channel". To get the latter, set it to "Separate Channels". This parameter provides two very different ways of dealing with a MIDI note stream. The one you chose depends on what you want to do with the data.

A good way to think about "One Multiplexed Channel" is a single pipe, with all the notes coming down one pipe, kind of like an audio wave but much slower. This seems the obvious way to use MIDI data. Conceptually you might think of it something like this;

72,74,76,77,79,81...

But really the pipe is carrying note on and off message:

72 on,72 off,74 on,74 off,76 on,76 off,77 on,77 off,79 on, 79 off,81 on, 81 off...

While this stream can certainly be used, it's not the natural way to thing of a string of notes. A more useful approach, at least to start, is to think of each note number having its own Houdini channel. This channel only contains note on/off events when the note should "sound". Just think of a piano, each key is a separate Houdini channel. Or think of musical notation, each key is a Houdini channel. Which is how all the DAWs in the world ended up representing MIDI stream like this:



This is what you get when "Note Output" is set to "Separate Channels"

Finally, a good way to pull all this together is to click on the MIDI in node, and hit the "i" information button, you'll see something like this:



The important thing here is the list of Houdini channels. Notice there is a channel for each note. The channels are named based on the MIDI channel and the note number. For example "ch1n74" is the MIDI channel one and the note number 74. This name of the Houdini channel for this note stream. The "ch" and "n" are set above, the "1" is the MIDI channel, and the "74" is the note number. If we want to receive information about this note in another node, this the channel name that we will use to get that information.

Note that Houdini understand situations there are situations where you might have a whole bunch of channels and your going to want to use them all individually. This is handled through Houdini functions that take both a channel name and an index. The index basically lets a node step through all of the channels without actually knowing their names. We'll use this to great effect below.

Here's the most basic MIDI in CHOP:



So now we have 88 (in this case) Houdini streams of note on/off messages. The Houdini channel functions will output 1 when the note is on and 0 when the note is off. This channel can be use do to anything anywhere in your project. The channel is accessed using the chopcf() function. The first parameter of this function is a path to the CHOP, usually an output null. The second parameter is an index, which lets us use just one chop function call to access 88 (or more) Houdini channels. As mentioned above, this is a real time saver for MIDI work. The third parameter is the frame number that the function should return the channel value for. Usually this looks something like this:

chopcf("../chopnet1/out", $PR, $F)

The parameters $PR is the primitive number. Since the line has 88 points, $PR is run from 1 to 88, accessing each MIDI note number in turn. As mentioned, you can use this function anywhere, scaled as needed, to do anything. Here's a super simple example:



Beside the chopnet, there's a line (with 88 points). A sphere, that we can use to copy to each point. Then the copy to points node. So far all basic stuff. Finally, there is a primitive properties node. This is where we suck in the MIDI stream and use to great effect:



To get things flowing, start the animation timeline



Each time a MIDI note goes on, the little ball does up. When it goes off, the little ball goes back down. Not really that exciting, but usually simple examples are the easiest to understand.

Also, to make the transition from "note on" to "note off" a little smoother, you can add envelope node after the MIDI in:



Hope this is helpful, further updates as events warrant.
Edited by Reynold Dodson - April 19, 2022 19:59:28

Attachments:
chop.png (10.1 KB)
chopnet1.png (3.8 KB)
envelope.png (13.9 KB)
geo.png (21.8 KB)
midi-animation.gif (359.1 KB)
midiin-info.png (88.5 KB)
midiin-note.png (17.2 KB)
midiin-source.png (14.3 KB)
notes-in-live.png (12.0 KB)
primitive.png (34.9 KB)
chops-MIDI-v2.hiplc (256.2 KB)
Simple.mid (307 bytes)

  • Quick Links