MIDI Module

This module implements a basic MIDI In and MIDI Out interface for 3.3v to 5v microcontrollers. MIDI is a 5v protocol, so special steps were taken to step up the voltage on output, and step it down (if 3.3v board) on input. This module includes a specific .NET Gadgeteer-compatible 10 pin connector for use with .NET Gadgeteer mainboards, as well as a 5 pin .1" standard header for use with other boards such as the Netduino.

The board is open source hardware (see the source tree here for the Eagle board and schematic files) and open source software.

midi_module_assembled.png

Assembly Guide and Ordering Information

MIDI Module Hardware Assembly Guide Here. Ordering information is on the same page.

MIDI Module in Action

Here's a video of the prototype module in action:
http://www.youtube.com/watch?v=PNeQ14DQbF0

Andrew Duthie has a great write-up and video showing off the arpeggiator he wrote in a single evening using this module and a MeeBlip Micro. Awesome, Andrew!
http://devhammer.net/blog/gadgeteer-and-midi-making-music-with-microcontrollers

Visual Studio Designer Support for Gadgeteer

Here's an example of the MIDI module in use in the simple sequencer sample in Visual Studio.

midi_module_on_designer.png

Examples

Test source code includes a loopback tester as well as a simple pre-programmed sequencer. Here's what the .NET Gadgeteer code looks like for using the MIDI module to do a loopback test:

public partial class Program
{
    private byte _note = 33;
    private byte _velocity = 127;
    private MidiChannel _channel = MidiChannel.Channel01;


    // This method is run when the mainboard is powered up or reset.   
    void ProgramStarted()
    {
        Debug.Print("Program Started");

        midi.MessageReceived += midi_MessageReceived;
        midi.EnableReceiver();

        button.ButtonPressed += button_ButtonPressed;
    }

    void button_ButtonPressed(Button sender, Button.ButtonState state)
    {
        Debug.Print("Button Pressed");
        midi.SendNoteOn(_channel, _note, _velocity);
        Debug.Print("MIDI Message Sent ============== ");
    }

    void midi_MessageReceived(MidiModule sender, MidiMessage message)
    {
        Debug.Print("MIDI Message Received ============== ");

        if (message.Channel != _channel)
            Debug.Print("Incorrect Channel Received: " + message.Channel);
        else
            Debug.Print("Correct channel received.");

        if (message.DataByte1 != _note)
            Debug.Print("Incorrect note received: " + message.DataByte1);
        else
            Debug.Print("Correct note received.");

        if (message.DataByte2 != _velocity)
            Debug.Print("Incorrect velocity received: " + message.DataByte2);
        else
            Debug.Print("Correct velocity received.");

    }
}

Here's the same thing, but for the Netduino

public class Program
{
    private static byte _note = MidiUtility.A440NoteNumber;
    private static byte _velocity = 127;
    private static MidiChannel _channel = MidiChannel.Channel01;

    private static MidiModule _midi;
    private static InterruptPort _button1;

    public static void Main()
    {
        // RX on Netduino Pin 2, TX on Pin 3
        _midi = new MidiModule(SerialPorts.COM2);

        _midi.MessageReceived += OnMidiMessageReceived;
        _midi.EnableReceiver();

        _button1 = new InterruptPort(Pins.ONBOARD_SW1, true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
        _button1.OnInterrupt += OnButton1Pressed;

        Thread.Sleep(Timeout.Infinite);
    }

    static void OnButton1Pressed(uint data1, uint data2, DateTime time)
    {
        Debug.Print("Button 1 Pressed.");
        _midi.SendNoteOn(_channel, _note, _velocity);
        Debug.Print("MIDI Message Sent ============== ");
    }

    static void OnMidiMessageReceived(MidiModule sender, MidiMessageRecievedEventArgs args)
    {
        Debug.Print("MIDI Message Received ============== ");

        if (args.Message.Channel != _channel)
            Debug.Print("Incorrect Channel Received: " + args.Message.Channel);
        else
            Debug.Print("Correct channel received.");

        if (args.Message.DataByte1 != _note)
            Debug.Print("Incorrect note received: " + args.Message.DataByte1);
        else
            Debug.Print("Correct note received.");

        if (args.Message.DataByte2 != _velocity)
            Debug.Print("Incorrect velocity received: " + args.Message.DataByte2);
        else
            Debug.Print("Correct velocity received.");            
    }
}

Performance Note

The code which processes the MIDI Soft Thru (where anything sent to MIDI IN is replicated to MIDI Out) is written in NETMF. As such, it saturates easily when you're doing live performance type stuff with pitch bends and other data-heavy operations. The end result is latency. Soft Thru is a convenience for use in some situations, but should be turned off (one line of code to turn it on/off) if not needed. I continue to optimize that part of the driver, but there's not a ton you can do to make that more efficient.

Similarly, NETMF (Gadgeteer, Netduino, etc.) isn't well suited to heavy traffic processing or time-critical work (such as generating clock timing messages). If you have a complex setup or send a lot of data, isolating the MIDI Module so that it only receives relevant data will greatly improve performance.

Support for Netduino Classic/Plus

The source tree includes a driver and loopback test project for the Netduino class. Here's a picture of the module in use with a regular old Netduino. (forgive the pile of wires, I didn't have any M/F jumper wires handy. Instead of male headers, you could decide to solder female headers on your MIDI module to make this type of connection easier. 5 wires are needed: Serial RX and TX, Ground, 5v and 3V3)

midi_netduino_classic.jpg

Support for Netduino GO

The source tree includes a UART-mode driver as well as a test project for the Netduino GO. Plug the MIDI module into the board and have some fun :)

midi_netduino_go.jpg

Currently, the module driver is almost identical to the Netduino Classic/Plus version. That may change over time.

Construction and Design History

You can find a little history here on my blog. Not required reading, but interesting if you want to see the earlier versions of the MIDI module.

Your Additions

I'm interested in how you might use this module, and what changes you might like. Please use the Issue Tracker for bugs and feature requests, and the Discussion list for everything else.

Last edited Jan 2, 2013 at 4:57 PM by Psychlist1972, version 15

Comments

No comments yet.