USB-MIDI device (all inputs/outputs)?

Status
Not open for further replies.

kriista

Member
So I've been using Arduino stuff for music for some time, and I always use it as serial, and send it into Max/MSP where I parse the stuff. This works ok, but I often have pretty serious kernel panics (greyscreen on a mac) related to serial/buffer stuff.

So what I want to do is setup an Arduino/Teensy to be a generic input device. So all digital inputs would be sent as 0/127 (binary) and analog inputs would end 0-127.

But the idea being that all inputs are being read and sent as midi.
There's a sacrifice in resolution for analog inputs this way, but in exchange for bulletproof stability (class-compliant MIDI).

I know there's the Maxuino library that lets you control everything on the Arduino from Max, but it, too, uses serial, and I want to avoid that.

I found this page here which looks pretty relevant:
http://www.pjrc.com/teensy/td_midi.html

I've never programmed using teensy before, much less reprogrammed the input chip. From the looks of it it's as simple as picking the 'USB type' in the teensy IDE?

So to setup 12analog in, and 22digital in (max inputs on a teensy3?), it would be a matter of picking the USB type and setting up code to read all analog/digital I/O and send corresponding MIDI CC/noteon messages?

A second bit would be setting up more or less the reverse. A friend of mine has build a voltage to relay box for me so that I can switch hardware stuff via MIDI. So I'd like to build another teensy to take midi INPUT from my computer, and set 0-5v on 16 digital pins. Would it be the same thing be reverse?
 
Note, if you need more inputs and outputs, you can get I2C (or SPI) I/O expanders. I just ordered some 8/16 port I2C expanders from Adafruit (not the PWM versions), that will get here in a few days:


I would imagine that when you get to a lot of pins supported, you will run into power issues, or possibly that it just is too long to read the analog ports. :cool:

In terms of sending stuff to the mac, I might think about using networking or something similar if you are getting kernel panics on USB input. However, I'm not sure there is a teensy ethernet/wifi that is currently supported.

Alternatively, the MAC may have in-band flow control turned on (control-S/control-Q), and if you are sending binary, it may hit some limit. If that is the case, you would encode the input so you are only sending printable characters and a newline every so often.
 
Last edited:
12/22 is WAY more than I'd need as it is, so I wouldn't need to expand the default teensy stuff.

I think the main thing is that in Max/MSP you 'manually' parse the serialport, and I've just found that to be unstable. Also the ftdi drivers on their own (again, this is with regular arduino/serial) aren't bulletproof either and can kernel panic just by unplugging an ftdi device.
 
I've never programmed using teensy before, much less reprogrammed the input chip. From the looks of it it's as simple as picking the 'USB type' in the teensy IDE?

Yes. Just select MIDI from the Tools > USB Type menu. Next time you upload, Teensy will become a class-compliant USB MIDI device. It really is that easy. Teensy has features like this that don't exist on any other Arduino compatible board.

It's actually a composite device, with MIDI and a special HID channel that is used to emulate serial. That gives you the ability to still use Serial.print() to the Arduino Serial Monitor, even though it's not actually a USB serial device.

And yes, the stuff you're looking to do with MIDI messages should work very nicely. Just build your code to send and receive MIDI with the functions documented here:

http://www.pjrc.com/teensy/td_midi.html
 
So when you change the USB type, you can still upload to it? From my understanding, when you change the Arduino USB behavior, you lock out the ability to edit the sketches on it.

So from the look of the example sketch you don't define a baudrate or anything? That's all handled by using the usbMIDI commands in teensy?

Secondly, for RECEIVING midi on the teensy, the lower part of that page is quite confusing. If I only want noteon/off messages, that means my code would have the following in it:

void OnNoteOn(byte channel, byte note, byte velocity)
void OnNoteOff(byte channel, byte note, byte velocity)
usbMIDI.setHandleNoteOff(OnNoteOff)
usbMIDI.setHandleNoteOn(OnNoteOn)
usbMIDI.read();

What actually returns the input? Like how do I know that midi note 60 is 127?
 
So when you change the USB type, you can still upload to it?

Yes, you can still upload.

However, the one caveat is that in (hopefully rare) cases where your program crashes with interrupts disabled, or if it shuts off the USB, then you'll need to press the button. The software will print a message asking you to press the button, if it can't automatically reboot the board (usually about 5 seconds). In normal Arduino usage, those cases are pretty uncommon. Normally the upload works every time, and it also uploads faster than normal Arduino boards.

If you edit the USB code or other stuff using interrupts or libraries that do sophisticated stuff with timers or other interrupt-based hardware, the pushbutton press might be required occasionally, depending on what you do. Even then, it's as simple as just pressing the pushbutton if the upload doesn't happen automatically within a few seconds.


From my understanding, when you change the Arduino USB behavior, you lock out the ability to edit the sketches on it.

That sounds like the painful process of reprogramming Arduino Uno's USB chip.

Teensy isn't anything like that at all. This stuff works very easily. When you click Upload, a helper program Teensyduino installs searches for all the known USB types (from the Tools > USB Type menu). It knows how to request an automatic reboot from every single type. The result is you can just click Upload in Arduino and it all works easily and automatically.

I know this stuff is terrible on Arduino Uno when you stray from USB Serial. I've put a LOT of work over the years into making Teensy implement these non-serial types very easily, like you'd expect from Arduino with regular serial.

So from the look of the example sketch you don't define a baudrate or anything? That's all handled by using the usbMIDI commands in teensy?

Yes, really, it truly is class-compliant USB MIDI.

I know how unbelievable that must sound if you only know regular Arduino boards, but it is true. It really is USB MIDI.

Secondly, for RECEIVING midi on the teensy, the lower part of that page is quite confusing. If I only want noteon/off messages, that means my code would have the following in it:

void OnNoteOn(byte channel, byte note, byte velocity)
void OnNoteOff(byte channel, byte note, byte velocity)
usbMIDI.setHandleNoteOff(OnNoteOff)
usbMIDI.setHandleNoteOn(OnNoteOn)
usbMIDI.read();

What actually returns the input? Like how do I know that midi note 60 is 127?

There are 2 ways to receive. The handler functions are the easy way that most people prefer. You create your functions that do whatever you want when those messages arrive. In setup(), you use the setHandle... functions to set them up, and in loop() you call read(). You'll know which note number it was because the note number is one of the 3 parameters that your handler function receives when it gets automatically called.

The other way is looking at the return value from read() and calling the functions to find out what MIDI message arrived. Using that approach, when read() indicates a new message arrived, you'd find out its note number by calling usbMIDI.getData1().

Either way works. Most people prefer the handler functions.

These 2 ways closely mirror how the MIDI library (for serial-based MIDI on 5-pin DIN connectors) works. The intention is you can convert most code written for that MIDI library to Teensy's USB MIDI by just adding the "usb" prefix, and code from USB MIDI to regular MIDI by removing "usb". A couple years ago, Francois Best (author of the MIDI library) and I collaborated on unifying our APIs, to make user code as easily portable as possible between his library and Teensyduino's USB MIDI. So some parts of the API are the way they are today for the sake of this compatibility.


It sounds like you have a lot of experience doing this with regular Arduino. You should really get a Teensy board and give this a try. They're very affordable (a Teensy 2.0 is about half as much as a regular Arduino Uno), so your risk is low and I'm sure you'll like the reward! If you're very used to doing MIDI over Arduino Uno's USB Serial, I'm confident you'll be really impressed how much better this works on Teensy.
 
Last edited:
Also, I should mention one other feature, which exists on Teensy 2.0, but is not yet implemented on Teensy 3.0.

Teensy 2.0 emulates Arduino Uno's 2-chip reset behavior when you open the Arduino Serial Monitor. If you're used to the board resetting automatically when you open the serial monitor, you should get a Teensy 2.0.

The workaround is to use "while (!Serial)" on Teensy 3.0. Arduino's Leonardo and Due's native port also need this, because they also do not emulate the 2-chip reset.

The 2 chip reset involves the '328 chip resetting when you open the serial monitor, but the USB chip continues running. If both chips were to reset, the USB would disconnect right before you try to use it, which obviously is no good.

On Teensy 2.0, there is code within the USB stack, implement on all USB types (not only USB serial) which detects the Arduino Serial Monitor opening and emulates a 328-only reset. The details are quite complex (I've shared this with the Arduino developers, but they were uninterested because it's too much work). You can look at the source code the Teensyduino places in hardware/teensy/cores if you really want to dig into the gory details.

But the simple story is Teensy 2.0 implements this Arduino Uno 2-chip reset behavior, even though Teensy is only a single chip. Teensy 3.0 will do the same someday, but it's currently not implemented, so if you go with a 3.0 board and you print stuff in setup() that you expect to see in the serial monitor, don't forget the "while (!Serial)" workaround, which works in all USB types, despite the word "Serial".
 
Ah, so the teensy is your design?

That's awesome.

I've seen it come up several times over the year, mainly in performance comparisons (in terms of serial latency/throughput). I've not needed to buy another arduino in some time so I've never bought one. The simplicity of USB/MIDI seems like a game changer, and it's weird to think that that's not the standard way that all Arduino's would work. From doing a bit of reading, the steps involved in doing the same on an Arduino are tedious!

I think I'll go with a teensy 3 for the pinouts/formfactor. I don't anticipate needing the serialmonitor at all, as it'd just be a straight up setup. The idea is to make a 'black box' that I can use to prototype/test hardware to USB/MIDI (ie buttons, pots, sliders, misc sensors).

The READ version I described will get hardwired into the 5v to relay device I described. Still don't fully understand the read part, but your response is thorough, I just need to code it up and I'm sure it will make sense then. I'm just thinking in terms of Max/MSP paradigm of parsing where MIDI comes in, and you separate out the channel you want, and then you have the isolated 0-127 value there.
 
It occurs to me that those of us used to the Teensy are taking for granted how much easier it is compared to all the other Arduino-esque platforms out there. Which means that some people will not believe how easy it is and will be looking for the extra steps which must, surely, be missing.

To recap, on other platforms
1) Read all about reprogramming the second CPU to be a MIDI device
2) Buy hardware to reprogram it.
3) Flash chip with MIDI
4) Find it doesn't work. Suspect your code is wrong
4) Discover you can no longer program your Arduino because of 3)
5) Read up on flashing the original bootloader. Panic.
6) Flash chip with bootloader
7) Upload new program
8) Program doesn't work, MIDI not working.
9) Oh, right. Goto 3)
10) Decide that not outputting MIDI, and instead using a host based serial to MIDI converter is a real good idea

I left out all the bits about optocouplers.

In contrast, on Teensy: select MIDI from menu and MIDI-over-USB all works first time without any "did I just brick the hardware" moments; plus its a lot faster and lower lag/congestion than MIDI-over-DIN.
 
Last edited:
what I want to do is setup an Arduino/Teensy to be a generic input device. So all digital inputs would be sent as 0/127 (binary) and analog inputs would end 0-127.

But the idea being that all inputs are being read and sent as midi.
There's a sacrifice in resolution for analog inputs this way, but in exchange for bulletproof stability (class-compliant MIDI).

Note that you could send more than 7bit (0..127) analog values over MIDI. There are two ways, one using pairs of CC to send MSB and LSB, the other using NRPN. Either way you can use up to 14bits. Since it seems you are both creating and consuming the messages yourself, you have the flexibility to use these if you want to.
 
Last edited:
Still don't fully understand the read part, but your response is thorough, I just need to code it up and I'm sure it will make sense then.

You might start with the examples in File > Examples > Teensy > USB_MIDI.

They're pretty basic, but maybe they'll save you a little time compared to starting completely from scratch.
 
Note that you could send more than 7bit (0..127) analog values over MIDI. There are two ways, one using pairs of CC to sens MSB and LSB, the other using NRPN. Either way you can use up to 14bits. Since it seems you are both creating and consuming the messages yoursefl, you have the flexibility to use these if you want to.

That's definitely good to know. I'll probably just keep it 7bit for my first build as the idea is to have a generic plug/play way to test sensors/hardware without having to dig into concating values (which I wouldn't be able to do in generic DAW software).

I'll be ordering a couple of these soon for sure.
 
Status
Not open for further replies.
Back
Top