Go Down

Topic: Arduino Realtime Audio Processing (Read 42969 times) previous topic - next topic

Chippy569

sorry to bump such an old thread, but I'm really interested in your project. One of the limitations I see is your 3KHz limitation in audio signal. Out of curiosity, what would need to exist for that limit to be lower?

mattgilbertnet

#16
Apr 22, 2010, 05:47 pm Last Edit: Apr 22, 2010, 06:04 pm by mattgilbertnet Reason: 1
This is very very very cool. Thanks for the work and the great documentation. I'm definitely using this in my Audio Electronics class. (probably a lot)

MMarvelous, regarding the audio out, I was able to use a different circuit since I didn't have an inductor handy. The circuit I used is here:
http://www.tigoe.net/pcomp/img/audio-out.jpg
from this page, near the bottom:
http://www.tigoe.net/pcomp/code/input-output/analog-output
It seems to work ok.
Edit: Actually, the low pass is pretty strong on that filter, and cutting it in half seems a better fit.

fux, the analog inputs in the diagram on that page are flipped: the audio input is labeled "analog input 0" and the effect control is labeled "analog input 1", but in the code (the reverb and phasor code at least) and the text descriptions it's the other way around. This threw me off at first, so I thought you'd like to know if you hadn't noticed it already.

Thanks again!

mattgilbertnet

#17
May 18, 2010, 04:36 am Last Edit: May 18, 2010, 04:45 am by mattgilbertnet Reason: 1
Just got together a pitch dropping effect by modifying one of these examples. It's got a good bit of noise, but it's ok for a creepy, sloppy sort of effect, or maybe someone could figure out how to get rid of the noise. I've been trying to find smoother granular methods, but no dice so far. Anyway, I thought someone might find it interesting:

Code: [Select]

/* Arduino Audio Pitch Drop
*
* Arduino Realtime Audio Processing
* 2 ADC 8-Bit Mode
* anaöog input 1 is used to sample the audio signal
* analog input 0 is used to control an audio effect
* PWM DAC with Timer2 as analog output



* KHM 2008 / Lab3/  Martin Nawrath nawrath@khm.de
* Kunsthochschule fuer Medien Koeln
* Academy of Media Arts Cologne

*/


#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))


int ledPin = 13;                 // LED connected to digital pin 13
int testPin = 7;


boolean div32;
boolean div16;
// interrupt variables accessed globally
volatile boolean f_sample;
volatile byte badc0;
volatile byte badc1;
volatile byte ibb;



int cnta;
int icnt0;
int icnt1;
int icnt2;
int cnt2;
int iw1;
int iw2;
int iw3;
int iw;
byte bb;

byte dry[512];  // Audio Memory Array 8-Bit


void setup()
{
 pinMode(ledPin, OUTPUT);      // sets the digital pin as output
 pinMode(testPin, OUTPUT);
 Serial.begin(57600);        // connect to the serial port
 Serial.println("Arduino Audio Pitch drop");





 // set adc prescaler  to 64 for 19kHz sampling frequency
 cbi(ADCSRA, ADPS2);
 sbi(ADCSRA, ADPS1);
 sbi(ADCSRA, ADPS0);




 sbi(ADMUX,ADLAR);  // 8-Bit ADC in ADCH Register
 sbi(ADMUX,REFS0);  // VCC Reference
 cbi(ADMUX,REFS1);
 cbi(ADMUX,MUX0);   // Set Input Multiplexer to Channel 0
 cbi(ADMUX,MUX1);
 cbi(ADMUX,MUX2);
 cbi(ADMUX,MUX3);


 // Timer2 PWM Mode set to fast PWM
 cbi (TCCR2A, COM2A0);
 sbi (TCCR2A, COM2A1);
 sbi (TCCR2A, WGM20);
 sbi (TCCR2A, WGM21);

 cbi (TCCR2B, WGM22);




 // Timer2 Clock Prescaler to : 1
 sbi (TCCR2B, CS20);
 cbi (TCCR2B, CS21);
 cbi (TCCR2B, CS22);

 // Timer2 PWM Port Enable
 sbi(DDRB,3);                    // set digital pin 11 to output

 //cli();                         // disable interrupts to avoid distortion
 cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay is off now
 sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt


 Serial.print("ADC offset=");     // trim to 127
 iw1=badc0;  
 Serial.println(iw1);
}

boolean update_toggle = false;

void loop()
{
 while (!f_sample) {     // wait for Sample Value from ADC
 }                       // Cycle 15625 KHz = 64uSec

 f_sample=false;

 bb=badc1;
 
 dry[icnt0]=bb;          // write to buffer
 
 iw1=dry[icnt1] ;              // read the delay buffer
 iw2=dry[icnt2] ;              // read the delay buffer
 iw3 = ((iw1*icnt1) + (iw2*(256-icnt1)))/256;

 if(badc0 != 255){
   badc0=badc0/16+2;            // linit poti value to 512
 }
 
 icnt0++;
 if(update_toggle!=1){
   icnt1++;
 }
 update_toggle = (update_toggle + 1) % badc0;
 icnt0 = icnt0 & 511;         // limit index 0..511  
 icnt1 = icnt1 & 255;         // limit index 0..255
 icnt2 = icnt1 + 256;         // limit index 256..511

 
 bb = iw3;



 OCR2A=bb;            // Sample Value to PWM Output



} // loop


//******************************************************************
// Timer2 Interrupt Service at 62.5 KHz
// here the audio and pot signal is sampled in a rate of:  16Mhz / 256 / 2 / 2 = 15625 Hz
// runtime : xxxx microseconds
ISR(TIMER2_OVF_vect) {

 PORTB = PORTB  | 1 ;

 div32=!div32;                            // divide timer2 frequency / 2 to 31.25kHz
 if (div32){
   div16=!div16;  //
   if (div16) {                       // sample channel 0 and 1 alternately so each channel is sampled with 15.6kHz
     badc0=ADCH;                    // get ADC channel 0
     sbi(ADMUX,MUX0);               // set multiplexer to channel 1
   }
   else
   {
     badc1=ADCH;                    // get ADC channel 1
     cbi(ADMUX,MUX0);               // set multiplexer to channel 0
     f_sample=true;
   }
   ibb++;
   ibb--;
   ibb++;
   ibb--;    // short delay before start conversion
   sbi(ADCSRA,ADSC);              // start next conversion
 }

}


bswift5528

Hi, real noob to audio processing here as well...I'm still trying to process and understand a lot of what's going on here, but I'm hoping that the core principles here will serve my needs without too much modification.

I'm interested in an application where I would want to sample 5 or 10 inputs at a rate of something not too much less than 1kHz.  From what I figure, if you can sample 2 inputs at ~15kHz, then I should be able to sample 10 at ~3kHz, right?  Does it change very much if I'm doing an external multiplex into one pin (as opposed to the 2 of your setup)?

Another goal here is to dump the digitally sampled data off of the Arduino over serial to a computer.  marnaw said earlier that the timing modifications we're making here would screw up some of the other functions like delay() and analogRead(), so are we stuck with having to somehow reimplement the Serial library if we want to achieve this?  My first thought was that I might require another "normal" Arduino to accomplish this, but then, oh, how do I get the data between the two Arduinos without serial?

Any help/advice would be greatly appreciated!  Cheers!  --Brandon

bswift5528

Ok, so I gave it a bit more thought, and I'm still trying to decipher this timing/interrupt scheme here.  It's not intuitive to me yet...

I've been using a 4051 multiplexer (http://www.arduino.cc/playground/Learning/4051) for other things in the past, and I wanted to use one here to test my idea out, so I looked into the various delays involved in addressing/signal switching on that thing before going much further.

Seems it's not so bad, actually!  The 4051 multiplexer has a max (not typical) 1000 nanosec delay between switching an address bit and output signal.  Add that to 7 µs digitalWrite() overhead and we've got (1 +7N) µsec delay to address the multiplexer and so have to wait (assuming N=3 address bits) 22 µsec between reads?  Using all 8 inputs on the mux, then do I have to wait at least 176 µsec between reads on an individual channel?  If true, then that makes my sampling frequency (1/(2*176 µsec) ~ 3 kHz?  Again, maybe I'm thinking too linearly here and don't fundamentally understand the timing/interrupt thing that's going on here...

Can I actually get this to work, or am I just crazy?  Would I have to go to an Arduino Mega to be able to read a bunch of channels (with 16 analog inputs, as opposed to being limited to 6) or can you see any way I can still use a Duemilanove with two 4051 multiplexers feeding two analog pins being able to read 16 channels?

Also, is there any way to still put the ADC in 10-bit mode and not sacrifice to much?  Could you still do this audio processing in a 10-bit mode?  I assume you'd be sacrificing the high-end of your frequency space by being forced to sample at a lower rate, but remember that this is not a problem for me.  I only care about frequencies under 1kHz, so any sampling frequency above that is fine!

Oh, and also remember that I don't want PWM analog output here, I want a stream of digital data that I'll be dumping over to a computer.  Thanks!

bswift5528

Sorry to keep going here, but I'm slowly coming up with more questions here as I dig deeper.  Looking at the Atmega168 specs, and at the audio processing code from Martin, I can see how some of the ADC settings are set, and why, but I don't understand how you're telling it to only do an 8-bit conversion instead of a 10-bit.  I see in the timer interrupt code that when you do "badc0=ADCH;" it's only reading the ADCH register, but according to pg. 257 of the datasheet, ADCH is still the 8 most-significant bits of a 10-bit number.  I guess that by doing that, you're losing those last two, least-significant bits of info, effectively making it an 8-bit resolution measurement...but still, why throw away that resolution when it's sitting in the ADCL register, waiting to be read???  Why not read both registers and get the full 10-bit number?  (And how would you, uh, go about that anyway?)  Does it really take that much more time?

I still don't really understand what the PORTD and PORTB lines do, either.  After a read of https://www.mainframe.cx/~ckuethe/avr-c-tutorial/ I sort of see what you're doing with the PORTD lines (just switching Pin7 on/off?).  As for the "PORTB = PORTB | 1;", you're turning on Pin8/PB0?  (also, any reason to not use the |= operator here?)  On pg. 79 of the datasheet it says "PCINT0: Pin Change Interrupt source 0. The PB0 pin can serve as an external interrupt source." Does it have anything to do with that, cause I don't see anything else that we're doing with Pin8 here...

So, let me try to summarize here, the ADC can read at a rate of 16MHz/32/13 = 38.4kHz, or 26µs, and the Timer2 interrupt is set at 32kHz, or every 31.2µs.

I'm now starting to get it, I think.  Do you mind if I say what I think is going on here?  Ok, thanks.  At the start of the program, we go into the while(!f_sample){} loop and get "stuck" there.  Meanwhile, Timer2 overflows and the interruption code begins running.  div32 starts at 0, is flipped to 1, then we do the first read of the ADC from the Pin0 input.  At the end of the ISR macro we restart the next ADC conversion (since we didn't automatically by reading out the other ADCL register?).  We're still stuck in the while(!f_sample) loop for another Timer2 interrupt, only this time, nothing really happens...[wait, wait, wait: are we just are ensuring that enough time went by during that timer cycle that the ADC has time to finish the job?  It should have since it takes 26µs to do the conversion and the timer is set for 31µs!]  Anyway, nothing happens that time around, for some reason, and we get sent back to the while loop in the main loop program, the timer overflows again, and bang, we get back into the interrupt code and read the value of Pin1 with the ADC, finally setting f_sample true.  Exiting back to the main program loop, we do a few things, hopefully not taking longer than about 125µs (4 Timer2 loops, right?), otherwise the interrupt sampling (which is happening intermittently during those last instructions in main after the while(!f_sample){}) will become unsynchronized because we'd have left the while(){} too early.

Anyway, I think I'm most confused about why the div32 business is in there.  I guess in the original code, the Timer2 interrupt frequency was just about 2x faster than the ADC conversion frequency, so why didn't you just prescale the timer by a factor of 2?  Ohhhhh....cause you can't.  You can do it by factors of 1, 8, 32, 64, etc., but not 2.  Got it.  Ok, so now with the ADC and Timer2 settings that have been discussed earlier in the thread, then, we don't even need that div32 part of the code, I think, since the ADC and Timer2 frequencies are matched more appropriately!  Does that sound right?

Removing the div32 delay in the code, then, can we then sample each channel in what Martin originally laid out at 32kHz/2 = 16kHz?  The other divide-by-2 was from the div32 business.  I'm getting the 32kHz from the TCCR2B/CS2n settings in the provided code, and the very last bit of this post http://usethearduino.blogspot.com/2008/11/changing-pwm-frequency-on-arduino.html (which, by the way, the datasheet says that CS22 is read-only on pg. 155), not the 62.5kHz like the code comments say.

Say I scale up to 16 channels, then that would still give me the 1kHz sampling I'm looking for, but it's uncomfortable...I'd rather use timer0 where I can make the base rate 64kHz if that's at all a good idea for my application.  Is that something that would be fine?  No, I think I'd still be limited by the fact that the ADC is only ready to read at a rate of 38.4kHz with a prescaler of 32, ADC clock rate of 500MHz.  If I used a 2x higher frequency on Timer0, then I'd have to put that div32 bit in there again, reducing the whole thing back to how it essentially is now.  I could always take the prescaler to 16, but that would make the ADC run at 1MHz and from other things I've read that doesn't give the best results.  I *suppose* I can deal with a 1kHz sampling rate, with a 500Hz Nyqiust-sampled frequency...

Finally, if I actually burn this to the Arduino with all these low-level things set, will it return to the "normal" settings if I burn another sketch to it later that I've already used?  I know the answer is probably "don't worry, it's fine to do" but I just want to check. :)  

Again, if anyone has any comments, that would be great!

bswift5528

Found something interesting in the datasheet, pg 246...
Quote
By default, the successive approximation circuitry requires an input clock frequency between 50 kHz and 200 kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the input clock frequency to the ADC can be higher than 200 kHz to get a higher sample rate.

So, if we're using a prescale factor of 32 to bring the ADC clock speed to 500kHz, then we're opting for a lower-resolution mode in that sense, and perhaps the least-significant bits would be either not generated or total garbage (can't tell from datasheet yet).  Even if we prescale by 64 to 250kHz, it seems that would not work either, if we indeed want to try to get 10-bit resolution.  For 10-bit resolution, we'd have to prescale by 128 for a 125kHz ADC clock, so that one complete conversion could be done on a 125kHz/13 = 9.6 kHz timescale.  This is certainly no good for realtime audio processing 2 channels (4.8kHz sampling), but would be fine for what I want to do except for the fact that I'd be limited to about 8 channels (1.2 kHz sampling).  :(  

I wonder if I could get away with running the ADC at 250kHz and still get decent 10-bit conversion?  That would be great.  Then I could sample 16 channels!  I wouldn't mind if it was a little noisy, I guess, but I'd like the extra bits of resolution over my data being that quantized.  250kHz isn't that much faster than 200kHz, right?  :P  It's worth doing an experiment when I get around to putting some hardware together.  

And it's making me wonder that it says "by default" the circuitry needs a 50-200kHz clock...does that imply that there's a way around that??  Anyone here know anything about that?

And one other thing:  the ADC is able to generate its own interrupts (datasheet, pg. 245, top).  Why weren't you using that, Martin?  Because you were using PWM output and needed that for some reason?  If I just want to transfer the data over serial to a computer (I haven't yet worked out if that can transfer data fast enough to keep up with the sampling), then would it be better to use just the ADC interrupt and not bother with a timer interrupt?

In the end, though, it seems like I have to make the decision if the time-resolution or voltage-resolution is more important, which can again only happen when I start getting hardware together to see what the output is like.  :)

drhex

Nice "thinking out loud", Brandon!

bswift5528

(Thanks!  I was making a lot of notes to myself  after that first post and thought "this might be useful to someone else who also hasn't come across a lot of this stuff.")

mattgilbertnet

I've been working with this project a lot, and I decided to make a version with a few changes. The things I wanted to change were:
  • Audio input signal was weak for me, so I wanted to amplify it, improving sound quality
  • The audio output needed to be heavily filtered to remove the PWM buzz, removing a lot of higher frequencies in the process.
  • Add a mic input.


To increase the input signal strength, I used LM358 amplifier circuit. Some feedback on this part would be very appreciated. It's a basic non-inverting amp, but I couldn't get it to work properly without adding a 10K resistor in an odd place (The one by the note in the schematic below. Sorry that the note's text is so small). Without it, the baseline voltage of the input signal would drift upwards, floating out of range rather quickly. The 10K resistor keeps it from doing this: It still drifts up, but doesn't go out of range.


To avoid the need to filter out the high frequencies on the audio output, I replaced the output circuit with an R2R DAC like this one:
http://blog.makezine.com/archive/2008/05/makeit_protodac_shield_fo.html
That provides 8bit output without using PWM and so only a tiny bit of high frequencies need to be filtered out due to the digital stairstepping. Here's the full circuit:



Of course, a few lines of the code needed to change to output to pins 0-7 (PORTD), rather than the PWM output. Here's the code:

Code: [Select]
/* Arduino Audio Loopback Test
*
* Arduino Realtime Audio Processing
* 2 ADC 8-Bit Mode
* ana[ch65533]og input 1 is used to sample the audio signal
* analog input 0 is used to control an audio effect
* PWM DAC with Timer2 as analog output



* KHM 2008 / Lab3/  Martin Nawrath nawrath@khm.de
* Kunsthochschule fuer Medien Koeln
* Academy of Media Arts Cologne

*/


#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))


int ledPin = 13;                 // LED connected to digital pin 13
//int testPin = 7;


boolean div32;
boolean div16;
// interrupt variables accessed globally
volatile boolean f_sample;
volatile byte badc0;
volatile byte badc1;
volatile byte ibb;



int cnta;
int icnt;

int cnt2;
int iw1;

int iw;
byte bb;

byte dd[1024];  // Audio Memory Array 8-Bit


void setup()
{
 //R2R: Initialize output ports
//  PORTD = B11111111;
 for(int i=0; i < 8; i++){
   pinMode(i, OUTPUT);
 }

//  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
//  pinMode(testPin, OUTPUT);
/*
 Serial.begin(57600);        // connect to the serial port
 Serial.println("Arduino Audio Reverb");
*/

 fill_sinewave();        // reload wave after 1 second


 // set adc prescaler  to 64 for 19kHz sampling frequency
 cbi(ADCSRA, ADPS2);
 sbi(ADCSRA, ADPS1);
 sbi(ADCSRA, ADPS0);




 sbi(ADMUX,ADLAR);  // 8-Bit ADC in ADCH Register
 sbi(ADMUX,REFS0);  // VCC Reference
 cbi(ADMUX,REFS1);
 cbi(ADMUX,MUX0);   // Set Input Multiplexer to Channel 0
 cbi(ADMUX,MUX1);
 cbi(ADMUX,MUX2);
 cbi(ADMUX,MUX3);


 // Timer2 PWM Mode set to fast PWM
 cbi (TCCR2A, COM2A0);
 sbi (TCCR2A, COM2A1);
 sbi (TCCR2A, WGM20);
 sbi (TCCR2A, WGM21);

 cbi (TCCR2B, WGM22);




 // Timer2 Clock Prescaler to : 1
 sbi (TCCR2B, CS20);
 cbi (TCCR2B, CS21);
 cbi (TCCR2B, CS22);

 // Timer2 PWM Port Enable
 sbi(DDRB,3);                    // set digital pin 11 to output

 //cli();                         // disable interrupts to avoid distortion
 cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay is off now
 sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt


 //Serial.print("ADC offset=");     // trim to 127
 iw1=badc1;  
 //Serial.println(iw1);
 
 
 

}



void loop()
{
 while (!f_sample) {     // wait for Sample Value from ADC
 }                       // Cycle 15625 KHz = 64uSec

//  PORTD = PORTD  | 128;   // Test Output on pin 7
 f_sample=false;

 bb=dd[icnt] ;              // read the delay buffer
 iw = 127-bb ;              // substract offset
 iw = iw * badc0 / 255;     // scale delayed sample with potentiometer

 iw1 = 127 - badc1;          // substract offset from new sample
 iw1=iw1+iw;                 // add delayed sample and new sample
 if (iw1 < -127) iw1=-127;   // Audio limiter
 if (iw1 > 127) iw1=127;     // Audio limiter

 bb= 127+iw1;                // add offset
 dd[icnt]=bb;                // store sample in audio buffer

 icnt++;
 icnt = icnt & 1023;         // limit bufferindex 0..511

/*  cnt2++;               // let the led blink about every second
 if (cnt2 >= 15360){
   cnt2=0;
   PORTB = PORTB ^ 32;   // Toggle LED on Pin 11
 }
*/
 OCR2A=bb;            // Sample Value to PWM Output
 PORTD=bb;
//  PORTD = PORTD  ^ 128;   // Test Output on pin 7


} // loop
//******************************************************************
void fill_sinewave(){
 float pi = 3.141592;
 float dx ;
 float fd ;
 float fcnt;
 dx=2 * pi / 512;                    // fill the 512 byte bufferarry
 for (iw = 0; iw <= 511; iw++){      // with  50 periods sinewawe
   fd= 127*sin(fcnt);                // fundamental tone
   fcnt=fcnt+dx;                     // in the range of 0 to 2xpi  and 1/512 increments
   bb=127+fd;                        // add dc offset to sinewawe
   dd[iw]=bb;                        // write value into array

 }
}


//******************************************************************
// Timer2 Interrupt Service at 62.5 KHz
// here the audio and pot signal is sampled in a rate of:  16Mhz / 256 / 2 / 2 = 15625 Hz
// runtime : xxxx microseconds
ISR(TIMER2_OVF_vect) {

 PORTB = PORTB  | 1 ;

 div32=!div32;                            // divide timer2 frequency / 2 to 31.25kHz
 if (div32){
   div16=!div16;  //
   if (div16) {                       // sample channel 0 and 1 alternately so each channel is sampled with 15.6kHz
     badc0=ADCH;                    // get ADC channel 0
     sbi(ADMUX,MUX0);               // set multiplexer to channel 1
   }
   else
   {
     badc1=ADCH;                    // get ADC channel 1
     cbi(ADMUX,MUX0);               // set multiplexer to channel 0
     f_sample=true;
   }
   ibb++;
   ibb--;
   ibb++;
   ibb--;    // short delay before start conversion
   sbi(ADCSRA,ADSC);              // start next conversion
 }

}


In my experience, the output quality is much much better with these changes, and you can even pop on a powered electret element, boost the amplifier gain and have a standalone mic/voice changer kind of unit. Like I said, any feedback especially on the amplifier circuit would be greatly appreciated.

Bloosey

Hi all
Thank you very much for this thread. I am slowly learning what I am doing. Sorry about this bump.
On the original circuit diagram it shows the audio input going to pin 0 and the potentiometer input going to pin one for control purposes.

In the attached code example it states at the top...and seems to indicate in the code itself (I am still wrestling with the interupt code) that audio input goes to pin 1 and pot control to pin 0.

Is the later the correct way.

The reason that I ask is not to be pedantic but when I have been trying to cobble this together I am getting a distorted output as the result of an input on pin 0 and pin 1.
I will have to investigate further but if someone can confirm that it is analog input pin one(1) that I plug the output of the guitar into at least I will have reasonable control.

Any help would be much appreciated.

Bloosey

Thank you MattGibertcom for answering my question above.
I should have read the thread more carefully but I guess I am glad i was able to work it out for myself. Now I can get on with trying to get rid of the noise.

plaucks

If you remember from the original hardware post for this code, the output runs through and RLC system.
I have set up the DAC with my 2R value 47K and my R value 22K.

The output runs through the inductor and decouples with a 0.22uF capacitor.
My circuit is almost noiseless.

I think the original preamp phase was a bit wonky, so I redesigned it using an optoisolator circuit.
Check it out here.

http://monksoundworks.blogspot.com/

Good luck!

mattgilbertnet

plauks, I'd like to try out your circuit. Which optoisolator did you use?

plaucks

Radio shack IR emitter and collector diodes jammed tip to tip inside a cut down ball point pen and wrapped in tape.
If you go to the trouble to build the preamp, all parts from Radio Shack by the way, definitely play it directly through your amp for a second.
You will appreciate the natural fuzz sound, and it's cool that your guitar signal is turning into light :)

Good luck.
Get in touch if you have any questions

Go Up