The audio relays are set like:
The chorus effect is based on 2 signals running in parallel. Both are delayed following a "triangular" shape, meaning that the delay grows to a point and then decreases. Doing this action in a loop. There is always a delay in the signal, this is why the output is always a bit delayed (around 40ms) and could be confusing when playing fast parts.
So, the delay time is not constant (like in a Delay, Echo or Reverb pedal). In this case, the delay is increased and decreased endlessly.
The trick is that the 2 signals running in parallel will have this increase/decrease of delay time in opposite ways, so when the 1st signal is increasing its delay time, the 2ns signal will decrease it at the same time. You can clearly see this factor in the code:
analogWrite(DELAY1, chorus_counter);
analogWrite(DELAY2, 410 - chorus_counter);
The "chorus_counter" signal will vary between 230 and 180 (230+180=410).
The millis(); function is used to create a delay (the delay(); function cannot be used because it will "freeze" the code during its execution and the encoder and other functions wont be attended). More info about how to use millis(); to create a delay(); here:
www.arduino.cc/en/tutorial/BlinkWithoutDelay
Additional setting: the code also allows to connect the input with the output when pressing the TAP footswitch. It will remove any latency and make the effect more subtle.
The complete code looks like:
// CC-by-www.ElectroSmash.com Chorus Effect Pedal.
// More info about the project at www.ElectroSmash.com/Time-Manipulator
// Pin Definitions:
#define DELAY1 10
#define DELAY2 9
#define SWA 3
#define SWB 14
#define SWC 2
#define SWD 4
#define LED1_G 1
#define LED1_R 0
#define LED2_G 5
#define LED2_R 6
#define ENC_A 16
#define ENC_B 18
#define ENC_GND 17
#define ENC_PUSH 19
#define BYPASS_DETECT 8
#define TAP_DETECT 15
//VARIABLES
unsigned int ENC_counter = 100;
int ENC_aState;
int ENC_aLastState;
int ENC_aState_selection=0;
int ENC_aLastState_selection=0;
unsigned long delay_currentMillis, delay_previousMillis = 0;
int direction_up=0;
int chorus_counter = 0;
// the setup function runs once when you press reset or power the board
void setup()
{
//set the pins //init the values
pinMode(DELAY1, OUTPUT); analogWrite(DELAY1, 100);
pinMode(DELAY2, OUTPUT); analogWrite(DELAY2, 100);
pinMode(SWA, OUTPUT); digitalWrite(SWA, LOW);
pinMode(SWB, OUTPUT); digitalWrite(SWB, LOW);
pinMode(SWC, OUTPUT); digitalWrite(SWC, LOW);
pinMode(SWD, OUTPUT); digitalWrite(SWD, LOW);
pinMode(LED1_G, OUTPUT); analogWrite(LED1_G, 0);
pinMode(LED1_R, OUTPUT); analogWrite(LED1_R, 0);
pinMode(LED2_G, OUTPUT); analogWrite(LED2_G, 0);
pinMode(LED2_R, OUTPUT); analogWrite(LED2_R, 0);
pinMode(ENC_A, INPUT_PULLUP);
pinMode(ENC_B, INPUT_PULLUP);
pinMode(ENC_GND, OUTPUT);
pinMode(ENC_PUSH, INPUT_PULLUP);
pinMode(BYPASS_DETECT, INPUT_PULLUP);
pinMode(TAP_DETECT, INPUT_PULLUP);
ENC_aLastState = digitalRead(ENC_A);
void read_encoder(void);
}
void loop() // the loop function runs over and over again forever
{
//detect if the effect is on or off
while((digitalRead(BYPASS_DETECT) == LOW))
{
digitalWrite(LED1_R,LOW);digitalWrite(LED2_R,LOW);digitalWrite(LED1_G,LOW);digitalWrite(LED2_G,LOW);
}
read_encoder();
digitalWrite(SWA, HIGH);digitalWrite(SWB, LOW);digitalWrite(SWD, HIGH);
digitalWrite(SWC,!digitalRead(TAP_DETECT));
if (direction_up==1)
{
digitalWrite(LED1_R,HIGH);digitalWrite(LED2_R,HIGH);digitalWrite(LED1_G,LOW);digitalWrite(LED2_G,LOW);
if (chorus_counter>230) {chorus_counter=230; direction_up=0;}
//delay created by millis();
delay_currentMillis = millis();
if (delay_currentMillis - delay_previousMillis >= 30 + ENC_counter>>1)
{
delay_previousMillis = delay_currentMillis;
chorus_counter++; //if too fast try divider
}
}
else
{
digitalWrite(LED1_R,LOW);digitalWrite(LED2_R,LOW);digitalWrite(LED1_G,HIGH);digitalWrite(LED2_G,HIGH);
if (chorus_counter<180) {chorus_counter=180;direction_up=1;}
//delay created by millis();
delay_currentMillis = millis();
if (delay_currentMillis - delay_previousMillis >= 30 + ENC_counter>>1)
{
delay_previousMillis = delay_currentMillis;
chorus_counter--; //if too fast try divider
}
}
analogWrite(DELAY1, chorus_counter);
analogWrite(DELAY2, 410 - chorus_counter);
}
void read_encoder(void)
{
ENC_aState = digitalRead(ENC_A); // Reads the "current" state
if (ENC_aState != ENC_aLastState)
{
if (digitalRead(ENC_B) != ENC_aState)
{if(ENC_counter>50)ENC_counter-=5;}
else
{if(ENC_counter<230)ENC_counter+=5;}
}
ENC_aLastState = ENC_aState; // Updates the prev. state
}