[posted] TeensyMIDIPolySynth

kd5rxt-mark

Well-known member
OK, so here's yet another Teensy4-based MIDI-capable 16-note polyphonic 2-voice synthesizer . . . that's a real mouthful.

PERSONAL BACKGROUND: I am a software engineer by day, so I write software (almost) all day long. My wife thinks I'm absolutely crazy for many reasons, but mostly because I also like to write software when I get home & want to relax !! However, truth be known, my hobby software is very often quite sloppy & unprofessional, so if you happen to take a look at my sketch, make sure to set your expectations appropriately low.

PROJECT OBJECTIVE/BACKGROUND: I've always been interested in synthesizers from the time that I started developing my taste in late '70s / early '80s music (think Styx, Kansas, ELO, etc.). I've longed to understand both how synths worked & the deep meaning of all of the terminology (e.g. VFO, LFO, CV, envelope, attack, decay, filtering, etc.). In the process of ordering a PC board from OshPark (in addition to software, I dabble in hardware/PCBs as well), the checkout process asked if i would like to add a Teensy 4.0 to my order. I thought to myself "I don't have any idea what a Teensy is, but for the price. . . sure !!" Upon receipt of that order, I did some quick research on "Teensy projects" & the first thing I found was, with the addition of an inexpensive "Teensy Audio Board", I could produce a very functional synthesizer. BONUS !! So, off I went . . .

CAPABILITIES (the initial idea for the capabilities that I would target was based upon a friend's Behringer Neutron - a *real* synthesizer, albeit monophonic & only *slightly* more expensive):
- implemented using the Teensy 4.0 + Teensy 4.0 Audio Board, plus Sparkfun 16-channel analog MUXs to manage the 48-pots, the 42 pushbuttons, and the 42 LEDs (the LEDs will need to be converted over to being driven using 74HC595 8-output shift register boards instead - the analog MUXs are managing so many inputs/outputs that the duty cycle on driving the LEDs is very low, so they are way too dim !!)
- 16-note polyphony, 2-voice (2 VFOs) per note
- LFO #1 serves as an input into the two VFO waveform generators for FM modulation
- modulation LFO can mix any combination of sine, square, pulse (with adjustable duty cycle), triangle, sawtooth, & sample/hold (each with amplitude control, both positive & negative, as well as waveform on/off pushbutton control)
- the modulation LFO can also operate in "single waveform" mode (to allow quick changes among the selectable waveforms)
- each of the two VFOs has an independent octave control (+/- 3 octave range)
- each of the two VFOs can mix any combination of sine, square, triangle, sawtooth, string, white noise, pink noise (each with individual amplitude control, both positive & negative, as well as individual waveform on/off pushbutton control), & tonesweep (with sweep rate control, either rising or falling frequency, & on/off pushbutton control)
- each of the two VFOs can also operate in "single waveform" mode (to allow quick changes among the selectable waveforms)
- the output from each of the two VFOs feed into an envelope generator, with attack, hold, decay, sustain, & release controls
- LFO #2 serves as an input into the filter for FM modulation of the corner frequency
- filter LFO can mix any combination of sine, square, pulse (with adjustable duty cycle), triangle, sawtooth, & sample/hold (each with amplitude control, both positive & negative, as well as individual waveform on/off pushbutton control)
- the filter LFO can also operate in "single waveform" mode (to allow quick changes among the selectable waveforms)
- the output from the envelope generator feeds into a filter, with selections for NONE (no filtering), lowpass, bandpass, & highpass, (with any mix of the last three) as well as control of the corner frequency & resonance
- control of master volume, AB balance (balance between the two VFOs), VFO tuning (to allow the output from this synth to be tuned to a physical instrument, like a piano), & AB detuning (add a small beat difference between the two VFOs)
- MIDI channel can be set to "All" (respond to all notes on all channels), or any individual channel from 1-16
- includes a "MIDI panic" button (stop all notes immediately without a power-cycle)
- has MIDI-in & MIDI-thru jacks
- has 1/8" audio out jack
- LIPO battery powered (12-20 hours of operation on a single charge), w/ Adafruit PowerBoost 1000 for battery management, as well as USB-powered
- appears as a USB MIDI device (named "Teensy16PolySynth")
- fully supports use of PitchBend wheel, Modulation wheel, & sustain pedal

LESSONS LEARNED:
1) this is definitely a one-off project . . . if I were to consider building another one, I'd definitely put the effort into designing a PC board for it - I would not survive trying to wire a 2nd copy
1) this is *NOT* a project that you take on to build something for less money than if you went out & bought the same capabilities !!
2) the wiring was very, very, very, very tedious & almost prevented me from completing the project
3) writing the software was the easy part for me (& I don't think it will ever be "finally & fully done") - again, it is very sloppy, but fully functional !!
4) I now completely understand synth terminology (at least the terms that I needed for this) & can at least appreciate the functionality (if not the actual operation under the covers) of the components (VFO, LFO, envelope, filter, mixer, etc.) of a real synth
5) the Teensy audio library is absolutely amazing in how easy it is to use & all of the capabilities that it provides !!

IF I WERE TO DO THIS AGAIN, CHANGES TO BE CONSIDERED:
- much of the layout was driven by the "plastic storage box" chosen for the build - get a bigger box (so more controls can be accomodated) !!
- add a separate envelope generator for each VFO
- add a separate envelope generator for the modulation LFO
- add a separate envelope generator for the filter LFO
- need to figure out how to add portamento/glide

FINAL COMMENTS:
The source is available for perusal on my Google Drive at the following link: https://drive.google.com/open?id=1ULPmJhpSQKHGne5fTUbfLNNLCdPRF13J

Example video of circus music played (via MIDI file) on a TeensyMIDIPolySynth configuration which emulates my idea of a calliope: https://youtu.be/5jyEEnRqu9s

Example video of carousel music played (via MIDI file) on a TeensyMIDIPolySynth configuration which emulates my idea of a calliope: https://youtu.be/adJfd6ney_g

The two MIDI files used for the YouTube videos can be found in the "MIDI" sub-folder via the Google Drive link given above. Looking at the content of these two example MIDI files can give a feel for the complexity of the polyphonic content that the TeensyMIDIPolySynth is capable of playing !!

I don't have any "in-progress" pictures (I don't want to be reminded of the pain), but a few pictures of the finished product can be found in the "pictures" sub-folder via the Google Drive link given above. That same pictures sub-folder also contains several snapshots from the Teensy Audio Layout GUI for reference.

The front-panel labeling started out as just a "drill template" & I had tentatively planned to add tape labels to the controls. I definitely did not look forward to how I was going to keep the haphazard alignment of the labels from making the finished product look very unprofessional. After laying out the drill template in the 2D/3D CAD program that I use, I realized that the drill template could easily transform into a full front panel overlay, with the labels included in the print. However, if you look closely (ignoring the hand-labeled areas), you can see where I changed my mind on some of the controls, so there are still a few label tape overlays.

Mark J Culross
KD5RXT

P.S. If you would like to try out the "calliope" for yourself, you don't need to build a full TeensyMIDIPolySynth of your own (even if you thought you might want to endure the pain !!). You can simply connect a Teensy4.0 + Teensy 4.0 Audio Board together & you have all the hardware that's needed !! Appropriate initial values are already incorporated into the setup() function. Simply change the "#define" lines near the top of the source file as follows, compile, download, & you're all set to use it as a USB MIDI device emulating my idea of a calliope:

//#define CHECK_CYCLE_TIME
//#define DEBUG_NOTE_MSGS
//#define DEBUG_CC_MSGS
//#define DEBUG_POTS
//#define DEBUG_PBUTTONS
//#define DISABLE_POT_MUX_SETTLING_TIME
//#define DISABLE_PB_MUX_SETTLING_TIME
//#define ENABLE_LED_MUX_SETTLING_TIME
//#define DISABLE_STATUS
#define DISABLE_POT_READ
#define DISABLE_PB_READ
#define DISABLE_EEPROM_READ
#define DISABLE_EEPROM_WRITE
//#define DEBUG_EEPROM_WRITE
//#define DEBUG_EEPROM_READ
//#define DEBUG_MAKE_NOTE_AVAILABLE
#define SKIP_LED_TEST

Have fun !! MJC
 
Last edited:
Oh crikey!!! Yes the Audio Library can seductively carry you away! Your wiring is quite neat considering the audacity of so many controls and LEDs. You've got multiple waveforms mixing together, which is interesting and sounds very good in the demo. Building your own synth teaches you lots about the decisions and connections that go into producing particular sounds and modulation. Some things are global and some work on a per voice basis.
 
Looks cool! Out of curiosity have you explored using a touchscreen display with little vgl? I've been using one push click rotary encoder and a touchscreen to great effect, minimal wiring just a bit more coding
 
Looks cool! Out of curiosity have you explored using a touchscreen display with little vgl? I've been using one push click rotary encoder and a touchscreen to great effect, minimal wiring just a bit more coding

I agree that the TFT would be a great addition (again, yet another reason why I need a bigger box !!). I did originally include that in my plans when I first started into this project. I have used the Adafruit 2.8" TFT w/ resistive touchscreen in lots of prior Arduino projects. However, since I started playing with the Teensy, I have not been able to get the touchscreen to work with the Teensy using the default Adafruit libraries. I have looked briefly at the ILI9341_t3 library (& have not kept up on whether it is also usable with the T4), but *all* of my experience is with the Adafruit library & because of my CDO (spelling it correctly) personality, it just is not easy for me to let that go !! Your suggestion of using the rotary encoder also sounds very good !!

Thanks,

Mark J Culross
KD5RXT
 
Good writeup Mark...and yes I am still trying to pull the serial writes to console to my build...your code isn't as busy as the code I am converting...

Mike
 
As RABB17 suggested, you may have a look at LittleVGL. It has nothing to do with Adafruit, nor with ILI9341_t3; it is a powerful GUI library entirely in C which supports many displays and input peripherals; it has a very small footprint and should work wonders with T4.
I'm using it for a Polysynth project with a 5" capacitive touchscreen linked to a Linux SBC.
 
RABB17 & XFer: Many thanks to both of you for the LittleVGL recommendation. I was not previously aware of this capability. I guess I know what I'll be playing with next !! I've been toying with the idea of an "add-on" box (connecting via CAT5 or some other simple & readily available cable . . . also considered nRF24L01 as I have used that in a few prior Arduino projects as well, eliminating the cabling) providing the ability to save/restore settings from the TeensyMIDIPolySynth, allowing me to quickly change between different setups (patches). Looks like I can now reasonably accomplish that using another Teensy+TFT+rotary encoder+littleVGL, all in a small box.

I really appreciate your feedback/suggestions !!

Mark J Culross
KD5RXT
 
I'm a total inept vs. GUI design :p but I'm sure you'll enjoy it! Great support, too.
Very first main menu for my project:

synth-gui-v0.1_lr.jpg
 
My TeensyMIDIPolySynth continues to evolve (now up to firmware version 4.2 & counting). The LED drive conversion is complete & working very well. Formerly, the LEDs were driven from the MUXs. That turned out to be a poor design choice. Because the MUXs were also used to read the pots & pushbuttons, the short time allocated to drive to the LEDs without adversely affecting the sample rate on the pots/pushbuttons caused to LEDs to be very dim. Funny, after changing to driving the LEDs using a bucket-brigade of shift registers (74HC595 breakout boards), the high-efficiency LEDs are actually now too bright !! I ended up using a PWM signal whose duty cycle is set by reading an additional pot to drive the output enable pin on the shift registers, allowing the LEDs to be selectively dimmed (e.g. for backstage, low-light operations), but still have full range of brightness (e.g. for operations even in full sun). Each of the control pots/pushbuttons was previously being sampled every 40-50ms when sharing the MUXs with the LEDs. Now that the LEDs are no longer part of the MUX operations, as an added bonus, each of the pots/pushbuttons are now sampled every 3-5ms thru the MUXs !!

The links given in post #1 for source, videos, pictures & MIDI files remain valid.

Here are some quick instructions if you'd like to experiment with the capabilities of the TeensyMIDIPolySynth on your own. The source employs strategic #ifdef/#ifndef/#endif statements which allow the MIDI operations to work without depending upon the remainder of the hardware that I built up (pots, pushbuttons, LEDs). It is entirely possible to experiment on your own by simply doing the following:

1) connect a Teensy 4.0/4.1 & a Rev D Audio Shield together

2) verify that the source contains the following near the top of the file:

//#define DEBUG_MEMORY_USAGE // uncomment to show audio buffer usage
//#define DEBUG_NOTE_MSGS // uncomment to show all MIDI noteOn/noteOff message activities
//#define DEBUG_CC_MSGS // uncomment to show all MIDI CC message activities
//#define DEBUG_POTS // uncomment to show specifics of pot sampling
//#define DEBUG_PBUTTONS // uncomment to show specifics of pushbutton sampling
//#define DEBUG_EEPROM_WRITE // uncomment to show specifics of EEPROM writes
//#define DEBUG_EEPROM_READ // uncomment to show specifics of EEPROM writes
//#define DEBUG_MAKE_NOTE_AVAILABLE // uncomment to show specifics of when notes are deallocated & made available
#define DEBUG_MAXIMUM_NOTES // uncomment to show a scrolling graph of note allocation/deallocation
#define DEBUG_DROPPED_NOTES // uncomment to show when notes are ignored (exceeded 16-poly notes)
#define DISABLE_POT_READ // uncomment to not read any pots (for running Teensy + Audio Shield w/o the actual TeensyMIDIPolySynth hardware)
#define DISABLE_PB_READ // uncomment to not read any pushbuttons (for running Teensy + Audio Shield w/o the actual TeensyMIDIPolySynth hardware)
#define DISABLE_EEPROM_READ // uncomment to not read settings from EEPROM (for running Teensy + Audio Shield w/o the actual TeensyMIDIPolySynth hardware)
#define DISABLE_EEPROM_WRITE // uncomment to not write settings to EEPROM (for running Teensy + Audio Shield w/o the actual TeensyMIDIPolySynth hardware)
#define SKIP_LED_TEST // uncomment to not test the LEDs (for running Teensy + Audio Shield w/o the actual TeensyMIDIPolySynth hardware)

3) configure your Arduino IDE as follows:

Tools/Board: "Teensy 4.0" or "Teensy 4.1" (as appropriate)
Tools/USB Type: "Serial + MIDI"
Tools/CPU Speed: "600MHz"
Tools/Optimize: "Fastest"
Tools/Keyboard Layout: "US English"
Tools/Port: "COMx Serial (Teensy 4.0)"

4) build & upload the resulting firmware to your Teensy

5) with your Teensy connected to your PC via USB, select the "Teensy16PolySynth" as the MIDI output device in your MIDI player app

6) play your favorite MIDI file (be aware that if the MIDI file applies the sustain peddle & doesn't remove it, all the notes might just run together & make an awful, muddy sound)

7) if you hook/wire up the 2nd USB port, you can connect a MIDI keyboard directly to the Teensy in USBhost mode & thus be able to "play" your TeensyMIDIPolySynth hardware

8) as a alternative, you can use your PC as a MIDI pass-thru & hook your MIDI keyboard thru your PC to "play" your TeensyMIDIPolySynth that way as well

If you really want to get the full experience, you can tinker the values in the "defaults()" function & see what other kinds of sounds you can create (by default, the source code is configured to sound like a calliope)

Good luck & have fun !!

Mark J Culross
KD5RXT
 
Last edited:
And here are a few more videos of my TeensyMIDIPolySynth in action:

(as a clarinet sound) : https://youtu.be/ka2uaDPyMTs

(as a accordion sound) : https://youtu.be/p1xfJp7eug8

(as a hammer dulcimer sound) : https://youtu.be/49o3yW9nNdQ


I continue to be absolutely amazed at the versatility & capabilities of the Teensy 4.0 + sound library !!

Mark J Culross
KD5RXT

P.S. For those familiar with the inner workings of commercial synthesizers, none of the TeensyMIDIPolySynth sounds in any of the videos posted so far involve any "samples". They were all created by twiddling the knobs until I got the intended sound . . . or at least as close as I can get with the controls that I have designed & built into the hardware & firmware. MJC
 
I agree with the conclusion: wiring all that must have been maddening!
There's a reason modern electronics largely use touch screens :-D
 
Forgot to post sooner that portamento/glide is now implemented in the latest firmware (as well as a variety of other additions), source for which is posted on my Google Drive...instructions for tinkering with the capability without the actual hardware still apply as before.

I would like to include multiple "patch definitions" in the defaults() function, with all but one (most likely the original calliope since that's what I started with) commented out, where you can easily uncomment a different setup & play with the different sounds, again, without the actual hardware. I'm saving that for another rainy day !!


Good luck & have fun !!

Mark J Culross
KD5RXT
 
Back
Top