2

I would like to plot frequency graphs similar to the ones that Audacity can draw:

Audacity frequency PNG

I did not find a software to do that (in command line) so I started to play with python to do it, using the specgram function. As I am not able to redo such a graph (the purple one from audacity), I was wondering if someone know exactly what Audacity is plotting, waht it means, and is there any pseudo-code somewhere? I have less than basic knowledge in audio processing, but if someone guides me on that part, I think I can code any suggestion/pseudo code/procedure. Right now, I'm here, plotting something like this which is roughly what I have seen everywhere so far.

My amplitude and freq graphs PNG

> pxx, freqs, bins, _ = plt.specgram(y, NFFT=s, Fs=rate, noverlap=0,
                                        cmap=plt.cm.binary, sides='onesided',
                                        window=signal.blackmanharris(s),
                                        scale_by_freq=True,
                                        mode='magnitude')
plot(freqs, numpy.log10(pxx.max(axis=1)))

I don't understand how can I get these "decrease" of dB vs. frequency which I can see on any audio WAV with Audacity

Cheers

David Maust
  • 8,080
  • 3
  • 32
  • 36
edwin
  • 21
  • 1
  • 2

2 Answers2

0

As far as I see Audacity plots the magnitude spectrum, i.e. the absolute value of the fourier transform of the first 2048 samples. You plot the maximum amplitude in all time chunks relating to each frequency bin of the short time fourier transform.

Maybe this fits your needs:

import numpy as np
from scipy import signal
from matplotlib import pyplot as plt

y = y[0:2048] * signal.blackmanharris(2048)
X_amp = np.abs(np.fft.rfft(y))
X_db = 20 * np.log10(X_amp)
freqs = np.fft.rfftfreq(2048, 1/rate)
plt.plot(freqs, X_db)

EDIT:

Oh I found this page in the Audacity manual. So plt.specgram should be fine to imitate Audacity, just take np.average(pxx, axis=1). The manual does not say what hop size is used... maybe try to set the noverlap-parameter to s/2. (A common choice.)

Frank Zalkow
  • 3,850
  • 1
  • 22
  • 23
0

Thanks, I was close but you found it. Finally the code is quite simple:

pxx, freqs, bins, _ = plt.specgram(y, NFFT=s, Fs=rate, noverlap=0,
                                   cmap=plt.cm.binary, sides='onesided',
                                   window=signal.blackmanharris(s),
                                   scale_by_freq=True,
                                   mode='magnitude')
plot(freqs, 20 * log10(mean(pxx, axis=1)), 'g')

And, except the y-axis unit, I'm almost one pixel accurate against audacity:

Final plot

edwin
  • 21
  • 1
  • 2