4

I tried generating two nearly inaudible tones in Audacity, with frequencies 16 kHz and 18 kHz. (With a sampling rate of 48 kHz, I also tried this at 44.1 kHz) Playing each in isolation results in a high frequency tone, as expected. But when they are both played together, a loud low frequency sound is heard.

After playing it and recording it, I looked at the spectrogram, it looked like this (the top two tracks are the 16 and 18 kHz tones, generated by audacity-- the bottom two are the results of recording it (in stereo, oops)):

unwanted artifacts, much lower than 16 kHz or 18 kHz

This seemed very odd to me-- the sum of two inaudible frequencies should never result in an audible frequency-- in fact, it should never contain any other frequencies at all!

I expected this to be the result of some sort of non linear operation like saturation, aliasing-- but the most likely culprit seems to be resampling. This site looks a lot like what I'm experiencing. This looks exactly like what I'm seeing...Image below enter image description here

I tried it again, synthesizing a file from scratch with Python/NumPy/SciPy. output.wav (make sure to download this *.wav file rather than using the embedded player, as the embedded player seems to produce something similar to Audacity on my machine. In Foobar 2000 or VLC it sounds high frequency like expected, but after importing to Audacity without editing the sampling rate it sounds low frequency. Windows Media Player can not even open the file).

So the problem seems to be with Audacity, as generating my own wav file from "scratch" and playing it in VLC or Foobar 2000 works as expected.

I know some signal processing math but I have limited experience actually dealing with the practical effects of audio processing software (or could it be the hardware's fault?). I hope someone could shed some light on this!

(Here is the Python code to generate the wav file):

import numpy as np
from scipy.io import wavfile

#fs = 44.1e3 # similar effects with either of these
fs = 48.0e3
t = np.arange(0, 1.0, 1.0/fs)

f1 = 16e3
f2 = 18e3

x = np.sin(2*np.pi*f1*t) + np.sin(2*np.pi*f2*t)

fname = 'output.wav'
wavfile.write( fname, fs, x )

TL;DR: download and listen to output.wav in VLC or Foobar 2000. It sounds high frequency, as expected. But Audacity butchers it! Why?

4

You're quite right that it's some sort of nonlinear operation – hard digital clipping in fact. And honestly it's somewhat obvious why this happens: you're superimposing two sine waves, each of which is already peak-normalised. The result of such a combination will in general exceed 0 dBFS, and without special handling (limiter etc.) that means the signal will need to be clipped if you try to DA-convert or store it in a dynamic-limited format. Aliasing ensues.

Now, at least with the Python script this does not immediately happen: the scipy library stores in floating-point sample format, which has no hard limit at 0 dBFS, only a “soft limit” when the resolution decreases at high positive dB levels (realistically, that will never cause audible artifacts, at least not with 64-bit (double precision) floats). Floating point is great, it has long been the standard for professional audio processing and increasingly also for storage – but at least the 64-bit variety is largely unseen in the consumer sector, which would be why Windows Media Player can't open it.

Apart from that, AFAIK no hardware has DA converters that can directly deal with floating-point, so a program that plays such a file will have to get it down to integer resolution somehow. There's basically two choices:

  • Limit the dynamic range, or even peak-normalise the entire file before playing. That ensures no samples exceed 0 dBFS, so there's no clipping/aliasing... but the problem is, you're meddling with the file's loudness. That's no big deal in a media player, so e.g. Foobar 2000 appears to choose this route; but it can definitely be a problem in professional audio productions when the mix of multiple tracks gets messed up without it being immediately obvious.
  • Well, just clip. It'll sound horrible, but at least it's obvious that there is some problem, which is in a sense preferrable to “silent failure” for serious applications – because you are pointed to the problem and can then deal with it properly. So that seems to be what your Audacity does.

Actually, my Audacity install (2.0.5) does not do this1, so I can't be completely sure; but most likely this is indeed the matter. I.e., the problem doesn't really have anything to do with resampling. (Though resampling can sure enough cause similar trouble: a single file that's peak-normalised in one sample rate may exceed 0 dBFS in another!)


1And nor does any other DAW I know: they just do all their internal processing in floating-point anyway, and then limit at the very end, after the master fader.

  • Oh perfect-- I guess I assumed that this was somehow handled elsewhere. But I changed the Python script to add two sine waves with 0.5 amplitude instead of 1.0 and Audacity now handles it perfectly. Thank you very much! – Alex B. Feb 18 '15 at 1:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.