I know I’ve already posted articles in the past about MicroDexed, but here is yet another one – I primarily wanted to make a video talking about some of the functionality.
MicroDexed on Teensy4.0
After my last post about Dexed on the Teensy, I got an email telling me about MicroDexed.
These makers have already ported Dexed to the Teensy 4.0 and added a nice LCD based GUI to the software. They even have a custom PCB and a manual on how to build it. But I couldn’t find a schematic in their documentation. Undeterred, I read through the source code and reverse engineered the hardware based on the build manual and software source code. I already had most of the necessary parts so I ordered a Teensy 4.x audio shield and was able to get a working version of MicroDexed. I am impressed with the results, much better than what I have been able to acheive. Hats off to the folks at Parasitstudio.
There are a few caveats, that I’d like to share in case you want to take on this challenge yourself.
- My i2C LCD display was not compatible with the 3rd party LCD library that was provided so I rewrote the LCD library.
- The Code assumes you have a Teensy 3.x Audio board. The pins used to control the audio board are different between version 3.x and 4.x. I struggled with this for a while because the rotary encoder uses digital pin 8 which will collide with the Teensy 4.x audio board. It works fine with the Teensy 3.x audio board but you will have to remap it for the Teensy 4.x audio shield. I just used pin 9.
- There is quite a bit of latency due to the animated LCD display. In the video, you can see that when I disable the LCD display, the MIDI latency goes away. However, the code out of the box does not compile if ENABLE_LCD_UI is disabled. I had to expand the conditional compile directives to get the code to compile without errors.
A lot of information is available in the documentation and most of the important bits of code is in config.h.
When I first started out porting Dexed to the Raspberry Pi Pico, my goal was to attempt to create a DX clone for under $10. Although the Pico was only $5, all of the other parts pushed the BOM costs closer to $20 and I was ultimately only able to get 2 voice polyphony out of the prototype.
A Teensy 4.0 and 4.x audio shield will set you back about $35. Of course, like the Pico, you’ll need some power circuitry, an LCD, a couple rotary encoders, MIDI/Audio connectors and a case which will add to the cost. But MicroDexed is able to run 2 Dexed instances that each have 32 voice polyphony according to the source code. I have not confirmed the max polyphony, by the way. So if we allocate $20 for the rest of the circuitry, we could have 2 DX clones for a little over $50! If we consolidate 4 Teensy into a single project then it is conceivable to have TX816 clone for under $200!
As I only got the prototype working recently, I still need to play with the MicroDexed to look into all of the features. The MIDI implementation looks quite comprehensive. Given the success with MicroDexed on the Teensy, I may consolidate several to build a TX816 clone as well as connect it to the sequencer.
More Polyphony, slightly better sound.
I ported DEXED to both the ESP32 processor and TEENSY4.0 MCU + Audio Shield. Pictured is the Teensy4.0 + audio shield and a 128×32 OLED display to display the patch name.
With the Teensy4.0 I have been able to confirm at least 10 voice polyphony! However, there is a slight “glitchiness” to the sound which is more pronounced depending on the patch. You can really hear it in the YouTube video, especially the E.Organ1 patch! I think it is mostly software based because it is virtually non-existent on some of the other patches.
What about the ESP32？
I couldn’t get the ESP32 board to quite work but the problems can be overcome. One issue is that the ESP32 software development environment is built around a RTOS. It does not appear that one can develop an application in a “bare metal” or near “bare metal” mode like the Raspberry Pi Pico. As a side note, the Raspberry Pi Pico supports both a “bare metal” environment as well as a Arduino centric library. The ESP32 RTOS assumes your process will yield to a watchdog process and this yielding and task switching will take approximately 10 milliseconds. Well, 10 milliseconds in real-time audio is forever and causes big glitches in the sound generation. I was able to get around that by using a suggestion in some forums to set the task priority to the taskIDLE priority
xTaskCreate(someFunction, “HumanReadableNameofTask”, 4096, NULL, tskIDLE_PRIORITY, NULL)
The ESP32 restriction of working in the confines of an RTOS was an unexpected hurdle in porting DEXED. But ultimately I couldn’t get DEXED to run on the ESP32 because the DAC I have doesn’t work well with the DMA of the ESP32. I’ll have to look into a different DAC to fix that. That will be a separate project.
As an aside, the Teensy audio library only works in the Arduino environment. The Pi Pico can work either in a “bare metal” environment mode or Arduino environment. The ESP32 only works within its RTOS environment.
When I first worked on getting DEXED to run on the Pico Pi, my objective was to try and get a really cheap DX7 clone running. Since the Pico Pi is only a $5 MCU, just adding a cheap DAC seemed like I could get a DX7 clone for under $10. But I could ultimately on get 2 voice polyphony out of it. I pursued the ESP32 MCU as it is only about a $8 MCU but, as I mentioned, I couldn’t quite get it to work. Which brings me to the TEENSY4.0 board. This board list for $20 USD but since I don’t live in the US, it ends up costing me more around $25 locally. But for that amount of money, getting 10 voice polyphony out of the Teensy makes sense. The processor is board is 5 times cost of the Pico Pi which could only generate 2 voice polyphony so getting 5x polyphony would be expected to make sense from a cost perspective. The Teensy audio daughter board lists for about $14 and is more expensive than my home brew DAC I built for the Pico Pi but given that it just “worked out of the box” and I didn’t have to fiddle with any clocks or software to get the precise sampling rates was well worth the cost. The Pico Pi prototype had some noise issues and given that I am convinced that the noise issues on the Teensy are likely all software based, I think it’s well worth the cost.
But given the cost of the Teensy and daughter board, it might make more sense to just run DEXED on a raspberry pi. But then there is no fun in that as it would just likely work. There would be no porting work involved and that’s a lot of the fun!
Building the MIDI sequencer with the Raspberry Pi Pico was a great learning experience and a chance to learn the details and features of the Pico microcontroller.
I thought it would really cool to combine the sequencer with a sound source other than my Reface DX or other MIDI synths, so I embarked on building a Pico based synthesizer. After searching for different ideas, I found a few open source software emulations of the fabled DX7. One in particular that caught my eye was a program called DEXED. It is open source and written in C/C++ which made it an attractive candidate to attempt a port to the Pico. I had no idea if the Pico would be fast enough to run the software but decided build a prototype and give it a try.
So with a minimal number of parts, the Pico Pi, a 12 bit DAC, a MIDI in circuit, a 2-digit 7segment LED and BCD driver, a active low pass filter, I built the circuit and proceeded to port DEXED to the Pico. The point of this project was to see if Pico could run DEXED. I wasn’t too worried about sound quality as long as it was “good enough”.
Well, to my surprise, I was able to get it to work. In fact, I ported the original DX7 ROM into the code and am able to confirm that it indeed sounds like the original DX7! I guess it would be more accurate to call what I created a TF1 clone (one of the modules in the TX816), since the DX7 has a keyboard, touch panel, etc and the TX7 also has and LCD screen with some buttons. The 7segment LED and BCD driver isn’t necessary to make the prototype function correctly but it made it easier to figure out which patch was selected.
However, the prototype isn’t without problems. First, it’s really noisy. It has a low pass filter, but it has a lot of noise and hum. This has a lot to do with the cheap DAC I chose as well as the fact I used the same power source for both digital and analog power references! Of course, this can be remedied with a better design and additional parts but my goal was just to see if the Pico could run a port of DEXED. I figure I can work on cleaning up the audio quality later once I proved that microcontroller could run DEXED.
But the other limitation and probably the biggest problem with the prototype is that the Pico can only handle 2 voice polyphony and that’s after overclocking the Pico to 290Mhz. I have a few ideas on how to fix this.
– Optimize DEXED. I admit I don’t understand the code well enough to try and make it run more efficiently. It might work great on a modern core i7 but the ARM core M0 processor in the Pico even overclocked at 290Mhz cannot cope. But DEXED looks like it already has a lot of optimizations by using trigonometric lookup tables but it does have some 64-bit math and a logarithmic math. However, I am doubtful optimizing those bits would amount to a significant amount of additional polyphony.
– Try to use the second core of the Pico. Since the Pico is a dual core processor, it might be possible to double the polyphony by leveraging the second core on the device. But even so, that would still only amount to 4 voice polyphony. I know that writing low level multi-core code can be tricky so this might be a lot of effort for not a lot of gain.
– Try a different microcontroller with more horsepower. I’ve been looking into the ESP32 whose specs look like it might be sufficient to run DEXED and get 8 voice polyphony or even more.
Many people think of the Yamaha Montage as an FM synth and a sample based (AWM) synth. But if you own an FM synth like the Yamaha Montage then you also own an synth with additive synthesis capabilities.
A typical waveform is the square wave. A square wave is just all of the odd partials add 1/N amplitudes. So, the fundamental has a relative amplitude of 1.0. All even partials have a relative amplitude of 0 so we can skip those. The 3rd partial has a relative amplitude of 1/3 (0.33), the 5th partial is 1/5 (0.20), the 7th partial at (1/7) 0.14, the 9th partial at (1/9) 0.11, the 11th partial at 1/11 (0.09) , the 13th at 1/13 (0.08), the 15th at 1/15 (0.07) etc.
I used algorithm 1 which is all 8 operators as carriers.
Then set the relative frequency and levels as follows:
But the result sounded nothing like a square wave! In fact, when I looked at the output, it looked like this:
Which you can see is just a simple sine wave!
It turns out that the operator levels are not linear but exponential. Here are the relative measurements I measured the AC voltage of the single operator output at 440Hz and normalized the results.
|Op Lvl||Normalized Magnitude|
At operator level 9 and lower, my DMM could not read any voltage so I just assumed it was a normalized level of about 0.01. Now resetting the operator levels to the normalized values as follows:
Then I got something that looked like
But that’s not a square wave – but it sounded like a square wave. The scope output looked like the operators were not in phase. After some investigation, I found that the operator frequencies drift. I was playing A440 on the keyboard and the Montage is tuned to 440.0Hz. I measured the frequency of a single sine wave on a DMM and found that the frequency would drift between 438Hz and 442Hz. I also confirmed there is no pitch modulation on the operator. I don’t know if this is intentional or an idiosyncrasy of the Montage OS version I am using which is version 3.50.0. When I reset the oscilloscope to trigger at the beginning of the sound, it looked like
This looks very much like a square wave comprised of the first 8 partials. So we can safely assume that the operators are in sync in the beginning but drifts over time.
The Montage can generate up to 31 partials, so let’s try that. This can be accomplished with a performance with 2 FMX parts.
FMX Part 1
FMX Part 2
Here is what it looks like
Is it a true square wave? No. It has some very some “ringing” in wave which I cannot explain. But when I compare it to the sampled square wave form (see below), it sounded the same to my ears. I can’t hear much over 12kHz so it might sound different to you.
We also know that FM synthesis can generate a “square” wave with 2 operators stacked with a 2:1 Carrier/Modulator frequency ratio.
Using any algorithm that has a 2 operator stack we can get square waves with varying degrees of “squareness”. It’s not really a true square wave but get’s pretty close. Here is the output of the waveform with various modulator operator output levels.
Modulator Output level is 67
Modulator Output Level 72
Modulator Output Level 75
They look like square waves and sound like square waves but is not as bright as the squarewave generated with the additive synthesis.
The Montage has an AWM (sample based) synth engine also. If we look at the Synth waveforms, there is a square wave sample (#2136) called P50-1 which is a square wave with a 50% duty cycle and looks like.
You can see it has the sharp pointy edges as you’d expect in a square wave but it had a bit of slope on the tops and bottoms which frankly surprised me. Regardless, it sounded the same as the square wave created with additive synthesis.
So, the Montage has 3 unique ways to generate waveforms like a square wave. Of course, the Montage has filters, effects, and a myriad of modulation sources which can be used to modulate these waveforms.