Source code for analysis.SpectralSpreadAnalysis
from __future__ import print_function, division
import numpy as np
import logging
import pdb
from Analysis import Analysis
[docs]class SpectralSpreadAnalysis(Analysis):
"""
Spectral spread descriptor class for generation of spectral spread audio
analysis.
This descriptor calculates the spectral spread for overlapping grains of an
AnalysedAudioFile object. A full definition of spectral spread analysis can
be found in the documentation.
Arguments:
- analysis_group: the HDF5 file group to use for the storage of the
analysis.
- config: The configuration module used to configure the analysis
"""
def __init__(self, AnalysedAudioFile, frames, analysis_group, config=None):
super(SpectralSpreadAnalysis, self).__init__(AnalysedAudioFile,frames, analysis_group, 'SpcSprd')
self.logger = logging.getLogger(__name__+'.{0}Analysis'.format(self.name))
# Store reference to the file to be analysed
self.AnalysedAudioFile = AnalysedAudioFile
self.nyquist_rate = self.AnalysedAudioFile.samplerate / 2.
try:
spccntr = self.AnalysedAudioFile.analyses["spccntr"]
except KeyError:
raise KeyError("Spectral Centroid analysis is required for "
"spectral spread analysis.")
try:
fft = self.AnalysedAudioFile.analyses["fft"]
except KeyError:
raise KeyError("FFT analysis is required for spectral spread "
"analysis.")
self.analysis_group = analysis_group
self.logger.info("Creating Spectral Spread analysis for {0}".format(self.AnalysedAudioFile.name))
self.create_analysis(
fft.analysis['frames'],
spccntr.analysis['frames'],
self.AnalysedAudioFile.samplerate
)
self.spccntr_window_count = None
@staticmethod
[docs] def create_spcsprd_analysis(fft, spectral_centroid, samplerate, output_format = "ind"):
'''
Calculate the spectral spread of the fft frames.
fft: Real fft frames.
spectral_centroid: spectral centroid frames (in index format).
length: the length of the window used to calculate the FFT.
samplerate: the samplerate of the audio analysed.
'''
fft = fft[:]
spectral_centroid = spectral_centroid[:]
# Get the positive magnitudes of each bin.
magnitudes = np.abs(fft)
mag_max = np.max(magnitudes)
if not mag_max:
y = np.empty(magnitudes.shape[0])
y.fill(np.nan)
return y
# Get the index for each bin
if output_format == "ind":
freqs = np.arange(np.size(fft, axis=1))
elif output_format == "freq":
freqs = np.fft.rfftfreq((np.size(fft, axis=1)*2)-1, 1.0/samplerate)
else:
raise ValueError("\'{0}\' is not a valid output "
"format.".format(output_format))
spectral_centroid = np.vstack(spectral_centroid)
a = (freqs-spectral_centroid)**2
mag_sqrd = magnitudes**2
# Calculate the weighted mean
y = np.sqrt(np.sum(a*mag_sqrd, axis=1) / (np.sum(mag_sqrd, axis=1)))
return y
@staticmethod
[docs] def calc_spcsprd_frame_times(spcsprd_frames, sample_frame_count, samplerate):
"""Calculate times for frames using sample size and samplerate."""
# Get number of frames for time and frequency
timebins = spcsprd_frames.shape[0]
# Create array ranging from 0 to number of time frames
scale = np.arange(timebins+1)
# divide the number of samples by the total number of frames, then
# multiply by the frame numbers.
spcsprd_times = (float(sample_frame_count)/float(timebins)) * scale[:-1].astype(float)
# Divide by the samplerate to give times in seconds
spcsprd_times = spcsprd_times / samplerate
return spcsprd_times