Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 3 FirstFirst 1 2 3 LastLast
Results 26 to 50 of 71

Thread: New Guy Looking For Teensy DSP programming tips

  1. #26
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    p.s. No need for speed. I'd just like to provide an input 16-bit stereo wav file containing several sine waves at different frequencies to the library fir or biquad input and obtain the corresponding output wav file for analysis. I want to remain 100% digital. In the case of a cascaded biquad, it would also be interesting to observe the digital signal (wav file) at intermediate stages.

  2. #27
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,364
    Quote Originally Posted by Bill Glass View Post
    I'd just like to provide an input 16-bit stereo wav file containing several sine waves at different frequencies to the library fir or biquad input and obtain the corresponding output wav file for analysis.
    You mentioned Matlab before - surely it can generate whatever you want?

  3. #28
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    Quote Originally Posted by MarkT View Post
    You mentioned Matlab before - surely it can generate whatever you want?
    No problem with generating wav files. I just wanted to be able to short circuit the audio board and directly(100% digitally) analyze various Teensy library FIR, IIR filter responses with no extra degradation due to the DAC, ADC. I think I found the solution by storing my input wav files on the SD card and using the AudioOutputUSB object to output the filter response to Audacity on my PC for recording. Let me know if you agree. Here's my code:
    Code:
     #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    AudioOutputUSB           audioOutput;               //Puts digital samples to Audacity input (MME, digital audio interface) for recording to wav file
    AudioPlaySdWav           playSdWav1;
    AudioOutputI2S           i2s2;           
    AudioConnection          patchCord1(playSdWav1, 0, i2s2, 0);
    AudioConnection          patchCord2(playSdWav1, 0, i2s2, 1);
    AudioConnection          patchCord3(playSdWav1, 0,audioOutput,0);
    AudioConnection          patchCord4(playSdWav1, 1,audioOutput,1);
    AudioControlSGTL5000     sgtl5000_1;     //xy=132.20001220703125,142
    
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    
    void setup(void)
    {
      Serial.begin(9600);
      AudioMemory(32);
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.5);
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
      delay(1000);
    }
    
    void loop(void)
    {
      if (playSdWav1.isPlaying() == false) 
      {
        Serial.println("Start playing");
        playSdWav1.play("Tower.wav");
        delay(10);
      }  
    //--------------------------- volume control ----------------------------
      static int volume = 0;
      // Volume control
      int n = analogRead(0);
      if (n != volume) 
      {
        volume = n;
        sgtl5000_1.volume((float)n / 1023.);
      }
    }

  4. #29
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    p.s. The filters will be patched in between playSdWav1 and audioOutput

  5. #30
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,364
    I was thinking save the output to the SDcard too... If that works

  6. #31
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    My SDcard reader is already not very reliable in only 1 direction. It's easier to get the USB digital Teensy ouput to Audacity fClick image for larger version. 

Name:	multisinout.jpg 
Views:	20 
Size:	116.0 KB 
ID:	26220or analysis or creating wav files. Attached, the spectrum obtained.

  7. #32
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    I sure would like to get a clear and precise answer concerning a question that I asked to Paul Stoffregen concerning 100% digitally evaluating library filter xfer functions. "Using the SDcard Player, configuring the Teensy USB audio output connected to my PC USB port then using Audacity to digitally record the samples after selecting digital audio interface(Teensy)". In my code below, what is in the path connecting the audio samples on the SD card to the Audacity digital input audio samples (except for the 128 sample queue in the Teensy)? Thanx.

    Code:
     #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #define DEBUG
    
    #define PASSTHRU
    #define USE_SD
    //#define USE_FIR
    
    #ifdef USE_SD
      AudioPlaySdWav          playSdWav1;
      AudioOutputUSB          audioOutput;    //Puts digital samples to Audacity input (MME, digital audio interface) for recording to wav file
    #else
      AudioInputI2S           i2s1;           
    #endif
    #ifdef USE_FIR
      AudioFilterFIR          fir1;           
      AudioFilterFIR          fir2;           
    #endif
    AudioRecordQueue          queue3;         
    AudioRecordQueue          queue1;         
    AudioPlayQueue            queue2;         
    AudioPlayQueue            queue4;         
    AudioOutputI2S            i2s2;           
    #ifdef USE_FIR
    #ifdef USE_SD
        AudioConnection       patchCord1(playSdWav1, 0, fir1, 0);
        AudioConnection       patchCord2(playSdWav1, 1, fir2, 0);
    #else
        AudioConnection       patchCord1(i2s1, 0, fir1, 0);
        AudioConnection       patchCord2(i2s1, 1, fir2, 0);
    #endif
      AudioConnection         patchCord3(fir1, queue1);
      AudioConnection         patchCord4(fir2, queue3);
    #else //#ifdef USE_FIR
    #ifdef USE_SD
        AudioConnection       patchCord1(playSdWav1, 0, queue1, 0);
        AudioConnection       patchCord2(playSdWav1, 1, queue3, 0);
    #else
        AudioConnection       patchCord1(i2s1, 0, queue1, 0);
        AudioConnection       patchCord2(i2s1, 1, queue3, 0);
    #endif
    #endif //#ifdef USE_FIR
    AudioConnection           patchCord5(queue2, 0, i2s2, 0);
    AudioConnection           patchCord6(queue4, 0, i2s2, 1);
    #ifdef USE_SD
      AudioConnection         patchCord7(queue2, 0, audioOutput,0);
      AudioConnection         patchCord8(queue4, 0, audioOutput,1);
    #endif
    AudioControlSGTL5000      sgtl5000_1;     
    
    #ifdef USE_SD
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    #else 
    //const int myInput = AUDIO_INPUT_MIC;
    const int myInput = AUDIO_INPUT_LINEIN;
    #endif
    
    #ifdef USE_FIR
    //---------------------------------------------FIR parameters ---------------------
    #define NUM_COEFFS 50
    //Arbitrary xfer function using fft for hpf fc=4000 fir filter design - (choice no. 13 of calcfilt.m)
    double coefs1[] =
    {
    #include "num.h"
    };
    double coefs2[] =
    {
    #include "num.h"  
    };
    short int COEFS1[NUM_COEFFS];
    short int COEFS2[NUM_COEFFS];
    //---------------------------------------------------------------------------------
    #endif //#ifdef USE_FIR
    int32_t agcGain1=0x08000000;//.5 in Q3.29 format
    int32_t agcGain2=0x08000000;//.5 in Q3.29 format
    int32_t ref=293504;//.07*AUDIO_BLOCK_SAMPLES in Q15 format(2293*128)
    
    
    void setup() {
      Serial.begin(9600);
      delay(300);
    
      // allocate memory for the audio library
      AudioMemory(32);
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.5);
    #ifdef USE_SD
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
      delay(1000);
    #else
      sgtl5000_1.inputSelect(myInput);
    #endif 
    
    #ifdef USE_FIR
      // Initialize the filter
      transformCoeffs( COEFS1, coefs1, NUM_COEFFS );
      transformCoeffs( COEFS2, coefs2, NUM_COEFFS );
      fir1.begin(COEFS1,NUM_COEFFS);
      fir2.begin(COEFS2,NUM_COEFFS);
    #endif
      // Start the record queue
      queue1.begin();
      queue3.begin();
    #ifdef DEBUG
      Serial.println("setup done");
    #endif
    }
    
    // audio volume
    int volume = 0;
    unsigned long last_time = millis();
    
    void loop()
    {
    #ifdef USE_SD
      if (playSdWav1.isPlaying() == false) 
      {
        Serial.println("Start playing");
        playSdWav1.play("Tower.wav");
    //    playSdWav1.play("multisin.wav");
    //    playSdWav1.play("noise.wav");
        delay(10);
      }
    #endif
    //--------------------------- Left channel -----------------------------
      if (queue1.available() >= 1) //Left Channel
      {
        agcCalc(queue1.readBuffer(),queue2.getBuffer(),&agcGain1);
        // Free the input audio buffer
        queue1.freeBuffer();
        // and play it back into the audio queue
        queue2.playBuffer();
      } //if (queue1.available() >= 1)
    //--------------------------- Right channel -----------------------------
      if (queue3.available() >= 1) 
      {
        agcCalc(queue3.readBuffer(),queue4.getBuffer(),&agcGain2);
        // Free the input audio buffer
        queue3.freeBuffer();
        // and play it back into the audio queue
        queue4.playBuffer();
      } //if (queue3.available() >= 1)
    //--------------------------- Volume control -----------------------------
      int n = analogRead(0);
      if (n != volume) 
      {
        volume = n;
        sgtl5000_1.volume((float)n / 1023.);
        //uncomment this line if your audio shield has the volume pot
        //audioShield.volume((float)n / 1023);
      }  
    //----------------------------- done --------------------------------------  
    #ifdef DEBUG  
      // 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(" (");    
        Serial.print(AudioProcessorUsageMax());
        Serial.print(" %),  Mem = ");
        Serial.print(AudioMemoryUsage());
        Serial.print(" (");    
        Serial.print(AudioMemoryUsageMax());
        Serial.println(")");
        Serial.print(" agcGain1: ");
        Serial.print((float)agcGain1/(float)0x10000000);
        Serial.print(" agcGain2: ");
        Serial.println((float)agcGain2/(float)0x10000000);
        last_time = millis();
      }
    #endif
    }
    
    void transformCoeffs( short int out[], double in[], int k )
    {
      for ( int i = 0 ; i < k ; i++ )
        out[i] = 32767 * in[i];
    }
    
    void agcCalc(int16_t *inbuf,int16_t *outbuf,int32_t *agcGain)
    {
      int16_t *bp1=inbuf,*bp2=outbuf;
    #ifdef PASSTHRU
        // Copy from input to output buffer
        for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) 
        {
          *bp2++ = *bp1++;
        }
    #else
        // Apply agcGain on input with saturation to output buffer
        int32_t sum=0,sum1=0,sum2=0,sum3=0,res,res1,res2,res3,err;
        for(int i = 0;i < AUDIO_BLOCK_SAMPLES>>2;i++) 
        { 
          //ref. dspinst.h in Teensy audio library
          res=signed_multiply_32x16b(*agcGain>>12,*bp1++);
          res1=signed_multiply_32x16b(*agcGain>>12,*bp1++);
          res2=signed_multiply_32x16b(*agcGain>>12,*bp1++);
          res3=signed_multiply_32x16b(*agcGain>>12,*bp1++);
          *bp2++=saturate16(res);
          *bp2++=saturate16(res1);
          *bp2++=saturate16(res2);
          *bp2++=saturate16(res3);
          sum+=abs(res);
          sum1+=abs(res1);
          sum2+=abs(res2);
          sum3+=abs(res3);
        }
        sum+=(sum1+sum2+sum3);
        // Calculate new agcGain for next input buffer
        err=ref-sum; 
        *agcGain+=err>>3; //update gain 
        *agcGain=min(*agcGain,0x7ff80000); //keep agcGain < 8.0
        *agcGain=max(*agcGain,0); //keep agcGain >= 0
    #endif
    }

  8. #33
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    143
    Quote Originally Posted by Bill Glass View Post
    I sure would like to get a clear and precise answer concerning a question that I asked to Paul Stoffregen concerning 100% digitally evaluating library filter xfer functions. "Using the SDcard Player, configuring the Teensy USB audio output connected to my PC USB port then using Audacity to digitally record the samples after selecting digital audio interface(Teensy)". In my code below, what is in the path connecting the audio samples on the SD card to the Audacity digital input audio samples (except for the 128 sample queue in the Teensy)? Thanx.
    Short answer - too much! Here's your patch in the Audio System Design Tool:
    Click image for larger version. 

Name:	2021-10-20 11_07_06-Audio System Design Tool for Teensy Audio Library.png 
Views:	20 
Size:	19.6 KB 
ID:	26225
    fir1+2 and queue1+2 have too many connections to their inputs: current rules are that the last connection made wins, so fir1 and queue1 are both fed by i2s1, and playSDwav1 is ignored. I think it's the same for the other channel... Your code feeds queue1 through to queue2, so I'd expect the net effect to be to be to send i2s1 through to i2s2 and audioOutput (USB) unchanged. The SD card audio samples get lost...

    Cheers

    Jonathan

  9. #34
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    NO. The GUI tool doesn't take into consideration the #ifdef's according to what I programmed (relook at my code). See correct attached image here: Click image for larger version. 

Name:	config.jpg 
Views:	17 
Size:	44.0 KB 
ID:	26228

  10. #35
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    Slight error (I'm a rookie with this GUI tool and I didn't knpw you could unwrap the imported code without xy coordinates). I just removed the #ifdef code not compiled and imported & unwrapped it in the GUI tool to give: Click image for larger version. 

Name:	configa.jpg 
Views:	18 
Size:	15.5 KB 
ID:	26230

  11. #36
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    But my original question remains: "What is in the path connecting the audio samples on the SD card to the Audacity digital input audio samples (except for the 128 sample queue in the Teensy)?". Sample rate converters? Digital filters? Others?

    Thanx

  12. #37
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    143
    Ah, OK. As far as I know the only item in the path which isn't a simple word-for-word transfer may be in the USB audio driver (cores/teensy4/usb_audio.cpp), which has to cope with the sample rate not being exactly 44100Hz. But I don't know about that in any detail, just that the USB interface has never worked very well for me...

    You might want to look at @Frank B's WavePlayerEx which can play and record at the same time on an SD card - a bit of a tedious process, but may work if you're finding artefacts in the USB stream.

  13. #38
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    Quote Originally Posted by h4yn0nnym0u5e View Post
    Ah, OK. As far as I know the only item in the path which isn't a simple word-for-word transfer may be in the USB audio driver (cores/teensy4/usb_audio.cpp), which has to cope with the sample rate not being exactly 44100Hz. But I don't know about that in any detail, just that the USB interface has never worked very well for me...

    You might want to look at @Frank B's WavePlayerEx which can play and record at the same time on an SD card - a bit of a tedious process, but may work if you're finding artefacts in the USB stream.
    I did an experiment with Audacity where I programmed fs=48000 and I obtained a wav file from Audacity at 48000 even though I configured Audacity for "digital audio interface(Teensy)". Maybe there's several sample rate conversions in series? I'll try and look at (cores/teensy4/usb_audio.cpp). Thanx

  14. #39
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,409
    Quote Originally Posted by Bill Glass View Post
    I did an experiment with Audacity where I programmed fs=48000 and I obtained a wav file from Audacity at 48000 even though I configured Audacity for "digital audio interface(Teensy)". Maybe there's several sample rate conversions in series? I'll try and look at (cores/teensy4/usb_audio.cpp). Thanx
    Your PC converts the samplerate to 44100Hz before sending the data to the Teensy.
    The Teensy tells the PC that it can do 44100Hz only.

  15. #40
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    Quote Originally Posted by Frank B View Post
    Your PC converts the samplerate to 44100Hz before sending the data to the Teensy.
    The Teensy tells the PC that it can do 44100Hz only.
    Samples are coming from the Teensy to the PC at 44100 +- epsilon via the USB driver. I configured the Audicity digital recording rate to 48000. Who's doing the conversion to 48000? Audacity software or the PC? Is it a polyphase filter with UP/Down ratio of 160/147 ? Who takes care of epsilon? The PC (on the sound card?) or the USB audio driver? Is that an asrc? How many sample rate converters are in series between the SD card to the Audacity sample buffers? Sorry for all the questions. I'm too curious I guess. Thanx

  16. #41
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,409
    Quote Originally Posted by Bill Glass View Post
    Samples are coming from the Teensy to the PC at 44100 +- epsilon via the USB driver. I configured the Audicity digital recording rate to 48000. Who's doing the conversion to 48000? Audacity software or the PC? Is it a polyphase filter with UP/Down ratio of 160/147 ? Who takes care of epsilon? The PC (on the sound card?) or the USB audio driver? Is that an asrc? How many sample rate converters are in series between the SD card to the Audacity sample buffers? Sorry for all the questions. I'm too curious I guess. Thanx
    I can't answer this
    But I know - at least on windows, you can change the default samplerate to 44100. I *think* no conversion will happen then.

  17. #42
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    Quote Originally Posted by Frank B View Post
    I can't answer this
    But I know - at least on windows, you can change the default samplerate to 44100. I *think* no conversion will happen then.
    But there's gotta be an asynchronous sample rate conversion somewhere. Otherwise, if the PC is running at 44101(crystal precision) and the Teensy USB audio driver is at 44999, there's gonna be 2 lost samples and glitches every second in the audio signal on the headphones and on the Audacity or other audio evaluation software. I tried to understand the (cores/teensy4/usb_audio.cpp) but didn't understand a whole lot.

  18. #43
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,409
    Hi Bill,
    this does not happen, there is no conversion. Best is to look at the code, it uses a buffer.
    However, from time to time things like this happen:
    Code:
                    // buffer overrun, PC sending too fast
                    AudioInputUSB::incoming_count = count + avail;
                    if (len > 0) {
                        usb_audio_overrun_count++;
                        printf("!");
                        //serial_phex(len);
                    }
                    return;
    it just skips data.
    In most cases this is not audible. Or perhaps only when you know that it happens, use headphones or whatever..
    First, when this was new, there were audible clicks.
    Perhaps the PC adjusts the speed, too. There is a "feedback" - this would mean the PC has to adjust the rate (at least for TX to Teensy).
    Edit: Yes, there is stuff like this: usb_audio_sync_feedback = feedback_accumulator (line 86). Beginning to remember some details..

    Edit: So, yes, I think the driver on the PC does the most work. For Linux, we could take a look at the sourcecode there..

    The Teensy code is here:
    https://github.com/PaulStoffregen/co.../usb_audio.cpp

    The planned 1170 CPU has hardware to do sample rate conversion.
    Last edited by Frank B; 10-21-2021 at 11:11 AM.

  19. #44
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,409
    The Audio lib has resampling code (Resampler.h/.cpp) - it's used for S/PDIF.

    Does anyone know if it can be used i.e. for 11kHz - 44kHz or 48kHz->44kHz?
    What is Alexander's username here?

  20. #45
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    Quote Originally Posted by Frank B View Post
    Hi Bill,
    it just skips data.
    In most cases this is not audible. Or perhaps only when you know that it happens, use headphones or whatever..
    Hi Frank;

    Interesting and surprising for doing that with high quality audio. But, effectively, I can't hear the xtra or missing samples on my PC. I remember when I was working, we developed a phone asynchronous sample rate converter to smoothly add or remove a sample to a block of samples. But this was for voice band range (low fs). I never did the experiment for fs=44100 where the glitch must be less audible. There are now HW asynchronous SRC's but that means xtra HW. It can also be done in SW using a FIR with adaptable group delay coefficient values according to the current fsin to fsout phase relation but ya need xtra buffers (more latency) and more cycles.

  21. #46
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,409
    Quote Originally Posted by Bill Glass View Post
    Hi Frank;

    Interesting and surprising for doing that with high quality audio. But, effectively, I can't hear the xtra or missing samples on my PC. I remember when I was working, we developed a phone asynchronous sample rate converter to smoothly add or remove a sample to a block of samples. But this was for voice band range (low fs). I never did the experiment for fs=44100 where the glitch must be less audible. There are now HW asynchronous SRC's but that means xtra HW. It can also be done in SW using a FIR with adaptable group delay coefficient values according to the current fsin to fsout phase relation but ya need xtra buffers (more latency) and more cycles.
    Yes, when I wrote the reply, I did not remember the "feedback" thing. I edited the post later..

  22. #47
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    What I found today. Teensy 4.0 configured as a passthru: input wav file containing 10000 Hz tone named sig.wav & played from Teensy SD card, sent thru a FIR with center tap at 1.0 and all others 0.0, copied from input to output queues, and sent to USB output interface. USB connected to my PC and Teensy output signal recorded with Audacity and saved in file out.wav. Enclosed find spectral analysis, of sig.wav, out.wav, and Teensy sketch. Any comments?

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    //#define DEBUG
    #define PASSTHRU
    #define USE_SD
    
    #ifdef USE_SD
    AudioPlaySdWav            playSdWav1;
    AudioOutputUSB            audioOutput;    //Puts digital samples to Audacity input (MME, digital audio interface) for recording to wav file
    #else
    AudioInputI2S             i2s1;           
    #endif
    AudioFilterFIR            fir1;           
    AudioFilterFIR            fir2;           
    AudioRecordQueue          queue3;         
    AudioRecordQueue          queue1;         
    AudioPlayQueue            queue2;         
    AudioPlayQueue            queue4;         
    AudioOutputI2S            i2s2;           
    #ifdef USE_SD
    AudioConnection           patchCord1(playSdWav1, 0, fir1, 0);
    AudioConnection           patchCord2(playSdWav1, 1, fir2, 0);
    #else
    AudioConnection           patchCord1(i2s1, 0, fir1, 0);
    AudioConnection           patchCord2(i2s1, 1, fir2, 0);
    #endif
    AudioConnection           patchCord3(fir1, queue1);
    AudioConnection           patchCord4(fir2, queue3);
    AudioConnection           patchCord5(queue2, 0, i2s2, 0);
    AudioConnection           patchCord6(queue4, 0, i2s2, 1);
    #ifdef USE_SD
    AudioConnection           patchCord7(queue2, 0, audioOutput,0);
    AudioConnection           patchCord8(queue4, 0, audioOutput,1);
    #endif
    AudioControlSGTL5000      sgtl5000_1;     
    
    #ifdef USE_SD
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    #else 
    //const int myInput = AUDIO_INPUT_MIC;
    const int myInput = AUDIO_INPUT_LINEIN;
    #endif
    //---------------------------------------------FIR parameters ---------------------
    //#define FIRFILTER HIPASSFILTER
    #define FIRFILTER FLATFILTER
    #define NUM_COEFFS 50
    double HIPASSFILTER[]=
    {
    #include "numHipass.h" //Arbitrary xfer function using fft for hpf fc=4000 fir filter design - (choice no. 13 of calcfilt.m)
    };
    double FLATFILTER[]=
    {
    #include "numflat.h" //Arbitrary xfer function using fft for flat fir filter design - (choice no. 14 of calcfilt.m)
    };
    double *coefs1 = FIRFILTER;
    double *coefs2 = FIRFILTER;
    short int COEFS1[NUM_COEFFS];
    short int COEFS2[NUM_COEFFS];
    //---------------------------------------------------------------------------------
    int32_t agcGain1=0x08000000;//.5 in Q3.29 format
    int32_t agcGain2=0x08000000;//.5 in Q3.29 format
    int32_t ref=293504;//.07*AUDIO_BLOCK_SAMPLES in Q15 format(2293*128)
    #ifdef DEBUG
    uint32_t cyc1=0,cyc2=0;
    #endif
    
    void setup() {
      Serial.begin(9600);
      delay(300);
    
      // allocate memory for the audio library
      AudioMemory(32);
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.5);
    #ifdef USE_SD
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
      delay(1000);
    #else
      sgtl5000_1.inputSelect(myInput);
    #endif 
      // Initialize the filter
      transformCoeffs( COEFS1, coefs1, NUM_COEFFS );
      transformCoeffs( COEFS2, coefs2, NUM_COEFFS );
      fir1.begin(COEFS1,NUM_COEFFS);
      fir2.begin(COEFS2,NUM_COEFFS);
      // Start the record queue
      queue1.begin();
      queue3.begin();
    #ifdef DEBUG
      Serial.println("setup done");
    #endif
    }
    
    // audio volume
    int volume = 0;
    unsigned long last_time = millis();
    
    void loop()
    {
    #ifdef USE_SD
      if (playSdWav1.isPlaying() == false) 
      {
        Serial.println("Start playing");
    //    playSdWav1.play("Tower.wav");
    //    playSdWav1.play("multisin.wav");
        playSdWav1.play("sig.wav");
    //    playSdWav1.play("noise.wav");
        delay(10);
      }
    #endif
    //--------------------------- Left channel -----------------------------
      if (queue1.available() >= 1) //Left Channel
      {
    #ifdef DEBUG
        cyc1 = ARM_DWT_CYCCNT;
        agcCalc(queue1.readBuffer(),queue2.getBuffer(),&agcGain1);
        cyc1 = ARM_DWT_CYCCNT - cyc1;
    #else
        agcCalc(queue1.readBuffer(),queue2.getBuffer(),&agcGain1);
    #endif
        // Free the input audio buffer
        queue1.freeBuffer();
        // and play it back into the audio queue
        queue2.playBuffer();
      } //if (queue1.available() >= 1)
    //--------------------------- Right channel -----------------------------
      if (queue3.available() >= 1) 
      {
    #ifdef DEBUG
        cyc2 = ARM_DWT_CYCCNT;
        agcCalc(queue3.readBuffer(),queue4.getBuffer(),&agcGain2);
        cyc2 = ARM_DWT_CYCCNT - cyc2;
    #else
        agcCalc(queue3.readBuffer(),queue4.getBuffer(),&agcGain2);
    #endif
        // Free the input audio buffer
        queue3.freeBuffer();
        // and play it back into the audio queue
        queue4.playBuffer();
      } //if (queue3.available() >= 1)
    //--------------------------- Volume control -----------------------------
      int n = analogRead(0);
      if (n != volume) 
      {
        volume = n;
        sgtl5000_1.volume((float)n / 1023.);
        //uncomment this line if your audio shield has the volume pot
        //audioShield.volume((float)n / 1023);
      }  
    //----------------------------- done --------------------------------------  
    #ifdef DEBUG  
      // 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(" (");    
        Serial.print(AudioProcessorUsageMax());
        Serial.print(" %),  Mem = ");
        Serial.print(AudioMemoryUsage());
        Serial.print(" (");    
        Serial.print(AudioMemoryUsageMax());
        Serial.println(")");
        Serial.print("agc1: Gain=");
        Serial.print((float)agcGain1/(float)0x10000000);
        Serial.print(" cycles/sample=");
        Serial.println((float)cyc1/(float)AUDIO_BLOCK_SAMPLES);
        Serial.print("agc2: Gain=");
        Serial.print((float)agcGain2/(float)0x10000000);
        Serial.print(" cycles/sample=");
        Serial.println((float)cyc2/(float)AUDIO_BLOCK_SAMPLES);
        Serial.println("");
        last_time = millis();
      }
    #endif
    }
    
    void transformCoeffs( short int out[], double in[], int k )
    {
      for ( int i = 0 ; i < k ; i++ )
        out[i] = 32767 * in[i];
    }
    
    void agcCalc(int16_t *inbuf,int16_t *outbuf,int32_t *agcGain)
    {
      int16_t *bp1=inbuf,*bp2=outbuf;
    #ifdef PASSTHRU
        // Copy from input to output buffer
        for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) 
        {
          *bp2++ = *bp1++;
        }
    #else
        // Apply agcGain on input with saturation to output buffer
        int32_t sum=0,sum1=0,sum2=0,sum3=0,res,res1,res2,res3,err;
        for(int i = 0;i < AUDIO_BLOCK_SAMPLES>>2;i++) 
        { 
          //ref. dspinst.h in Teensy audio library
          res=signed_multiply_32x16b(*agcGain>>12,*bp1++);
          res1=signed_multiply_32x16b(*agcGain>>12,*bp1++);
          res2=signed_multiply_32x16b(*agcGain>>12,*bp1++);
          res3=signed_multiply_32x16b(*agcGain>>12,*bp1++);
          *bp2++=saturate16(res);
          *bp2++=saturate16(res1);
          *bp2++=saturate16(res2);
          *bp2++=saturate16(res3);
          sum+=abs(res);
          sum1+=abs(res1);
          sum2+=abs(res2);
          sum3+=abs(res3);
        }
        sum+=(sum1+sum2+sum3);
        // Calculate new agcGain for next input buffer
        err=ref-sum; 
        *agcGain+=err>>3; //update gain 
        *agcGain=min(*agcGain,0x7ff80000); //keep agcGain < 8.0
        *agcGain=max(*agcGain,0); //keep agcGain >= 0
    #endif
    }
    Click image for larger version. 

Name:	sig.jpg 
Views:	23 
Size:	45.0 KB 
ID:	26254
    Click image for larger version. 

Name:	out.jpg 
Views:	26 
Size:	51.1 KB 
ID:	26255

  23. #48
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,364
    The spectrum suggests the host computer's audio system did some rate-conversion or similar that added a bit of extra quantization noise. That FIR
    filter is the null filter. If you save the result in a memory buffer and then write to SDcard you'll be able to see the real output unencumbered by the
    host computer's handling.

    Me, I'd just simulate using Python and simpy.signal if investigating such things rather than trying to use a microcontroller. You can do similar in Matlab
    I'm sure.

  24. #49
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    77
    Quote Originally Posted by MarkT View Post
    The spectrum suggests the host computer's audio system did some rate-conversion or similar that added a bit of extra quantization noise. That FIR
    filter is the null filter. If you save the result in a memory buffer and then write to SDcard you'll be able to see the real output unencumbered by the
    host computer's handling.

    Me, I'd just simulate using Python and simpy.signal if investigating such things rather than trying to use a microcontroller. You can do similar in Matlab
    I'm sure.
    Well, I simulate before.
    Firstly, Mathlab.
    Secondly, C(mingw64 on my PC) in fixed point including dspinst.h to emulate the DSP Cortex instructions.
    Finally, I code the Teensy.
    I like to compare the Teensy results with the simulation results and explain the differences.
    Do you know how the Teensy USB driver copes with sampling rate differences between the Teensy clock and the PC clock? Even if they're both ideally at 44100, there will be drift.

  25. #50
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,364
    Ive not looked the the USB audio code, its not a secret, but its probably quite complex low level DMA stuff.

    I suspect the computer internally is converting to a common representation (perhaps at a different rate),
    and converting back for passing to apps like Audacity. There is a definitely a change to the noise floor and
    a couple of obvious spurs around 6kHz and 14kHz, so something has been processed. The main tone
    is ultra-clean though (suggesting no jitter added - ie no adhoc clock-mismatch correction)

Posting Permissions

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