Go Down

Topic: 8 voice + resonant filters arduino synth (Read 11792 times) previous topic - next topic


I am part way through building yet another arduino based synthesizer.

Not as fancy a box as others yet, but I am quite happy with the software. I am designing it as a self-contained toddler proof synth, for my daughter to play with, hence the lack of moving parts / switches outside the box, speaker inside the box etc.
Roughly 32khz output sample rate.
8 voice polyphonic oscillators (each with independent pitch and volume), based on 256 sample 8 bit wavetables.
Square, sine, sawtooth, triangle waves
One resonant low pass filter (a dirty hack of a filter, based on the filter from the meeblip open source synth).
8 Capacitive touch sensing input 'keys' so you can play chords easily.
All the processor intensive bits written in assembly and very heavily optimised in order for it to work without maxing out the arduino.

A not quite up to date, but making a nice noise video. It now sounds a fair bit better thanks to 'Grumpymike' from here, who fixed my amplifier problems.


More information and code here:


Good, well done.

You should let that little hand we glimpsed at the end have a go.   :)


It looks like you're using PWM and a lowpass filter to output the audio, I'm using the same kind of thing for my synth.
At ~32KHz sample rate, that's about 500 step resolution for the PWM.  (I would guess it's actually 512)

How are you getting the "headroom" for 8 notes 8 bit waveforms?  Do you just have the normal volume of each oscillator at 25%?


I use 8 bit oscillators, each with 64 possible volume levels. I currently make the maximum total oscillator volume (sum of all the volumes) be 64 - if several oscillators are full on, it lowers their volumes so that the total is exactly 64.

After the resonant filter code, it multiplies everything by 4 (the filter requires some headroom to work) with clipping in case the filter is resonating strongly.

I've just fixed the link to the code on my web page, so you can see how it works:-

Also, a new video - now has pressure sensitive pitch bend and filter modulation touch sensors too (also made out of random bolts I had lying around).


I don't have any hardware low-pass filtering, as the 32khz sound is filtered out in my lm386 amp which apparently has pretty much no response above 20khz (for that matter, I can't hear anywhere near 32khz anyway). I just bung it straight off pin 11 -> pin 3 on the lm386 amplifier, then straight to the speakers (oh, there's a couple of capacitors & resistors in there to remove DC bias and to lower volume, but nothing clever.


I also did a bit of fiddling with it yesterday, just to see, and it appears to be happy enough doing 16 oscillators, as long as the resonant filter is turned off. 32 was a no-no though!

With 16 oscillators, I doubled them up and detuned each one, and it sounded pretty awesome! I think I like my filter too much though, so I'll stick with the 8.


Thanks for all the tips, and for showing your code!

Your code and the meeblip code have allowed me to put my synth code together.

I based mine on your code some, but changed some things to my liking, like variable names obviously, or the order of variables within the oscillator struct, etc.

But I had to write my own code for the part that figures out the sample from the waveform arrays;  I want on my synth for each oscillator to be able to have a different waveform; that required some new code.  I also implemented a square wave with duty cycle control, pretty simply just comparing the sawtooth waveform sample to the duty cycle variable.  That would sound so awesome if your synth had a contact for duty cycle modulation!  *hint hint*

I'm gonna try to finish the ISR code tonight, I'l hopefully get the whole program working tomorrow!


Nice one, good to see it being useful.

The funny ordering of the variables in the oscillator struct was because the way I'd written it, it made the reading code slightly faster (I think an instruction or two), because I'd originally had to use two pointer registers.

Definitely agree that it should allow different waves - I'm basically using each oscillator as an individual note, so they want to all sound the same, hence the same wave for all of them.


In the reordering of the oscillator struct variables, at least the way I did it, it seems like it's simply a reordering of the assembler commands, not any extra commands.  But I haven't actually counted.

The extra waveforms did add some more instructions, but that was neccessary.  The number of extra clock cycles varies a bit whether the wave is square or not, but I think it's only 4-5 extra cycles; again, I haven't counted.
I also could not simply do the #define'd OSCILLATORASM and just type it 8 times, because of the labels and branching used to select waveforms, since the labels could not be redefined.  So I dedicated one register to be a variable to keep track of a loop.  At the end of the oscillator calculations, this variable is decremented; if it then doesn't equal 0, then it branches to a label at the beginning of the code.  The number of iterations depends on the initial value of the variable.

And PWM!:  pwm woot


New slightly updated version of the code on my site now -


Just some nerdy optimisations, in particular I've optimised the oscillator code slightly, by swapping round a few stores / adds, and I am pretty confident that it is the minimum number of instructions required to do a 256 byte wavetable oscillator - 14 instructions per oscillator per sample.

I'm also in the process of re-boxing it into a nicer case, adding some battery / power supply cleverness and headphone + usb sockets. It isn't going to be as fancy and nice looking as SciGuy's one above, but it will at least keep the circuitry safe and out of reach of tiny fingers!



You should let that little hand we glimpsed at the end have a go.   smiley



Joe - thanks for that, it was fantastic.  :)

Go Up