I've been experimenting with the mozzi library to create a 2 oscillator synth with a single lfo.
All works fine, but there is a clicking noise when playing.
After some research and experiments I found out it's because my Arduino UNO can't keep up with calculations.
Is there a way to optimize my code? Especially the keyboard input part that to me looks messy. I don't know of another way of making sure the buttons will work when held down.
To summarize my hardware setup:
- x12 buttons (keyboard), assigned from pin 13 to pin 10 and from pin 8 to pin 1
- x1 button (to switch the lfo function) assigned to pin 0
- x5 potentiometer, assigned from pin A0 to pin A4. In order to control: octaves, waveform of aOsc, waveform of bOsc, volume mix between aOsc and bOsc and lfo frequency.
This is my code:
#include <MozziGuts.h>
#include <Oscil.h>
#include <PinChangeInt.h>
#include <tables/saw2048_int8.h>
#include <tables/triangle_dist_cubed_2048_int8.h>
#include <tables/square_no_alias_2048_int8.h>
#include <tables/sin256_int8.h>
#define CONTROL_RATE 128
Oscil <2048, AUDIO_RATE> aOsc(TRIANGLE_DIST_CUBED_2048_DATA);
Oscil <2048, AUDIO_RATE> bOsc(TRIANGLE_DIST_CUBED_2048_DATA);
Oscil <256, CONTROL_RATE> cOsc(SIN256_DATA); //lfo
#define C 523.25
#define Db 554.37
#define D 587.33
#define Eb 622.25
#define E 659.26
#define F 698.46
#define Gb 739.99
#define G 783.99
#define Ab 830.61
#define A 880
#define Bb 932.33
#define B 987.77
volatile int timer = 0;
volatile int timer2 = 0;
int button=1;
float freq;
int oct=1;
int waveA;
int waveB;
int lfoFreq = 0;
float detune = 0;
float ampMod = 1;
float volumeA, volumeB;
int sum;
int out;
int knob1;
int knob2;
int knob3;
int knob4;
int knob5;
volatile bool sw = false;
void setup()
{
pinMode(13, INPUT_PULLUP);
pinMode(12, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);
pinMode(0, INPUT_PULLUP);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
pinMode(A4, INPUT);
PCintPort::attachInterrupt(0, lfoSwitch, RISING);
PCintPort::attachInterrupt(13, lfoReset, RISING);
PCintPort::attachInterrupt(12, lfoReset, RISING);
PCintPort::attachInterrupt(11, lfoReset, RISING);
PCintPort::attachInterrupt(10, lfoReset, RISING);
PCintPort::attachInterrupt(8, lfoReset, RISING);
PCintPort::attachInterrupt(7, lfoReset, RISING);
PCintPort::attachInterrupt(6, lfoReset, RISING);
PCintPort::attachInterrupt(5, lfoReset, RISING);
PCintPort::attachInterrupt(4, lfoReset, RISING);
PCintPort::attachInterrupt(3, lfoReset, RISING);
PCintPort::attachInterrupt(2, lfoReset, RISING);
PCintPort::attachInterrupt(1, lfoReset, RISING);
startMozzi(CONTROL_RATE);
}
void updateControl()
{
knob1 = mozziAnalogRead(A0);
oct = (knob1/204)+1;
if(oct%2!=0 && oct>1)
{
oct++;
}
waveA = mozziAnalogRead(A1);
if(waveA<=511)
{
aOsc.setTable(TRIANGLE_DIST_CUBED_2048_DATA);
}
else if(waveA>511)
{
aOsc.setTable(SQUARE_NO_ALIAS_2048_DATA);
}
waveB = mozziAnalogRead(A2);
if(waveB<=511)
{
bOsc.setTable(TRIANGLE_DIST_CUBED_2048_DATA);
}
else if(waveB>511)
{
bOsc.setTable(SAW2048_DATA);
}
knob4 = mozziAnalogRead(A3);
volumeB = (float)knob4/1023;
volumeA = 1 - volumeB;
knob5 = mozziAnalogRead(A4);
lfoFreq = ((float)knob5/51);
cOsc.setFreq(lfoFreq); //lfo
button=1;
if(digitalRead(13) == 0)
{
freq=C;
button = 0;
}
else if(digitalRead(12) == 0)
{
freq=Db;
button = 0;
}
else if(digitalRead(11) == 0)
{
freq=D;
button = 0;
}
else if(digitalRead(10) == 0)
{
freq=Eb;
button = 0;
}
else if(digitalRead(8) == 0)
{
freq=E;
button = 0;
}
else if(digitalRead(7) == 0)
{
freq=F;
button = 0;
}
else if(digitalRead(6) == 0)
{
freq=Gb;
button = 0;
}
else if(digitalRead(5) == 0)
{
freq=G;
button = 0;
}
else if(digitalRead(4) == 0)
{
freq=Ab;
button = 0;
}
else if(digitalRead(3) == 0)
{
freq=A;
button = 0;
}
else if(digitalRead(2) == 0)
{
freq=Bb;
button = 0;
}
else if(digitalRead(1) == 0)
{
freq=B;
button = 0;
}
else if (button!=0)
{
freq=0;
}
//lfo selector
if(!sw)
{
detune = ((float)cOsc.next()/(128))*freq;//for pitch control with lfo
if(lfoFreq<=0)
{
detune = 0;
}
ampMod=1;
}
if(sw)
{
detune = 0;
ampMod = 1 - ((float)cOsc.next()/(128));
if(lfoFreq<=0)
{
ampMod = 1;
}
}
aOsc.setFreq(freq*oct+detune);
bOsc.setFreq((freq*oct-detune)/2);
}
int updateAudio(){
out = aOsc.next()*volumeA+bOsc.next()*volumeB;
return out*ampMod;
}
void loop(){
audioHook();
}
void lfoSwitch()
{
if((millis()-timer)>200)
{
sw = !sw;
timer = millis();
}
}
void lfoReset()
{
if((millis()-timer2)>200)
{
cOsc.setPhase(0);
timer2 = millis();
}
}