Warning! I strongly recommend using an old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments or amplification!
These are the key Arduino tutorials for the main concepts used in this project:
If you are new to Arduino, see the Getting Started pages.
- Arduino Uno
- 6x AD9833 signal generator modules
- AD9833 shield as described here: AD9833 Poly Signal Generator
- MIDI In module, see Arduino MIDI Interfaces
- Amplification/speaker for output
This is using the shield as is with the mono jumper present and using both switches and potentiometers and with a MIDI module connected up to 5V, GND and RX via the header included on the shield.
I added an additional “button 3” as a momentary push-button connected up to D4 which I use to change the polyphony mode, largely for demonstration purposes, but you could equally do that in code and rebuilding.
I have six signal generators available and so have a choice for how to use them. In the end, I implemented four different modes of polyphony as follows:
|Mode||Polyphony||Signal Generators per note|
As mentioned above, I added a third switch to allow me to cycle between the different polyphony modes, but you can get a similar effect without an additional button by changing the DEFAULT_POLY_MODE definition and rebuilding.
To support these modes, the code has the idea of notes, oscillators and signal generators. Each note requires an oscillator to voice it (this is a conceptual construct in the code, it doesn’t exist in the hardware). Each oscillator comprises one or mode signal generators depending on the mode.
In the polyphonic modes, there is a choice of how to handle the polyphony. If POLY_OVERWRITE is defined then new notes replace the oldest playing notes. Without this, new note are ignored.
There are a number of complications in the code, but I’ll only give some highlights here – the code is pretty heavily commented.
- When changing polyphonic modes, I have to be careful of “hanging on” oscillators, so I reset all playing notes and frequencies when a mode change is detected.
- When changing frequencies, the pots can be a little unprecise on the boundaries, so there is a minor delay after pot changes to stop a large number of sharp cut-outs in frequencies when changing.
- When handling the two pot-driven parameters – freqscale and freqdiff – as one adds to the frequency and one multiplies, I have to check for multiplying by the zero parameter (which yields a total of zero of course) otherwise the other parameter has no effect either.
- When freqscale and freqdiff are both zero, it would be neat to have all signal generators sounding at the same frequency. Unfortunately from my experiments, there must be some error in the frequency accuracy, or phase, or timing of the different AD9833 modules, or something… as when all units are supposedly playing the same frequency there is a very slow phase-effect going on. Eventually (minutes) the output will tend to almost zero and be slow to recover. For this reason, then there is no frequency modulation from the pots, I only sound one signal generator at the base frequency.
- There are helper functions to set the frequency. These are polymode aware so will set the appropriate number of signal generators for the “oscillator” for that note, for that mode.
- There is an extensive “TEST” mode that prints out a lot of the polymode, frequency, signal generator and note information to the serial console. This disables MIDI and just plays a single set of six notes to highlight the different polyphonic modes.
It took a very long time and lots of experimentation to work out the “slow beating” issue with all frequency generators on at the same frequency. I started to wonder if it was something to do with my simplistic mixing arrangement. It was compounded by the complex interplay between the modulation parameters from the potentiometers, so there is quite a bit of code simply to support the mode changes in a nice-sounding way.
But I’m actually quite pleased with the end results. Yes, the mixing is simplistic, but for the sake of supporting six very cheap signal generating modules, I think the results are actually pretty good!