The dsp-G0 Analog modeling synth

I've seen a lot of synths based on the Arduino and belive me, there are as many as **** in China.

So I built an Analog modeling synth with the NXP LPC810 and it needed a scanboard to be able to set parameters.

Building the scanboard with a Nano I couldn't resist porting my DSP code to the Arduino.
So I added a MCP4921 12-bit DAC and after some optimizing it runs with a sample frequency of 8372hz.

So how does it sound?
I would say pretty good at 8KHz 12-bit PCM, It beats the heck out of all the Arduino Bleeps.
There is some aliasing due to my poor passive LP filter but overall its great.

Specs:

Arduino Nano at 8KHz and 12-bit PCM.
16-DCO with morph oscillators (arbitrary waveform)
16-bit 3 pole 18dB LP DCF with resonance (Yes, It rings)
1 LFO for filter.
1 ADSR ENV for DCA.
1 ADSR ENV for DCF.

All with 16-bit resolution.

So I decided to call it the dsp-G0.
Runs perfect on ATmega328 @ 16MHz

Would be interesting to hear it. Video?

This one's cool: http://bleeplabs.com/store/nebulophone/

What's the point of a synth with no video to see how it sounds?

I need to figure out how to make a video with Hi-fi sound first.
Most of my cameras give crappy sound.

There is no point in just posting an audiofile because it could come from anything.

What most people do to gain cycles on the Arduino is to setup the oscillator as a wavetable and precalculate the filter on the wavetable.

While this saves cycles it also removes the soul in the sound and makes it sound boring.

My 24-bit phaseacc also drive a wavetable but I use it to choose and morph the DCO waveforms.
Then I run all the DCO's through a realtime calculated LPF filter.

The alising from the wavetables also goes through the filter and gives character to the sound instead of noise.

Thats the way Roland did it on the original JP-8000.
There is no interpolation.

This puts a load on the CPU to calculate the filter in realtime on every sample.

We cant use floating point calculations in the sample ISR so we use integers instead.
And it has to be able to process 16-bit signed samples at the sample rate.

So I wrote a 18dB 3 pole resonant LPF in assembly.
It takes only 132 cycles to calculate a 16-signed sample.

//---------------- DCF block ---------------------------------------
    
    // 18dB 3pole lowpass DCF with resonance. The MX-filter 
      coefficient=CUTOFF^0xFF;   
      #define M(MX, MX1, MX2) \
      asm volatile ( \
        "clr r26 \n\t"\
        "mulsu %B1, %A2 \n\t"\
        "movw %A0, r0 \n\t"\
        "mul %A1, %A2 \n\t"\
        "add %A0, r1 \n\t"\
        "adc %B0, r26 \n\t"\
        "clr r1 \n\t"\
        : \
        "=&r" (MX) \
        : \
        "a" (MX1), \
        "a" (MX2) \
        :\
        "r26"\
      ) 
      M(MX1, M0, coefficient);
      M(MX2, M1, CUTOFF);
      M0=MX1+MX2;
      M(MX1, M1, coefficient);
      M(MX2, M2, CUTOFF);
      M1=MX1+MX2;
      M(MX1, M2, coefficient);
      M(MX2, M3, CUTOFF);
      M2=MX1+MX2;
      M(MX1, M3, coefficient);
      M(MX2, M4, CUTOFF);
      M3=MX1+MX2;
      M(MX1, M4, coefficient);
      M(MX2, M5, CUTOFF);
      M4=MX1+MX2;
      M(MX1, M5, coefficient);
      M(MX2, M6, CUTOFF);
      M5=MX1+MX2;
      M(MX1, M0, RESONANCE);
      M6 = in-MX1;
      out=M0;
    //-----------------------------------------------------------------

My oscillator section have only 4 parameters, Range, Detune, Waveform and Wrap.
I really picked the raisins out of the JP-8000.

Per voice its a 3 DCO structure.

DCO1 plays the basic key pressed on the keyboard.
DCO2 and 3 plays the DCO1 pitch offset by the Range (+/-24 semi) and detuned +/- (0-0.062) the Detune parameter.

The Waveform knob has from right to left: Sine, Triangle, Square and Saw.
By turning the knob it morphs seamlessly between the waveforms.

The Wrap knob is the most difficult to explain.
It offsets the waveform so that it overflows and wraps around at the bottom.
On the Saw waveform it frequency doubles and on the others introduce harmonics and distorsion to the sound.

I only have 1 LFO onboard for live performance but through MIDI-CC any parameter can be realtime modified.

The LFO section has only 2 parameters: Rate and Shape
The shape can be Sine or Sample & Hold (random).

It only routed to the DCF.

The DCF section has 8 parameters: Cutoff, Resonance, ENV Mod, LFO Mod, Attack, Decay, Sustain and Release.

Nothing strange.

And the DCA section has (surprise, surprise): Attack, Decay, Sustain and Release.

Now comes the limitation.

If you have the numbers right you add up to a total of 5 note polyphony and 15 DCOs.
The limitation is the polyphony, its not polyphonic but paraphonic.

It has 5 separate voices but only 1 DCF and 1 DCA.
That means that all the 5 notes has to go through the same filter and amp.

How do you solve that?
It will cut voices or retrigger on chords?

Yes, You choose either staccato or legato, but not both at the same time.

So you can select Gate or Hold mode depending on style.
Gate adds a voice as long as the key is hold and drops it if released.
Hold adds every key pressed to the envelope and drops all keys once all are released and a new one is played.

In both modes it will retrigger the ENVs when all notes are released and a new one is played again.

Here is an audiofile playing with a single voice and Saw waveform.
There is clipping because I found another laptop with a mic input and it overdrives a bit.

This is just a single voice on the dsp-G0.
This one uses 3 DCOs.

I'm twisting all the oscillator knobs and the filter but the waveform is Saw in the entire clip.


https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/144326541&auto_play=false&hide_related=false&visual=true

test.mp3 (3.22 MB)

Can you embed Soundcloud files here like you do with YouTube?

I tried in the post above to no avail.

This is the algorithm for my DCO's:

range=0.5+(((float)RANGEPOT/255)*1.5);
FREQ[x+1] = (FREQ[x]+((FREQ[x]*DETUNE*((float)DETUNE/255))))*range;
FREQ[x+2] = (FREQ[x]-((FREQ[x]*DETUNE*((float)DETUNE/255))))*range;

janost:
This is just a single voice on the dsp-G0.
This one uses 3 DCOs.

I'm twisting all the oscillator knobs and the filter but the waveform is Saw in the entire clip.

Cool.

With only one filter and one ADSR this is really just a monophonic synth. The other waveforms just provide harmonics.

Maybe you could try it with the filter cutoff in the middle of the range of notes being pressed.

Actually it's paraphonic like string synths in the 70's.
Or like the Moog Sub 37.

You can play chords but the ENVs retrigger only when all the keys have been released.
Up to 5 notes at the same time.

The Hold mode adds DCOs to the output and does not drop them until you release all the keys.
The Gate mode adds DCOs to the output but drops them when a key is released.

What holds back the sampling frequency now is not the filter code.
It only takes 132 cycles.

What takes time is the 15 32bit phaseaccumulator adding.

If I can write that in assembly I can up the sampling frequency to something like 30KHz.

Pretty impressive of the ATmega328 @ 16MHz.

I ordered a 2.2" 320x240 TFT on eBay.
I'm building this synth as a module for AMsynths.co.uk so I'm going to use 8 pots and an LCD for feedback.

Fungus, did you use a write-only schema for your Space Invaders game on the TFT?

The reason I ask is because I'm only interested in painting menus on the TFT.

And perhaps writing a library for the TFT on the LPC810 :slight_smile:

For the scanboard I found Pro Mini's for $2 each on eBay.

It's not worth building something yourself if the price is that low.

On Indiegogo

Ok, I got my show in the spotlight.

How about I port this to my favorite platform?

It's 84MHz, 32bit, ARM C3 and has two 12bit DACs built in.
It also has a shitload of flash and sram.

I can get it for $20 on eBay.

The dsp-G2 would run awesome on the Due.

Will people laugh at me if I do it with a Due?