Trinket USB MIDI Multi-Pot Mozzi Synthesis

As I mentioned last time, I wanted to get my Trinket handling USB MIDI (as a MIDI host) so I could plug my Korg minikeys directly into it.  This wasn’t quite as straight forward as I imagined it would be, but I got there in the end.

  • In part 2 I start to look at how to achieve polyphony with Mozzi on the Trinket.
  • In part 3 I further optimise the code for better performance.
  • In this follow-up post, I look into running the same code on the SAMD51 based ItsyBitsy board.

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

These are the key tutorials for the main concepts used in this project:

If you are new to microcontrollers, see the Getting Started pages.

Parts list

  • Adafruit Trinket M0 (or probably any other Adafruit M0 board)
  • 1x 10uF non-polar capacitor (optional)
  • 2x 1kΩ resistors (optional)
  • 4x 10kΩ potentiometers
  • 3.5mm jack socket (optional) and amplification
  • Breadboard and jumper wires

The Circuit

TrinketUSBMIDIMultiPotSynth_bb

This is essentially the circuit from Trinket FM Synthesis with Mozzi but with two added potentiometers on the remaining two IO pins.  The potentiometers are wired up as follows (left to right in the diagram):

  • Pot 1 – GPIO 3 – Waveform – sine, triangle, saw, square.
  • Pot 2 – GPIO 4 – FM Intensity.
  • Pot 3 – GPIO 0 – Modulation Rate.
  • Pot 4 – GPIO 2 – Modulation Ratio.

As the Trinket is acting as a USB host rather than a device, it will have to power the attached device itself.  Consequently I can’t power it via its micro-USB port.  Instead, I’m using a USB power supply to feed 5V into the “USB” pin on the Trinket via the breadboard.  This gets passed through to the micro-USB connector to power the attached device and the Trinket includes regulators to take this down to its own 3.3V.

Warning: The “top” +ve rail of the breadboard is running at 5V and MUST NOT BE CONNECTED TO THE REST OF THE CIRCUIT.  The “bottom” +ve rail of the breadboard is running at 3.3V from the 3V pin of the Trinket.  I’ve used orange for 3V power and red for 5V in the circuit diagram above and photo below.  Both grounds are connected together (black).  I strongly recommend you check your power and ground connections before turning anything on!

I was having my usual noise issues using the USB keyboard – there are real ground issues in all this – but I found it was greatly reduced if I connected the outer part of the USB cable to GND, hence the crocodile clip you can see in the photo below.  Once again I’m also using a “micro USB OTG adaptor” too.

2021-03-22 20.34.53

The Code

The code was a little more complicated to get going than I first thought. It is essentially a combination of the following two projects:

In that I am attempting to use the SAMD port of the USB Host Shield library with the Arduino MIDI Library and Mozzi.

The complication is that I am wanting to use the Trinket as a USB host MIDI device, which isn’t directly supported.  I spent a while looking at a range of approaches:

  • Using the SAMD USB Host library and writing some simple MIDI handling of my own for receiving.
  • Swapping out the USB device side of the USBMIDI “transport” for the Arduino MIDI Library with the code for a USB host instead.
  • Writing a new “transport” for the Arduino MIDI Library to use the USB MIDI code from the SAMD USB host library.

In the end I went with the last option, and was going to start with the Arduino-USBMIDI transport and see how far I could get when I happened to stumble across an experimental version of Arduino-UHS2MIDI which was actually doing exactly what I needed, except it is for the original USB host shield.

So in the end the task became “how to port the UHS2MIDI code to work with the SAMD USB Host library”.

Here is what you need to do if you want to give it a try.

  1. Download the code in ZIP form from the Arduino-UHS2MIDI GitHub repository and extract it in a temporary area.  You can’t import this one from within the Arduino environment as a proper library yet.
  2. Create a new sketch for this project and take the three files in the src area and copy them into the sketch directory.
  3. You need to have installed the USB Host Library SAMD (as described here).
  4. There are some changes required to the UHS2-MIDI.h file as described below.

The original Mozzi code still won’t quite work “as is” as it has to be updated for the following:

  1. To use UHS2-MIDI rather than the default MIDI serial port code.
  2. To configure the potentiometers for the Trinkets four IO ports.
  3. To replace the use of mozziAnalogRead with the original analogRead.
  4. I couldn’t use a “custom” MIDI initialisation with UHS2-MIDI as I did in the original (I tried, but couldn’t quite work out how to add it in properly), so wasn’t able to include the option to set “Use1ByteParsing” to false.  This means there is the potential for stalling of the MIDI handling if there is too much going on within the main control loop. I compensated for this by adding additional MIDI.read() calls at various points throughout the code.

I also took the opportunity to tidy up a few other odds and ends, for example to allow the pre-setting of the ADSR parameters at the start and removing some of the extensive debug code from the original.

One final modification – I gave it the option to be a USB device too, which means optionally using the original USBMIDI library.  This is chosen using a at the top of the file.  Depending on the setting it will either include USB-MIDI or USH2-MIDI and initialise the MIDI device as required.

// Uncomment the following to act as a USB Host device.
// Comment it out to act as a USB device.
#define USBHnotD 1

#ifdef USBHnotD
// Uses USB Host Library Transport for the MIDI library
#include "UHS2-MIDI.h"
USBHost UsbH;
UHS2MIDI_CREATE_DEFAULT_INSTANCE(&UsbH);
#else
// Uses USB MIDI Transport for the MIDI library
#include <USB-MIDI.h>
USBMIDI_CREATE_DEFAULT_INSTANCE();
#endif

It seems to still work, so I don’t think I’ve broken anything significant!

Find it on GitHub here.

Changes to UHS2-MIDI.H for USB Host Library SAMD

Line 57:
uhs2MidiTransport(USB *p, uint8_t cableNumber = 0) : USBH_MIDI(p)
Becomes:
uhs2MidiTransport(USBHost *p, uint8_t cableNumber = 0) : USBH_MIDI(p)

Line 64:
uint8_t uhs2MidiTransport::SendData(usbMidiEventPacket_t packet){
Becomes:
uint8_t SendData(usbMidiEventPacket_t packet){

Line 69:
usbMidiEventPacket_t uhs2MidiTransport::RecvData(){
Becomes:
usbMidiEventPacket_t RecvData(){

This also means that the examples provided with the UHS2MIDI code will no longer compile unless similar changes are made there.

To use this as a MIDI transport for the Arduino MIDI library requires the following:

#include "UHS2-MIDI.h"

// Initialise the USB host MIDI handling
USBHost UsbH;
UHS2MIDI_CREATE_DEFAULT_INSTANCE(&UsbH);

and then from this point onwards it pretty much works as before.

Closing Thoughts

It was a fair bit more involved than I initially anticipated getting this up and running, but it seems to work ok once I got there.  There are a few things I’d like to explore further now:

  • How much processing power is being taken up by Mozzi on the 48MHz, 32-bit SAMD21 (compared to the 16MHz, 8-bit ATmega328 on an Uno or Nano).
  • A better arrangement for powering the whole thing.
  • Do something about the ground/noise issues with that USB keyboard!
  • See if it is possible to get a dual-oscillator configuration running for some simple polyphony.

Kevin

5 thoughts on “Trinket USB MIDI Multi-Pot Mozzi Synthesis

    1. I did a bit of playing around with USB MIDI here: https://diyelectromusic.wordpress.com/2021/03/11/usb-midi-to-midi-revisited/. I would imagine the difficulty will be getting the trinket to give out a useful voltage for a CV… I’ve seen a number of projects based on ATmega328 Arduinos and ATtiny85s even, but these are natively 5V already, giving 5 octaves at 1v/oct useful range…

      I’d guess you’d need some kind of driver stage, but I’m afraid that electronics isn’t my strong point, so can’t really advise, but I have seen people use a Teensy for this purpose so there might be some useful info there you might be able to bring over to the Trinket… Here is one example (I can’t vouch for it, I was just looking around) https://github.com/elkayem/usbMIDI2CV_MC/tree/master/Electronics – I wonder if the output stage after the DAC would work with a Trinket’s native DAC… either way you’d need some amplification…

      … but I guess if you were going to these kinds of lengths, then getting yourself a cheap Nano or 5V Pro Micro might be the cheaper option? That is where my thinking currently takes me anyway.

      Good luck!
      Kevin

      Liked by 1 person

  1. Yeah that will be the tricky part. I’m going to attempt to reuse gdsports’ pwm code and boost it through a logic level shifter. I was excited about the DAC but i’m not sure how to go about using it and its 10 bit (i’m not an electronics guy either). I have a nano but it needs a usb host shield i believe and pro micros here (australia) are 30 bucks!

    Like

    1. I guess the difference between PWM and the DAC is that for PWM you are logic level shift in the “digital” domain – i.e. the 0 vs full voltage “sweep” is updated and you’ll (hopefully) get 5V PWM out the other side ready for appropriate filtering/etc. You’ll need a level shifter/buffer that can work at your PWM’s carrier frequency though, which might rule out some of the cheaper ones… I seem to recall reading somewhere that it is possible to saturate an Op Amp and end up “amplifying” the PWM level of an input to the power rails of the Op Amp… but I might be making that up!

      With the DAC you have an analog 0-3V3 signal already so it is more a case of amplification than level shifting. For that I’d imagine we’d be talking Op Amps and/or transistors to amplify the signal to 5V. The plus side is that you won’t (shouldn’t) need any additional filtering on the output for smoothing…

      Neither of these are things I’ve done, but that is what I’d be reading about to do it myself.

      Either way I suspect your design would benefit from a buffer stage of some sort regardless to keep your trinket safe against any CV inputs drawing too much from it when in use…

      Another random idea – if you had an SPI driven 5V happy DAC maybe you could drive that from the Trinket? You might even get away with an I2C DAC, as the MIDI stream/CV is probably not changing quick enough to be an issue.

      Whatever you end up with, do report back and let me know how you get on!

      Kevin

      Like

Leave a comment