Analyzing the frequency spectrum of audio

We can apply many techniques to analyze audio, and, therefore, we can debate at length about which techniques are most appropriate. The most obvious method is purportedly the FFT. As a variation, we can use the short-time Fourier transform (STFT). The STFT splits the signal in the time domain into equal parts, and it then applies the FFT to each segment. Another algorithm we will use is the cepstrum, which was originally used to analyze earthquakes but was later successfully applied to speech analysis. The power cepstrum is given by the following equation:

Analyzing the frequency spectrum of audio

The algorithm is as follows:

  1. Calculate the Fourier transform.
  2. Compute the squared magnitude of the transform.
  3. Take the logarithm of the previous result.
  4. Apply the inverse Fourier transform.
  5. Calculate the squared magnitude again.

The cepstrum is, in general, useful when we have large changes in the frequency domain. An important use case of the cepstrum is to form feature vectors for audio classification. This requires a mapping from frequency to the mel scale (refer to the Wikipedia page mentioned in the See also section).

How to do it...

  1. The imports are as follows:
    import dautil as dl
    import matplotlib.pyplot as plt
    import numpy as np
    from ch6util import read_wav
    from IPython.display import HTML
  2. Define the following function to calculate the magnitude of the signal with FFT:
    def amplitude(arr):
        return np.abs(np.fft.fft(arr))
  3. Load the data as follows:
    rate, audio = read_wav()
  4. Plot the audio waveform:
    sp = dl.plotting.Subplotter(2, 2, context)
    t = np.arange(0, len(audio)/float(rate), 1./rate)
    sp.ax.plot(t, audio)
    freqs = np.fft.fftfreq(audio.size, 1./rate)
    indices = np.where(freqs > 0)[0]
    sp.label()
  5. Plot the amplitude spectrum:
    magnitude = amplitude(audio)
    sp.next_ax().semilogy(freqs[indices], magnitude[indices])
    sp.label()
  6. Plot the cepstrum as follows:
    cepstrum = dl.ts.power(np.fft.ifft(np.log(magnitude ** 2)))
    sp.next_ax().semilogy(cepstrum)
    sp.label()
  7. Plot the STFT as a contour diagram:
    npieces = 200
    stft_amps = []
    
    for i, c in enumerate(dl.collect.chunk(audio[: npieces ** 2], len(audio)/npieces)):
        amps = amplitude(c)
        stft_amps.extend(amps)
    
    stft_freqs = np.linspace(0, rate, npieces)
    stft_times = np.linspace(0, len(stft_amps)/float(rate), npieces)
    sp.next_ax().contour(stft_freqs/rate, stft_freqs,
               np.log(stft_amps).reshape(npieces, npieces))
    sp.label()
        
    HTML(sp.exit())

Refer to the following screenshot for the end result:

How to do it...

The example code is in the analyzing_audio.ipynb file in this book's code bundle.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset