Source code for analysis.SpectralCentroidAnalysis
from __future__ import print_function, division
import numpy as np
import logging
import pdb
from Analysis import Analysis
[docs]class SpectralCentroidAnalysis(Analysis):
"""
Spectral centroid descriptor class for generation of spectral centroid
audio analysis.
This descriptor calculates the spectral centroid for overlapping grains of
an AnalysedAudioFile object. A full definition of spectral centroid
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(SpectralCentroidAnalysis, self).__init__(AnalysedAudioFile,frames, analysis_group, 'SpcCntr')
# Create logger for module
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:
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 Centroid analysis for {0}".format(self.AnalysedAudioFile.name))
self.create_analysis(
self.create_spccntr_analysis,
fft.analysis['frames'],
self.AnalysedAudioFile.samplerate
)
self.spccntr_window_count = None
@staticmethod
[docs] def create_spccntr_analysis(fft, samplerate, output_format="ind"):
'''
Calculate the spectral centroid of the fft frames.
samplerate: the samplerate of the audio analysed.
output_format = Choose either "freq" for output in Hz or "ind" for bin
index output
'''
fft = fft[:]
# Get the positive magnitudes of each bin.
magnitudes = np.abs(fft)
# Get the highest magnitude.
mag_max = np.max(magnitudes)
if not mag_max:
y = np.empty(magnitudes.shape[0])
y.fill(np.nan)
return y
# Calculate the centre frequency of each rfft bin.
if output_format == "freq":
freqs = np.fft.rfftfreq((np.size(fft, axis=1)*2)-1, 1.0/samplerate)
elif output_format == "ind":
freqs = np.arange(np.size(fft, axis=1))
else:
raise ValueError("\'{0}\' is not a valid output "
"format.".format(output_format))
# Calculate the weighted mean
y = np.sum(magnitudes*freqs, axis=1) / (np.sum(magnitudes, axis=1))
return y
@staticmethod
[docs] def calc_spccntr_frame_times(spccntr_frames, sample_frame_count, samplerate):
"""Calculate times for frames using sample size and samplerate."""
# Get number of frames for time and frequency
timebins = spccntr_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.
spccntr_times = (float(sample_frame_count)/float(timebins)) * scale[:-1].astype(float)
# Divide by the samplerate to give times in seconds
spccntr_times = spccntr_times / samplerate
return spccntr_times