Midi 2.0

Looking forward to getting into this code towards the end of summer. Is it going to be possible to bring this to teensy 3.2 devices?
 
Glad to hear it, @ETMoody3.
The Korg Keystage is one of the very devices that satisfy the criteria Paul set, so plugging it into
the Teensy host port is a solid test.

Tell me more about your MIDI-to-CV build. It's exactly the kind of project that gains the most from MIDI 2.0, and I'd love to
understand what you put together.

While you catch up on the reading, there are Teensy recipes to look at. midi2 (the portable C99 core) has teensy-device-midi2,
closer to the metal. midi2cpp (the C++ wrapper) has teensy41-midi2, the control surface and the host. The recipes
pass the MIDI Association's MIDI 2.0 Workbench, so they make a clean reference to start from. ;)
 
@yeahtuna,
The current work lives entirely in the Teensy 4.x USB stack (iMXRT), and the 3.2 uses a different USB peripheral (Kinetis,
Full Speed), so it isn't a recompile, it's a real port of the descriptors and the raw UMP I/O against the other stack.

A device on 3.2 is feasible: UMP can run fine at Full Speed and the descriptors already carry the 12 Mbit variant. Nobody has
written that port yet, but the descriptors are a starting point if you want to take it on. A host on 3.2 is out: it has no USB
host port. If host is what you're after, the boards that have one are the 3.6, 4.0 and 4.1, and the host recipe is validated on the
4.1 today. That said, I don't have a 3.2 on hand to say for sure on the device side.
 
Closing the validation loop on the Teensy 4.1 MIDI 2.0 device: the cores fork descriptors now pass the two references that
matter.
Windows MIDI Services (Microsoft's native stack): the Teensy enumerates as a native MIDI 2.0 endpoint over Kernel Streaming, and the MIDI Services Console decodes the whole stream natively, 32-bit Note On/Off, 32-bit CC, Pitch Bend, Per-Note Controllers, Flex Data, all with the right Group and Channel.

WMS.jpg


MIDI 2.0 Workbench (the MIDI Association's conformance tool): the recipe passes the checklist with no errors and no warnings.
WorkbenchII.png

The descriptors behind this are minimal and transport only, 625 lines in teensy4/, no application logic, in the cores style.
What this opens up: with native MIDI 2.0, the 32-bit resolution and the per-note controllers feed straight into the Audio Library, high-resolution continuous control reaching the DSP without the 7-bit steps. A synth or effect that actually uses MIDI 2.0's resolution in the sound path, on hardware you already have on the bench, is close to unheard of right now. That is the door these descriptors open.

If you want to try it, the recipes are in midi2cpp: github.com/sauloverissimo/midi2cpp. There are device, control surface and host examples for the Teensy 4.1, ready to clone and flash.

👍
 
I installed via the Library Manager, hoping for an easy install. I think it would be best if I just manually install as I have moved my portable arduino installation onto cloud storage so it can be shared between systems. Where should I put the library relative the the main arduino folder?

1786774743701.png
 
I installed via the Library Manager, hoping for an easy install. I think it would be best if I just manually install as I have moved my portable arduino installation onto cloud storage so it can be shared between systems. Where should I put the library relative the the main arduino folder?

View attachment 39693

Hi @yeahtuna! Glad you're trying it out. I think it's something simple, and this should do it:

The usb_midi2.h: No such file or directory error is from the other half of the setup, not from the library. Your midi2cpp from the Library Manager is already the right version (0.9.0), so you can leave it as is.

What's missing are the cores fork descriptors. They don't come through the Library Manager; they're an overlay onto the Teensy core. Most direct path:

1. Go to github.com/sauloverissimo/cores, switch to the feature/usb-midi2-descriptors branch, and download it as a ZIP (Code > Download ZIP).

2. From the ZIP you only need 5 files, from the teensy4/ folder. Copy them into the Teensy core, overwriting:
usb.c, usb_desc.c, usb_desc.h, usb_midi2.c, usb_midi2.h On Arduino 1.8.19 the core lives at:

<your-arduino-folder>/hardware/teensy/avr/cores/teensy4/

3. Restart Arduino and compile. The #include <usb_midi2.h> will resolve.

Since your install is portable on the cloud, that core travels with it between systems, so it's a one-time thing. 👍
 
That worked, but only after an hours worth of messing around. I did get it to compile. I'll report all the issues I had tomorrow.
 
@sauloverissimo So here is my install process using Arduino 1.8.19 on Windows. There one some edit you can make the processs a bit smoother for others.

1. Install via the Library Manager.

2. Go to github.com/sauloverissimo/cores, switch to the feature/usb-midi2-descriptors branch, and download it as a ZIP (Code > Download ZIP). From the ZIP, copy the following files into hardware/teensy/avr/cores/teensy4/, overwritting where necessary:
usb.c, usb_desc.c, usb_desc.h, usb_midi2.c, usb_midi2.h

3. Edit hardware/teensy/avr/boards.txt. Find teensy41.build.flags.cpp definition and add:
-std=gnu++17 -D_GLIBCXX_USE_C99 -D__cplusplus=201703L

Note: Mine already had -std=gpn++14, so I just edited it. -D_GLIBCXX_USE_C99 had to be added due to any include issue, but should probably be fixed by editing the library described below (according to Gemini):
Add #include <cstdio> to midi2_bridge.cpp (or midi2_bridge.h):

  1. Open midi2_bridge.cpp.
  2. Add this at the top with the other includes:
    C++

    #include <cstdio>
    using std::snprintf;

  3. Save and recompile

-D__cplusplus=201703L had to be added because of the following code. I think on modern compilters, a different define should be checked.
Code:
#if __cplusplus < 201703L
#  error "midi2cpp requires C++17 or newer. Set CMAKE_CXX_STANDARD=17 (or pass -std=c++17 to your build)."
#endif

Gemini seems to think this would work. but I never tested it.
Code:
#if (__cplusplus < 201703L) && !defined(__cpp_inline_variables) && !defined(__cpp_structured_bindings)
#  error "midi2cpp requires C++17 or newer. Set CMAKE_CXX_STANDARD=17 (or pass -std=c++17 to your build)."
#endif


4. Edit hardware/teensy/avr/cores/teensy4/usb_midi2.c
Code:
// Add function prototype
extern int usb_midi_write_packed(uint32_t n);

// Add missing function definition
int usb_midi_write_packed_n(const uint32_t *words, uint32_t count) {
    int ret = 0;
    while (count > 0) {
        ret = usb_midi_write_packed(*words);
        if (ret < 0) break;
        words++;
        count--;
    }
    return ret;
}
 
Last edited:
@yeahtuna, thanks a lot for the writeup, this really helps. A real-world install log is exactly what smooths the path for others. I'll fold it into the recipe README, because it matters.

On C++17: Teensyduino 1.60+ already ships -std=gnu++17 by default in teensy41.build.flags.cpp, so updating to 1.60+ removes that
edit. Your boards.txt change is the right workaround for staying on an older version.

On USBHost_t36: yes, the host side works too, same pattern as the device. There's a fork and a recipe:

- Fork: github.com/sauloverissimo/USBHost_t36, branch feature/midi2-host-base. Download the ZIP and copy 2 files (USBHost_t36.h and midi.cpp) over the library, in hardware/teensy/avr/libraries/USBHost_t36/.
- Recipe: teensy41-host-midi2 in midi2cpp. USB Type = Serial (the Teensy becomes a pure host; debug goes out on the Serial Monitor).
- Hardware: a USB host cable on the Teensy 4.1 plus a USB MIDI 2.0 device to plug in (another Teensy running teensy41-midi2 works, or any MIDI 2.0 controller).

On the host: it's newer than the device, I've been working on it since May and haven't sent a PR to Paul yet, so it's more experimental. But it's validated and running very well. I ran a stress test of 144k UMPs over 9m43s, 0.00% loss. Still maturing it though.

;)
 
I tried to add MIDI2 support for an eDRUMin 12, but it's not looking good. I would definately need to do lots of code shuffling.

Code:
[FONT=Calibri]Using MID 2.0
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:   FLASH: code:352820, data:33476, headers:8592   free for files:7731576
teensy_size:    RAM1: variables:168128, code:340080, padding:20368   free for local variables:-4288
teensy_size:    RAM2: variables:5856  free for malloc/new:518432
Error program exceeds memory space

Not Using MIDI 2.0
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:   FLASH: code:332084, data:33476, headers:8848   free for files:7752056
teensy_size:    RAM1: variables:168128, code:319344, padding:8336   free for local variables:28480
teensy_size:    RAM2: variables:5856  free for malloc/new:518432

Hmmm. But I did manage to get it to fit on an eDRUMin 8. There's hope. That's enough for today.
 
@yeahtuna, from what I'm seeing (I could be wrong), it's not the variables, it's ITCM. The variables are identical in both builds
(168128).

What grew is code: MIDI 2.0 adds ~20.7KB (340080 vs 319344), and that pushes ITCM from 10 to 11 32KB blocks. It's that 11th block
(360448) plus the variables (168128) that overflows RAM1 by exactly those 4288 bytes.

Is this code yours? If so, is there any room to trim it so it all fits in RAM1?
 
Ya, it's my code. I just need to more stuff to RAM2 and test.

From the research that I've done, for drum devices anyway, most of the work is going to be in getting the MIDI-CI bit working properly, but that seems to be very poorly defined at the moment.
 
Last edited:
Finally got some real testing done using the MIDI 2.0 library. I'm just sending MIDI 1.0 messages, but CC, NoteOn/Off and aftertouch all seem to be working properly.

I honestly think 7 bit velocities are fine for drumming, but profiles and property exchange are things the e-drum world desperately needs.
 
@GraveV You make up a good point, from the customer's perspective, it is backwards compatible, but not for developers. Also, there's no reason why a MIDI-CI API couldn't have been aggreed upon and implemented over MIDI 1.0 using sysEx messages. And now that I can test and start implementing MIDI 2.0, all that I can do is reimplement MIDI 1.0 functionality because Profiles, and Property Exchange are still not well defined.
 
@yeahtuna Don't feed the troll. Imagine how many kWh of energy and litres of water were wasted so that an LLM could generate a vacuous summary of this thread -- all paid for with some unfortunate suckers retirement savings -- so that a nonsensical spam link could be posted to your thread. The human race is doomed
 
@yeahtuna Don't feed the troll. Imagine how many kWh of energy and litres of water were wasted so that an LLM could generate a vacuous summary of this thread -- all paid for with some unfortunate suckers retirement savings -- so that a nonsensical spam link could be posted to your thread. The human race is doomei
 
@yeahtuna Nice, if it's your code you've got all the room to move things around. RAM2 should do it. By the numbers you were only 4288 bytes
over on DTCM, so pushing a handful of variables to RAM2 (DMAMEM) should let the rest settle in. Less invasive than touching the
code.

On MIDI-CI: I hear you, it's the fuzziest part right now. One thing that might take some weight off: the negotiation that
actually unlocks the 32-bit resolution is UMP Stream Endpoint Discovery (MT 0xF), not MIDI-CI. MIDI-CI (Profiles, Property
Exchange) is an optional layer on top. For a drum instrument sending high-res notes you can stay on Stream Discovery and leave
CI out, at least to start, and that also saves a good chunk of that code.

If you do go for CI, what's feeling poorly defined to you? I ran into some ambiguities implementing it too, and I might be able to
save you time by pointing at how the Workbench and Windows MIDI Services expect the replies to look
 
@sauloverissimo I've been spending more time testing and I'm consistently running into issues when sending lots of sysEx messages in a short period of time. Does your library do anything to prevent a partial sysEx messages from being transfered while it's still being packed? This was a notorious issue with the old usbMIDI library which required modification to prevent sysEx from being truncated or dropped, especially on Linux and macOS where USB devices are polled more aggressviely.

UPDATE: After wasting the better part of a day, I'm thinks that macOS has broken sending sysEx messages to MIDI 2.0 devices using legacy API's. So much for the promise of backwards compatibility.

UPDATE UPDATE: I needed to uninstall the device so that the new driver sould be loaded.....It's always something stupid. Mostly working again.
 
Last edited:
@yeahtuna<
Yes, and it covers more than SysEx. In the fork the UMP writes are atomic: a message goes on the wire whole or not at all, never a
fragment. That holds for any multi-word UMP, and multi-packet SysEx stops at the first short write instead of leaving a hole in the middle. It's exactly the old usbMIDI gap. Glad the driver reload sorted your case.
 
Glad to hear it, @ETMoody3.
The Korg Keystage is one of the very devices that satisfy the criteria Paul set, so plugging it into
the Teensy host port is a solid test.

Tell me more about your MIDI-to-CV build. It's exactly the kind of project that gains the most from MIDI 2.0, and I'd love to
understand what you put together.

While you catch up on the reading, there are Teensy recipes to look at. midi2 (the portable C99 core) has teensy-device-midi2,
closer to the metal. midi2cpp (the C++ wrapper) has teensy41-midi2, the control surface and the host. The recipes
pass the MIDI Association's MIDI 2.0 Workbench, so they make a clean reference to start from. ;)
I'm sorry, life has kept me from being able to pay a lot of attention to this... but I'll get there.

The MIDI to Cv is Teensy 4.1 driving 6 MCP 4922 DAC chips for 12 outputs, scaled to -6v to +6v for recreations of Moog modules. I have MIDI clock - based LFO functions, duophonic poly aftertouch, channel aftertouch, continuous controllers all assignable. I do not have MIDI note - to - pitch implemented as there is a separate module that does that. Seems to work well, even with all 12 being sent CC "LFO" data at the same time.

I am using the USBHost library for both MIDI keyboards and a remote control panel ( esp32 - based 'HMI' )

There's so many applications for MIDI 2.0 capabilities here.
midi2cv.jpg
 
Last edited:
There is a somewhat strange, fairly small, and moderately inexpensive (as these things go) mini synthesizer called Gamma, from this.is.Noise, Inc. I saw an ad for it on Facebook, which casually mentioned MIDI 2.0 as one of the features.


I asked a question on that ad, and they responded, pointing me to the relevant section of the manual which does indeed describe the MIDI 2.0 capability to some extent:


I don't own this device and have no experience with it, but for those developing MIDI 2.0 implementations it occurred to me that a USD 300 synth (which can be a controller, or can be an externally-controlled synth) was a more affordable and more capable thing to test with, than a USD 700 Korg Keystage which is a controller only.
 
Back
Top