I've managed to get 8 virtual midi cables working over USB for Teensy 3.2/3.6 on OSX and Windows 10, don't have Linux but it should work (famous last words)...
This thread helped start the ball rolling : thread
Hopefully the way I've done it is fairly clean (the midi send/receive commands haven't changed ) and useful to some people.
The files that need to be changed (OSX locations) are:
/Applications/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_desc.c
/Applications/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_midi.c
/Applications/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_midi.h
Installation:
1/ Make a copy of these files: usb_desc.c , usb_midi.c , usb_midi.h
On MacOs in finder goto Applications/Arduino right click show Package contents then
/Contents/Java/hardware/teensy/avr/cores/teensy3/
2/ replace them with the three files attached.
Usage:
Before sending set the virtual midi cable using usbMIDI.setMidiCable(cable). Note there is no bounds checking and cable needs to be between 0 and 7.
int cable = 7; // cable can be from 0 to 7
int note = 45;
usbMIDI.setMidiCable(cable);
usbMIDI.sendNoteOn(note,0x7F,1); // note , vel, channel
Receiving:
It up to you to check what virtual midi cable received the midi data and decide what to do with it...
Serial.print("Cable, cb=");
int cable = usbMIDI.getCable();
Serial.print(cable, DEC);
Example code
The example below sends 50 note on's and 50 note off's as fast as possible when a button is pressed.
It also writes to the serial terminal when a midi message (note on, off, pitch bend, control change etc) is received.
The 50 notes sent across eight ports/virtual midi cables (400 in total) were received by the software (Reaper64 in this case) in 3ms - not too shabby.
Preliminary Testing
- tested Arduino 1.6.12 and Teensyduino 1.32(?) and
Arduino 1.8.0 and Teensyduino 1.34
- left running for a couple of hours pumping midi Note on/off's across 8 ports to Ableton Live no problems.
- works using USB profiles: Midi / Midi + Serial and Midi + Serial + Audio (audio not tested but shows up in device manager and in OSX and PC)
- works on T3.2, T3.6 (fairly cursory - mainly 3.2)
The need for more than one midi port/cable:
If you are trying to implement some kinds to midi automation e.g. HUI/Mackie etc then you need more than one port. One port limits you to 8 channels. Frequently you need to be able to control up to 32 channels.
---
Hope I haven't missed something...
This thread helped start the ball rolling : thread
Hopefully the way I've done it is fairly clean (the midi send/receive commands haven't changed ) and useful to some people.
The files that need to be changed (OSX locations) are:
/Applications/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_desc.c
/Applications/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_midi.c
/Applications/Arduino.app/Contents/Java/hardware/teensy/avr/cores/teensy3/usb_midi.h
Installation:
1/ Make a copy of these files: usb_desc.c , usb_midi.c , usb_midi.h
On MacOs in finder goto Applications/Arduino right click show Package contents then
/Contents/Java/hardware/teensy/avr/cores/teensy3/
2/ replace them with the three files attached.
Usage:
Before sending set the virtual midi cable using usbMIDI.setMidiCable(cable). Note there is no bounds checking and cable needs to be between 0 and 7.
int cable = 7; // cable can be from 0 to 7
int note = 45;
usbMIDI.setMidiCable(cable);
usbMIDI.sendNoteOn(note,0x7F,1); // note , vel, channel
Receiving:
It up to you to check what virtual midi cable received the midi data and decide what to do with it...
Serial.print("Cable, cb=");
int cable = usbMIDI.getCable();
Serial.print(cable, DEC);
Example code
The example below sends 50 note on's and 50 note off's as fast as possible when a button is pressed.
It also writes to the serial terminal when a midi message (note on, off, pitch bend, control change etc) is received.
Code:
#include <Bounce.h>
Bounce button2 = Bounce(2, 55);
void setup() {
Serial.begin(115200);
delay(300);
usbMIDI.setHandleNoteOff (OnNoteOff);
usbMIDI.setHandleNoteOn (OnNoteOn);
usbMIDI.setHandleVelocityChange(OnVelocityChange);
usbMIDI.setHandleControlChange(OnControlChange);
usbMIDI.setHandleProgramChange(OnProgramChange);
usbMIDI.setHandleAfterTouch(OnAfterTouch);
usbMIDI.setHandlePitchChange(OnPitchChange);
pinMode(2, INPUT_PULLUP);
}
void loop() {
usbMIDI.read(); // USB MIDI receive
button2.update();
int value = button2.read();
if(value == LOW){
delay(50);
send_notes();
delay(250);
}
}
void send_notes(){
int cable = 0;
int i = 0;
for (i=0;i<50;i++){
for ( cable = 0; cable < 8; cable++){
usbMIDI.setMidiCable(cable);
usbMIDI.sendNoteOn(i,0x7F,1); // note , vel, channel
}
}
for (i=0;i<50;i++){
for ( cable = 0; cable < 8; cable++){
usbMIDI.setMidiCable(cable);
usbMIDI.sendNoteOff(i,0x00,1); // note , vel, channel
}
}
usbMIDI.send_now();
}
void OnNoteOn( byte channel, byte note, byte velocity) {
Serial.print("Cable, cb=");
int cable = usbMIDI.getCable();
Serial.print(cable, DEC);
Serial.print("Note On, ch=");
Serial.print(channel, DEC);
Serial.print(", note=");
Serial.print(note, DEC);
Serial.print(", velocity=");
Serial.print(velocity, DEC);
Serial.println();
}
void OnNoteOff(byte channel, byte note, byte velocity) {
Serial.print("Cable, cb=");
Serial.print(usbMIDI.getCable(), DEC);
Serial.print("Note Off, ch=");
Serial.print(channel, DEC);
Serial.print(", note=");
Serial.print(note, DEC);
Serial.print(", velocity=");
Serial.print(velocity, DEC);
Serial.println();
}
void OnVelocityChange(byte channel, byte note, byte velocity) {
Serial.print("Cable, cb=");
Serial.print(usbMIDI.getCable(), DEC);
Serial.print("Velocity Change, ch=");
Serial.print(channel, DEC);
Serial.print(", note=");
Serial.print(note, DEC);
Serial.print(", velocity=");
Serial.print(velocity, DEC);
Serial.println();
}
void OnControlChange(byte channel, byte control, byte value) {
Serial.print("Cable, cb=");
Serial.print(usbMIDI.getCable(), DEC);
Serial.print("Control Change, ch=");
Serial.print(channel, DEC);
Serial.print(", control=");
Serial.print(control, DEC);
Serial.print(", value=");
Serial.print(value, DEC);
Serial.println();
}
void OnProgramChange(byte channel, byte program) {
Serial.print("Cable, cb=");
Serial.print(usbMIDI.getCable(), DEC);
Serial.print("Program Change, ch=");
Serial.print(channel, DEC);
Serial.print(", program=");
Serial.print(program, DEC);
Serial.println();
}
void OnAfterTouch(byte channel, byte pressure) {
Serial.print("Cable, cb=");
Serial.print(usbMIDI.getCable(), DEC);
Serial.print("After Touch, ch=");
Serial.print(channel, DEC);
Serial.print(", pressure=");
Serial.print(pressure, DEC);
Serial.println();
}
void OnPitchChange( byte channel, int pitch) {
uint8_t data1;
uint8_t data2;
uint8_t type;
uint8_t ch;
data1 = usbMIDI.getData1();
data2 = usbMIDI.getData1();
type = usbMIDI.getType();
ch = usbMIDI.getChannel();
Serial.print("Cable, cb=");
Serial.print(usbMIDI.getCable(), DEC);
Serial.print("Data1 = ");
Serial.print(data1, DEC);
Serial.print("Data2 = ");
Serial.print(data2, DEC);
Serial.print("Type = ");
Serial.print(type, DEC);
Serial.print("Channel = ");
Serial.print(ch, DEC);
Serial.print("Pitch Change, ch=");
Serial.print(channel, DEC);
Serial.print(", pitch=");
Serial.print(pitch, DEC);
Serial.println();
}
The 50 notes sent across eight ports/virtual midi cables (400 in total) were received by the software (Reaper64 in this case) in 3ms - not too shabby.
Preliminary Testing
- tested Arduino 1.6.12 and Teensyduino 1.32(?) and
Arduino 1.8.0 and Teensyduino 1.34
- left running for a couple of hours pumping midi Note on/off's across 8 ports to Ableton Live no problems.
- works using USB profiles: Midi / Midi + Serial and Midi + Serial + Audio (audio not tested but shows up in device manager and in OSX and PC)
- works on T3.2, T3.6 (fairly cursory - mainly 3.2)
The need for more than one midi port/cable:
If you are trying to implement some kinds to midi automation e.g. HUI/Mackie etc then you need more than one port. One port limits you to 8 channels. Frequently you need to be able to control up to 32 channels.
---
Hope I haven't missed something...
Attachments
Last edited: