Source separation on a microphone recording and a know generated signal

Status
Not open for further replies.

MadMind

Well-known member
Hi everyone,

It's been 3 days that I'm fighting with a signal problem and as I'm pretty begginer, I think I'm missing some subtilities. I'd be really grateful if someone could help me to understand what's wrong with my code.

What I want to do is : reading the microphone RMS value variation without reading the generated signal sent to the speaker (the microphone being close from the speaker).

So, I did a schema (attached) to illustrate what I had in mind when I wrote the code (much more clear that writing a novel here).

Cancel signal schema.jpg

https://forum.pjrc.com/images/attach/jpg.gif

The big question I can't solve is how I could detect an accurate delay by scanning the change in RMS values on both signals, knowing that I need to scan RMS values every 50ms to have a pretty stable value.

Here is my current code :

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MedianFilter.h>   //https://github.com/daPhoosa/MedianFilter
#include <RunningAverage.h> //https://playground.arduino.cc/Main/RunningAverage
#include <Bounce.h>

// GUItool: begin automatically generated code
AudioSynthNoiseWhite     noise1;         //xy=82,272
AudioPlaySdWav           playSdWav2;     //xy=82,388
AudioPlaySdWav           playSdWav1;     //xy=83,357
AudioMixer4              mixer1;         //xy=242,291
AudioMixer4              mixer2;         //xy=245,370
AudioMixer4              mixer3;         //xy=413,320
AudioInputI2S            i2s2;           //xy=554,155
AudioEffectDelay         delay1;         //xy=574,319
AudioOutputI2S           i2s1;           //xy=575,405
AudioAnalyzePeak         peak_Mic;          //xy=742,186
AudioAnalyzeRMS          rms_Mic;           //xy=747,149
AudioAnalyzeRMS          rms_interne;           //xy=813,274
AudioAnalyzePeak         peak_interne;          //xy=815,309
AudioConnection          patchCord1(noise1, 0, mixer1, 0);
AudioConnection          patchCord2(playSdWav2, 0, mixer2, 2);
AudioConnection          patchCord3(playSdWav2, 1, mixer2, 3);
AudioConnection          patchCord4(playSdWav1, 0, mixer2, 0);
AudioConnection          patchCord5(playSdWav1, 1, mixer2, 1);
AudioConnection          patchCord6(mixer1, 0, mixer3, 0);
AudioConnection          patchCord7(mixer2, 0, mixer3, 1);
AudioConnection          patchCord8(mixer3, delay1);
AudioConnection          patchCord9(mixer3, 0, i2s1, 0);
AudioConnection          patchCord10(i2s2, 0, rms_Mic, 0);
AudioConnection          patchCord11(i2s2, 0, peak_Mic, 0);
AudioConnection          patchCord12(delay1, 0, rms_interne, 0);
AudioConnection          patchCord13(delay1, 0, peak_interne, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=641,494
// GUItool: end automatically generated code

MedianFilter MedianGainCompens(30, 0);
elapsedMillis msecs;

//REGLAGES Variables :

int freqRms = 50; //SETTING 
uint8_t PeakDetect = 0 ; // SETTING

// INIT :

uint8_t MicroRms;
uint8_t NoiseRms;
uint8_t Gaincompens;
uint8_t memMic;
uint8_t memNoise;
uint8_t Deriv_Mic;
uint8_t Deriv_Noise;
uint8_t Micro_Gaincompens;
uint8_t GainCompensMedian;
uint8_t InternalRms ;

float InternalPeak ;
float MicroPeak ;

String SoundFile, SoundType;
int resetMillis = 0;
int resetMillis1 = 0;
int resetMillis2 = 0;
int Delai_Compens = 0;
int condition;
int condition1;
int condition2;
int LastCondition = 0;
int LastCondition1 = 0;
int LastCondition2 = 0;


void setup() {
  Serial.begin(9600);
  AudioMemory(120);             // Audio connections require memory to work.  For more detailed information, see the MemoryAndCpuUsage example
  SoundFile = String();
  SoundType = String(".WAV");
  sgtl5000_1.enable();
  sgtl5000_1.volume(1);
  sgtl5000_1.inputSelect(AUDIO_INPUT_MIC);
  sgtl5000_1.micGain(20);
  SPI.setMOSI(7);
  SPI.setSCK(14);
  noise1.amplitude(1);
  delay(1000);
}

void loop() {
  // MIC / INTERNAL SIGNAL CALIBRATION

  //  Gain Compensation Calibration
  while (millis() < 5000) {
    condition = millis() - resetMillis  < freqRms;
    // Scan RMS value every freqRms msecs.
    if (condition) {
      if (condition != LastCondition) {
        InternalRms = rms_interne.read() * 1000;
        MicroRms = rms_Mic.read() * 1000;
        LastCondition = 1;
      }
    }
    else {
      LastCondition = 0;
      resetMillis = millis();
    }
    Gaincompens = InternalRms - MicroRms;
    MedianGainCompens.in(Gaincompens);
    GainCompensMedian = MedianGainCompens.out();
  }

  // Delay Compensation Calibration

  while (millis() > 5000 && millis() < 10000) {

    //    --------
    //    Burst Noise generation
    //    --------

    if (millis() - resetMillis1 < 500) {
      noise1.amplitude(0);
    }
    if (millis() - resetMillis1 > 500) {
      noise1.amplitude(1);
    }
    if (millis() - resetMillis1 > 1000) {
      resetMillis1 = millis();
    }

    //Calculate the delay between the 2 signals.

    condition = millis() - resetMillis  < freqRms;
    // Scan RMS value every freqRms msecs.
    if (condition) {
      if (condition != LastCondition) {
        InternalRms = rms_interne.read() * 1000;
        MicroRms = rms_Mic.read() * 1000 + GainCompensMedian; //Microphone RMS value + the gain compensation found with the first calibration.
        // Find the derivative in order to know sharp varations to be able to calculate the delay when the noise is playing.
        Deriv_Noise = InternalRms - memNoise;
        memNoise = InternalRms;
        Deriv_Mic = Micro_Gaincompens - memMic ;
        memMic = Micro_Gaincompens;
        LastCondition = 1;
      }
    }
    else {
      LastCondition = 0;
      resetMillis = millis();
    }

    //Threshold to detect a sharp variation
    condition1 = Deriv_Noise > PeakDetect;
    condition2 =  Deriv_Mic > PeakDetect;

    // Detect the delay between variation of both signals. 
    
    if (condition1) {
      if (condition1 != LastCondition1) {
        //        Serial.println("PEAK Noise");
        resetMillis2 = millis();
        LastCondition1 = condition1;
      }
    }
    else {
      LastCondition1 = 0;
    }

    if (condition2) {
      if (condition2 != LastCondition2) {
        //        Serial.println("PEAK Micro");
        Delai_Compens = millis() - resetMillis2;
        LastCondition2 = condition2;
      }
    }
    else {
      LastCondition2 = 0;
    }
  }
  noise1.amplitude(0);
}
 
Last edited:
I got confused
so again, what do you wanted to do?
forget bout RMS (as the name says it is an mean value) and tell us your intention.

In particular: The picture you show makes no sense to me
after estimating the intensity of a signal (aka, RMS) you cannot get a corrected signal.

what type of signals do you have?
what are you asked to do?
 
Hello,

Sorry, I thought it would have been easier to understand with that picture but it seemed that it totally failed...
I'm trying to explain it better with words then :

I want to create a sonic "character" which reacts according to the sound atmosphere around it (so it has a loudspeaker, and it has a microphone, both centralized on a teensy 3.2 with audio adaptor). The problem is that when it sings, I don't want him to catch itself though the microphone.

So there are two signal :
1/ The generated signal which is the sound I'm playing from Teensy & audioshield to the speaker.
2/ The microphone signal which capture the soundscape of the place AND the generated signal once it reach the speaker (which I don't want).

As I know the signal I'm sending to the speakers (I can measure it before reaching the speakers), a friend adviced me to subtract the generated signal to the microphone signal in order to only get the soundscape around the microphone without the sound generated and played though the speaker.

I hope it sounds clearer until now ?

For that purpose, I need to calibrate the signals because both have a different gain and a timing delay. This delay is the difference between the generated signal which hits the speaker and this signal hitting the microphone after havind travelled thought the air and got into the teensy though analog pin.

I already did the compensation gain by scanning RMS every 50 ms. Now I want to know the delay between both signal in order to be able to delay the generated signal with the right value.

The problem I have is :

I need to use the microphone signal with the RMS gain compensation and using RMS needs to have a read time period in order to make it more stable. So I'm loosing the time precision which would allow to know the delay compensation.
(see this post : https://forum.pjrc.com/threads/45855-AudioAnalyzeRMS-problem)

I hope it's a bit more clear for you and the community... Tell me if there is still something blurry. I'll do my best to explain what's in my head.

Thx a lot !!!

PS : I already did that with Pure Data and it worked pretty well.
 
the proper way to determine delay and gain would be cross correlation of signal with received sound (aka matched filter).

concerning the implementation: Is the distance and orientation of the loudspeaker to microphone constant or variable?

If it is a question of calibration (initial setup in a constant environment) then you are free to choose signal and you can transmit short pulse for easier analysis.
 
Thanks for your reply !
No, nothing is moving so when I have the gain and delay value, everything is fine :).

I'm already doing the pulse technique by sending a short noise signal every 500ms (you can see it in the code bellow). The problem is that when I want to analyse the delay, it's not accurate enough due to the RMS read time period which I fixed around 50ms. If I reduce it, the value become to behave like random noise because I read the absolute value of the signal every sample so it's not possible to track the beggining of the pulse with threshold. It's a problem of precision. I don't understand why it was working in Pure data and not in teensy. Do you have an idea ?

Code:
// --------
// Burst Noise generation
// --------

if (millis() - resetMillis1 < 500) {
noise1.amplitude(0);
}
if (millis() - resetMillis1 > 500) {
noise1.amplitude(1);
}
if (millis() - resetMillis1 > 1000) {
resetMillis1 = millis();
}
 
Last edited:
Thanks for your reply !
No, nothing is moving so when I have the gain and delay value, everything is fine :).

I'm already doing the pulse technique by sending a short noise signal every 500ms (you can see it in the code bellow). The problem is that when I want to analyse the delay, it's not accurate enough due to the RMS read time period which I fixed around 50ms. If I reduce it, the value become to behave like random noise because I read the absolute value of the signal every sample so it's not possible to track the beggining of the pulse with threshold. It's a problem of precision. I don't understand why it was working in Pure data and not in teensy. Do you have an idea ?

Great that it is constant

I have no knowledge of Pure data.
but forget for the moment the RMS

Important is to know the physical separation of speaker (in space or better in time) so that one understands the complexity
after that we find an easy implementation (with or without RMS block)
 
The speaker will be separated from the microphone of about 10 or 20 cm.
So what would be your suggestion in order to measure the delay between both signals without using an Rms block ?
 
The speaker will be separated from the microphone of about 10 or 20 cm.
So what would be your suggestion in order to measure the delay between both signals without using an Rms block ?

I would try first (EDIT: does not work, please use code from post #12)
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            i2s1;           //xy=173,467
AudioSynthWaveform       waveform1;      //xy=175,622
AudioEffectDelay         delay1;         //xy=368,621
AudioOutputI2S           i2s2;           //xy=393,747
AudioEffectMultiply      multiply1;      //xy=574,512
AudioAnalyzeRMS          rms1;           //xy=739,512
AudioConnection          patchCord1(i2s1, 0, multiply1, 0);
AudioConnection          patchCord2(waveform1, delay1);
AudioConnection          patchCord3(waveform1, 0, i2s2, 0);
AudioConnection          patchCord4(delay1, 0, multiply1, 1);
AudioConnection          patchCord5(multiply1, rms1);
AudioControlSGTL5000     sgtl5000_1;     //xy=179,758
// GUItool: end automatically generated code

//const int myInput = AUDIO_INPUT_LINEIN;
const int myInput = AUDIO_INPUT_MIC;

void setup() {
  // put your setup code here, to run once:
  AudioMemory(24);


  // setup audio board
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  
  // setup microphone
  sgtl5000_1.micGain(31); // from 0 to 63

  // setup headphone
  sgtl5000_1.volume(0.5); 

  // setup waveform
  waveform1.pulseWidth(0.01); // 0.03 ms pulse
  waveform1.begin(1.0, 1000, WAVEFORM_PULSE);
  
  // setup delay
  // use only one delay
  delay1.delay(0,0.0);
  for(int ii=1; ii<8; ii++) delay1.disable(ii);
}

uint32_t avg;         // accumulator for rms reads
#define NAVG 10       // number of rms reads for final answer

#define MINDEL 0.0f   // min delay
#define MAXDEL 3.0f   // max delay 3 ms equals 1 m
#define NSTEP 100     // number of steps between 0 and MAXDEL

uint32_t del=0;

void loop() {
  // put your main code here, to run repeatedly:
  static uint32_t iavg=0;

  for(int ii=0; ii <NSTEP; ii++)
  { float fdel = MINDEL+(MAXDEL-MINDEL)*ii/(float)NSTEP; 
    delay1.delay(0,fdel);     //  this may generate some transients
    while(!rms1.available()); // so wait and discard first rms reading
    while(iavg++ < NAVG)
    {
      while(!rms1.available());
      float val = rms1.read();
      avg += val*val;           // accumulate energy not intensity
      iavg++;

    }
    Serial.printf("%d %f %f\n\r",ii, fdel, sqrt(avg)/NAVG);
    iavg=0;
   delay(100);
  }
}
To see the structure impurt the lines between // GUITool into to the Audio System Design Tool

This implements a matched filter and steps through all possible delays.
The RMS value will be max for the right delay and the value will be equal to the received intensity.
As you know the transmitted intensity you get easily the attenuation factor

Caveat:
the program compiles but I have no Hardware set up to test it
I suspect it to be very fast so I inserted a delay(100); after each Serial.printf.

You may modify setup for your hardware

Obviously one can do that also (faster) with FFT based cross-correlation, but that is another story
 
Last edited:
Hello Mate,

First of all, big big thanks for the time you involved in helping me and writing this code. I'm really grateful.

Your approach is very interesting and I didn't think to multiply both signal to see the maximum value. Well done ! I think I understood the in and the out but I can't unfortunatly follow everything your code as I'm still a begginer. I'd love to understand every step in order to improve my skills but I have some interrogations...the while loop without brackets seems particulary mystical to me... May be it's a kind of shortcut ? Also, when I upload it on the teensy, I can't see any printed value on the monitor. I added a serial and changed the delay value as you suggested but nothing's happening..

I have other questions but I'm trying to spend more time t
 
The while loop without brackets is a while loop that doesn't do anything except to keep checking (!rms1.available()) until it returns true. This is a "busy wait" method.

As for serial you may want to add a Serial print message in setup() just to see if you need to debug where/what you're printing to. Make sure you can get serial output from a part of the program that you know will execute correctly. Then if it works in setup, but you still get no output from the loop, you can start putting more print messages in different parts of the loop to figure out where it's getting stuck.

Right now you have 2 questions to answer:
1) Is it not printing serial because serial is setup wrong or you're not monitoring the right serial output?
2) Is it not printing serial because the main loop of the program is not working correctly?
 
To get the serial printout working you should add yield() to the while loop


Code:
while(!rms1.available()) yield;

there are other issues
variable "avg" must be declared as float and not as uint32_t
the "iavg++;" line must be removed otherwise this variable will be incremented twice.

However I cannot get delay working properly, but I'm working on it (At least I'm trying to understand what is (not) going on)
 
I played around with my (pseudo) matched filter idea and come up with
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

#define SIMULATE
#ifdef SIMULATE
// GUItool: begin automatically generated code
AudioSynthToneSweep      tonesweep1;     //xy=292,317
AudioEffectDelay         delay1;         //xy=538,186
AudioEffectDelay         delay2;         //xy=541,429
AudioEffectMultiply      multiply2;      //xy=797,476
AudioOutputUSB           usb1;           //xy=800,343
AudioOutputI2S           i2s1;           //xy=803,195
AudioAnalyzeRMS          rms1;           //xy=933,476
AudioConnection          patchCord1(tonesweep1, delay2);
AudioConnection          patchCord2(tonesweep1, delay1);
AudioConnection          patchCord3(delay1, 0, i2s1, 0);
AudioConnection          patchCord4(delay1, 0, usb1, 0);
AudioConnection          patchCord5(delay1, 0, multiply2, 0);
AudioConnection          patchCord6(delay2, 0, multiply2, 1);
AudioConnection          patchCord7(delay2, 0, i2s1, 1);
AudioConnection          patchCord8(delay2, 0, usb1, 1);
AudioConnection          patchCord9(multiply2, rms1);
AudioControlSGTL5000     sgtl5000_1;     //xy=302,471
// GUItool: end automatically generated code

#else

// GUItool: begin automatically generated code
AudioSynthToneSweep      tonesweep1;     //xy=292,317
AudioOutputI2S           i2s1;           //xy=492,176
AudioEffectDelay         delay2;         //xy=541,429
AudioInputI2S            i2s2;           //xy=622,177
AudioEffectMultiply      multiply2;      //xy=797,476
AudioOutputUSB           usb1;           //xy=915,366
AudioAnalyzeRMS          rms1;           //xy=933,476
AudioConnection          patchCord1(tonesweep1, delay2);
AudioConnection          patchCord2(tonesweep1, 0, i2s1, 0);
AudioConnection          patchCord3(tonesweep1, 0, i2s1, 1);
AudioConnection          patchCord4(delay2, 0, multiply2, 1);
AudioConnection          patchCord5(delay2, 0, usb1, 1);
AudioConnection          patchCord6(i2s2, 0, multiply2, 0);
AudioConnection          patchCord7(i2s2, 0, usb1, 0);
AudioConnection          patchCord8(multiply2, rms1);
AudioControlSGTL5000     sgtl5000_1;     //xy=292,476
// GUItool: end automatically generated code
#endif

//const int myInput = AUDIO_INPUT_LINEIN;
const int myInput = AUDIO_INPUT_MIC;

void ping(int idel)
{
  float fdel = idel*1000.0f/AUDIO_SAMPLE_RATE_EXACT;
  AudioNoInterrupts();
  rms1.read(); // clear rms counter/accumulator
  delay2.delay(0,fdel); // delay in ms
  AudioInterrupts();
  tonesweep1.play(1.0,500,3000,0.01);
  while(tonesweep1.isPlaying()) yield();
  while(!rms1.available()) yield();
  float val=rms1.read()*AUDIO_BLOCK_SAMPLES;
  Serial.printf("%d %f %f\n\r",idel,fdel,val);
}

void setup() {
  // put your setup code here, to run once:
  AudioMemory(12);

  while(!Serial);
  Serial.println("TestShift");

  AudioNoInterrupts();
  // setup audio board
  sgtl5000_1.enable();
  
  // setup headphone
  sgtl5000_1.volume(0.1); 

#ifdef SIMULATE
  delay1.delay(0,1.5); // delay in ms
  for(int ii=1;ii<8;ii++) delay1.disable(ii);
#else
  sgtl5000_1.inputSelect(myInput);
  // setup microphone
  sgtl5000_1.micGain(31); // from 0 to 63
#endif
  for(int ii=1;ii<8;ii++) delay2.disable(ii);
}

void loop() {
  static int idel=1;
  if(idel<0) return;
  ping(idel);
  idel++;
  if(idel>128) idel=-1; // mark to stop 
}

first, I realized that waveform object is not the right one to use, best (also for resolution) is a sweep (I chose from 500 to 3 kHz for 10 ms)
then I had to get the rms reading issue correct.

the above program has two version, one simulation of 1.5 ms delay and one to be used with microphone.
As I do not have hardware (speaker and microphone) ready for test, I only tested the SIMULATE part of the program.

Edit2: I call it pseudo match filter as it used rms and not a simple sum as is would be for real matched filter

Let me know how it turn out.
Edit1: you must compile with Serial+MIDI+Audio switched on
 
Last edited:
Hey mates !

Very sorry to reply as much late but I wanted to be sure that the other parts of my code work. Now it's done I can focus on that problem and I will try to understand everything you did. I'll keep you updated how it is working on the hardware as soon as possible.

Again, thanks a lot !!!

Have a great day.
 
OK, so I tested your code. The simulation is working and it also seems to work with the micro !!! It finds a value like 0.204 ms which looks like something coherent.

Again, thanks a lot for your precious help ! If you come in Paris, let me know and I offer you a beer ! :)

Now, I still want to understand your work but it’s difficult for me.

I do apologize for my low understanding level but it’s been 3 hours that I’m trying to understand by myself and many things stay very blurry for me. I don’t want to just use your work without understanding it precisly so I allow myself to ask you some elementary questions :

1/ Questions about signal processing :

- Why is the tonesweep better than the pulse you used before ? Does a Noise pulse like I did, would have worked ?

- Does the 128 iterations you chosen correspond to the number of block samples on purpose ? If yes, what is the purpose ?

- Why do you multiply the rms value with the window (I guess AUDIO_BLOCK_SAMPLES is the window ?)


2/ Questions about the code formalism :

- Why do we need the 2 while loop in the ping function ?
Here is how I understand this part, which make no sense to me :
We check if the tonesweep1 is playing, if yes we go to the next step.
We check is there is no rms reading, if yes, we go to the next step.
So if there is no sound or a rms available the function stop and nothing’s happen.

So the yield function is above all, much more confusing for me, because it says to go to the next step whatever the case. what’s the point in using this while loops to check a condition which will be ignored after ?

- I understand that fdel calculates the time ellapsed between 1000 samples and then check it every 1000 samples. Is there a reason why you chosen 1000 ?

Thanks a lot for your help and sorry again for asking as many questions.

In order to improve the code and make it more automatic, what do you think about compiling every values in an array, and then check the maximum value of the rms measurement in order to return the right delay corresponding to that maximum ? !

I’ll try to do it later and repost on the forum if it’s working.

Thx !
 
- Why is the tonesweep better than the pulse you used before ? Does a Noise pulse like I did, would have worked ?
In order to get a decent processing gain the time-bandwidth product should be high.
tonesweep is good but noise pulses would work, but have not looked into that

- Does the 128 iterations you chosen correspond to the number of block samples on purpose ? If yes, what is the purpose ?
I stepped sample by sample through a complete audio block. you can increase to any number
idel is the delay in samples, fdel is the delay in ms, as required by the delay object.

- Why do you multiply the rms value with the window (I guess AUDIO_BLOCK_SAMPLES is the window ?)
only to undo the 'mean' part of the rms, and to get some higher number to be printed. You can change.

- Why do we need the 2 while loop in the ping function ?
Here is how I understand this part, which make no sense to me :
We check if the tonesweep1 is playing, if yes we go to the next step.
We check is there is no rms reading, if yes, we go to the next step.
So if there is no sound or a rms available the function stop and nothing’s happen.

yes, the intention was to wait until sweep has finished and until some rms is available
but you easily can replace
Code:
 while(tonesweep1.isPlaying()) yield();
  while(!rms1.available()) yield();

by say
Code:
delay(100);
and to wait for 100 ms for reading the rms value.
unfortunately, the longer you wait, the smaller the rms value gets
but
Code:
  int dt=100;
delay(dt);
float val=rms1.read()*(dt/3)*AUDIO_BLOCK_SAMPLES;
compensates somewhat for the mean estimation in the rms object (result is multiplied by the number od samples used to calculate the rms)

So the yield function is above all, much more confusing for me, because it says to go to the next step whatever the case. what’s the point in using this while loops to check a condition which will be ignored after ?
The yield()s are not necessary, but calls some event handler (like serial).

- I understand that fdel calculates the time ellapsed between 1000 samples and then check it every 1000 samples. Is there a reason why you chosen 1000 ?
this is to convert the delay in milliseconds to seconds (frequency is in Hz). there is not check every 1000 samples

In order to improve the code and make it more automatic, what do you think about compiling every values in an array, and then check the maximum value of the rms measurement in order to return the right delay corresponding to that maximum ? !

yes
 
Hi mate !

Thank you for your explanations !

I did the little arrangements for selecting the right delay and measure the gain compensation. It works very well on the simulation code :

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MedianFilter.h>

// GUItool: begin automatically generated code
AudioSynthToneSweep      tonesweep1;     //xy=144,281
AudioEffectDelay         delay1;         //xy=386,153
AudioEffectDelay         delay2;         //xy=387,391
AudioAnalyzeRMS          rms2;           //xy=526,85
AudioAnalyzeRMS          rms3;           //xy=549,452
AudioEffectMultiply      multiply2;      //xy=644,341
AudioOutputI2S           i2s1;           //xy=683,115
AudioAnalyzeRMS          rms1;           //xy=787,341
AudioConnection          patchCord1(tonesweep1, delay2);
AudioConnection          patchCord2(tonesweep1, delay1);
AudioConnection          patchCord3(delay1, 0, i2s1, 0);
AudioConnection          patchCord4(delay1, 0, multiply2, 0);
AudioConnection          patchCord5(delay1, 0, rms2, 0);
AudioConnection          patchCord6(delay2, 0, multiply2, 1);
AudioConnection          patchCord7(delay2, 0, i2s1, 1);
AudioConnection          patchCord8(delay2, 0, rms3, 0);
AudioConnection          patchCord9(multiply2, rms1);
AudioControlSGTL5000     sgtl5000_1;     //xy=154,435
// GUItool: end automatically generated code

MedianFilter Median(10, 0);

const int myInput = AUDIO_INPUT_MIC;
float valMax = 0;
float delayCompens = 0;
float GainCompens = 0;
float GainCompensMedian = 0;

void ping(int idel)
{
  float fdel = idel * 1000.0f / AUDIO_SAMPLE_RATE_EXACT;
  AudioNoInterrupts();
  rms2.read(); // clear rms counter/accumulator
  rms3.read(); // clear rms counter/accumulator
  rms1.read(); // clear rms counter/accumulator
  delay2.delay(0, fdel); // delay in ms
  AudioInterrupts();
  tonesweep1.play(1.0, 500, 3000, 0.01);
  while (tonesweep1.isPlaying()) yield();
  while (!rms1.available()) yield();
  float val1 = rms2.read() * AUDIO_BLOCK_SAMPLES;
  float val2 = rms3.read() * AUDIO_BLOCK_SAMPLES;
  float val = rms1.read() * AUDIO_BLOCK_SAMPLES;
  if (val > valMax) {
    valMax = val;
    delayCompens = fdel;
  }

  GainCompens = val2 - val1;
  Median.in(GainCompens);
  GainCompensMedian = Median.out();
  Serial.printf("%d %f %f %f %f\n\r", idel, fdel, val1, val2, val);
}

void setup() {
  // put your setup code here, to run once:
  AudioMemory(12);
  while (!Serial);
  Serial.println("TestShift");

  AudioNoInterrupts();
  // setup audio board
  sgtl5000_1.enable();

  // setup headphone
  sgtl5000_1.volume(0.1);
  delay1.delay(0, 1.5); // delay in ms
  for (int ii = 1; ii < 8; ii++) delay1.disable(ii);
  for (int ii = 1; ii < 8; ii++) delay2.disable(ii);
}

void loop() {
  static int idel = 1;
  if (idel < 0) return;
  ping(idel);
  idel++;
  if (idel > 128) {
    Serial.print("The Delay compensation is : ");
    Serial.println(delayCompens);
    Serial.print("The Gain compensation is : ");
    Serial.println(GainCompens);
    idel = -1; // mark to stop
  }
}
}

But I still have some troubles on the final version with the microphone.

The main problem is that it seems to freeze after some time and the multiply object sends back a sequence of 0 like this :
Capture d’écran 2017-08-31 à 11.08.12.png

When it works, it still sends back a 0 every two idel values :

Capture d’écran 2017-08-31 à 11.07.35.png

I don't understand why. Do you have an idea ?

Edit 1 : I've deleted the median filter for measuring the median gain compensation because it stoped the program after 15 or 20 iterations in the final version of the code.
 
Ok ! I see. But...I don't understand how do you send the 0 stream right after the tonesweep's end.

Do you do that thanks to this part ? :

Code:
    for(i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
      bp[i] = (short)(( (short)(arm_sin_q31((uint32_t)((tone_phase >> 15)&0x7fffffff))>>16) *tone_amp) >> 16);

Where I'm supposed to add it ?

EDIT 1 : Why does it bug sporadicly ? I'm often have that 0 stream and sometime the 0 appears once every 2 idel values.

EDIT 2 : I did different testing with this code
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MedianFilter.h>

// GUItool: begin automatically generated code
AudioSynthToneSweep      tonesweep1;     //xy=139,238
AudioOutputI2S           i2s1;           //xy=339,97
AudioEffectDelay         delay2;         //xy=388,350
AudioInputI2S            i2s2;           //xy=469,98
AudioAnalyzeRMS          rmsMic;           //xy=637,92
AudioEffectMultiply      multiply2;      //xy=659,397
AudioAnalyzeRMS          rmsSigInt;           //xy=660,302
AudioAnalyzeRMS          rms1;           //xy=811,397
AudioConnection          patchCord1(tonesweep1, delay2);
AudioConnection          patchCord2(tonesweep1, 0, i2s1, 0);
AudioConnection          patchCord3(tonesweep1, 0, i2s1, 1);
AudioConnection          patchCord4(delay2, 0, multiply2, 1);
AudioConnection          patchCord5(delay2, 0, rmsSigInt, 0);
AudioConnection          patchCord6(i2s2, 0, multiply2, 0);
AudioConnection          patchCord7(i2s2, 0, rmsMic, 0);
AudioConnection          patchCord8(multiply2, rms1);
AudioControlSGTL5000     sgtl5000_1;     //xy=139,397
// GUItool: end automatically generated code

//MedianFilter Median(10, 0);

const int myInput = AUDIO_INPUT_MIC;
float valMax = 0;
float delayCompens = 0;

float GainCompens = 0;
float GainCompensMedian = 0;

void ping(int idel)
{
  float fdel = idel * 1000.0f / AUDIO_SAMPLE_RATE_EXACT;
  AudioNoInterrupts();
  rms1.read();      // clear rms counter/accumulator
  rmsMic.read();    // clear rms counter/accumulator
  rmsSigInt.read(); // clear rms counter/accumulator
  delay2.delay(0, fdel); // delay in ms
  AudioInterrupts();
  tonesweep1.play(1.0, 500, 3000, 0.01);
  while (tonesweep1.isPlaying()) yield();
  while (!rms1.available()) yield();
  float val = rms1.read() * AUDIO_BLOCK_SAMPLES;
  float val2 = rmsSigInt.read() * AUDIO_BLOCK_SAMPLES;
  float val3 = rmsMic.read() * AUDIO_BLOCK_SAMPLES;

  if (val > valMax) {
    valMax = val;
    delayCompens = fdel;
  }

  GainCompens = val2 - val3;
  //  Median.in(GainCompens);
  //  GainCompensMedian = Median.out();x
  Serial.printf("%d %f %f %f %f\n\r", idel, fdel, val2, val3, val);
}

void setup() {
  // put your setup code here, to run once:
  AudioMemory(12);
  while (!Serial);
  Serial.println("TestShift");
  AudioNoInterrupts();
  // setup audio board
  sgtl5000_1.enable();
  // setup headphone
  sgtl5000_1.volume(0.7);
  sgtl5000_1.inputSelect(myInput);
  // setup microphone
  sgtl5000_1.micGain(31); // from 0 to 63
  for (int ii = 1; ii < 8; ii++) delay2.disable(ii);
}

void loop() {
  static int idel = 1;
  if (idel < 0) return;
  ping(idel);
  idel++;
  if (idel > 128) {
    Serial.print("The Delay compensation is : ");
    Serial.println(delayCompens);
    Serial.print("The Gain compensation is : ");
    Serial.println(GainCompens);
    idel = -1; // mark to stop
  }
}

When it's working every two measurements, there is a strong inconsistency between the delay compensation it send me back. once I get 2,7 and another time 1.7...
I got confused...
 
Last edited:
No,
this one
First, I noted that this routine only transmits audio objects while sweep in ongoing. To overcome this, I replaced in toneseeep 'update' function
Code:
Code:
  if(!sweep_busy)return;
by
Code:
Code:
  if(!sweep_busy)
  {
	block = allocate();
	if(block) {
		bp = block->data;
		short *ebp = bp + AUDIO_BLOCK_SAMPLES;
		while(bp < ebp) *bp++ = 0;
		// send the samples to the left channel
		transmit(block);
		release(block);
	}
	return;
  }
meaning update sends out empty (zeroed) audio objects to keep attached functions happy.

This allowed me to run the above sketch continuously and to read some cross-multiply values.
 
EDIT 1 : Why does it bug sporadicly ? I'm often have that 0 stream and sometime the 0 appears once every 2 idel values.
That is not a bug but an intended feature by Pete, to avoid use of audio buffers when nothing happens.

BTW, If you are using usb-audio you need also T-1.39.1 to address a bug in usb-audio.
 
I guess I have to replace the "sweep_busy" boolean by !tonesweep1.isPlaying() but I don't know which are the right variables to replace
"block", "data" and "bp". Also, the "allocate()" and the "transmit()" functions don't seem to work properly as they're not recognised by the Arduino IDE. Do I have to DL an external library ?

I'm really grateful for your help and I really feel that I improve my skills thanks to you !

Long life to PJRC forum !!!!
 
I guess I have to replace the "sweep_busy" boolean by !tonesweep1.isPlaying() but I don't know which are the right variables to replace
"block", "data" and "bp". Also, the "allocate()" and the "transmit()" functions don't seem to work properly as they're not recognised by the Arduino IDE. Do I have to DL an external library ?

I'm really grateful for your help and I really feel that I improve my skills thanks to you !

Long life to PJRC forum !!!!

NO, simply replace the single line by the extended version (do a cut an paste) in the file synth_tonesweep.cpp that you find in the audio library of teensyduno
 
Ok !

I just did the manipulation but now the program is freezing after 9, 10 or 11 iterations... don't understand why it's doing this wheareas it's perfectly working in the simulation code, even without changing tonesweep object...

EDIT 1 : The simulation is not working anymore with the added code inside the tone sweep object. It's also freezing.
EDIT 2 : After a couple of try, the simulation work again...but the hardware version is still freezing

Here is the code (I just deleted the usb object in the structure) :

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <MedianFilter.h>

// GUItool: begin automatically generated code
AudioSynthToneSweep      tonesweep1;     //xy=139,238
AudioOutputI2S           i2s1;           //xy=339,97
AudioEffectDelay         delay2;         //xy=388,350
AudioInputI2S            i2s2;           //xy=469,98
AudioAnalyzeRMS          rmsMic;           //xy=637,92
AudioEffectMultiply      multiply2;      //xy=659,397
AudioAnalyzeRMS          rmsSigInt;           //xy=660,302
AudioAnalyzeRMS          rms1;           //xy=811,397
AudioConnection          patchCord1(tonesweep1, delay2);
AudioConnection          patchCord2(tonesweep1, 0, i2s1, 0);
AudioConnection          patchCord3(tonesweep1, 0, i2s1, 1);
AudioConnection          patchCord4(delay2, 0, multiply2, 1);
AudioConnection          patchCord5(delay2, 0, rmsSigInt, 0);
AudioConnection          patchCord6(i2s2, 0, multiply2, 0);
AudioConnection          patchCord7(i2s2, 0, rmsMic, 0);
AudioConnection          patchCord8(multiply2, rms1);
AudioControlSGTL5000     sgtl5000_1;     //xy=139,397
// GUItool: end automatically generated code

//MedianFilter Median(10, 0);

const int myInput = AUDIO_INPUT_MIC;
float valMax = 0;
float delayCompens = 0;

float GainCompens = 0;
float GainCompensMedian = 0;

void ping(int idel)
{
  float fdel = idel * 1000.0f / AUDIO_SAMPLE_RATE_EXACT;
  AudioNoInterrupts();
  rms1.read();      // clear rms counter/accumulator
  delay2.delay(0, fdel); // delay in ms
  AudioInterrupts();
  tonesweep1.play(1.0, 500, 3000, 0.01);
  while (tonesweep1.isPlaying()) yield();
  while (!rms1.available()) yield();
  float val = rms1.read() * AUDIO_BLOCK_SAMPLES;
  if (val > valMax) {
    valMax = val;
    delayCompens = fdel;
  }
  Serial.printf("%d %f %f\n\r", idel, fdel, val);
}

void setup() {
  // put your setup code here, to run once:
  AudioMemory(12);
  while (!Serial);
  Serial.println("TestShift");
  AudioNoInterrupts();
  // setup audio board
  sgtl5000_1.enable();
  // setup headphone
  sgtl5000_1.volume(0.7);
  sgtl5000_1.inputSelect(myInput);
  // setup microphone
  sgtl5000_1.micGain(31); // from 0 to 63
  for (int ii = 1; ii < 8; ii++) delay2.disable(ii);
}

void loop() {
  static int idel = 1;
  if (idel < 0) return;
  ping(idel);
  idel++;
  if (idel > 128) {
    Serial.print("The Delay compensation is : ");
    Serial.println(delayCompens);
    Serial.print("The Gain compensation is : ");
    Serial.println(GainCompens);
    idel = -1; // mark to stop
  }
}
 
Last edited:
Cannot test your HW, but

You may need to increase AudioMemory to say 32

Also, suggest to replace in your ino file

Code:
while (tonesweep1.isPlaying()) yield();
while (!rms1.available()) yield();
by
Code:
delay(100);

and see if it still freezing
 
Yeah, that was the key, 50 is a correct value to avoid freezing. But now, there is 1 or 2 glitch which appear, even in increasing or decreasing the value before it freezes...

Also, introducing the delay in the loop messes it up. Once it's done, the delay send back an incoherent value, even in the simulation code.

Last problem : in the HW code, the delay are constantly changing every time I launch the program (even when I use the while()). I guess it can change if there is variation in the sound atmosphere around but even when it's very quiet it changes every time...

#despair

EDIT 1 : When I make the HP closer from the microphone, the delay compensation seems to increase which makes no sense to me.
 
Last edited:
Status
Not open for further replies.
Back
Top