Teensy 3.5 Basic Gain using inbuilt ADC and DAC and MAX9814 mic

Status
Not open for further replies.

4bdu1

Member
Hello all, I am working on project to capture sounds using the mic and perform some processing. I want to implement a digital gain to control the amplification of the sound that it is output through the headphone connected to a 3.5mm jack. I tried with the below code. When I comment out the analogRead line for the potentiometer I can hear the sound from the mic through the inbuilt dac on the teensy via the headphones but when I uncomment I dont hear anything. Any help please. Thank you.

Code:
//These are the includes from the Teensy Audio Library
#include <Audio.h>      //Teensy Audio Library
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

#include <OpenAudio_ArduinoLibrary.h> //for AudioConvert_I16toF32, AudioConvert_F32toI16, and AudioEffectGain_F32

//create audio library objects for handling the audio
AudioInputAnalog           i2s_in;       
AudioConvert_I16toF32   int2Float1, int2Float2;    //Converts Int16 to Float.  See class in AudioStream_F32.h
AudioEffectGain_F32     gain1, gain2;  //Applies digital gain to audio data.  Expected Float data.  
AudioConvert_F32toI16   float2Int1, float2Int2;    //Converts Float to Int16.  See class in AudioStream_F32.h
AudioOutputAnalog          i2s_out;       //Digital audio *to* the Teensy Audio Board DAC.  Expects Int16.  Stereo

//Make all of the audio connections
AudioConnection         patchCord1(i2s_in, 0, int2Float1, 0);    //connect the Left input to the Left Int->Float converter
AudioConnection         patchCord2(i2s_in, 1, int2Float2, 0);    //connect the Right input to the Right Int->Float converter
AudioConnection_F32     patchCord10(int2Float1, 0, gain1, 0);    //Left.  makes Float connections between objects
AudioConnection_F32     patchCord11(int2Float2, 0, gain2, 0);    //Right.  makes Float connections between objects
AudioConnection_F32     patchCord12(gain1, 0, float2Int1, 0);    //Left.  makes Float connections between objects
AudioConnection_F32     patchCord13(gain2, 0, float2Int2, 0);    //Right.  makes Float connections between objects
AudioConnection         patchCord20(float2Int1, 0, i2s_out, 0);  //connect the Left float processor to the Left output
AudioConnection         patchCord21(float2Int2, 0, i2s_out, 1);  //connect the Right float processor to the Right output


#define POT_PIN A3  //potentiometer is tied to this pin


void setup() {
  Serial.begin(115200);   //open the USB serial link to enable debugging messages
  delay(500);             //give the computer's USB serial system a moment to catch up.
  Serial.println("OpenAudio_ArduinoLibrary BasicGain_Float...");
  // Audio connections require memory
  AudioMemory(10);      //allocate Int16 audio data blocks
  AudioMemory_F32(10);  //allocate Float32 audio data blocks
  // setup any other other features
  pinMode(POT_PIN, INPUT); //set the potentiometer's input pin as an INPUT

} //end setup()


// define the loop() function, the function that is repeated over and over for the life of the device
unsigned long updatePeriod_millis = 100; //how many milliseconds between updating gain reading?
unsigned long lastUpdate_millis = 0;
unsigned long curTime_millis = 0;
int prev_gain_dB = 0;
void loop() {
  //choose to sleep ("wait for interrupt") instead of spinning our wheels doing nothing but consuming power
  asm(" WFI");  //ARM-specific.  Will wake on next interrupt.  The audio library issues tons of interrupts, so we wake up often.
  
  //has enough time passed to try updating the GUI?
  curTime_millis = millis(); //what time is it right now
  if (curTime_millis < lastUpdate_millis) lastUpdate_millis = 0; //handle wrap-around of the clock
  if ((curTime_millis - lastUpdate_millis) > updatePeriod_millis) { //is it time to update the user interface?
    
    //read potentiometer
    float val = float(analogRead(POT_PIN)) / 1024.0; //0.0 to 1.0
    val = 0.1*(float)((int)(10.0*val + 0.5));  //quantize so that it doesn't chatter
        
    //compute desired digital gain
    const float min_gain_dB = -20.0, max_gain_dB = 40.0; //set desired gain range
    float gain_dB = min_gain_dB + (max_gain_dB - min_gain_dB)*val; //computed desired gain value in dB

    //if the gain is different than before, set the new gain value
    if (abs(gain_dB - prev_gain_dB) > 1.0) { //is it different than before
      gain1.setGain_dB(gain_dB);  //set the gain of the Left-channel gain processor
      gain2.setGain_dB(gain_dB);  //set the gain of the Right-channel gain processor
      Serial.print("Digital Gain dB = "); Serial.println(gain_dB); //print text to Serial port for debugging
      prev_gain_dB = gain_dB;  //we will use this value the next time around
    }
 
    lastUpdate_millis = curTime_millis; //we will use this value the next time around.
  } // end if

} //end loop();
 
Last edited:
maybe not relevant but for stereo DAC (select DACS in gui) and/or change to AudioOutputAnalogStereo i2s_out;

or do you want AudioOutputI2S for the audio adaptor headphone jack?
 
maybe not relevant but for stereo DAC (select DACS in gui) and/or change to AudioOutputAnalogStereo i2s_out;

or do you want AudioOutputI2S for the audio adaptor headphone jack?

Sorry to mention, I'm not using the audio adaptor. I connected a 3.5mm jack to the inbuilt dac and connected headphones. Do I still need to change to AudioOutputAnalogStereo ?

I changed to AudioOutputAnalogStereo but still the same issue

I can listen to the signal from the mic when the analogRead line is commented out but not when it is uncommented.
 
There is something highly unlogical: On one side, you write in the title that you are using the built-in ADCs and DACs, but your code you published uses I2S inputs and outputs as if you were using the audio shield plugged onto the Teensy and thus the ADC and DAC from the SGTL5000 instead of the built-in ones.

In case you are using the audio shield and thus the SGTL5000 ADCs and DACs, there is no reason why analogRead should not work.

But if you use the Teensy's ADC(s) for audio input (in contradiction to the code which you published), it is normal that trying to use the same ADC for analogRead() will break the audio flow.
 
There is something highly unlogical: On one side, you write in the title that you are using the built-in ADCs and DACs, but your code you published uses I2S inputs and outputs as if you were using the audio shield plugged onto the Teensy and thus the ADC and DAC from the SGTL5000 instead of the built-in ones.

In case you are using the audio shield and thus the SGTL5000 ADCs and DACs, there is no reason why analogRead should not work.

But if you use the Teensy's ADC(s) for audio input (in contradiction to the code which you published), it is normal that trying to use the same ADC for analogRead() will break the audio flow.


Sorry for the variable namings, if you check the type you would realize they are the inbuilt adc and dac I am referring to. I modified some parts of a code from the openaudio arduino library by chip.

Is there a way to use the Teensy's ADC(s) for audio input and use analog read like when using the audio shield?
 
In case you use both internal ADC(s) for stereo audio, there is no way to do analogRead() for a potentiometer and you would for example have to use a rotary encoder instead. This is documented in the right sidebar of the audio design tool: "analogRead() must not be used, because AudioInputAnalogStereo is regularly accessing the ADC hardware. If both access the hardware at the same moment, analogRead() can end up waiting forever, which effectively crashes your program."

In case you use only one internal ADC for mono audio, PJRC issued the same warning as above about not using analogRead(), so it is safer to not use it. But basically, by carefully selecting the audio input pin and the potentiometer pin, so that these are internally multiplexed to different ADCs as documented in the MUX chapter of the reference manual, you could have luck and get it perhaps working. But better is again using a rotary encoder instead of a potentiometer.

To handle one or more rotary encoder knobs, there is a small and resource efficient code to do so: https://forum.pjrc.com/threads/44592-Encoders-(once-more)?p=145056&viewfull=1#post145056
 
In case you use both internal ADC(s) for stereo audio, there is no way to do analogRead() for a potentiometer and you would for example have to use a rotary encoder instead. This is documented in the right sidebar of the audio design tool: "analogRead() must not be used, because AudioInputAnalogStereo is regularly accessing the ADC hardware. If both access the hardware at the same moment, analogRead() can end up waiting forever, which effectively crashes your program."

In case you use only one internal ADC for mono audio, PJRC issued the same warning as above about not using analogRead(), so it is safer to not use it. But basically, by carefully selecting the audio input pin and the potentiometer pin, so that these are internally multiplexed to different ADCs as documented in the MUX chapter of the reference manual, you could have luck and get it perhaps working. But better is again using a rotary encoder instead of a potentiometer.

To handle one or more rotary encoder knobs, there is a small and resource efficient code to do so: https://forum.pjrc.com/threads/44592-Encoders-(once-more)?p=145056&viewfull=1#post145056


Ok thank you so much. Would definitely try that and also probably try using buttons for an easier alternative maybe.
 
Sorry to mention, I'm not using the audio adaptor. I connected a 3.5mm jack to the inbuilt dac and connected headphones. Do I still need to change to AudioOutputAnalogStereo ?

I changed to AudioOutputAnalogStereo but still the same issue

I can listen to the signal from the mic when the analogRead line is commented out but not when it is uncommented.

a question

How is you're headphone connected to the teensy? Is there a seperate amp or is it a direct connection and working?
 
a question

How is you're headphone connected to the teensy? Is there a seperate amp or is it a direct connection and working?

I connected a 3.5mm jack to the inbuilt dac and just connected the headphones directly and yes it's working
 
From 1st post on this thread.......
"When I comment out the analogRead line for the potentiometer I can hear the sound from the mic through the inbuilt dac on the teensy via the headphones but when I uncomment I dont hear anything. Any help please."

You dont need either Potentiometers or Encoders to control amplitude, or gain, or Volume......
You just need numbers........

Touch a touch pin and let it run a counter up and down to give touch volume control.....
and ADC pin will get analog audio in to teensy
and DAC pin will get audio out of teensy, or I2S will get digital audio in and digital audio out of teensy.......nothing else needed..!...!..
 
I hadn't tried the ADC pin with audio before so I thought I would give it a go......very basic setup.
I used the PassThroAudio sketch in the examples and commented out the PWM output.
So Just the audio input on pin A2 and audio output on DAC and powered by USB port.
Audio in was Lineout from a tablet playing a 440 Hz sinewave tone and output was to LineIn on my PC with Audacity Recording.
All worked, no crackling or messing about, but for the full sinewave input I was getting only the positive half cycles out. Still a good clean waveform no interference.
Just wondering does anyone else get this, or is it my too basic a setup, I didn't use the "filter" type network shown in the GUI pages, but I don't think that is the problem..??.
I need to investigate more....does ADC work for Pos and Neg parts of a waveform..??

Regards this thread...where you want to input audio, process it, and output audio, watch it and listen to it.....would this simple sketch not be a good place to start and move from there.....the sketch is in the audio library examples under teensy
 
I have tried out further testing......ADC audio direct on ADC pin......

The analogue audio sinewave signal Lineout from tablet to pin A2 and output DAC pin to Linein on PC works OK when connected as in the diagram shown in the GUI.
The RC network is required........
It adds 0.6 volts bias to signal.......derived by the 10k and 2.2k from the 3.3 volt pin. This lifts the signal so as to be all positive and works with a good sound, no interference that I can see or hear when playing it in Audacity
 
I hadn't tried the ADC pin with audio before so I thought I would give it a go......very basic setup.
I used the PassThroAudio sketch in the examples and commented out the PWM output.
So Just the audio input on pin A2 and audio output on DAC and powered by USB port.
Audio in was Lineout from a tablet playing a 440 Hz sinewave tone and output was to LineIn on my PC with Audacity Recording.
All worked, no crackling or messing about, but for the full sinewave input I was getting only the positive half cycles out. Still a good clean waveform no interference.
Just wondering does anyone else get this, or is it my too basic a setup, I didn't use the "filter" type network shown in the GUI pages, but I don't think that is the problem..??.
I need to investigate more....does ADC work for Pos and Neg parts of a waveform..??

Regards this thread...where you want to input audio, process it, and output audio, watch it and listen to it.....would this simple sketch not be a good place to start and move from there.....the sketch is in the audio library examples under teensy

I have been able to implement that already and based on suggestions given here I have also been able to control the volume using buttons. It works well except for some background noise which I'm guessing is from the usb port of my laptop since I'm using that to power for the mean time.
 
I have tried out further testing......ADC audio direct on ADC pin......

The analogue audio sinewave signal Lineout from tablet to pin A2 and output DAC pin to Linein on PC works OK when connected as in the diagram shown in the GUI.
The RC network is required........
It adds 0.6 volts bias to signal.......derived by the 10k and 2.2k from the 3.3 volt pin. This lifts the signal so as to be all positive and works with a good sound, no interference that I can see or hear when playing it in Audacity

I am using the MAX9814 mic from tindie. It works fine but there's some background sound/noise which I would like to suppress. I tried with little success so I was thinking it's probably noise from the power supply which is the usb port from my laptop. I am trying to get heart signals from the mic that's connected at the tube of a stethoscope chest piece.. so any little background noise is easily noticeable since the heart sounds I'm getting are not that clear enough.

I went through chip's hearing aid project and tried using a dynamic range compressor to lower the noise frequencies a bit. I got a better response than the former but not as best as I would want it. Increasing the gain or volume still brings the background noise up a bit. I tried using an analog filter with the mic to filter the noise but I was getting unclear sounds. I don't know if they were connection problems or not because I coulde here the noise was reduced but the sound I was listening to wasn't clear and had some stuttering effect sort of.
 
If you are getting stuttering.....more than likely you have bad connections...??

There are not many connections needed so should be easy to check...???

To isolate the source of background noise.....Have you a scope.......where do you see the noise.....

If you don't have a scope....use Audacity......of download a software scope that uses your sound card as inputs...

Power the assembly from batteries will eliminate noise from USB....

Did you try the MIC on its own into PC and watch and listen using Audacity.....

Did you try teensy on its own with a clean audio in signal......

You need to be able to state the step you are at....and the result of each step.....
 
One other suggestion.....

Is the signal being clipped.....this would give distortion.....you should see this in Audacity....and may hear it as background noise...??.

Reduce the gain or use a potentiometer as volume control on the input between the MIC and teensy input pin
 
Another suggestion.....

I assume you are now not using the code you posted in your initial post for this project.......

Because it probably would most definitely give all sorts of background noises...?????

This is the problem of trying to sort problems for users when they don't post the code they are using.....or at least snippets of it to illustrate the problem
 
Another suggestion.....

I assume you are now not using the code you posted in your initial post for this project.......

Because it probably would most definitely give all sorts of background noises...?????

This is the problem of trying to sort problems for users when they don't post the code they are using.....or at least snippets of it to illustrate the problem

This is my current code

Code:
#include <Bounce.h>
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include "filters.h"

#include <OpenAudio_ArduinoLibrary.h> //for AudioConvert_I16toF32, AudioConvert_F32toI16, and AudioEffectGain_F32

//Create audio library objects for handling the audio
AudioConvert_I16toF32   int2Float1;    //Converts Int16 to Float.  See class in AudioStream_F32.h
AudioEffectGain_F32     gain1;  //Applies digital gain to audio data.  Expected Float data.  
AudioConvert_F32toI16   float2Int1, float2Int2;    //Converts Float to Int16.  See class in AudioStream_F32.h
AudioInputAnalog        adc1;  
AudioOutputAnalog       dac1;
AudioFilterFIR          firFilter;

AudioEffectCompressor_F32 comp1;

AudioConnection         patchCord1(adc1,int2Float1);    //connect the input to the Int->Float converter 
AudioConnection_F32     patchCord10(int2Float1, 0, comp1, 0);    //makes Float connections between objects
AudioConnection_F32     patchCord12(comp1, 0, float2Int1, 0);    //makes Float connections between objects
AudioConnection         patchCord13(float2Int1,firFilter); //float connection to filter
AudioConnection         patchCord14(firFilter,dac1); //route output of filter to DAC
//AudioConnection         patchCord20(float2Int1,dac1);  //connect the float processor to the output

// Bounce objects to easily and reliably read the buttons
Bounce buttonVolumeUp = Bounce(4, 8);
Bounce buttonVolumeDown =   Bounce(5, 8);  // 8 = 8 ms debounce time


Bounce firstMode = Bounce(0, 8);
Bounce secondMode = Bounce(1, 8);
Bounce thirdMode = Bounce(2, 8);


void setupMyCompressors(boolean use_HP_filter, float knee_dBFS, float comp_ratio, float attack_sec, float release_sec) {
  comp1.enableHPFilter(use_HP_filter);   
  comp1.setThresh_dBFS(knee_dBFS);      
  comp1.setCompressionRatio(comp_ratio); 

  float fs_Hz = AUDIO_SAMPLE_RATE;
  comp1.setAttack_sec(attack_sec, fs_Hz);       
  comp1.setRelease_sec(release_sec, fs_Hz);   
}


struct fir_filter {
  short *coeffs;
  short num_coeffs;  //num_coeffs must be an even number, 4 or higher
};

//index of current filter. Start with the bell mode
int fir_index = 0;

struct fir_filter fir_list[] = {
  {f_mode_band_pass, 38},
  {s_mode_band_pass, 38},
  {t_mode_band_pass, 38}
};


void setup() {
  Serial.begin(115200);
  delay(500); 
   // Configure the pushbutton pins
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  
  dac1.analogReference(INTERNAL);
  Serial.println("OpenAudio_ArduinoLibrary BasicGain_Float... Modified"); 

  // Audio connections require memory
  AudioMemory(60);      //allocate Int16 audio data blocks
  AudioMemory_F32(60);  //allocate Float32 audio data blocks


  boolean use_HP_filter = true; //enable the software HP filter to get rid of DC?
  float knee_dBFS, comp_ratio, attack_sec, release_sec;

  if (true) {
      Serial.println("Configuring Compressor for fast response for use as a limitter.");
      knee_dBFS = -15.0f; comp_ratio = 5.0f;  attack_sec = 0.005f;  release_sec = 0.200f;
  } else {
      Serial.println("Configuring Compressor for slow response more like an automatic volume control.");
      knee_dBFS = -50.0; comp_ratio = 5.0;  attack_sec = 1.0;  release_sec = 2.0;
  }

  setupMyCompressors(use_HP_filter, knee_dBFS, comp_ratio, attack_sec, release_sec);


  //initialize the filter
  firFilter.begin(fir_list[0].coeffs, fir_list[0].num_coeffs);
  Serial.println("filter initialized... Setup done");
  
}

int prev_gain_dB = 0;
float val = 0.50; //set initial volume
unsigned long last_time = millis();

void loop() {
  asm(" WFI");

  buttonVolumeUp.update();
  buttonVolumeDown.update();
  
  firstMode.update();
  secondMode.update();
  thirdMode.update();

    // Respond to button presses
  if (buttonVolumeUp.fallingEdge()) {
    Serial.println("VolumeUp Button Press");
    val += 0.25;
    if(val > 1) val = 1;
    Serial.println(val);
  }
  
  if (buttonVolumeDown.fallingEdge()) {
    Serial.println("VolumeDown Button Press");
    val -=  0.25;
    if(val < 0) val = 0;
    Serial.println(val);
  }

  if(firstMode.fallingEdge()){
    firFilter.begin(fir_list[0].coeffs, fir_list[0].num_coeffs);
  }

  if(secondMode.fallingEdge()){
    firFilter.begin(fir_list[1].coeffs, fir_list[1].num_coeffs);
  }

  if(thirdMode.fallingEdge()){
    firFilter.begin(fir_list[2].coeffs, fir_list[2].num_coeffs);
  }
  
  
    
    //read volume val
    val = 0.1*(float)((int)(10.0*val + 0.5));  //quantize so that it doesn't chatter
    Serial.println(val);
        
    //compute desired digital gain
    const float min_gain_dB = -20.0, max_gain_dB = 60.0; //set desired gain range
    float gain_dB = min_gain_dB + (max_gain_dB - min_gain_dB)*val; //computed desired gain value in dB
    Serial.print("gain_dB: ");
    Serial.println(gain_dB);

      //if the gain is different than before, set the new gain value
    if (abs(gain_dB - prev_gain_dB) > 1.0) { //is it different than before
      comp1.setPreGain_dB(gain_dB);  //set the gain of the Left-channel gain processor
      Serial.print("Digital Gain dB = ");// Serial.println(gain_dB); //print text to Serial port for debugging
      prev_gain_dB = gain_dB;
    } 
 delay(100);



 // print information about resource usage
  // Proc = 18 (18),  Mem = 4 (5)
  if (millis() - last_time >= 2500) {
    Serial.print("Proc = ");
    Serial.print(AudioProcessorUsage());
    Serial.print(" (");    
    Serial.print(AudioProcessorUsageMax());
    Serial.print("),  Mem = ");
    Serial.print(AudioMemoryUsage());
    Serial.print(" (");    
    Serial.print(AudioMemoryUsageMax());
    Serial.println(")");
    last_time = millis();
  }
}
 
You post the code but don't say what bit cause trouble..??

What is your problem...is it background noice..????

Is it noise picked up by the mic....OR...is it noise from power rails or earth loops etc.....??

If I was trying to analyse it I would first remove all the conversions and filters you have added, to bring it to a basic program and see what is happening with the basics.
Look at the inputs and outputs on Audacity waveforms and listen to it.

If noise is still there, investigate where it is coming from.....???
 
Status
Not open for further replies.
Back
Top