New Guy Looking For Teensy DSP programming tips

Status
Not open for further replies.
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.
 
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?
 
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.);
  }
}
 
p.s. The filters will be patched in between playSdWav1 and audioOutput
 
My SDcard reader is already not very reliable in only 1 direction. It's easier to get the USB digital Teensy ouput to Audacity f multisinout.jpgor analysis or creating wav files. Attached, the spectrum obtained.
 
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
}
 
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:
2021-10-20 11_07_06-Audio System Design Tool for Teensy Audio Library.png
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
 
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: config.jpg
 
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: configa.jpg
 
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
 
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.
 
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
 
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.
 
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
 
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.
 
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.
 
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/cores/blob/master/teensy4/usb_audio.cpp

The planned 1170 CPU has hardware to do sample rate conversion.
 
Last edited:
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?
 
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.
 
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..
 
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
}
sig.jpg
out.jpg
 
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.
 
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.
 
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)
 
Status
Not open for further replies.
Back
Top