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

Thread: New Guy Looking For Teensy DSP programming tips

  1. #26
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    28
    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,235
    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
    28
    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
    28
    p.s. The filters will be patched in between playSdWav1 and audioOutput

  5. #30
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,235
    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
    28
    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:	6 
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
    28
    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
    122
    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:	4 
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
    28
    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:	3 
Size:	44.0 KB 
ID:	26228

  10. #35
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    28
    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:	5 
Size:	15.5 KB 
ID:	26230

  11. #36
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    28
    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
    122
    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
    28
    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,285
    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
    28
    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,285
    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
    28
    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.

Posting Permissions

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