Board index › Products › Audio Codec Shield

Feeding delayed output back into input.

22 posts · 26287 views

Feeding delayed output back into input.

by ArcAttack » Sat Nov 17, 2012 00:20 UTC
Howdy.

First off the board is pretty sweet. Currently using it with an arduino uno and looking to get the maple.

After futzing around with the variable delay sketch, i was curious how i could go about feeding the delayed out put back into the input. Any suggestions on resources to help me figure this out? I

Thanks in advance!

Re: Feeding delayed output back into input.

by guest » Sat Nov 17, 2012 06:45 UTC
feedback is a great idea. there are 2 ways to do this. one is digitally. you just take your output variable and add it back in with your input variable before you do any math. the downside to this is that it takes up more processor resources. you can also do it in analog with a potentiometer. just connect the top of the pot to HP_L, or HP_R which are the headphone outputs. connect the bottom of the pot to HP_C, which is ground. then connect the wiper to IN_L or IN_R. the pot will then allow you to control the level of feedback. a 10k pot should be fine, a log taper would be best, but probably doesnt matter too much.

Re: Feeding delayed output back into input.

by ArcAttack » Sat Nov 17, 2012 08:39 UTC
guest wrote:feedback is a great idea. there are 2 ways to do this. one is digitally. you just take your output variable and add it back in with your input variable before you do any math. the downside to this is that it takes up more processor resources. you can also do it in analog with a potentiometer. just connect the top of the pot to HP_L, or HP_R which are the headphone outputs. connect the bottom of the pot to HP_C, which is ground. then connect the wiper to IN_L or IN_R. the pot will then allow you to control the level of feedback. a 10k pot should be fine, a log taper would be best, but probably doesnt matter too much.


Thanks guest! I had just figured the digital bit out right before I read that.

Now I'm having that darnedest time trying to get the serial monitor to work. I tried adding a

Serial.println(mod0_value);

and i cant seem to get it to function.

#define SAMPLE_RATE 22 // 44.1kHz sample rate
#define ADCS 1 // only 1 ADC used here -> MOD0
#define LINVOL 20
// include necessary libraries
#include <Wire.h>
#include <SPI.h>
#include <AudioCodec.h>

// create data variables for audio transfer
// even though the function is mono, the codec requires stereo data
int left_in = 0; // in from codec (LINE_IN)
int right_in = 0;
int left_out = 0; // out to codec (HP_OUT)
int right_out = 0;

// create variable for ADC result
// it only has positive values -> unsigned
unsigned int mod0_value =0;

// create a delay buffer in memory
#define SIZE 800 // buffer size is limited by microcontroller SRAM size
int delaymem[SIZE]; // 800 positions x 2 bytes = 1600 bytes of SRAM
unsigned int location = 0; // buffer location to read/write from
unsigned int boundary = 0; // end of buffer position

void setup() {
  // call this last if you are setting up other things
  
  Serial.begin(9600);
  AudioCodec_init(); // setup codec and microcontroller registers
}

void loop() {
  while (1){
  int sensorValue = mod0_value;
  //Serial.println(sensorValue); //if this isnt commented out then the program freezes
  
  };
  // reduces clock jitter
}

// timer1 interrupt routine - all data processed here
ISR(TIMER1_COMPA_vect, ISR_NAKED) { // dont store any registers

  // &'s are necessary on data_in variables
  AudioCodec_data(&left_in, &right_in, left_out, right_out);
  
  // pass left input to right output
  right_out = left_out;

  //fetch data from buffer and put it into output register
  left_out = delaymem[location];
  // put new data in same location for maximal delay time
  delaymem[location++] = left_in + (left_out * .95); // post increment location to go to next memory location
  // check if location has gotten bigger than buffer size
  //left_in = left_out;
  if (location >= boundary) {
    location = 0; // reset location
  }

  // & is required before adc variable
  AudioCodec_ADC(&mod0_value);

  // scale ADC value to match buffer size
  // note the use of the fancy fast math function
  // you can read about these in the readme file
  unsigned int scale = SIZE;
  unsigned int newmod;
  if (mod0_value > 30000) 
      {
      newmod = 11000;
      }
  if (mod0_value < 30000) 
    {
     if (mod0_value > 10000) 
         {
      newmod = 16500;//low?
         }
         else 
         {
      newmod = 22000;}
      
    }
 // if (mod0_value < 1)
   //  {newmod = 44000;}
  MultiU16X16toH16(boundary, newmod, scale);

  reti(); // dont forget to return from the interrupt
}

Re: Feeding delayed output back into input.

by guest » Sat Nov 17, 2012 17:40 UTC
im not sure if serial can work with the codecshield. there arent too many free clock cycles, and i think it is blocking, which means it doesnt let other things happen while it is processing. you can try running it at its fastest rate, and see if that helps.

one other thing that you will have to do, to get any code to run in the loop() section, is to change the interrupt declaration. right now it is like this:

ISR(TIMER1_COMPA_vect, ISR_NAKED) { // dont store any registers
// some code here
reit();
}


you should change it to:

ISR(TIMER1_COMPA_vect) { // store registers
// some code here
// no reti
}


this will allow the main loop() to have its variables saved when the interrupt is called, otherwise the interrupt just clobbers them all.

if none of that works, i can give you some code that will work, its just that the arduino libraries are too bulky to work with the fast processing required by the codecshield.

Re: Feeding delayed output back into input.

by guest » Sat Nov 17, 2012 17:43 UTC
i knew i had looked at this before. here is a forum post describing exactly what you want to do:

viewtopic.php?f=21&t=302

Re: Feeding delayed output back into input.

by ArcAttack » Sat Nov 17, 2012 19:54 UTC
Ok here is the loop code:

void loop() {
  while (1){
 if (Serial.available() > 0) {
      // read the oldest byte in the serial buffer:
      // mod1_value = Serial.read() << 8;
       Serial.println(mod1_value)
     }
  };
  // reduces clock jitter
}



and i took out isnaked and reti; but still no luck :-/

Re: Feeding delayed output back into input.

by guest » Sat Nov 17, 2012 20:32 UTC
are you running this on an UNO or Dueminlaove? also, when did you download the library, and which one did you grab? i will double check that this all works.

Re: Feeding delayed output back into input.

by guest » Sat Nov 17, 2012 21:15 UTC
ok, so here is probably what the problem is: mod0_value gets modified only in the interrupt, so the main code has no idea that it is changing, and therefore compiles out the (aparantly) non-used code. to fix this, mod0_value needs to become volatile, which tells the compiler that it might be changing elsewhere. but, its not defined that way in the library, so it cant be declared volatile directly. to work around this, do the following:

volatile unsigned int serial_out = 0;

void loop() {
  if (Serial.available() > 0) {
    Serial.println(serial_out)
   }
}

and then in the interrupt:

serial_out = mod0_value;

Re: Feeding delayed output back into input.

by ArcAttack » Sat Nov 17, 2012 22:11 UTC
So I tried that. The program runs fine but still no Serial communication through the serial monitor.

Thanks again for the help!



guest wrote:ok, so here is probably what the problem is: mod0_value gets modified only in the interrupt, so the main code has no idea that it is changing, and therefore compiles out the (aparantly) non-used code. to fix this, mod0_value needs to become volatile, which tells the compiler that it might be changing elsewhere. but, its not defined that way in the library, so it cant be declared volatile directly. to work around this, do the following:

volatile unsigned int serial_out = 0;

void loop() {
  if (Serial.available() > 0) {
    Serial.println(serial_out)
   }
}

and then in the interrupt:

serial_out = mod0_value;

Re: Feeding delayed output back into input.

by guest » Sat Nov 17, 2012 23:00 UTC
i ran it on my arduino, and it worked, but i had to send a character first before the serial was recognized. try sending a character in the serial monitor, that should activate the serial.available(). are you calling serial.begin() before the codec initialization?

Re: Feeding delayed output back into input.

by ArcAttack » Sat Nov 17, 2012 23:47 UTC
Yeah
void loop() {
if (Serial.available() > 0) {
Serial.println(88);
Serial.println(serial_out);
}}


Still no luck :-/ Even tried different baud rates.


#include <mult16x16.h>
#include <mult16x8.h>
#include <mult32x16.h>

/*
variable_delay.pde
guest openmusiclabs 6.22.11
this program takes input from the left channel, and delays it
by a variable amount, set by the MOD0 knob.  it then presents
this delayed data on the left channel, with the non-delayed
data coming out of the right channel.
*/

// setup codec parameters
// must be done before #includes
// see readme file in libraries folder for explanations
#define SAMPLE_RATE 44 // 44.1kHz sample rate
#define ADCS 2 // only 1 ADC used here -> MOD0
#define LINVOL 22
//#define RHPVOL 127
//#define LHPVOL 127
// include necessary libraries
#include <Wire.h>
#include <SPI.h>
#include <AudioCodec.h>

// create data variables for audio transfer
// even though the function is mono, the codec requires stereo data
int left_in = 0; // in from codec (LINE_IN)
int right_in = 0;
int left_out = 0; // out to codec (HP_OUT)
int right_out = 0;

// create variable for ADC result
// it only has positive values -> unsigned
unsigned int mod0_value =0;
unsigned int mod1_value =0;
//int vol = 0;
// create a delay buffer in memory
#define SIZE 800 // buffer size is limited by microcontroller SRAM size
int delaymem[SIZE]; // 800 positions x 2 bytes = 1600 bytes of SRAM
unsigned int location = 0; // buffer location to read/write from
unsigned int boundary = 0; // end of buffer position

void setup() {
  // call this last if you are setting up other things
  
  Serial.begin(1200);
  Serial.println(88);
  AudioCodec_init(); // setup codec and microcontroller registers
}

volatile unsigned int serial_out = 0;

void loop() {
  if (Serial.available() > 0) {
    Serial.println(88);
    Serial.println(serial_out);
   }}



// timer1 interrupt routine - all data processed here
ISR(TIMER1_COMPA_vect){//, ISR_NAKED) { // dont store any registers
  serial_out = mod0_value;
  // &'s are necessary on data_in variables
  AudioCodec_data(&left_in, &right_in, left_out, right_out);
  unsigned int vol;
  unsigned int off = 1;
  // pass left input to right output
  right_out = left_out;
 
      
  //Serial.println(sensorValue);
  //fetch data from buffer and put it into output register
  left_out = delaymem[location];
  // put new data in same location for maximal delay time

  MultiSU16X16toH16(vol, left_out, mod1_value);
  delaymem[location++] = (left_in + (vol))*off; // post increment location to go to next memory location
  // check if location has gotten bigger than buffer size
  //left_in = left_out;
  if (location >= boundary) {
    location = 0; // reset location
  }

              
  // & is required before adc variable
  AudioCodec_ADC(&mod0_value,&mod1_value);
  
  if (mod1_value < 60000) {
         off = 1;
          } 
          else 
          {
          off = 0;
          }
  // scale ADC value to match buffer size
  // note the use of the fancy fast math function
  // you can read about these in the readme file
  unsigned int scale = SIZE;
  unsigned int newmod;
  
  if (mod0_value > 30000) 
      {
        if (mod0_value < 60000)
        {
      newmod = 11000;
        }
        else
        {
      newmod = 8250;
        }  
    }
  if (mod0_value < 30000) 
    {
     if (mod0_value > 10000) 
         {
      newmod = 16500;//low?
         }
         else 
         {
      newmod = 22000;}
      
    }
     
 // if (mod0_value < 1)
   //  {newmod = 44000;}
  MultiU16X16toH16(boundary, newmod, scale);

  //reti(); // dont forget to return from the interrupt
}

Re: Feeding delayed output back into input.

by guest » Sun Nov 18, 2012 00:33 UTC
i just ran your code, and it worked. i had to comment out the #include <mult>'s a the top, and im not sure why. i think it has to do with the library structure on my computer.

im using an Duelimanove and arduino-00022. i will try it with arduino1.0, and see if i can round up an UNO to try it with as well. what platforms are you using?

Re: Feeding delayed output back into input.

by guest » Sun Nov 18, 2012 00:44 UTC
ok, so it doesnt work with arduino1.0. i will figure out why. i never transitioned to 1.0 because it was more bloated and buggy than 0022.

Re: Feeding delayed output back into input.

by guest » Sun Nov 18, 2012 01:06 UTC
the problem is somehwere in serial.available(). if you get rid of the serial.available() line and just send the data out, then it should work. the arduino1.0 serial code uses interrupts, and blocks the codecshield, so the audio quality drops. i will look into why serial.available() messes with it. there are work arounds for the audio quality if you need that as a permanent feature, but if youre just using it for debugging, then its probably not worth it.

Re: Feeding delayed output back into input.

by guest » Sun Nov 18, 2012 01:24 UTC
very strange. i put a serial.read() command into the loop, and then it worked. i think serial.avaialble() doesnt do anything unless there is something setup to read the data bytes. serial.available() is a function which returns the number of bytes waiting on the incoming receive buffer. so perhaps the receive buffer isnt bothered with if there isnt anything to read the data, and therefore it always returns 0.

Re: Feeding delayed output back into input.

by ArcAttack » Sun Nov 18, 2012 09:13 UTC
well, after futzing about it for a while, i got the codec shield working with the mega, and with your tweaks the usb serial monitor works fine. Thanks again for all your help!


P.S.

do you know a guy named Chris Hatfield?

Re: Feeding delayed output back into input.

by guest » Sun Nov 18, 2012 18:46 UTC
wow, congrats on getting it working with the mega. was there anything extra you had to do, that isnt documented in the mega thread? it would be good info for others.

i dont think i know chris hatfield.

Re: Feeding delayed output back into input.

by ArcAttack » Sun Nov 18, 2012 21:12 UTC
Yeah, there was a little. I'm taking photos and documenting it to explain how I did it. I was planning on making a new thread to explain what we did.

Thanks again for all your help!

wow, congrats on getting it working with the mega. was there anything extra you had to do, that isnt documented in the mega thread? it would be good info for others.

i dont think i know chris hatfield.

Re: Feeding delayed output back into input.

by ArcAttack » Sun Nov 18, 2012 23:29 UTC
Hey guest! do you think we could chat on IM. I wanna make sure that my arduino mega fix makes sense and had some questions about the audiocodec.h

guest wrote:wow, congrats on getting it working with the mega. was there anything extra you had to do, that isnt documented in the mega thread? it would be good info for others.

i dont think i know chris hatfield.

Re: Feeding delayed output back into input.

by guest » Mon Nov 19, 2012 17:25 UTC
it doesnt seem like our forums have a pm system. if you want, i can set aside a time where we both can post at the same time to the forums. the delay should be pretty small.

Re: Feeding delayed output back into input.

by ArcAttack » Tue Nov 20, 2012 02:12 UTC
Sounds good to me or you can just email me Giovanni[at]Arcattack.com

Re: Feeding delayed output back into input.

by guest » Wed Nov 21, 2012 19:42 UTC
either way is fine with me as well. i sent you some mail