Jteensy8000 - Clone of a clone with extra filters

bk40

Active member
Hi,

I’ve been lurking here for a while now and finally at a point that I feel brave enough to show the project.

Started as a way of teaching myself the teensy. Project was to clone the behringer jt-4000. Be able to open its patches. Hit loads of hardware issues so far up on that until the code was finished (never going to be)

Currently I’ve ported it to use the microdexed hardware as I had built one and it had inputs and outputs ready to go.

It’s grown to a 6 voice but can be overclocked to do 8 voices. And it’s now jt8000 as it has increased functionality to match the jp8000.

Additional features, obxa filter, virtual analogue filter bank based on “THE ART OF VA FILTER DESIGN” by Vadim Zavalishin.

Feedback ocilator path for all Oscillators, superchorus recreation and god knows how much else. I’ve been at this a while. Oh I also updated the audio waveforms so that you can modulate pitch and frequency as it fitted my needs better.

There is a html editor, usb host support.

To come loading of syx, fill in final missing features

Will work with just teensy4.1 connected to pc but might need to change your audio shield but it does do usb audio too.

All new code should be easy to port in to existing projects so feel free to play with the supersaw or filter elsewhere

Picture and example

See the Code this is all open source as I’ve used various AI tools to create. I will put proper headers in there at some point.

Hope there is something someone finds interesting here.

I need to do some serious work on the hardware as I’d prefer to have a board made.

Things I’m needing.

1. What is the best display that works well.
2. Has anyone had success with using multiple pots via multiplexing. I kept getting noisy results. I want to use sliders and pots for almost every feature. I’ve tried various layouts.

Respect to everyone whose done work here I’ve looked and where possible followed advice

Thanks
Kris
 
Today I was working on patches and the cc updating each of the editors. I ended up just playing for a while


There is another that I changed some filter modes during playing

 
1. What is the best display that works well.

ILI9431 is the best supported, though many others work too.


2. Has anyone had success with using multiple pots via multiplexing. I kept getting noisy results. I want to use sliders and pots for almost every feature. I’ve tried various layouts.

Muxing always adds some noise. There are a few things you can do the lessen the effect.

1: Use lower impedance pots, like 5K or 10K. Diminishing returns below 5K.

2: Add a ceramic capacitor like 10nF between each pot output and GND.

3: Wait a short time between changing the mux pins and starting the analog read.

See the Code this is all open source as I’ve used various AI tools to create. I will put proper headers in there at some point.

Should any of this eventually be merged with the audio library? If so, please consider adding MIT license headers to those files. Needs to be MIT same as the rest of the library, if it is to be merged in future versions.
 
If you use encoders and lose the sliders then you can get a really stable interface, I used to use pots all the time, upto 128 in one project, noise is always a problem. I try to use encoders attached to mcp23017 chips now, it just uses 2 lines (i2c) instead of multiple address and input lines for mux devices. You can even add LEDs and buttons to the MCP chips. Each chip has 16 inputs and that is 8 encoders per chip, 8 chips on one i2c bus is 64 encoders. I've expanded the library to use 2 i2c busses with the same library for 256 inputs or outputs.
 
If you use encoders and lose the sliders then you can get a really stable interface, I used to use pots all the time, upto 128 in one project, noise is always a problem. I try to use encoders attached to mcp23017 chips now, it just uses 2 lines (i2c) instead of multiple address and input lines for mux devices. You can even add LEDs and buttons to the MCP chips. Each chip has 16 inputs and that is 8 encoders per chip, 8 chips on one i2c bus is 64 encoders. I've expanded the library to use 2 i2c busses with the same library for 256 inputs or outputs.
I prefer the feel of programming the sounds with pots. But I’ve been through 3 builds already and even with the capacitors but always struggled

But maybe I’m just using the wrong ones.

Do you have any recommendations?

And thanks I’ll look in to the library
 
I always use RK-09 10K pots of some type or other when I build with pots, my current project is using sliders and pots and I get a little jitter just on two of them at mid way point, a bit annoying as these are tuning related pots. Anyway I moved away from pots and sliders to encoders where possible. I was always weary of them, it felt daunting, but when you realise the benefits of continuous controllers life becomes simple. When using an encoder it will always be in the right position when you recall a patch, so no huge jumps when turning the VCF cutoff. I use 24 position encoders for good movement, plus you can put acceleration on them for fast moving through parameters and there is no jitter. Additionally you can use the switch type encoders and use the switches as fast access, so if I push my Attack encoder button it immediately goes to 0 and push again and it returns to the last setting. I use that a lot for fast zero of modulation etc. The library is modified from the orginal so I have local copies that I use. You can checkout my github page for vesrsions of this. Probably best to look at https://github.com/craigyjp/Teensy-Hybrid-TDM-Synth as that has a lot of encoder and LEDs attached to the MCP chips, for buttons I'm using 74HC165 simply as it was built before I doubled the capacity of the library to manage 16 MCP chips which is in this build. https://github.com/craigyjp/Super-JX-10-V4-Vecoven-Editor You are looking at the AdaFruit libraries, the Button libs and the rotaryOverMCP stuff. If you look at HWControls.h it shows how you configure the MCP devices for encoders, buttons or LEDs and you will see how you can easily write to the LEDs or take action based on button pushes and encoder movements in my main code. checkEncoders();
 
If you are using Teensy pins 21 and 23 to transmit BCLK and MCLK, you may be experiencing high frequency effects like ringing or crosstalk or transmission line effects like relections, especially if the wires to the audio shield or whatever I2S chip you're using are not short.

Maybe try adding a series resistor, like 100 ohms, located close to the Teensy pin. A series resistor will go a long way towards calming such high frequency problems that can couple or cross talk into nearby signals.

For the analog inputs connected to the analog mux chips, maybe try A14-A17 which are farther away from those I2S clock pins.
 
If you are using Teensy pins 21 and 23 to transmit BCLK and MCLK, you may be experiencing high frequency effects like ringing or crosstalk or transmission line effects like relections, especially if the wires to the audio shield or whatever I2S chip you're using are not short.

Maybe try adding a series resistor, like 100 ohms, located close to the Teensy pin. A series resistor will go a long way towards calming such high frequency problems that can couple or cross talk into nearby signals.

For the analog inputs connected to the analog mux chips, maybe try A14-A17 which are farther away from those I2S clock pins.
Thanks for the advice. I will do another example board and see what results I can get
 
I always use RK-09 10K pots of some type or other when I build with pots, my current project is using sliders and pots and I get a little jitter just on two of them at mid way point, a bit annoying as these are tuning related pots. Anyway I moved away from pots and sliders to encoders where possible. I was always weary of them, it felt daunting, but when you realise the benefits of continuous controllers life becomes simple. When using an encoder it will always be in the right position when you recall a patch, so no huge jumps when turning the VCF cutoff. I use 24 position encoders for good movement, plus you can put acceleration on them for fast moving through parameters and there is no jitter. Additionally you can use the switch type encoders and use the switches as fast access, so if I push my Attack encoder button it immediately goes to 0 and push again and it returns to the last setting. I use that a lot for fast zero of modulation etc. The library is modified from the orginal so I have local copies that I use. You can checkout my github page for vesrsions of this. Probably best to look at https://github.com/craigyjp/Teensy-Hybrid-TDM-Synth as that has a lot of encoder and LEDs attached to the MCP chips, for buttons I'm using 74HC165 simply as it was built before I doubled the capacity of the library to manage 16 MCP chips which is in this build. https://github.com/craigyjp/Super-JX-10-V4-Vecoven-Editor You are looking at the AdaFruit libraries, the Button libs and the rotaryOverMCP stuff. If you look at HWControls.h it shows how you configure the MCP devices for encoders, buttons or LEDs and you will see how you can easily write to the LEDs or take action based on button pushes and encoder movements in my main code. checkEncoders();
Thanks I’ll have a read in to those, I like encoders for lots of things so happy to use them but cutoff and certain parameters I like to feel the feedback rather than click. So might be that I just have 4 assignable pots as my last hardware attempt used those pretty well and I had an encoder for navigation.
 
Thanks I’ll have a read in to those, I like encoders for lots of things so happy to use them but cutoff and certain parameters I like to feel the feedback rather than click. So might be that I just have 4 assignable pots as my last hardware attempt used those pretty well and I had an encoder for navigation.

I hope your project turns out well, I would like to have a go at building it if you finish and publish the build.
 
I hope your project turns out well, I would like to have a go at building it if you finish and publish the build.
Thanks me too, I have more changes then I’ll get the videos sorted. Turns out I’m a good bit out of touch with matching recordings to clips.

I’ve also designed the code to be hardware independent, it has an html editor, and juce version for daw integration. So even without my hardware as long as you have a teensy with psram installed it’ll play. Everything cc mapped (that was a mistake)

This is just my 1st guided design, without a goal I would never have managed to get close to producing.

But I have the supersaw matching as per all Adam’s white paper and lots of itterations. All I seem to have missed is the linearity of the detune amount. Every preset I’ve loaded needs it turned down. But also using polyblep and doubling sampling flags are in there too.

But I’ll calibrate that and envelopes.

I’ve dumped so many modules building this it’s going to fun gathering them all back up at the end.

This was the video I messed up, so the movement’s were to a demo but the audio was just me having a shot

 
Thanks me too, I have more changes then I’ll get the videos sorted. Turns out I’m a good bit out of touch with matching recordings to clips.

I’ve also designed the code to be hardware independent, it has an html editor, and juce version for daw integration. So even without my hardware as long as you have a teensy with psram installed it’ll play. Everything cc mapped (that was a mistake)

This is just my 1st guided design, without a goal I would never have managed to get close to producing.

But I have the supersaw matching as per all Adam’s white paper and lots of itterations. All I seem to have missed is the linearity of the detune amount. Every preset I’ve loaded needs it turned down. But also using polyblep and doubling sampling flags are in there too.

But I’ll calibrate that and envelopes.

I’ve dumped so many modules building this it’s going to fun gathering them all back up at the end.

This was the video I messed up, so the movement’s were to a demo but the audio was just me having a shot


I was just looking at a supersaw build myself, my plan was to go Pico per DCO and feed analogue filters, I wonder if I could build your front end and attach it to a CS42448 TDM board for 8 individual outputs.
 
I’d be honoured if someone could get anything from this work, audiosynthsupersaw is separate and can be initiated and work with the audio library.

I’ve worked on that for many hours so I will not messing with it for a bit.

Hypersaw and square will comeback. Done them but too many distractions so I had to refocus

My cpu grab is mostly with the filters at one point I do have 2 supersaw oscs running for multiple notes.

All this without over clocking, but I’m pushing the limit just now.

Will complete features then redo benchmarks
 
On mux'd pots - I use responsive analogue read which is great at smoothing out jitter. Also, I find it better to leave out the caps on individual pots when reading quickly through a mux.

Cheers, Paul
Thanks for that. Going to have a sit down after reading the other designs and most likely go for 2 designs.

One modular and one desktop. I had the module one working but my poor soldering was constantly letting me down.

Firmware will be same, just need to move away from the cc method. That was fine when doing the clone of behringer as they stripped it down. But it’s growing too big for that.

And this is just the start.
 
Thanks for that. Going to have a sit down after reading the other designs and most likely go for 2 designs.

One modular and one desktop. I had the module one working but my poor soldering was constantly letting me down.

Firmware will be same, just need to move away from the cc method. That was fine when doing the clone of behringer as they stripped it down. But it’s growing too big for that.

And this is just the start.
Cc is limiting in 2 ways, only about 120 usable parameters and also only 0-127 resolution which some people find a bit stroppy. Direct control with pots is better even if you only use 256 steps as doubles the resolution. You could use NRPN which increases the controls to a max or 16384 and of course the resolution as well. Also sysex which means basically you can do what you want.

When using an encoder I tend to keep it to 256 positions as anymore steps than that is difficult to navigate.
 
Cc is limiting in 2 ways, only about 120 usable parameters and also only 0-127 resolution which some people find a bit stroppy. Direct control with pots is better even if you only use 256 steps as doubles the resolution. You could use NRPN which increases the controls to a max or 16384 and of course the resolution as well. Also sysex which means basically you can do what you want.

When using an encoder I tend to keep it to 256 positions as anymore steps than that is difficult to navigate.
Thanks, I hated the cc restriction at the start but it was what I said I’d do so stuck it out. I have looked and started preparing for syx and nrpn but worried a switch will derail me just now.

So parked that until I get software at a good point.

I looks at your projects last night I had seen the TDM was very impressive.

I do have the parts for a moog filter sitting waiting to be built.

Love the programmer. I’ll be software done, flip to syx or nrpn. Then hardware layout an design. I like those sliders
 
I have absolutely no trouble getting stable reading with MIDI resolution (7 bit = 128 different positions) from dirt cheap Chinese analog pots. Yes raw ADC readings are noisy, but that is just a matter of proper post-processing in software. In my synth I read 64 pots and 48 analog hall sensors connected via multiplexers and I get absolutely stable reading (not even 1 bit noise at MIDI 7 bit resolution) and fast response time even without capacitors at pots (even though I initially made place for them on PCB).
My "secret formula" :) is not actually anything too complex, just averaging, hysteresis and scaling down.
1. I read pots 1000 times per second using 12-bit ADC via DMA
2. I run exponential moving average (essentially decimating input x16) using formula like this
Code:
avg_val = (current_val + 15 * avg_val )>>4
- at this point I got pretty smooth 12-bit readings
3. Now I apply hysteresis to avoid random moves up and down when pot does not actually move. To do so I get the averaged reading (obtained in step2) and subtract it from previous averaged reading. If absolute difference is less hysteresis then I do nothing. Hysteresis is the amount of LSB in 7 bits upscaled to 12 bit (1<<5) = 32. This way effectively removes +/-1 LSB trips when pot doesn't move.
4. When change computed in (3) is greater than hysteresis I compute new value as ( ( avg_val + 16 ) >> 5 ) - so I just scale 12 bit to 7 bit and round to nearest 7 bit number.

Below is a "pseudo code" that illustrates what I do:

C:
#define HYSTERESIS 33 // LSB + 1 , but you can bump it to 35 if your pots are super cheap and noisy

#define NUM_POTS 64

// the code below assumes 12 bit ADC

static int avg_value[ NUM_POTS ] = { 0 }; // static to keep values between "loops"
static int read_value[ NUM_POTS ] = { 0 };
for( int i = 0; i < NUM_POTS; i++ )
{
    int cur_value  = ... adc read .... // (in practice that reads from table that is feed  by DMA)
    avg_value [ i ] = ( cur_value + 15 * avg_value[ i ] ) >> 4; // exponential smoothing

    if( abs( avg_value[ i ] - read_value[ i ] ) > HYSTERESIS )
    {
        // this is only executed when pot moves more than 1 LSB
  
        read_value[ i ] = avg_value[ i ]; // store whatever we read in full 12 bit res
  
        int8_t midi_value = (int8_t) ( ( read_value[ i ] + 16 ) >> 5 ); // rounding and downscaling
  
        SendMidiCC( channel, i + 16 /* controller ID */ , midi_value );
    }
}

This gives perfectly smooth and fast readouts and no fluctuations when pots don't move.

You can see it in action in videos that I posted in other thread


As to 7-bit MIDI "limitation" - I don't consider it limitation at all. 127 different pot positions is plenty and you hardly can move pot more precisely than that. And having 127 discrete steps from pot is actually good thing in combating the noise (see above). The thing that some don't understand that limited resolution of MIDI CC does not mean that you have to have "stepped" control. In my synth I perform exponential smoothing and upscaling of MIDI CC to full 32-bit float, so when I turn the knob I get perfectly smooth, step-less transition and smooth filter sweeps. No stepping whatsoever. All you have to do is to upscale and interpolate from one position to another on sample-by-sample basis.
 
Last edited:
I have absolutely no trouble getting stable reading with MIDI resolution (7 bit = 128 different positions) from dirt cheap Chinese analog pots. Yes raw ADC readings are noisy, but that is just a matter of proper post-processing in software. In my synth I read 64 pots and 48 analog hall sensors connected via multiplexers and I get absolutely stable reading (not even 1 bit noise at MIDI 7 bit resolution) and fast response time even without capacitors at pots (even though I initially made place for them on PCB).
My "secret formula" :) is not actually anything too complex, just averaging, hysteresis and scaling down.
1. I read pots 1000 times per second using 12-bit ADC via DMA
2. I run exponential moving average (essentially decimating input x16) using formula like this
Code:
avg_val = (current_val + 15 * avg_val )>>4
- at this point I got pretty smooth 12-bit readings
3. Now I apply hysteresis to avoid random moves up and down when pot does not actually move. To do so I get the averaged reading (obtained in step2) and subtract it from previous averaged reading. If absolute difference is less hysteresis then I do nothing. Hysteresis is the amount of LSB in 7 bits upscaled to 12 bit (1<<5) = 32. This way effectively removes +/-1 LSB trips when pot doesn't move.
4. When change computed in (3) is greater than hysteresis I compute new value as ( ( avg_val + 16 ) >> 5 ) - so I just scale 12 bit to 7 bit and round to nearest 7 bit number.

Below is a "pseudo code" that illustrates what I do:

C:
#define HYSTERESIS 33 // LSB + 1 , but you can bump it to 35 if your pots are super cheap and noisy

#define NUM_POTS 64

// the code below assumes 12 bit ADC

static int avg_value[ NUM_POTS ] = { 0 }; // static to keep values between "loops"
static int read_value[ NUM_POTS ] = { 0 };
for( int i = 0; i < NUM_POTS; i++ )
{
    int cur_value  = ... adc read .... // (in practice that reads from table that is feed  by DMA)
    avg_value [ i ] = ( cur_value + 15 * avg_value[ i ] ) >> 4; // exponential smoothing

    if( abs( avg_value[ i ] - read_value[ i ] ) > HYSTERESIS )
    {
        // this is only executed when pot moves more than 1 LSB
 
        read_value[ i ] = avg_value[ i ]; // store whatever we read in full 12 bit res
 
        int8_t midi_value = (int8_t) ( ( read_value[ i ] + 16 ) >> 5 ); // rounding and downscaling
 
        SendMidiCC( channel, i + 16 /* controller ID */ , midi_value );
    }
}

This gives perfectly smooth and fast readouts and no fluctuations when pots don't move.

You can see it in action in videos that I posted in other thread


As to 7-bit MIDI "limitation" - I don't consider it limitation at all. 127 different pot positions is plenty and you hardly can move pot more precisely than that. And having 127 discrete steps from pot is actually good thing in combating the noise (see above). The thing that some don't understand that limited resolution of MIDI CC does not mean that you have to have "stepped" control. In my synth I perform exponential smoothing and upscaling of MIDI CC to full 32-bit float, so when I turn the knob I get perfectly smooth, step-less transition and smooth filter sweeps. No stepping whatsoever. All you have to do is to upscale and interpolate from one position to another on sample-by-sample basis.
Thanks for this. I managed to do similar with 4 local wired cheap pots. So will run this again and use your recommendation.

To be honest I had not used DMA much until earlier this week when I pushed the ui update out via dma as I was blocking midi in during some redraws.

Thanks again I’ll look in to it
 
You're very welcome
Having 7 bits is no better than cc control though is it which the OP wanted to get away from. So the resolution is super low.

To get better resolution like 512 or 1024 bits is harder but gives you better resolution and less stepping.
 
Having 7 bits is no better than cc control though is it which the OP wanted to get away from. So the resolution is super low.

To get better resolution like 512 or 1024 bits is harder but gives you better resolution and less stepping.

1024 bits???
Are you sure?

You probably meant 9 or 10 bits ( and 512 or 1024 unique values).

But going down to EARTH, did you actually try moving knob into 1024 unique positions???
With 127 steps (7 bits) your "one step" angle is about 2 degrees (since pot only moves approx 250 degrees). Do you know how small movement it is?

Are you trying to say that in REAL LIFE you can move knob with 0.25 degree precision? (250degrees/1024 steps)

Then you are a pot wizard, because I can't. For me it is hard enough to get 127 unique pot positions in reality

Also as I explained, 7 bits is NOT a problem, there is NO STEPPING if you implement your synth correctly - you do smoothing inside the synth. You can do the smoothing upto full FLOATING POINT 32 bit smoothness, using 7 bit CC as source.

Endless number of commercial synths that use 7 bit CC (like for example renowned Access Music Virus TI) use 7 bit CC and parameter smoothing and there is ZERO stepping when you sweep the filter, thanks to internal smoothing.
 
1024 bits???
Are you sure?

You probably meant 9 or 10 bits ( and 512 or 1024 unique values).

But going down to EARTH, did you actually try moving knob into 1024 unique positions???
With 127 steps (7 bits) your "one step" angle is about 2 degrees (since pot only moves approx 250 degrees). Do you know how small movement it is?

Are you trying to say that in REAL LIFE you can move knob with 0.25 degree precision? (250degrees/1024 steps)

Then you are a pot wizard, because I can't. For me it is hard enough to get 127 unique pot positions in reality

Also as I explained, 7 bits is NOT a problem, there is NO STEPPING if you implement your synth correctly - you do smoothing inside the synth. You can do the smoothing upto full FLOATING POINT 32 bit smoothness, using 7 bit CC as source.

Endless number of commercial synths that use 7 bit CC (like for example renowned Access Music Virus TI) use 7 bit CC and parameter smoothing and there is ZERO stepping when you sweep the filter, thanks to internal smoothing.
You know what I mean, 1024 possible positions, yes you can hear stepping on some synths when you use 7 bits resolution effectively cc, using at least 8 bits gives you smoother controls. Listen to an m1000 being controlled over cc.
 
That is problem of M1000, not pot. It didn't have proper param smoothing. Back in the day computing was costly. They were cutting corners since it was just 6809 8-bit CPU running at 2MHz, sweating all the way with basic stuff. They were using 8bit integer arithmetic for pretty much everything resulting in audible artifacts. Now the situation is 180 degrees different. You've got 600MHz ARM M7 CPU with hardware floating point unit that is easily 2000 times faster with integers and 25000 faster with 32-bit floating point than poor old 6809. Nowadays, you can do things that were impossible with old gear. When your CC input changes from say 97 to 98, you can perform per-sample (44100 steps per second) linear or exponential smoothing with 32-bit floating point accuracy between those two numbers resulting in absolutely fluid change with ZERO stepping at all. The key is NOT to pass CC directly to your synth, but to smooth all changes.
Back to the solution, the approach I have given (oversampling, averaging, hysteresis) is useful to get rid of noise with 8 bits and 9 bits and even 10 bits depending on how good your pots and ADC is. Anyway, dirt cheap Chinese pots give ZERO noise with 7/8 bits with this approach, and getting rid of noise was the problem, not the resolution.
 
Last edited:
Back
Top