Thanks for this awesome example. I have ported this over to run on my ESP32 S3 board that has external 12 bit DAC MCP4921 and ADC MCP3021. The ESP is running RTOS with a seperate core reading potentiometers, pushbuttons etc and also updates on the OLED display. Sound quality is excellent. I will be adding different modes to this to have dedicated reverb and echo separated, will also be including a sampler function. Thanks again great contribution.
8:00 Are you sure you are doing that right? Why would you define the variables inside the void loop()? Why not make them global and define them above the loop? Should be much faster.
I think its OK. All the code is actually inside a "while(1)" infinite loop to avoid falling off the end of loop() and having them being setup again. See the line right below the long declaration. My reason for putting the variable declarations inside loop() was to avoid globals (which admittedly would be OK for small code like this, and I think perhaps the shunning of globals is not as strong now as it once was). But I didn't want to let loop() complete anyway since I don't know the time overhead in the hidden main() that calls it.
Very cool! I modified your idea to do a simple delay (no reverb) to sync the audio of an analog radio with a digital SDR radio. I am using a 10 usec timer interrupt instead of the delay, and it seems to work. I never would have figured out the DC bias trick and +- 2048, so thanks for that explanation!!
next step, control your buffer length and the taps or oldvalue scalers with pots or rotary encoders rather than reprogramming it for every change. Where can we find the code?
Greetings! I've used your circuit and your code in a reverb/ delay pedal of my own using the arduino due, and I can't get the same result. I have attempted to use the analogWriteResolution(12) function, but I get no signal output with this. I get an output signal when I override the write to 10 bits, but it sounds very distorted. Any advice?
I would probably look at the amplitude and DC offset coming into the ADC. The resistor voltage divider I used biases it up to mid supply and the capacitor just passes the signal in without any attenuation. Do you have a way to look at the signal actually coming into the ADC to be sure that's all working? I.e. the signal coming to the ADC is less than 3V peak to peak and centered on about 1.6V ?
@@michaelmeixner Maybe try to 'instrument' the code by sprinkling some print statements to send values to the console. Of course you'll want to only print every 100th or 1000th value since the loop goes pretty fast - but maybe you can see where things are going wrong by comparing the numbers you see with what they should be. None should be 'clipped' (e.g. full scale). They should all be around the midpoint of the int range (if I remember the code correctly). Maybe start by looking at the ADC values being input and at the DAC values being output. Troubleshooting can be fun, and is an invaluable skill in general ! I learned a lot in my early days by repairing equipment, but the troubleshooting skills carried forward to my design work - since few things work the first time ;-) Good luck.
this is all great stuff. works quite well too considering you're not using timers. it demonstrates the basic principals. it sounds great even though you didn't use asynchronous ADC stuff or whatever. sounds great.
Sound is nothing more or less than balanced positive and negative pressure variations caused by vibrations of air molecules around the local ambient air pressure. Anything that is not balanced results in the bulk movement of air rather than vibration of air - a phenomenon we call "wind" :-) As all sound, including increases or decreases in volume, and mixing together of different sounds, is superimposed upon and referenced to the static ambient air pressure, the digital representation of that sound for processing purposes must also be referenced to arithmetic zero, representing ambient pressure. Subtracting 2048 (which is half the range of the ADC and the DAC) from the digitally converted value references the "no sound" condition - meaning static ambient pressure, to arithmetic zero. All positive numbers now (by convention) represent increases in sound pressure while negative numbers represent negative pressure. ( Imagine the air pressure waves caused by the skin of a base drum if you need something more graphic.) All signal conditioning - increases or decreases in volume, and mixing together of different sounds - can then be achieved simply by adding or subtracting digital representations of those sounds, resulting in digital signals above or below zero representing the momentary higher or lower air pressure of the resulting sound in air. At the end, of course, we want to output a voltage which is an analog of the sound pressure (that's why we call it analog sound) that can be amplified and converted back to vibrations in the air by a loudspeaker. The digital to analog converter (DAC) need unipolar numbers (numbers that are are zero or positive), however, not bipolar numbers, so we add the 2048 back in before sending it to the DAC. Numerical values above 2047 will result (again, by convention) in positive going pressure waves while values below that will result in negative pressure waves. Hope that explains it.
You're demonstrating delay / echo, not reverb. True reverb won't suffer from periodicity. I've been wanting to try running the original freeverb public domain source code (which implements a Schroeder Reverberator) on an embedded microcontroller or DSP chip. I bet that would sound amazing.
Interesting discussion point - and thanks for the reference to the Schroeder Reverb - I was not familiar with that. I went to the freeverb site at stanford.edu and chained through some of the references to see what freeverb is and how works. It appears to be a sophisticated signal processing technique overlayed onto the original digital reverb concept to address the periodicity issues. I did my first reverb in digital hardware as a senior design project back in the 70's and noticed the comb filter effects in the sound (periodicity issues). So I added more delay lines and it got better. Looks like they do even more than that. FWIW, technically the "reverb" in this video is still a reverb since it adds old delayed samples back into the ring buffer so they build on themselves (See time 10:33 ). The delay values used determine if it sounds like an echo or not (since the brain will distinguish sounds separated in time by 50ms or more as discrete sounds). But I totally agree that in the video, the code was producing discrete (reverberating) echos due to the long tap offsets used. And it is not a very good reverb at all due to having only two taps - which is probably why I demoed it in the echo'y way ;-) It's basically just the original schemes people tried in the 70s before processing power (and DSP methods) got good enough to do it well like in freeverb. (Looking at the papers the freeverb references, I found this one that provides some historical context. Looks like the "reverb" I implemented is their Figure 2 "Feedback Reverb Unit Using Two Dissimilar Delay Lines". They fix the problems with this approach in their figures 3, 4, and 5 designs which I didn't do. Thanks for comment and reference to the improved approaches available today ! 🙂 www.scribd.com/document/424404635/1972-Michael-Gerzon-Synthetic-Reverberation )
Unfortunately, no. The UNO does not have a DAC to output an analog signal at a high enough rate (it has a PWM, but it is too slow). Also the UNO processor and memory are not really sufficient to do very good audio.
Thanks. Agreed on the white-board discussion / diagram about it being delay. The code however does implement reverb by adding the delayed audio samples to the current-time ones before putting that into the storage buffer at the current-time tap. Only two delay taps implemented, but it seemed to be enough to mitigate the comb-filter effect one sometimes gets in a digital implementation :-)
Thanks for this awesome example. I have ported this over to run on my ESP32 S3 board that has external 12 bit DAC MCP4921 and ADC MCP3021. The ESP is running RTOS with a seperate core reading potentiometers, pushbuttons etc and also updates on the OLED display. Sound quality is excellent. I will be adding different modes to this to have dedicated reverb and echo separated, will also be including a sampler function. Thanks again great contribution.
Wow. That's awesome. It's great to hear that the video was helpful and the port was successful. Your project sounds excellent!
Isn't this more a delay rather than reverb?
I understand they are the same family, but they have different sonic results.
8:00 Are you sure you are doing that right? Why would you define the variables inside the void loop()? Why not make them global and define them above the loop? Should be much faster.
I think its OK. All the code is actually inside a "while(1)" infinite loop to avoid falling off the end of loop() and having them being setup again. See the line right below the long declaration. My reason for putting the variable declarations inside loop() was to avoid globals (which admittedly would be OK for small code like this, and I think perhaps the shunning of globals is not as strong now as it once was). But I didn't want to let loop() complete anyway since I don't know the time overhead in the hidden main() that calls it.
Very cool! I modified your idea to do a simple delay (no reverb) to sync the audio of an analog radio with a digital SDR radio. I am using a 10 usec timer interrupt instead of the delay, and it seems to work. I never would have figured out the DC bias trick and +- 2048, so thanks for that explanation!!
next step, control your buffer length and the taps or oldvalue scalers with pots or rotary encoders rather than reprogramming it for every change.
Where can we find the code?
Greetings! I've used your circuit and your code in a reverb/ delay pedal of my own using the arduino due, and I can't get the same result. I have attempted to use the analogWriteResolution(12) function, but I get no signal output with this. I get an output signal when I override the write to 10 bits, but it sounds very distorted. Any advice?
I would probably look at the amplitude and DC offset coming into the ADC. The resistor voltage divider I used biases it up to mid supply and the capacitor just passes the signal in without any attenuation. Do you have a way to look at the signal actually coming into the ADC to be sure that's all working? I.e. the signal coming to the ADC is less than 3V peak to peak and centered on about 1.6V ?
@@MegawattKS I don't have access to that equipment at the moment, but I certainly will give it a shot once I do again. Thanks for the advice!
@@michaelmeixner Maybe try to 'instrument' the code by sprinkling some print statements to send values to the console. Of course you'll want to only print every 100th or 1000th value since the loop goes pretty fast - but maybe you can see where things are going wrong by comparing the numbers you see with what they should be. None should be 'clipped' (e.g. full scale). They should all be around the midpoint of the int range (if I remember the code correctly). Maybe start by looking at the ADC values being input and at the DAC values being output. Troubleshooting can be fun, and is an invaluable skill in general ! I learned a lot in my early days by repairing equipment, but the troubleshooting skills carried forward to my design work - since few things work the first time ;-) Good luck.
hi i d'ont understand what is old value please. do you speak spanish?
where is the tap in the circuit?
The code please
this is all great stuff. works quite well too considering you're not using timers. it demonstrates the basic principals. it sounds great even though you didn't use asynchronous ADC stuff or whatever. sounds great.
Good research like this should include project code, it'd definitely be appreciated!
don't really undestand why subtracting the 2048 from the input read to make it bipolar if you're making it unipolar back out again for the output DAC
Sound is nothing more or less than balanced positive and negative pressure variations caused by vibrations of air molecules around the local ambient air pressure. Anything that is not balanced results in the bulk movement of air rather than vibration of air - a phenomenon we call "wind" :-) As all sound, including increases or decreases in volume, and mixing together of different sounds, is superimposed upon and referenced to the static ambient air pressure, the digital representation of that sound for processing purposes must also be referenced to arithmetic zero, representing ambient pressure. Subtracting 2048 (which is half the range of the ADC and the DAC) from the digitally converted value references the "no sound" condition - meaning static ambient pressure, to arithmetic zero. All positive numbers now (by convention) represent increases in sound pressure while negative numbers represent negative pressure. ( Imagine the air pressure waves caused by the skin of a base drum if you need something more graphic.) All signal conditioning - increases or decreases in volume, and mixing together of different sounds - can then be achieved simply by adding or subtracting digital representations of those sounds, resulting in digital signals above or below zero representing the momentary higher or lower air pressure of the resulting sound in air.
At the end, of course, we want to output a voltage which is an analog of the sound pressure (that's why we call it analog sound) that can be amplified and converted back to vibrations in the air by a loudspeaker. The digital to analog converter (DAC) need unipolar numbers (numbers that are are zero or positive), however, not bipolar numbers, so we add the 2048 back in before sending it to the DAC. Numerical values above 2047 will result (again, by convention) in positive going pressure waves while values below that will result in negative pressure waves.
Hope that explains it.
This is brilliant, can this be done with the arduino mega?
Steve King no. The mega has a different microprocessor than the due.
can I find code anywhere?
Michał Pikala
Can check with your mom. She’s has the right code
NEED THE CODE PLEASE :D
You're demonstrating delay / echo, not reverb. True reverb won't suffer from periodicity. I've been wanting to try running the original freeverb public domain source code (which implements a Schroeder Reverberator) on an embedded microcontroller or DSP chip. I bet that would sound amazing.
Interesting discussion point - and thanks for the reference to the Schroeder Reverb - I was not familiar with that. I went to the freeverb site at stanford.edu and chained through some of the references to see what freeverb is and how works. It appears to be a sophisticated signal processing technique overlayed onto the original digital reverb concept to address the periodicity issues. I did my first reverb in digital hardware as a senior design project back in the 70's and noticed the comb filter effects in the sound (periodicity issues). So I added more delay lines and it got better. Looks like they do even more than that. FWIW, technically the "reverb" in this video is still a reverb since it adds old delayed samples back into the ring buffer so they build on themselves (See time 10:33 ). The delay values used determine if it sounds like an echo or not (since the brain will distinguish sounds separated in time by 50ms or more as discrete sounds). But I totally agree that in the video, the code was producing discrete (reverberating) echos due to the long tap offsets used. And it is not a very good reverb at all due to having only two taps - which is probably why I demoed it in the echo'y way ;-) It's basically just the original schemes people tried in the 70s before processing power (and DSP methods) got good enough to do it well like in freeverb. (Looking at the papers the freeverb references, I found this one that provides some historical context. Looks like the "reverb" I implemented is their Figure 2 "Feedback Reverb Unit Using Two Dissimilar Delay Lines". They fix the problems with this approach in their figures 3, 4, and 5 designs which I didn't do. Thanks for comment and reference to the improved approaches available today ! 🙂 www.scribd.com/document/424404635/1972-Michael-Gerzon-Synthetic-Reverberation )
#define BSIZE 8000
int ring_buff[BSIZE];
#define T1 (BSIZE - (BSIZE / 5))
#define T2 (BSIZE - 1)
void setup() {
for (int i = 0; i < BSIZE; i++)
ring_buff[i] = 0;
pinMode(A0, INPUT);
analogReadResolution(12);
analogWriteResolution(12);
//serial setup
Serial.begin(9600);
}
void loop() {
int analogin;
int old_value1;
int old_value2;
int analogout;
int current_tap = 0;
int tap;
long loopcount = 0;
while (1) {
analogin = analogread(A0) - 2048;
delayMicroseconds(20);
tap = current_tap - T1;
if (tap < 0)
tap += BSIZE;
old_value1 = ring_buff[tap];
tap = current_tap - T2;
if (tap < 0)
tap += BSIZE;
old_value2 = ring_buff[tap];
old_value1 /= 3;
old_value2 /= 4;
analogout = analogin + old_value1 + old_value2;
if (analogout > 2047) analogout = 2047;
if (analogout < -2047) analogout = -2047;
ring_buff[current_tap] = analogout;
current_tap++;
if(current_tap >= BSIZE) current_tap -= BSIZE;
analogout += 2048;
analogWrite(DAC0, analogout);
}
}
This is untested
Are arduino UNO work same
Unfortunately, no. The UNO does not have a DAC to output an analog signal at a high enough rate (it has a PWM, but it is too slow). Also the UNO processor and memory are not really sufficient to do very good audio.
Good job! Respect!
Exelent, could you send me the code please?
This effect is called echo, not reverb.
Arkadi Hughes
It’s actually called “delay”
echo is a type of delay
Hello! Really great work? Tutorial here :)
Is there any way you could send me the code? That would be amazing!!
Thanks in advance
That's Delay not Reverb. Still super cool project. 🤘
Thanks. Agreed on the white-board discussion / diagram about it being delay. The code however does implement reverb by adding the delayed audio samples to the current-time ones before putting that into the storage buffer at the current-time tap. Only two delay taps implemented, but it seemed to be enough to mitigate the comb-filter effect one sometimes gets in a digital implementation :-)
hi i d'ont understand what is old value please. do you speak spanish?