MIDI


Introduction

This article explores various facets of ABox's MIDI implementation. It starts with an introduction to MIDI, MIDI Streams, the Midi In and Out objects, and describes the numbers and units you'll be working with.
The rest of the text details 4 applications:
  1. Playing the sound card's on-board synthesizer.
  2. Playing VST Instruments.
  3. Keyboard playable circuits.
  4. Connecting ABox to a sequencer with Hubi's Midi Loopback.
The best way to use this page is to make your browser narrow, launch ABox2, then position ABox2 along side. Then you can click on most of the circuits to send them to ABox.


MIDI

MIDI is the standard language that synthesizers, sequencers, keyboards, and controllers use to talk to each other. The language is very simple and consists of only 8 instructions. Most of them are just terse statements like "Turn on this note."
  1. Note On "Turn on this note on."
  2. Note Off "Turn this note off."
  3. Note Pressure "Press this note this hard."
  4. Pitch Wheel "The pitch wheel is at this position."
  5. Pressure "Press the keyboard this hard."
  6. Patch Number "The patch for this channel is ..."
  7. Controller "This controller's value is ..."
  8. Port commands. Timing information.
The first seven MIDI commands require a channel number. There are 16 channels available on each MIDI cable. Each channel may have different equipment attached to it. For example, on channel 5, you could have a keyboard and a synthesizer. The keyboard will send commands only to the synthesizer. Commands sent on the other 15 channels will be ignored.
The Controller command is used to adjust one of a large number of parameters. The Mod Wheel, for example, is assigned to controller number 1. So the command "Controller 1's value is 0" sets the Mod Wheel to it's lowest position.

When working with MIDI, you'll use the 8 commands to build sequences of instructions, or build sensors to respond to particular instructions by adjusting parameters on a synthesizer. Some commands are used far more often than others. For example, Note On and Note Off are probably the most used, while Patch Number might only be used once.

Inside an ABox circuit, you'll use MIDI Streams along with Midi In and Midi Out objects to manipulate MIDI commands.


MIDI Streams

Working with MIDI inside of ABox requires using MIDI streams. MIDI streams behave like a MIDI cable, there are 16 channels to send commands on. Unlike a MIDI cable, MIDI Streams only send commands in ONE direction.
Stream commands are often called events. This is to emphasize that a command is only a short, one-time, terse occurrence. Something must respond to the event, react accordingly, and perhaps, remember that the event occurred. Working with streams is all about building and/or responding to events.
Use a Midi In object to bring stream commands IN to a circuit as analog data. Use a Midi Out object to send analog data OUT to a MIDI stream. Either object may be connected to a hardware device such as a real MIDI port or on-board synthesizer.


Midi In and Midi Out

Midi In is used to extract events from a stream, in other words, it is a MIDI filter. It can have one input and up to 4 outputs. Use this object to build sensor circuitry that responds to MIDI events. Midi In can also be used as part of a polyphonic note tracking system.
The input may be a hardware device such as a MIDI port, or it may be a MIDI stream input pin (si). Input may also be a note tracker, in which case the object represents one note.
The output depends one which commands you are removing. You'll usually have at least one output, so or stream out. The data at this pin is always the remainder of the commands that you have not removed. For example, if you filter out the commands on channel 1, so will be the rest of the commands on channels 2-16. Data from the filtered commands will appear at the other three output pins.

Midi Out is the opposite of Midi In. It is used to insert commands into a stream. It can have up to 4 inputs and 1 output. The output may be to a hardware device such as a MIDI port, or it may be to an output pin (so).

There will always be at least one input pin, si or stream in. si stream data is merged with the events generated by the object. The other 3 inputs depend on the selected command. For example, if you set the object to generate Pitch Wheel commands, you'll see the V input pin that tracks the input data and generates pitch wheel events when appropriate. The new commands can be merged with another stream, containing note data for example. The combined stream can then be sent to a device.

On both objects, you'll see N and V pins. N is typically the number portion of a command, the controller number for example. V is typically the value portion of the command, the value of controller N. Both N and V are assumed to be midi numbers (see below).

Midi Out may show a t input trigger. This indicates that the command will only be sent when t changes sign. If the t input is not present, the commands will automatically be sent when appropriate.
Midi In will often display a ± output pin. This value changes sign to indicate that an event was received. It can optionally be used to trigger a Sample and Hold or any other object that needs a trigger event. In note tracker mode, however, the ± output indicates whether the note is on or off.


Units and Numbers

There are two units you'll be working with, midi and stream. Knowing the difference between these will help you understand what a particular section of circuitry is doing.
When you see the midi unit or color on a knob or readout you're working with analog data. Midi numbers always range from 0 to 128. With the exception of the pitch wheel, negative numbers are converted to positive, so -52.3 is the same as +52.3. When midi numbers are inserted into a stream, they are rounded to the closest whole number. So midi 52.3 gets rounded to 52.
When you see the stream unit or color, you're looking at MIDI commands. There are no displayable numbers associated with streams.


Applications

The example circuits may require that you tell ABox what devices you want to use.
  1. Playing the sound card's on-board synthesizer.
  2. Playing VST Instruments.
  3. Keyboard playable circuits.
  4. Connecting ABox to a sequencer with Hubi's Midi Loopback.


Ex1: Playing the sound card's synthesizer

This series of examples builds a simple random note player to illustrate basic Midi Out operation, nothing very musical. The output is to the onboard wave table synthesizer. If you don't hear any sound, right click on the Midi Out object and select another device.

We start with a 120 BPM square wave triggering a Random object. The bottom knob (7.01568 midi) sets the range of the generated notes. The top knob (58.7754 midi) scoots the notes up to about middle C. Example 1.1

The Midi Out object at the top right is set to track N mode. Track N monitors the N pin and emits Note On/Off events when N changes. The V input is the note velocity, how hard the note was struck. In this case, V sets the volume of the note.
You may notice that the sequence is not always playing quarter notes. In track N mode, N has to change enough to send a different midi note. Since notes are rounded, when N changes from 52.3 to 51.9, it results in the same midi note, 52.

Now let's add a patch change. The Midi Out is set to patch N mode. In this mode, a Patch Change command is sent when t triggers. The patch number comes from the N pin. Example 1.2 The output is a MIDI stream connected to the si input of the Midi Out in the previous example. In this way, we don't need to open another device, we just daisy-chain Midi Out's and let the stream merge do the rest.

Useful trick with the Delta object (triangle in the circle): When you turn the knob, the delta object goes negative. When you stop turning the knob, the delta object goes to zero, causing the positive edge t input to trigger. This has the added benefit of setting the patch when the circuit first starts playing.

Now we'll add two more notes on another channel. First, run the 120 BPM square wave into a divider via bus t8. The divider counts to 4 then outputs a trigger to bus t2. Random gets it's range from the 7.0158 knob (see above) and outputs numbers to the two knobs in the middle. Example 1.3

The two Midi Outs are set to track t mode and emit events on channel 2. Track t emits Note On when t goes positive to negative and Note Off on the negative to positive edge. Try changing the count on the divider to 2 or 3 to here the difference. V data comes from the 100.509 knob in the previous circuit.
The Midi Outs are chained together and the results sent to si input of the patch change object.

As a final touch, we'll add a sweeping pitch wheel to the first note generator. Example 1.4

The Pitch Wheel command requires only a V input, supplied by the sine wave. The sine wave gets it's frequency from the 120 BPM knob. The 17.6 knob sets the pitch wheel range, in this case just enough to add some pathos to an already macabre circuit. Try other wave shapes and ranges as well.



Ex2: Playing VST Instruments

This series of circuits demonstrates using MIDI streams to play VST instruments. Each of the examples uses MDA's DX10 plugin. If you don't already have this well written electric piano synth, download it from MDA's web site (choose VST Synths from the menu bar and follow the ever changing path to the final download site).

To use VST plugins in ABox you need to tell ABox where they are. Do this by creating a VST Plugin object and choosing "register plugins" from the popup panel. Navigate to the directory where the plugins are and select as many as you like. Press "Register" and ABox will do the rest.

To load a plugin into a circuit, create a VST plugin, summon the popup panel, and double click on the desired plugin. ABox will load the plugin and configure the object for use.

VST Instruments will have an si input at the bottom left. To play the instrument, simply connect a MIDI stream to si and connect the plugin's output to a Wave Out. The circuit shown below routes all MIDI events from the keyboard directly to the Plugin. Example 2.1

If you don't hear anything, make sure that the Midi In Object is connected to a device, and that you have the plugin installed.

The circuit below shows using 2 plugins independently. The Midi In object was set as a note stream filter. It routes notes 60-127 to the s1 pin and the rest to the so pin. Notes below middle C get sent to the top DX10, the rest get sent to the bottom DX10. Example 2.2

Using the techniques described above, we can build a complete random sequencer. The whole circuit is shown below. Example 3

While completely describing the circuit goes too far astray, the MIDI stream portion is shown below. Signal flow is from bottom to top. Example 3
The bottom two Midi Out objects are set to track t mode and inject notes into the stream when t2 goes from positive to negative.
The top Midi Out (middle object), is set to track n and injects notes when N changes.
Busses v0 and v1 control the velocity of the three generated notes.
The stream is then sent to the DX10 plugin which generates the sound.
Finally, the DX10 sends audio data to the Wave Out object where it then sends the jazzy wandering sequence to the speakers.

You may have noticed that the previous example and the above circuit have a similar architecture. Midi Out objects set to track mode are chained together and end up being sent to a device. In the first circuit, the device is a Midi Out object set to drive the on-board sound card synth. In the second circuit, the device is a the VST plugin/Wave Out pair.



Ex3: Keyboard playable circuits

In this series we'll develop a keyboard playable softsynth using various features of the Midi In object.
To use the example circuits you'll need a midi input device connected to a keyboard. Depending on your PC's configuration, you may need to re-assign the Midi In and Wave Out objects in each circuit. To do this, right click on them and select another device.

Example 3.1 We're building a software synthesizer so we'll need a Wave Out object, it's a good idea to use a Direct Sound device so we don't have to wait too long to hear the notes. Planning ahead, we'll add a mixer and master volume control. Each of the following examples will use this for audio output.

Below, the left Midi In object brings in data from the AWE64G midi port. To save a lot of wiring, we'll use a note tracker to keep track of what notes are being played. Trackers need at least two Midi In objects, a source and one or more destinations. The left Midi Object has been set as make tracker and is the source for tracker table 0, indicated by track 0 on its display. Example 3.1

The Midi In object on the right is a tracker destination, indicated by track 0 at the top of its display. This object now represents 1 note and outputs data we need to control a synthesizer. In this case, a triangle wave with F as the frequency and o as the on/off state. o is run through a decay filter to eliminate clicks and pops, then connects directly to the triangle wave's A input.

Right now all we have is a one note synthesizer with no other controls. To add more notes, all we have to do add more tracker destinations. A simple select-and-clone operation. Before we do that however, let's add some features.

First we'll add velocity control and an amplitude envelope. Example 3.2

o goes negative for every Note On event, so it's used to start the ADSR. The ADSR has the sustain turned on (vertical line) so it will wait for o to go positive. Fortunately, o goes to positive 0 to indicate Note Off.
The Sample and Hold (sh) grabs and remembers the velocity at the same time the ADSR starts. We use the sample and hold because the velocity may change during the note. All that's left is to multiply the ADSR envelope by the velocity. Now we have a velocity sensitive envelope.

The next feature to add is modulation control, but first we need something to modulate. Sometimes the Mod Wheel is used to set the vibrato depth, so we'll add an LFO to adjust the frequency and bring in the Mod Wheel controller. Example 3.3

The new synth, shown above, now has a sine wave before the triangle wave. Midi In F is connected to the O input so the sine wave will add to it. The frequency and amplitude of the new sine wave is controlled by bus m0 and m1 respectively.
Since we are planning to copy this circuit several times, using busses for the common parameters helps keep the circuit organized. Changing any of the common parameters will effect all objects the same, making the circuit easier to tweak. Also note that bus e0 is used as the envelope time for the ADSR.
To bring in Mod Wheel data (below), a new Midi In object is connected to the so pin of the tracker source. It's set to filter out controller number 1, the Mod Wheel. The V pin has the position of the wheel. Example 3.3
The three objects in the center account for a keyboard that never shuts off the Mod Wheel (aka: broken). If your keyboard works correctly, you can remove these objects. The > object (greater than) outputs -1 when the Mod Wheel's value is greater than 30, otherwise it outputs 0. Multiplying by the original value shuts off or turns on modulation.
The Mod Wheel needs to be scaled to appropriate ranges. The two multiplier knobs do this with a minimum of fuss. The top knob scales the rate to a maximum of .073 seconds. The bottom knob scales the depth (the amount added to the base frequency) to 17Hz. As the Mod Wheel is adjusted from 0 to maximum, the rate and depth will smoothly increase.

Example 3.4 Now we have mod control and can clone the synth circuit. To get 8 notes, make 8 copies. There's no built in limit to the number of tracker destinations, but eventually you'll run out of CPU power.



Ex4: Connecting ABox to a sequencer with Hubi's Midi Loopback

This section of examples explores a softsynth designed to play a specific MIDI file. Since ABox does not have a MIDI sequencer, you'll need to have one available. If you don't have a sequencer, Windows Media Player can be configured to do the job. To connect the sequencer to ABox, we'll use Hubi's Midi Loopback.

Hubi's Midi Loopback is a Windows driver that allows you to connect one midi program to another. It is free-ware, a search on the world wide web will quickly reveal several sites where you may download this indispensable tool. Once installed, the driver appears as a midi device, usually with the name of LB1. You can connect any program that uses Windows midi by selecting LBn from the device list.

One note of caution: If the program has a "thru" mode (a sequencer for example), be sure to turn it off, otherwise the loopback port may feedback on itself and not work correctly.

The sequence we'll be playing is called hbsolo.mid, a one track sequence of a guitar solo. Step one is to load hbsolo.mid into your sequencer and configure its output to use LB1. If you're using Windows Media Player, you'll need to get into "Multimedia" properties from the "Control Panel". Select the "Midi" tab, set "Output" to "Single Instrument" and highlight "LB1" from the list.

The sequence uses Pitch Wheel events to simulate string bending and hammer on/off techniques. Accidental notes are also present, so at most, we need a two note synthesizer. Here is the whole circuit, we'll take it apart piece by piece in the following text. Example 4

Example 4 We'll start analyzing the circuit from the output and work backwards to the Midi In objects. As in the previous softsynth example, we need a Wave Out object. Since we're playing from a sequencer, Direct Sound output is not absolutely necessary, but it doesn't hurt either.

Example 4 FM synthesis will be used for both notes, the core audio block is shown to the left. The bottom sine wave is the carrier and makes the sound. Amplitude is controlled by the A pin at the bottom. The top sine wave is the modulator and controls the sound quality of the carrier. Modulation depth is controlled by its A pin. Frequency is controlled by the F and O pins. Each of the three parameters will have some circuitry that connects it to the Midi In object.

Example 4 There are two amplitude controls, the envelope time (bus e1) and the volume (bus v0). Note that the v0 knob is set to dB to indicate that it controls the volume.

The envelope circuit, shown below, uses an ADSR to generate the envelope. It's triggered at the t input which is connected to a Midi In tracker object. Example 4
The ADSR's sustain is on (vertical line) so the ADSR will hold until t goes positive. The multiplier scales the ADSR to the desired range and the Decay object removes clicks and pops. The output of the Decay connects to the A input of the bottom sine wave oscillator.

To simulate picking a guitar string, we'll bump the modulation depth for a short period of time when the note starts. Example 4

Three controls are required to do this. e0 controls the time span of the modulation adjustment. m0 sets the amount we adjust the depth. Changing it affects how hard the string was plucked. m1 sets the center of the modulation depth. Changing it affects the general brightness of the FM synth. Example 4
An ADSR, multiplier and adder are all that's required to implement the adjustment. The output of the Add object connects to the A input of the top sine wave oscillator.

To properly implement the Pitch Wheel we'll need to understand how it's being used. The hbsolo sequence uses the Pitch Wheel to adjust the frequency of each note by ±1 octave. Maximum Pitch wheel means adjust the note +1 octave (or +12 midi notes). Minimum Pitch Wheel means adjust the note -12 midi notes (down one octave).

Pitch Wheel data from the Midi In object ranges from -1 to +1 with 0 being the center position (no pitch adjust). So we'll need to scale the Pitch Wheel data to the desired range (±12 notes) using a multiplier knob. Bus p0 is the results and connects to both FM synth modules.
p0 is added to the N note coming from a Midi In object. The results are a new midi note detuned by some fraction of a note. To convert from midi note to frequency, the MtoF setting on the Equation Builder is used. The output of MtoF connects to the F and O pins of the top sine wave oscillator. The results are that the Pitch Wheel smoothly adjusts the frequency of the desired without causing a Note On event.

Finally we get to the Midi In object. It's set as destination for tracker table 0. The tracker source object is shown above, next to the Pitch Wheel input. Notice that we're not using the V output. The hbsolo sequence has the same velocity for all notes, so we save a few clock cycles by not using it.

There are some improvements that could be made to both the sequence and the circuit.

While notes are held, the mod wheel could be used to add vibrato. This would need to be added to the sequence, and can be implemented in the circuit using the techniques described in the previous example.
Tempo changes could be added to the sequence to add dramatic pauses in the solo. No changes to the synthesizer circuit would needed for this.
Effects could be added to the synthesizer using either circuitry or VST plugins. A resonant delay after the FM output can add character to the instrument. Reverb might be used to transport the circuit from a dry close miked studio to center stage at the pavilion.





©1999-2002 Andy J Turner
All rights reserved.