Force integer-sample periods for "clean" audio test signals

Status
Not open for further replies.

zike

Member
Maybe this has been covered, pretty basic stuff, but in case it helps someone:

My "Oscilloscope Music" player toy delivers various CW audio test waveforms from the audio library AudioSynthWaveform object if an audio file is not supplied.

However, waveforms with sharp transitions (e.g., square, saw, triangle) had unacceptable artifacts due to aliased "leap-samples," unless the selected frequency happens to be an even-integer divisor of the sample rate (48 MHz/1088 = 44.11764706... kHz for Teensy audio). This is expected behavior, of course; the DAC output can only transition at the sample boundary nearest the theoretical "zero crossing", and that small residual error contains a lot of spurious energy if the transition covers the full output voltage range. For a band limited signal, of course, transitions between successive samples are small (by definition), and the timing error generates little energy.

The following trivial function returns the closest such "magic" frequency to any request. Not useful for music (tones will generally come out audibly sharp or flat above about octave 4; musical waveforms should be band-limited, anyway). But for test signals, a harmonically clean symmetric waveform may be more important than hitting some arbitrary frequency.

Code:
[HTML]
float closeTeensyFreq(float wantFreq) {
  //  Return nearest even-integer divisor of audio sample rate
  //  float samPeriod = (float) 1088. / 48000000. ; //  (from teensy forum post 160112)
  float wantHalfPer = 1 / (2 * wantFreq); 
  float gotHalfPer = samPeriod * round(wantHalfPer / samPeriod); 
  return (1 / (2 * gotHalfPer)) ; 
}
[/HTML]
 
Last edited:
Status
Not open for further replies.
Back
Top