Hi All,
Longtime reader, first time poster. I've been working with Arduino Uno for a while. I first started working with audio / dsp by reverse engineering the
DigDugDIY "Lofi Dreams" sampler and working with
NooTropics shield. I've been wanting to learn more about delay and reverb effects and the Uno just doesn't seem up to the task - so I upgraded to the Due for a bit more processing power and the onboard ADC & DAC.
I found
this YouTube tutorial that describes a simple Reverb using a ringbuffer. It's really more of a two tap delay and less of a reverb - so I've been messing with the code to see if I could get a full 3-knob delay (Effect Level, Delay Time, Feedback). I've had no issues implementing Effect Level and Feedback - but the Delay Time has proven to be more of a challenge.
Here is my current code:
//Setup the ring buffer
#define BSIZE 20000 //Buffer size, sets the maximum delay time.
int ring_buff[BSIZE]; //Ring buffer
void setup() {
//Initialize the buffer contents to all zero
for (int i=0; i<BSIZE; i++){
ring_buff[i] = 0;
}
//Enable the ADC and DAC pins
pinMode(A0, INPUT); // Define A0 as ADC input
pinMode(A1, INPUT); // Define A1 as a multi-purpose Pot (currently used for testing variable delay times)
analogReadResolution(12); //Override 10 bit default. We can go to 12 bits because the board used is a Due
analogWriteResolution(12); //Override default 8 bit since we'll use DAC1 output on Due board
//Open serial monitor transcript
Serial.begin(9600);
}
void loop() {
int analogin; //stores ADC data
float old_value1; // values read from the tap point
int analogout; //value to be output and stored into buffer at current_tap
int analogout_buf; //duplicate of analogue out taken before effect mix attenuation
int current_tap = 0; //The current tap point - incremented after each sample
int tap; //Temp variable used in indexing into older tap points
byte effectMix; // variable for setting the effect vs. input mix
int delayTime; // sets delay time
//While loop to improve effect timing
while (1) {
analogin = analogRead(A0) - 2048; //Making audio values bi-polar
effectMix = 0; //map(analogRead(2), 0, 4095, 0, 8);
delayTime = map(analogRead(1), 0, 4095, 225,5000)*4; //sets delay time, mapped usable values between 900 - 20000
tap = current_tap - delayTime; // sets temp tap value and grabs values earlier in the ring buffer
if (tap < 0){ //if tap is negative number, pushes it back to the top of the ring buffer
tap += BSIZE;
}
old_value1 = ring_buff[tap]; //grabs delayed audio for playback
//Scale values by a specfic divisor to determine feedback amount
old_value1 /= 2;
analogout_buf = analogin + old_value1; //add passthrough audio from ADC to scaled delayed audio
//Limit the outputs to mimic normal overload distortion
//avoid digital number wraparound - might not be needed for the buffer?
if(analogout_buf > 2047){ analogout_buf = 2047;}
if(analogout_buf < -2047){ analogout_buf = -2047;}
//Effect Level for repeats (i.e. turn down input signal)
//analogin = analogin >> effectMix; //commented out for testing
analogout = analogin + old_value1; //add passthrough audio from ADC to scaled delayed audio
//Limit the outputs to mimic normal overload distortion
//avoid digital number wraparound
if(analogout > 2047){ analogout = 2047;}
if(analogout < -2047){ analogout = -2047;}
//store duplicated output in buffer for "effect only" playback
ring_buff[current_tap] = analogout_buf;
//increment (circular) tap-point
current_tap++;
if(current_tap > BSIZE){ //if tap point goes beyond BSIZE, start back at 0
current_tap = 0;
}
//Scale the value back to an unsigned value in preparation for output to DAC
analogout += 2048;
//Write to DAC1 output pin on Due board
analogWrite(DAC1, analogout);
}
}
The minimum delayTime value (900) and maximum delayTime value (20000) sound acceptable. There is slight noise on the maximum delay time - no noise on the minimum. I can change the delay time on the fly and get the expected pitch warping - BUT! any values in between the minimum and maximum introduce noise. If I just set it at around 8000 (i.e. don't touch the pot) - the repeats are noisy. As if there is white noise mixed into the signal of the repeat.
If I remove the pot from the equation - set the delayTime to a constant 8000, there is no noise.
I've got examples of the playback at different setting here. See the comments for which pieces of audio represent which settings:
[edit]sample removed[edit]
What can I do to eliminate the noise? Why is the noise being introduced? Any help would be much appreciated!