Library hell - specifically tinysub and MIDI in general

How the hell do you tell what functions are IN a library? So far, I've been able to look at examples and pull from there. But there doesn't seem to be a single good example of handling incoming MIDI events on the entire internet I can use with either Tinyusb or USBmidi. I have been pounding my head into a screen for an hour trying to figure out how to see what the functions are and how to use them. Are libraries just a giant black hole / guessing game or is there some way of actually reading what is in them and how they are made? This is so frustrating to me.

I just want to fricking take an incoming CC MIDI message and read it.

THAT'S ALL. That's it. That shouldn't be that hard.

I don't think it is accurate to call an open source software a "black hole". Everything is there for anyone to see in the source code.

However, I understand that the source code is not the best form of documentation for many Arduino users, including myself when it comes to the more complex ones. But when it comes to free open source software, you're likely to get your money's worth either way. If not, we can go looking for something better or make our own from scratch.

So if you wanted to vent, then I guess it's as you say: "THAT'S ALL. That's it", mission accomplished and I sympathize. But if you want help you should provide some more information. We need to know exactly which libraries you are using. There are thousands of Arduino libraries; often multiple with the same or similar names. So playing guessing games is not a very productive use of the helper's time.

Sorry for venting. I’m trying to figure out how to use USB MIDI, specifically the adafruit tinyusb library.

I might be missing something obvious but how do I figure out how to use these functions and data structures?

There are some examples with incoming and outgoing note on and note off and one example of outgoing CC messages but I don’t see incoming CC messages even though I can tell there are functions for them.

I saw one person give the advice to never use libraries and just write your own code and then refer people to the midi specification and learn how the individual packets work. So far that seems easier than the library route. Again though I might be missing something obvious about libraries in general - maybe there is place other than examples where the functions are explained and defined. I just don’t know how to get there! Any help is appreciated. I am not a programmer but a hobbyist. I’ve made some complicated stuff but always by “stealing” from examples and adapting it. The idea of understanding packets of bits and bytes by reading a communications protocol and then writing my own code is new - but I’ll do it I have to. I’m just surprised a protocol as old as I am isn’t more accessible with a few easy functions calls (and maybe it is????? I hope)

Sorry again for venting!!!

See reply above. I didn’t hit reply to you specifically by accident. Thanks again!

Who cares what "one person" says? You can find all sorts of nonsense on the web.

If you can't make sense of the library code, and the documentation and examples are insufficient, then look for complete midi projects that use the library, and see what others have done.

If that is still not enough, do the best you can to accomplish some simple, isolated tasks that are just part of the big picture. If you run into trouble with those, post the details on this forum. Or maybe the Adafruit forum.

  1. Read the documentation if available
  2. Otherwise, all public functions will be in a header file (.h/.hpp)
  3. Read the source code to know what a function does if there's no documentation.

https://tttapa.github.io/Control-Surface-doc/Doxygen/d3/df7/midi-tutorial.html#midi_md-receiving

https://tttapa.github.io/Control-Surface-doc/Doxygen/da/d27/MIDI-Input-Fine-Grained-All-Callbacks_8ino-example.html#a9

I normally check the .h and .cpp files. (use notepad++ !) Sure some of the code might not be the same as the way i would write it, but then again, i might not be able to to begin with or i wouldn't need a library.
Just to check first what functions are available and what arguments they take, usually provides me with enough information. For midi there is actually quite decent examples, both included as examples, and online. Start out with the built in midi.h Locate the files on your drive and open them.

Again. Locate the files and open them. Keep in mind that normally i would use a board with a Atmega32u4 to make it show up as a midi device. (or a true UNO with a 16u4 as USB interface, but that is more complex)

TLDR: Isn't MIDIUSB_buzzer.ino the example that you're looking for?

I wish you hadn't mentioned "tinyUSB", because that's a whole different thing.
Or Adafruit, because the library you linked doesn't seem to have anything to do with them, either. (it GitHub - arduino-libraries/MIDIUSB: A MIDI library over USB, based on PluggableUSB I hope?) Note that the "pluggable USB" required by this library is the (default) alternative to the TinyUSB that Adafruit likes - they're not compatible...

It does indeed look poorly documented. In particular, there's no clue in the documentation how to tell whether any Midi Events have been received. :frowning:

Now, reading source code is a skill that doesn't necessarily require being able to write code, and just because you're not an experienced programmer doesn't mean you shouldn't or can't do it. (In fact, reading other peoples' code is a great way to learn more. If you've been cut&pasting from examples, you've already been doing it SOME.) (and... you'd be surprised at how much of "professional software engineering" consists of figuring out what others' code does, vs writing code from scratch. (alas, it is frequently more difficult to figure our existing code, or it seems that way.))

Fortunately, the midiUSB library is pretty simple.
First, let's look at MIDIUSB.h - that's the file that your sketch includes, so sooner or later, it will declare all of the functions that are usable. We want to look for the "Public:" part of some "class", and we find:

public:
        /// Creates a MIDI USB device with 2 endpoints
        MIDI_(void);
        /// Returns the number of bytes currently available from RX
        uint32_t available(void);
        /// Reads a new MIDI message from USB
        midiEventPacket_t read(void);
        /// Flushes TX MIDI channel
        void flush(void);
        /// Sends a MIDI message to USB
        void sendMIDI(midiEventPacket_t event);
        /// Sends a MIDI buffer of length size to USB
        size_t write(const uint8_t *buffer, size_t size);
        /// NIY
        operator bool();
};

Hey! Check out the functions that aren't mentioned in the docs! There's write(), and operator bool(), and the really promising looking available() - if available() is at all compatible with other Arduino IO functions, it will tell us whether there are any MIDI messages available.

We also need information about the midiEventPacket_t data type that read() returns; that seems to have been moved to a separate file MIDIUSB_Defs.h, which has:

typedef struct
{
        uint8_t header;
        uint8_t byte1;
        uint8_t byte2;
        uint8_t byte3;
} midiEventPacket_t;

That's a bit strange to me, since I though MIDI messages were variable length. I guess they're only variable length went sent via UART - the code in the examples says:

// First parameter is the event type (0x09 = note on, 0x08 = note off).
// Second parameter is note-on/note-off, combined with the channel.
// Channel can be anything between 0-15. Typically reported to the user as 1-16.
// Third parameter is the note number (48 = middle C).
// Fourth parameter is the velocity (64 = normal, 127 = fastest).

So... I guess that's OK. It'd be nice if there were definitions for all those message types., but... oh well.

hey, there's even an example (not a very fleshed-out example) of read() in MIDIUSB/MIDIUSB_read.ino at master · arduino-libraries/MIDIUSB · GitHub
It doesn't use available(); instead it checks for the message header being zero:

void loop() {
  midiEventPacket_t rx;
  do {
    rx = MidiUSB.read();
    if (rx.header != 0) {
      // does stuff

That's ... consistent with the way that Serial.read() behaves - return a special value if there is no data. We can check the implementation of read() in the .cpp file:


      if (USB_Available(MIDI_RX)) {
                accept();
                c = buffer->midiEvent[buffer->tail];
            } else {
                c.header = 0;
                :
        return c;

Sure enough - if no data is available, we'll get a msg.header of zero.

And there's another example MIDIUSB_buzzer.ino that actually plays notes based on received MIDI messages! It also more-or-less confirms that there are no symbolic constants for the message types :frowning:

So... that's how I'd go about figuring out how to use the library based on the source code. It's a shame I didn't notice the badly-named "buzzer" example to start with...

I've expanded/improved the documentation and submitted a pull request.

1 Like

To be fair there is also USB-MIDI.h in which the 'AllEvents' example should be nearly self-explanatory. Although if listening on the Serial port for Midi,

static void OnControlChange(byte channel, byte number, byte value) {
  Serial.print(F("ControlChange from channel: "));
  Serial.print(channel);
  Serial.print(F(", number: "));
  Serial.print(number);
  Serial.print(F(", value: "));
  Serial.println(value);
}

It might not be practical to send the results found, back on that same port in a different format.
But you can confirm it's functionality by making the program do whatever you want.
I would try and receive a CC msg and send back a note on or off for instance.

static void OnControlChange(byte channel, byte number, byte value) {
  if (number == 70) {
     if (value > 63)  MIDI.sendNoteOn(42, 100, 1);
     else MIDI.sendNoteOff(42, 0, 1);
  }
}

Also, there is the more elaborate Arduino MIDI library, which can apparently use the MIDIUSB library "underneath" higher level functions.

I just wanted to say thanks to everybody. I went to sleep early yesterday and won't have a chance to dive into this until at least this afternoon, but I've glanced at it and it looks like more than enough to solve my issues. Also, it gives me a pathway for future problems. I didn't know about header files (or really how to access documentation in general, other than random Google searches) and I didn't realize how the various MIDI libraries are connected. The buzzer.ino example in particular looks like it has everything I need. Best - Tom

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.