Incorrect/lossy audio sample values from PC to Teensy?

Status
Not open for further replies.

kk12

Active member
Im using Teensy as USB-soundcard, so its both playback and record device. Applying readBuffer(), playBuffer() and queues to write/read the data into short-arrays.

So I created a square wave in Audacity (44,1kHz, 16-bit PCM) to test if Teensy can read it correctly (sending back to PC in serial terminal). There should be only values e.g. 32767 and -32768. For some reason they don't keep stable:

...32269,32269,32272,32274,32275,32275,32278,32278,32282,32282,32285,
-32287,-32286,-32290,-32292,-32293,-32294,-32297,-32295,-32299,-32300,-32302,-32305,-32305,-32309,-32308,-32311,-32311,-32313...

Why is this and is it correct behaviour?

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

AudioControlSGTL5000      sgtl5000_1;     //xy=302,184

AudioInputUSB             usb1;           //xy=200,69  (must set Tools > USB Type to Audio)
AudioOutputI2S            i2s1;           //xy=365,94
AudioRecordQueue          rqueue1;
AudioPlayQueue            pqueue2;

AudioConnection          patchCord1(usb1, 0, rqueue1, 0);
AudioConnection          patchCord2(pqueue2, 0, i2s1, 0);

AudioInputI2S            i2s2;           //xy=105,63
AudioOutputUSB           usb2;
AudioRecordQueue         rqueue3;
AudioPlayQueue           pqueue4;

AudioConnection          patchCord3(i2s2, 0, rqueue3, 0);
AudioConnection          patchCord4(pqueue4, 0, usb2, 0);

const int myInput = AUDIO_INPUT_MIC;

int ret=0;
int i=0;
int j=0;

short array1[AUDIO_BLOCK_SAMPLES];
short array2[AUDIO_BLOCK_SAMPLES];

void setup() {                
  AudioMemory(24);
  sgtl5000_1.enable();
  sgtl5000_1.inputSelect(myInput);
  sgtl5000_1.volume(0.6);
  Serial.begin(19200);
  rqueue1.begin();
  rqueue3.begin();
  Serial.println("Begin");
}

void loop() {
  // read the PC's volume setting
  float vol = usb1.volume();

  // scale to a nice range (not too loud)
  // and adjust the audio shield output volume
  if (vol > 0) {
    // scale 0 = 1.0 range to:
    //  0.3 = almost silent
    //  0.8 = really loud
    vol = 0.3 + vol * 0.5;
  }

  // use the scaled volume setting.  Delete this for fixed volume.
  //sgtl5000_1.volume(vol);

  ret=rqueue1.available();
  //Serial.println(ret);

  if(ret>=1)
  {
    memcpy(&array1[0], rqueue1.readBuffer(), 2*AUDIO_BLOCK_SAMPLES);
    rqueue1.freeBuffer();

    unsigned int loop=0;
    while(loop<128)
    {
      Serial.print(array1[j], DEC);
      Serial.print(",");
      loop++;
    }
    Serial.println("");
  
    memcpy(pqueue2.getBuffer(), &array1[0], 2*AUDIO_BLOCK_SAMPLES);
    pqueue2.playBuffer();
  }

  
  ret=rqueue3.available();
  //Serial.println(ret);

  if(ret>=1)
  {
    memcpy(&array1[0], rqueue3.readBuffer(), 2*AUDIO_BLOCK_SAMPLES);
    rqueue3.freeBuffer();
  
    memcpy(pqueue4.getBuffer(), &array1[0], 2*AUDIO_BLOCK_SAMPLES);
    pqueue4.playBuffer();
  }
  
  //delay(100);
}
 
Last edited:
It's correct behavior, since a bandwidth of 22.05kHz (1/2 x the sampling frequency of 44.1kHz) will filter out the highest and inaudible harmonics which make a square wave visually and mathematically perfect without changing the audible result. Thus, Audacity does that filtering to prevent aliasing ghost tones and distortion. You might look at the pcm file which audacity generates by exporting it in RAW format and with a hex editor. There, you'll already find that the data is not only 32767 and -32768 but that the square would look somewhat smoothed. So, it's not the Teensy.
 
It's correct behavior, since a bandwidth of 22.05kHz (1/2 x the sampling frequency of 44.1kHz) will filter out the highest and inaudible harmonics which make a square wave visually and mathematically perfect without changing the audible result. Thus, Audacity does that filtering to prevent aliasing ghost tones and distortion. You might look at the pcm file which audacity generates by exporting it in RAW format and with a hex editor. There, you'll already find that the data is not only 32767 and -32768 but that the square would look somewhat smoothed. So, it's not the Teensy.

Do you mean Analyze / Sample Data Export -menu option? It prints out two values: -1.00000 and 0.99997. If Audacity isn't right (free) software for this kind of testing, what is?
 
Audacity is fully ok. But the Analyze / Sample Data Export menu option is not the right way to see because it will output raw and unfiltered float data. You'd have to export your square signal as a file with the file/export menu and choose raw audio.

But all that is a waste of time. You could simply accept that a visually ideal square wave signal can not exist in a bandwidth limited analog domain. Back to university and study Mr Nyquist's theorems if you don't believe me.

The smoothed/rounded signal which you are seeing is the audible part of the square wave. The latter has still inaudibly high harmonics which contribute to a visually perfect square wave but which can not be heard and that's why they are filtered away in any digital audio system. Let's take the example of a 10kHz square wave. It has harmonics at 30kHz, 50kHz, 70kHz and so on. If you sample it with 44.1kHz for digital audio without filtering, you would hear ghost tones through the folding effect at 44.1 - 30 = 14.1kHz, 50 - 44.1 = 5.9kHz and so on and the signal would not longer resemble to a square wave at all.

TLDR: The rounded and smoothed values which you are observing are the correct and expected result.

That's why every digital audio system (including Audacity) will filter the output, so that only the signal components lower as the half of the sampling frequency will come to the output, the others aren't audible anyway, so you won't hear the difference, but the waveform might look smoother.
 
So I created a square wave in Audacity (44,1kHz, 16-bit PCM)

Can you tell me exactly what you did in Audacity?

I mean, if I were to try it here, what exactly should I click in Audacity so I do it precisely the same way you did?
 
Audacity is fully ok. But the Analyze / Sample Data Export menu option is not the right way to see because it will output raw and unfiltered float data. You'd have to export your square signal as a file with the file/export menu and choose raw audio.

But all that is a waste of time. You could simply accept that a visually ideal square wave signal can not exist in a bandwidth limited analog domain. Back to university and study Mr Nyquist's theorems if you don't believe me.

The smoothed/rounded signal which you are seeing is the audible part of the square wave. The latter has still inaudibly high harmonics which contribute to a visually perfect square wave but which can not be heard and that's why they are filtered away in any digital audio system. Let's take the example of a 10kHz square wave. It has harmonics at 30kHz, 50kHz, 70kHz and so on. If you sample it with 44.1kHz for digital audio without filtering, you would hear ghost tones through the folding effect at 44.1 - 30 = 14.1kHz, 50 - 44.1 = 5.9kHz and so on and the signal would not longer resemble to a square wave at all.

TLDR: The rounded and smoothed values which you are observing are the correct and expected result.

That's why every digital audio system (including Audacity) will filter the output, so that only the signal components lower as the half of the sampling frequency will come to the output, the others aren't audible anyway, so you won't hear the difference, but the waveform might look smoother.

No matter if Analyze / Sample Data Export OR File / Export / Export Audio... other uncompressed files... raw....
After both exports, there is only two values in the file and not the values found in Teensy terminal.
 
Can you tell me exactly what you did in Audacity?

I mean, if I were to try it here, what exactly should I click in Audacity so I do it precisely the same way you did?

Generate / Tone / Square, 10 Hz, Amplitude 1, Duration 1 s

Also, I created a file with 1.00000 and -1.00000 values and imported it back to Audacity, but same problem remained.
 
So what Im trying to do, is using audio to carry data. I tried:

carrying one byte inside short (replacing lower byte)
replacing whole sample with 2 bytes

Both fail over 90% of tests and I assume it is because of this variation on sample values. Yet, if previous post on Mr Nyquist's theorem is correct on this digital audio line, I could just double or triple data? Or double sample rate.
 
Last edited:
Generate / Tone / Square, 10 Hz, Amplitude 1, Duration 1 s

Is Audacity playing live to the USB? Or is this being saved to a file and then sent somehow?

Which operating system & version are you using? Normally I test first with Linux. My Mac & Windows test machine is currently tied up with work on this issue.
 
Is Audacity playing live to the USB? Or is this being saved to a file and then sent somehow?

Which operating system & version are you using? Normally I test first with Linux. My Mac & Windows test machine is currently tied up with work on this issue.

Live to USB yes. Windows 10. Audacity works identically in Linux, but didn't test serial feedback there. Preferences: Quality are set to Best Quality and Dither to None. Sample rate 44100 Hz and format 16-bit.
 
I generated now 10s of 1kHz square wave at 1.0 amplitude in Audacity :
Capture d’écran 2018-08-22 à 12.42.49.png

Then I exported it in RAW format 16bit signed PCM :
Capture d’écran 2018-08-22 à 12.43.59.png

After opening the RAW file with a HEX editor, I found (as expected) values besides 32767 and -32768, due to rounding and anti-aliasing filtering :
Capture d’écran 2018-08-22 à 12.46.59.png

So what?
 
Strange, but in ever case irrelevant. It’s about audio, so these small visual “deviations” can not be perceived by a human ear, neither frequency nor level wise.
 
Status
Not open for further replies.
Back
Top