Hi, I am working on an output sequencer for guitar pedals and have run into an issue of “popping” or “clicking” as it is changing outputs. From some testing and analysis, it seems that this is coming from discontinuity between the original signal and the slightly delayed signal (after being processed through an external pedal). There is no pop when the external pedal is bypassed.
After seeing this post I thought that using the CrossFade utility might help me get around this. But the CrossFade is not eliminating the pop. If I write the fade over a long enough period, the pop gets quieter but then it starts delaying the signal switching outputs. I am wondering if I am not calling/utilizing it correctly, if there’s something else that I’ve missed in my code, or if a pop is just an inherent problem of this idea.
I am trying to start the crossfade as the channel change is coming up, fade to the original signal, and then fade back to the slightly delayed signal (the Return path from the external pedals).
Can you please tell me what I’m missing on the CrossFade utility? I think I have it running, but I’m not sure I understand it or am using it correctly.
(I’m running a Daisy Seed via Arduino.)
Here is my code-
#include <DaisyDuino.h>
DaisyHardware hw;
#define ledB D22 // blue led. pin 29, referenced to Daisy as D22, see Pinout
#define ledG D19 // green led, pin 26
#define ledR D21 // red led, pin 28
#define ch1 D15 // send 1, opens Channel 1. pin 22
#define ch2 D16 // pin 23
#define fsw D25 // pin 32, bypass
int byp = LOW; // LOW: running, HIGH: bypassed
long crntTime; // current Time
long prevTime; // previous Time
bool chSwitch = false; // switch between ch1 and ch2
long waitTime; // wait this long (milliseconds) until switching output
float pos; // Crossfade position
float mixOut;
float input;
float rtrns;
bool chngSoon; // channel change soon
bool chngNow; // channel change now
int chngCount; // counts up to channel change
static CrossFade cfade;
static Oscillator lfo;
size_t num_channels;
void bypass(){
byp = !byp;
}
void chTimer(){
crntTime = millis();
if (crntTime - prevTime <= 96){
chngSoon = true;
chngCount = 0;
}
if (crntTime - prevTime > waitTime){
prevTime = crntTime;
if (chSwitch == false) chSwitch = true;
else chSwitch = false;
}
}
void myCallback(float **in, float **out, size_t size){
hw.DebounceControls();
if (byp == HIGH){
digitalWrite(ledB, LOW);
digitalWrite(ledG, LOW);
digitalWrite(ledR, HIGH);
for (size_t i = 0; i < size; i++){
out[0][i] = in[0][i]; // write AudioIn1 (mainIn) to AudioOut1 (mainOut)
}
}
if (byp == LOW){
if (chSwitch == false){ // ch1
// passes mainIn to Send1|Rtrn1 to mainOut
digitalWrite(ledB, HIGH);
digitalWrite(ledG, LOW);
digitalWrite(ledR, LOW);
digitalWrite(ch1, HIGH); // turns ch1 on
digitalWrite(ch2, LOW);
}
else if (chSwitch == true){ // ch2
// passes mainIn to Send2|Rtrn2 to mainOut
digitalWrite(ledB, LOW);
digitalWrite(ledG, HIGH);
digitalWrite(ledR, LOW);
digitalWrite(ch1, LOW);
digitalWrite(ch2, HIGH); // turns ch2 on
}
for (size_t i = 0; i < size; i++){
out[1][i] = in[0][i]; // write AudioIn1 (mainIn) to AudioOut2 (Sends path)
input = in[0][i]; // main Input
rtrns = in[1][i]; // connected to Return path of external pedals
if (chngSoon == true && chngCount <= 48){
pos = i/size;
cfade.SetPos(pos);
mixOut = cfade.Process(input, rtrns);
chngCount++;
out[0][i] = mixOut; // writes CrossFade result to AudioOut1
}
if (chngSoon == true && chngCount > 48){
pos = i/size;
cfade.SetPos(pos);
mixOut = cfade.Process(rtrns, input);
chngCount++;
out[0][i] = mixOut;
}
if (chngSoon == false) out[0][i] = in[1][i]; // writes AudioIn2 (Return path) to AudioOut1 (mainOut)
if (chngCount >= 96){
chngSoon = false;
chngNow = false;
chngCount = 0;
}
}
}
chTimer();
}
void setup() {
float samplerate;
pinMode(ledB, OUTPUT);
pinMode(ledG, OUTPUT);
pinMode(ledR, OUTPUT);
pinMode(ch1, OUTPUT);
pinMode(ch2, OUTPUT);
attachInterrupt(digitalPinToInterrupt(fsw), bypass, RISING);
hw = DAISY.init(DAISY_SEED, AUDIO_SR_48K);
num_channels = hw.num_channels;
samplerate = DAISY.get_samplerate();
cfade.Init();
cfade.SetCurve(CROSSFADE_LIN); // or _CPOW?
prevTime = 0;
waitTime = 1250;
DAISY.begin(myCallback);
}
void loop() {}