Friday, 23 August 2013

Simple mono synth with groovuino library

Here is a simple example on how to make a monophnic 1-osc synth with the groovuino lib.
I added a low-pass filter and a very light sequencer.

Here is the video :



You just need 4 potentiometers and an audio out as described in this post :
http://groovuino.blogspot.fr/2013/03/the-goal-is-to-build-groovebox-using.html

The potentiometers are plugged on analog inputs 3,4,5 and 6.

Analog 3 : octave of the arpeggio
Analog 4 : filter frequency
Analog 5 : bpm
Analog 6 : choice of the arpeggio



The code :

Incude your libraries. We just need the osc and low-pass filter.


#include <arduino.h>
#include <osc.h>
#include <filter.h>

We will use the Due timer library. I like it. You can download it here https://github.com/ivanseidel/DueTimer, and copy the repository in your arduino library folder.

#include <DueTimer.h>

Now instanciate your oscillator and filter :

Osc osc;
LowPassFilter LP;


Some data we will need for the arpeggiator :

int step = 0;
int numarp = 0;
int count = 0;


The arpeggio sequences (8 sequences of 16 notes). You can build your own sequences.
0 is is A 440 Hz. 2 = B, 3 = C, 12 = A octave...


int nArps[8][16] = {
{0,0,12,0,0,0,3,15,2,14,0,0,-2,-2,0,12},
{0,12,-2,0,1,13,1,1,5,17,5,17,4,16,0,0}, 
{0,-2,0,3,5,3,0,-2,0,-2,0,3,5,6,5,3},
{0,0,12,0,24,22,12,15,0,-2,0,0,24,36,3,-2},
{0,12,0,15,0,19,0,18,0,15,0,12,0,24,0,-2},
{0,0,3,0,0,0,0,-2,0,0,0,0,0,3,5,-2},
{0,0,0,0,0,0,7,7,6,6,6,6,6,6,-2,-2},
{0,0,3,0,0,-2,0,0,0,0,3,0,5,3,0,3}};


Initialize everything :

void setup() 

  Serial.begin(9600); 

The analog inputs :

  pinMode(A6, INPUT);
  pinMode(A5, INPUT);
  pinMode(A4, INPUT);
  pinMode(A3, INPUT);

Start the timers : one 44.1 kHz for audio generation, and on 100 Hz for sequencer :

  Timer0.attachInterrupt(loop1).setFrequency(44100).start();
  Timer8.attachInterrupt(loop2).setFrequency(100).start();

Generate the wavetables. We'll only use Sine, Saw, and Square :

  createSineTable();
  createSawTable();  
  createSqTable();    

Initialize the DAC output.

  analogWrite(DAC1,0); 

Set cutoff and resonance to default values :

  LP.setCutoffFreq(255);
  LP.setResonance(255);

Set the oscillator to default values :

  osc.init();
  osc.setWaveform(0,30);
  osc.setVolOsc(0, 127);
  osc.setNote(50,50);



Read the potentiometers.
analog 6 selects the arpeggio number (8 arrpeggios, so the number is 3 bits long)
analog 4 sets the cutoff frequency

void loop() 

  numarp = analogRead(6)>>7;
  LP.setCutoffFreq(analogRead(4)>>3);
  delay(5);
}


Generate the sound :
One osc with LP filter.

void loop1() 

  int32_t ulOutput=2048;

  osc.next();

  ulOutput += LP.next(osc.output());
   
  if(ulOutput>4095) ulOutput=4095;
  if(ulOutput<0) ulOutput=0;
  dacc_write_conversion_data(DACC_INTERFACE, ulOutput); 
}

The sequencer :
analog 5 fixes the tempo. If the value is high, the time between 2 notes will be long.
analog 3 sets the octave. (it adds an integer * 12 to the note).

void loop2()
{
  if(count>=(analogRead(5)>>4))
  {
    if(step>=15) step = 0;
    else step+=1;
    osc.setNote((analogRead(3)>>7)*12+nArps[numarp][step],100);
    count = 0;
  }
  else count++;
}

11 comments:

  1. I tried loading this on a board I'm using.
    I had to change LowPassFilter2.h to filter.h to get it to compile. Is LowPassFilter2.h a new library?
    I had to also change DAC1 to DAC0 since that is what I use.
    What does each POT do? I'm having difficulty reproducing sounds similar to your video.

    ReplyDelete
  2. Ok are they:
    A3: key
    A4: filter cutoff
    A5: period
    A6: sequence select
    ?

    ReplyDelete
    Replies
    1. Hi,
      Yes you're right. I updated my post. The potentiometers act like this :
      Analog 3 : octave of the arpeggio
      Analog 4 : filter frequency
      Analog 5 : bpm
      Analog 6 : choice of the arpeggio

      I updated my library to add the new version of the filter. I updated too the osc.h file. In fact you can change the number of oscillator, or the glide mode in the file. In my library it was 3 oscillators by default, and glide on, so that's maybe why you got different sound than my video. Now I put 1 osc and glide off as default values, so it hould be ok now.
      Tell me if it works now.

      Thanks !

      Delete
  3. the new osc.h has a bug:
    osc.h: In member function 'void Osc::setNote(uint32_t, int32_t)':
    osc.h:128: error: 'else' without a previous 'if'

    ReplyDelete
    Replies
    1. Do you get this message?
      Groovuino_test1.ino:7: warning: undefined reference to `LowPassFilter::LowPassFilter()`

      Delete
    2. Yes, but it should work anyway.

      Delete
  4. In osc.setNote does it take a MIDI note in or something else?

    ReplyDelete
    Replies
    1. Yes, it's a value between 0-128, 0 is A-2, like MIDI.

      Delete
  5. Hey there Gaetan,

    Your library looks amazing! I'm having trouble to get this sketch to make any sound, though. I know my DACs are OK, because Duane B's DDS Sinwave example works fine on both DACs.

    Can you confirm that this sketch works with the latest version of the DueTimer library? I'm on version 1.4.1

    To minimize the chance that I've messed up the wiring for the pots, I've replaced the 4 calls to analogRead with a fixed value of 512, eg.
    numarp = analogRead(6)>>7;
    becomes
    numarp = 512>>7;

    Still no luck.

    By the way, I also get
    warning: undefined reference to `LowPassFilter::LowPassFilter()

    But that should be OK, right?

    I'm wondering if you could post an even more minimal sketch for testing purposes - just something like a single oscillator producing a test tone.

    Regards,
    MoShang

    ReplyDelete
  6. I got it going by commenting all the code relating to the filter, and replacing the line
    ulOutput += LP.next(osc.output());
    with
    ulOutput = osc.output();

    ReplyDelete