Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: Using the Audio Record Queue Object to get Raw ADC Data

  1. #1

    Using the Audio Record Queue Object to get Raw ADC Data

    Hey Guys! I知 currently trying to use the teensy audio library to visually represent audio. The way I知 doing this is mapping the two stereo audio inputs to the position coordinates on an LED array(Left amplitude controls the x position, right amplitude controls the y position). I知 still trying to understand how to pull raw ADC values using the audio library. I tried setting up two queues (one for each stereo channel), then I'm continuously grabbing values from the queue. So, according to the audio library documentation, I can get the pointer location of the raw integer values coming from the ADC using the readBuffer() function. I try to do that in the code below.

    I知 also not entirely sure if my hardware setup is working correctly. For this, I知 taking an audio input from my phone, running it through a preamp, then running it through the circuit that was detailed in the adcs section of the audio library. When I measure the DC value of either analog pin with a multimeter, it reads 0.604 Volts. My preamp gain is adjustable rn, but I can adjust the AC RMS voltage to be at around 400 mV, which is what I have it at now. I can make this bigger though. I致e got everything on a PCB rn, and it seems like I知 getting an audio signal there. I致e attached my schematics and code below.

    My questions are as follows:
    1. Am I correctly pulling data from these queue buffers?
    2. Is my understanding of the form of the ADC data correct? Should the values range from 0-65536 depending on the voltage, and the voltage
    range is between 0-1.2 Volts?
    3. Is there a way to adjust this voltage range? Or am I stuck with this?
    4. Are the values that I知 getting from the queue sensible values for both no audio and when audio is being played?
    5. Does my hardware setup look correct?


    Click image for larger version. 

Name:	log values - no audio.jpg 
Views:	12 
Size:	128.8 KB 
ID:	23418

    This is a log of the ADC values I'm getting when no audio is being played. This is very odd because I'm getting massive values when it should be sitting at about the halfway point. I would also think the value would stay relatively constant. Note that the two leftmost values are the ADC raw audio data from left and right channels

    Click image for larger version. 

Name:	log values - aud - weirdbehaviour.jpg 
Views:	9 
Size:	105.4 KB 
ID:	23419

    This is a snippet of the values when audio is being played through the audio jack

    Here's my code:

    Code:
    #define NUM_COL 16
    #define NUM_ROW 16
    #define NUM_LED NUM_COL*NUM_ROW
    #define LED_PIN 2
    #define BRIGHTNESS  64
    #define FPS 500
    #define FFT_GRAN 173
    #define LED_TYPE WS2812B
    #define COLOR_ORDER RGB
    
    #define MIN_BOUND 0 
    #define MAX_BOUND 65536
    
    #define MID_BAND 3 
    #define HIGH_BAND 55
    
    #include <FastLED.h>
    
    #include <Audio.h>
    #include <math.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioInputAnalogStereo   adcs1;          //xy=158,283
    AudioRecordQueue         L_Queue;           //xy=329,185
    AudioMixer4              mixer1;         //xy=330,274
    AudioRecordQueue         R_Queue;           //xy=330,381
    AudioAnalyzeFFT256       fft256;       //xy=484,267
    AudioConnection          patchCord1(adcs1, 0, mixer1, 0);
    AudioConnection          patchCord2(adcs1, 0, R_Queue, 0);
    AudioConnection          patchCord3(adcs1, 1, mixer1, 1);
    AudioConnection          patchCord4(adcs1, 1, L_Queue, 0);
    AudioConnection          patchCord5(mixer1, fft256);
    // GUItool: end automatically generated code
    
    
    int num_col = NUM_COL;
    int num_rows = NUM_ROW;
    
    float low_freq = 0;
    float mid_freq = 0;
    float high_freq = 0;
    float rms1_val = 0;
    float rms2_val = 0;
    
    int pos_x = 0;
    int pos_y = 0;
    
    uint16_t min_bound = 0;
    uint16_t max_bound = 65535;
    
    float mid_thresh = 0.14;
    float low_thresh = 0.14;
    int mid_band_bin = MID_BAND/FFT_GRAN;
    int high_band_bin = HIGH_BAND/FFT_GRAN;
    uint8_t red = 0;
    uint8_t green = 0;
    uint8_t blue = 0;
    
    CRGB leds[NUM_LED];
    
    
    
    void setup() {
      AudioMemory(50);
      Serial.begin(9600);
    
      FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LED).setCorrection( TypicalLEDStrip );
      FastLED.setBrightness(  BRIGHTNESS );
      delay(5000);
      L_Queue.begin();
      R_Queue.begin();
      delay(100);
      
    }
    
    void loop() {
    
      uint16_t (*buff_pointer_L) = (L_Queue.readBuffer());
      uint16_t (*buff_pointer_R) = (R_Queue.readBuffer());
    
     if((L_Queue.available() > 1) && (R_Queue.available() > 1)){
    
      for(int i = 0; i < 128; i++){
    
        //this conditional is to ensure that the ADC values are within the specified range
        if((*buff_pointer_L >= min_bound) && (*buff_pointer_L < max_bound)&&(*buff_pointer_R >= min_bound) && (*buff_pointer_R < max_bound)){
          pos_x = ampPosMap(*buff_pointer_L, NUM_COL);
          pos_y = ampPosMap(*buff_pointer_R, NUM_ROW);
    
          Serial.print("L_val - ");
          Serial.print(*buff_pointer_L);
          Serial.print("  ");
          Serial.print("R_val - ");
          Serial.print(*buff_pointer_R);
          Serial.print("  ");
          Serial.print("pos_x - ");
          Serial.print(pos_x);
          Serial.print("  ");
          Serial.print("pos_y - ");
          Serial.print(pos_y);
          Serial.println("  ");
        
        }
        buff_pointer_L++;
        buff_pointer_R++;
      }
      
      setLEDArray(255, 255, 255);    //setting to white for now
      
      FastLED.show();
      
      FastLED.delay(1000/FPS);//wait a period of time based on framerate
    
      //set same location to black
      setLEDArray(0, 0, 0);
      FastLED.show();
      L_Queue.freeBuffer();
      R_Queue.freeBuffer();
      
     }
    } 
    
    void setLEDArray(uint8_t red, uint8_t green, uint8_t blue){
      if(pos_y % 2 == 0){
        leds[pos_y*NUM_COL + pos_x] = CRGB(red, green, blue);
      }
      else{
        leds[(pos_y+1)*NUM_COL - pos_x] = CRGB(red, green, blue);
      }
    }
    
    int ampPosMap(uint16_t aud, float num){
      uint16_t gran = (max_bound - min_bound)/num;
      int pos_init = 0;
    
      pos_init = getPos(aud, min_bound, (min_bound+gran), gran, pos_init, num);
      return pos_init;
    }
    
    int getPos(float aud, float gran_low, float gran_high, float gran, int pos_init, int num){
        
      if((aud <= gran_high) && (aud > gran_low)){
        return pos_init;
      }
      else if(gran_low < max_bound){
        return (getPos(aud, (gran_low + gran), (gran_high + gran), gran, (pos_init + 1), num));
      }
      else{
        return (getPos(aud, (gran_low + gran), (gran_high + gran), gran, (pos_init - num + 1), 0));;
      }
    }
    and finally, my hardware schematic:

    Click image for larger version. 

Name:	preamp.jpg 
Views:	9 
Size:	48.9 KB 
ID:	23420

    this is my preamp circuit. R_in is the right input of an audio jack. I'm using an LM358 op-amp. This circuit came from an amplifier prototype board I bought. There's an identical circuit for L_in as well.

    Click image for larger version. 

Name:	analogcircuit.jpg 
Views:	7 
Size:	46.4 KB 
ID:	23421

    Here's the buffer circuit that was described in the documentation. This is fed directly into the teensy analog pins A2 and A3.

  2. #2
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,543
    The ADC values are signed 16-bit. This is why you see the large values such as 65369, it is actually a small negative number.

    This piece of your code is wrong:
    Code:
      uint16_t (*buff_pointer_L) = (L_Queue.readBuffer());
      uint16_t (*buff_pointer_R) = (R_Queue.readBuffer());
    
     if((L_Queue.available() > 1) && (R_Queue.available() > 1)){
    You should not call readBuffer unless there is a buffer available. Try this:
    Code:
     if((L_Queue.available() > 1) && (R_Queue.available() > 1)){
        uint16_t (*buff_pointer_L) = (L_Queue.readBuffer());
        uint16_t (*buff_pointer_R) = (R_Queue.readBuffer());
    Pete
    Last edited by el_supremo; 01-22-2021 at 10:51 PM. Reason: typo

  3. #3
    Good Catch! I'm still really confused about how to interpret the ADC values though. How can the value be signed if its describing only a positive range of voltages? Is there something I'm missing?

  4. #4
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,543
    I missed another problem
    Code:
     if((L_Queue.available() > 1) && (R_Queue.available() > 1)){
    Those should be >= otherwise you won't process anything until there's at least two buffers in each of the left and right channels. This would add a lag in the audio output.

    The AudioInputAnalogStereo update function performs DC offset removal which, in effect, converts the unsigned 16-bit integer from the ADCs into signed 16-bit integer. I presume that this is to make the ADC data compatible with the other functions in the Audio library which all assume that they receive int16_t data.

    Pete

  5. #5
    Senior Member
    Join Date
    Jul 2020
    Posts
    666
    Quote Originally Posted by Introspector View Post
    Good Catch! I'm still really confused about how to interpret the ADC values though. How can the value be signed if its describing only a positive range of voltages? Is there something I'm missing?
    Audio is an ac signal, typically I2S audio ADCs have a DC-removal filter built in so the result is strictly zero-centred.
    Oddly typical audio DACs are not DC-blocking, which is a problem (if the code crashes and your amp is DC-coupled then
    the speakers can be blown). Many class-D amps are not DC-blocking. Often a coupling capacitor is present in
    recommended circuits for this reason.

    Also a differential ADC will have a signed output even if its not especially designed for audio.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •