| ||
|
Shopping Cart
|
| Home | MP3 Player | 8051 Tools | All Projects | PJRC Store | Site Map |
|
You are here:
Teensy
|
|
|
Using USB MIDIWhen you select "MIDI" from the Tools->USB Type menu, the Teensy becomes a USB MIDI (Musical Instrument Digital Interface) device, capable of sending and receiving MIDI messages.MIDI can be used for non-music applications, such a controlling a large number of lights from a PC. Environments like Puredata and Max/MSP can give you access to MIDI for almost any purpose. MIDI is optimized to simultaneously transmit and receive large numbers of short messages with minimal delay. Teensyduino implements a "class compliant" MIDI device, which can work with the built-in drivers on all major operating systems. Transmitting MessagesThese functions allow you to transmit all of the standard MIDI messages.
usbMIDI.sendNoteOn(note, velocity, channel) usbMIDI.sendNoteOff(note, velocity, channel) usbMIDI.sendPolyPressure(note, pressure, channel) usbMIDI.sendControlChange(control, value, channel) usbMIDI.sendProgramChange(program, channel) usbMIDI.sendAfterTouch(pressure, channel) usbMIDI.sendPitchBend(value, channel) usbMIDI.sendSysEx(length, array) MIDI messages are grouped together into USB packets. Up to 16 messages can transmit at once! They are held for a brief time, not more than 1 ms, to facilitate grouping. You can use the send_now() function to immediately allow any buffered messagse to transmit
usbMIDI.send_now() USB bandwidth is shared among devices. Usually there is very little delay, unless other USB devices are using all the available USB bandwidth. Transmit ExamplesPhilip Cunningham's MIDI Controller reads 6 knobs and sends Control Change messages. Arcade Button MIDI Controller (instructables) This simple sketch shows how to use the Bounce library together with MIDI. A longer example can be found in File > Examples > Teensy > USB_MIDI > Buttons.
#include <Bounce.h> // Bounce library makes button change detection easy const int channel = 1; Bounce button1 = Bounce(1, 5); // 5 = 5 ms debounce time Bounce button2 = Bounce(2, 5); // which is appropriate for good Bounce button3 = Bounce(3, 5); // quality mechanical pushbuttons void setup() { pinMode(1, INPUT_PULLUP); pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); } void loop() { button1.update(); button2.update(); button3.update(); // Note On messages when each button is pressed if (button1.fallingEdge()) { usbMIDI.sendNoteOn(60, 99, channel); // 60 = C4 } if (button2.fallingEdge()) { usbMIDI.sendNoteOn(61, 99, channel); // 61 = C#4 } if (button3.fallingEdge()) { usbMIDI.sendNoteOn(62, 99, channel); // 62 = D4 } // Note Off messages when each button is released if (button1.risingEdge()) { usbMIDI.sendNoteOff(60, 0, channel); // 60 = C4 } if (button2.risingEdge()) { usbMIDI.sendNoteOff(61, 0, channel); // 61 = C#4 } if (button3.risingEdge()) { usbMIDI.sendNoteOff(62, 0, channel); // 62 = D4 } } Transmit IssuesWhen using MIDI-OX on Windows, together with a sketch that transmits but never receives, open only the input device. From the menu Options > MIDI Devices, select "USB Audio Device" in the MIDI Inputs box. Do NOT select "USB Audio Device" in the MIDI Outputs box. Uncheck the "Automatically attach Inputs to Outputs during selection" box, then click OK.Receiving Messages with Read & Callback FunctionsThe easiest way to receive MIDI messages is with functions that are automatically called when each type of message is received. Usually you would create one or more of these:
void OnNoteOn(byte channel, byte note, byte velocity) void OnNoteOff(byte channel, byte note, byte velocity) void OnVelocityChange(byte channel, byte note, byte velocity) void OnControlChange(byte channel, byte control, byte value) void OnProgramChange(byte channel, byte program) void OnAfterTouch(byte channel, byte pressure) void OnPitchChange(byte channel, int pitch) For each function you create, you must use the corresponding "setHandle" functions to tell usbMIDI to call it when that message type is read.
usbMIDI.setHandleNoteOff(OnNoteOff) usbMIDI.setHandleNoteOn(OnNoteOn) usbMIDI.setHandleVelocityChange(OnVelocityChange) usbMIDI.setHandleControlChange(OnControlChange) usbMIDI.setHandleProgramChange(OnProgramChange) usbMIDI.setHandleAfterTouch(OnAfterTouch) usbMIDI.setHandlePitchChange(OnPitchChange) Once everything is set up, you then need the "read" function to actually read data. The callback functions are only called when you use read. There are 2 choices for read:
usbMIDI.read(); // All Channels If you give a specific channel number to read, messages to other channels are ignored, which is easier than having to check the channel number in your callback function.
usbMIDI.read(channel); // One Specific Channel (1 to 16) TODO: simple example program Receiving Messages with Read & Query FunctionsInstead of callback functions, you can also check the return value from read(). When it returns true, a new message has arrived. The "get" functions allow you to access information about the most recently received MIDI message.usbMIDI.getType() The types are: 0 = Note Off, 1 = Note On, 2 = Velocity Change, 3 = Control Change, 4 = Program Change, 5 = After Touch, 6 = Pitch Bend, 7 = System Exclusive usbMIDI.getChannel()The getChannel function gives you the channel number, from 1 to 16. If you requested only a specific channel when calling read, there is no need to use this. usbMIDI.getData1() usbMIDI.getData2()The actual message data can be accessed with getData1 and getData2. usbMIDI.getSysExArray()For system exclusive messages, the message data is available as an array. Use getData1 to find the number of bytes stored in the array. Connecting Many Buttons & Knobs/SlidersOften MIDI controllers need more pushbuttons and knobs or sliders than can be connected directly. The inexpensive 74HC4051 chip can be used to connect 8 inputs to one pin. It works for analog or digital signals. Three digital pins are needed to control the 74HC4051, but those same 3 pins can control many chips.
To use these 74HC4051 chips, first select the desired channel using the 3 control pins. Then wait a brief time for the signals to propagate through the chips. 50 µs is plenty. Then you can read the pins. This process must be repeated 8 times to read all the signals.
// select 74HC4051 channel 5 (of 0 to 7) digitalWrite(1, HIGH); digitalWrite(2, LOW); digitalWrite(3, HIGH); // allow 50 us for signals to stablize delayMicroseconds(50); // read the signals routed to pins 10, 19, 20 // through channel 5 of each 74HC4051 chip buttonPin10channel5.update(); knobPin19channel5 = analogRead(19); knobPin20channel5 = analogRead(20); Drum Machine ExampleTODO: this section.... |