Auduino Wavetable Granular Synthesis

The original Auduino used a clever trick to efficiently calculate a triangle wave to use as the “grain” for the granular synthesis, but I always wanted to try it with a wavetable to see if that would work.  This project gives that a go.

Warning! I strongly recommend using old or second hand equipment for your experiments.  I am not responsible for any damage to expensive instruments!

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.

Parts list

The Circuit

Auduino_bb

This is the basic Auduino circuit but with the addition of a 6th potentiometer to select the waveform for the “grains”.

I used my Arduino PWM Output Filter Circuit shield to provide some additional output filtering and my potentiometer breakout from my Arduino Multi-pot Mozzi FM Synthesis project as shown below.

IMG_5446

The Code

The basic idea is to take the original Auduino code and instead of calculating the waveform to use “on the fly” (as with the original code), read the values from a wavetable instead.  I’ve lifted the code for wavetable generation straight out of my Arduino PWM Sound Output code and added optional code in the main loop() to select one of the four waveforms based on the last potentiometer reading as follows.

#ifdef WAVE_CONTROL
int newwave = analogRead(WAVE_CONTROL) >> 8; // 0 to 3
if (newwave != wave) {
wave = newwave;
setWavetable(wave);
}
#endif

In terms of reading from the wavetable rather than calculating the samples, I can use the same phase accumulator as before, and simply use the top 8-bits to give me an index between 0 and 255 to use to read values out of the wavetable.  This all happens in the PWM_INTERRUPT routine under some conditional compilation.  Notice that the grain amplitude calculation does not need to change.

#ifdef WAVETABLE
// Use top 16 bits as the index into the wavetable
value = wavetable[grainPhaseAcc >> 8];
#else
// Convert phase into a triangle wave
value = (grainPhaseAcc >> 7) & 0xff;
if (grainPhaseAcc & 0x8000) value = ~value;
#endif
// Multiply by current grain amplitude to get sample
output = value * (grainAmp >> 8);

This has to be repeated for both grains, using grainPhaseAcc and grain2PhaseAcc.

I’ve used the MIDI version of my enhanced Auduino code, but for this project I’m using it in non-MIDI mode, so I’ve enabled the “sync frequency” potentiometer on A5.

The full list of potentiometers and their uses is as follows:

  • A0 – Grain 1 frequency
  • A1 – Grain 1 decay
  • A2 – Grain 2 frequency
  • A3 – Grain 2 decay
  • A4 – Sync frequency
  • A5 – Wavetable selection: 0=Sine; 1=Saw; 2=Triangle; 3=Square

Find it on GitHub here.

Closing Thoughts

In the video, right at the start, you can just about see the four different waveforms being selected – sine, saw, triangle and square.  This has the sync frequency right down, and grain 2 effectively “off”, allowing us to almost see grain 1 in action.

You can certainly hear the difference when the waveform changes.

This would be something that would be quite nice to run on my Auduino Universal Synthesizer Panel which has six pots ready and waiting to go!  In fact, I might rebuild the code in the MIDI variant and give that a go!

Now I can use a wavetable as the “grain” there are some other possibilities too.  I might be able to draw the waveform to use or possible grab a short sample from an audio input in some capacity.  There are certainly a few other things to try now.

Kevin

 

8 thoughts on “Auduino Wavetable Granular Synthesis

  1. I’ve tried loading your software from github and it keeps calling for a midi.h library that I cannot find. Any suggestions as i’d love to try your wavetable implementation

    Like

      1. great this has certainly helped and now it uploads 🙂 Now I need to figure out why all my pots are behaving in the opposite way to how they worked on the original auduino before upgrading to your version. very strange…

        Like

  2. oh and BTW could it have something to do with this part of the code (which is different to the original):

    grainPhaseInc = mapPhaseInc(1023-analogRead(GRAIN_FREQ_CONTROL)) / 2;
    grainDecay = (1023-analogRead(GRAIN_DECAY_CONTROL)) / 8;
    grain2PhaseInc = mapPhaseInc(1023-analogRead(GRAIN2_FREQ_CONTROL)) / 2;
    grain2Decay = (1023-analogRead(GRAIN2_DECAY_CONTROL)) / 4;

    i’m not sure what the “1023” represents

    sorry about the questions. thanks for your help

    Like

    1. Oh yes, I can’t remember exactly why now, but I’ve reversed the sense of the pots. 1023 is the maximum value, so doing 1023-analogRead() will give a range of 1023 down to 0, rather than 0 up to 1023 as is usual.

      I think this was because in the original the code made the pots go the other way round for some reason. There is some discussion about this in “part 2”. I guess it depends how you’ve wired your own pots! I like to wire them so that fully anti-clockwise is 0 and fully clockwise is full – like a volume control, but for Auduino this would mean frequency decreases as you “turn it up”, hence reversing the values.

      If you want it back to the original, just remove the “1023-” bit in each line. In fact I ought to add this as a compilation option…

      Let me know how you get on.

      Kevin

      Like

      1. For what its worth I’ve also updated the code so that the default is the original Auduino pot handling, with a compilation option to do it my way 🙂

        Like

  3. Yay thanks Kevin. I ended up tinkering with the code too,removing the “1023-” and it worked!
    Thanks for updating the code. I’m looking forward to any variations you come up with in the future.

    Like

Leave a comment