From 08c52adafddabeb6c7f89bebd84f0ca830d9e7a5 Mon Sep 17 00:00:00 2001 From: John Glover Date: Fri, 29 Jun 2012 11:37:40 +0100 Subject: [sms] Rename sms.py to pysms.py. PEP8 cleanup of test_sms.py. --- simpl/__init__.py | 10 +- simpl/pysms.py | 601 +++++++++++++++++++++++++++++++++++++++++++++++++++++ simpl/sms.py | 601 ----------------------------------------------------- tests/test_base.py | 18 +- tests/test_sms.py | 309 ++++++++++++++------------- 5 files changed, 765 insertions(+), 774 deletions(-) create mode 100644 simpl/pysms.py delete mode 100644 simpl/sms.py diff --git a/simpl/__init__.py b/simpl/__init__.py index 66ede7c..32df530 100644 --- a/simpl/__init__.py +++ b/simpl/__init__.py @@ -17,11 +17,11 @@ SndObjPeakDetection = sndobj.SndObjPeakDetection SndObjPartialTracking = sndobj.SndObjPartialTracking SndObjSynthesis = sndobj.SndObjSynthesis -import sms -SMSPeakDetection = sms.SMSPeakDetection -SMSPartialTracking = sms.SMSPartialTracking -SMSSynthesis = sms.SMSSynthesis -SMSResidual = sms.SMSResidual +import pysms +SMSPeakDetection = pysms.SMSPeakDetection +SMSPartialTracking = pysms.SMSPartialTracking +SMSSynthesis = pysms.SMSSynthesis +SMSResidual = pysms.SMSResidual import mq MQPeakDetection = mq.MQPeakDetection diff --git a/simpl/pysms.py b/simpl/pysms.py new file mode 100644 index 0000000..e683ac2 --- /dev/null +++ b/simpl/pysms.py @@ -0,0 +1,601 @@ +import numpy as np +import simpl +import simpl.simplsms as simplsms + + +class SMSPeakDetection(simpl.PeakDetection): + "Sinusoidal peak detection using SMS" + + def __init__(self): + simpl.PeakDetection.__init__(self) + simplsms.sms_init() + # analysis parameters + self._analysis_params = simplsms.SMS_AnalParams() + simplsms.sms_initAnalParams(self._analysis_params) + self._analysis_params.iSamplingRate = self._sampling_rate + # set default hop and frame sizes to match those in the parent class + self._analysis_params.iFrameRate = self.sampling_rate / self._hop_size + self._analysis_params.iWindowType = simplsms.SMS_WIN_HAMMING + self._analysis_params.fHighestFreq = 20000 + self._analysis_params.iMaxDelayFrames = 4 + self._analysis_params.analDelay = 0 + self._analysis_params.minGoodFrames = 1 + self._analysis_params.iCleanTracks = 0 + self._analysis_params.iFormat = simplsms.SMS_FORMAT_HP + self._analysis_params.nTracks = self._max_peaks + self._analysis_params.maxPeaks = self._max_peaks + self._analysis_params.nGuides = self._max_peaks + self._analysis_params.preEmphasis = 0 + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + self._peaks = simplsms.SMS_SpectralPeaks(self._max_peaks) + # By default, SMS will change the size of the frames being read + # depending on the detected fundamental frequency (if any) of the + # input sound. To prevent this behaviour (useful when comparing + # different analysis algorithms), set the + # _static_frame_size variable to True + self._static_frame_size = False + + def __del__(self): + simplsms.sms_freeAnalysis(self._analysis_params) + simplsms.sms_freeSpectralPeaks(self._peaks) + simplsms.sms_free() + + # properties + max_frequency = property(lambda self: self.get_max_frequency(), + lambda self, x: self.set_max_frequency(x)) + default_fundamental = property(lambda self: self.get_default_fundamental(), + lambda self, x: self.set_default_fundamental(x)) + max_frame_delay = property(lambda self: self.get_max_frame_delay(), + lambda self, x: self.set_max_frame_delay(x)) + analysis_delay = property(lambda self: self.get_analysis_delay(), + lambda self, x: self.set_analysis_delay(x)) + min_good_frames = property(lambda self: self.get_min_good_frames(), + lambda self, x: self.set_min_good_frames(x)) + min_frequency = property(lambda self: self.get_min_frequency(), + lambda self, x: self.set_min_frequency(x)) + min_peak_amp = property(lambda self: self.get_min_peak_amp(), + lambda self, x: self.set_min_peak_amp(x)) + clean_tracks = property(lambda self: self.get_clean_tracks(), + lambda self, x: self.set_clean_tracks(x)) + format = property(lambda self: self.get_format(), + lambda self, x: self.set_format(x)) + pre_emphasis = property(lambda self: self.get_pre_emphasis(), + lambda self, x: self.set_pre_emphasis(x)) + + def get_max_frequency(self): + return self._analysis_params.fHighestFreq + + def set_max_frequency(self, max_frequency): + self._analysis_params.fHighestFreq = max_frequency + + def get_default_fundamental(self): + return self._analysis_params.fDefaultFundamental + + def set_default_fundamental(self, default_fundamental): + self._analysis_params.fDefaultFundamental = default_fundamental + + def get_max_frame_delay(self): + return self._analysis_params.iMaxDelayFrames + + def set_max_frame_delay(self, max_frame_delay): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.iMaxDelayFrames = max_frame_delay + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_analysis_delay(self): + return self._analysis_params.analDelay + + def set_analysis_delay(self, analysis_delay): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.analDelay = analysis_delay + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_min_good_frames(self): + return self._analysis_params.minGoodFrames + + def set_min_good_frames(self, min_good_frames): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.minGoodFrames = min_good_frames + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_min_frequency(self): + return self._analysis_params.fLowestFundamental + + def set_min_frequency(self, min_frequency): + self._analysis_params.fLowestFundamental = min_frequency + self._analysis_params.fLowestFreq = min_frequency + + def get_min_peak_amp(self): + return self._analysis_params.fMinPeakMag + + def set_min_peak_amp(self, min_peak_amp): + self._analysis_params.fMinPeakMag = min_peak_amp + + def get_clean_tracks(self): + return self._analysis_params.iCleanTracks + + def set_clean_tracks(self, x): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.iCleanTracks = x + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_format(self): + return self._analysis_params.iFormat + + def set_format(self, x): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.iFormat = x + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_pre_emphasis(self): + return self._analysis_params.preEmphasis + + def set_pre_emphasis(self, x): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.preEmphasis = x + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_hop_size(self): + return self._analysis_params.sizeHop + + def set_hop_size(self, hop_size): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.iFrameRate = self.sampling_rate / hop_size + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_max_peaks(self): + return self._analysis_params.maxPeaks + + def set_max_peaks(self, max_peaks): + simplsms.sms_freeAnalysis(self._analysis_params) + simplsms.sms_freeSpectralPeaks(self._peaks) + # make sure the new max is less than SMS_MAX_NPEAKS + if max_peaks > simplsms.SMS_MAX_NPEAKS: + print "Warning: max peaks (" + str(max_peaks) + ")", + print "set to more than the max. no. peaks possible in libsms." + print " Setting to", simplsms.SMS_MAX_NPEAKS, "instead." + max_peaks = simplsms.SMS_MAX_NPEAKS + # set analysis params + self._max_peaks = max_peaks + self._analysis_params.nTracks = max_peaks + self._analysis_params.maxPeaks = max_peaks + self._analysis_params.nGuides = max_peaks + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + # set peaks list + self._peaks = simplsms.SMS_SpectralPeaks(max_peaks) + + def get_sampling_rate(self): + return self._analysis_params.iSamplingRate + + def set_sampling_rate(self, sampling_rate): + self._analysis_params.iSamplingRate = sampling_rate + simplsms.sms_freeAnalysis(self._analysis_params) + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def set_window_size(self, window_size): + self._window_size = window_size + self._analysis_params.iDefaultSizeWindow = window_size + + def get_next_frame_size(self): + return self._analysis_params.sizeNextRead + + def find_peaks_in_frame(self, frame): + "Find and return all spectral peaks in a given frame of audio" + current_peaks = [] + num_peaks = simplsms.sms_findPeaks(frame.audio, + self._analysis_params, + self._peaks) + if num_peaks > 0: + amps = np.zeros(num_peaks, dtype=simpl.dtype) + freqs = np.zeros(num_peaks, dtype=simpl.dtype) + phases = np.zeros(num_peaks, dtype=simpl.dtype) + self._peaks.getFreq(freqs) + self._peaks.getMag(amps) + self._peaks.getPhase(phases) + for i in range(num_peaks): + p = simpl.Peak() + p.amplitude = amps[i] + p.frequency = freqs[i] + p.phase = phases[i] + current_peaks.append(p) + return current_peaks + + def find_peaks(self, audio): + """ + Find and return all spectral peaks in a given audio signal. + If the signal contains more than 1 frame worth of audio, + it will be broken up into separate frames, with a list of + peaks returned for each frame. + """ + # TODO: This hops by frame size rather than hop size in order to + # make sure the results are the same as with libsms. Make sure + # we have the same number of frames as the other algorithms. + self._analysis_params.iSizeSound = len(audio) + self.frames = [] + pos = 0 + # account for SMS analysis delay + # need an extra (max_frame_delay - 1) frames + num_samples = (len(audio) - self.hop_size) + ((self.max_frame_delay - 1) * self.hop_size) + while pos < num_samples: + # get the next frame size + if not self._static_frame_size: + self.frame_size = self.get_next_frame_size() + # get the next frame + frame = simpl.Frame() + frame.size = self.frame_size + frame.audio = audio[pos:pos + self.frame_size] + # find peaks + frame.peaks = self.find_peaks_in_frame(frame) + self.frames.append(frame) + pos += self.frame_size + return self.frames + + +class SMSPartialTracking(simpl.PartialTracking): + "Partial tracking using SMS" + + def __init__(self): + simpl.PartialTracking.__init__(self) + simplsms.sms_init() + self._analysis_params = simplsms.SMS_AnalParams() + simplsms.sms_initAnalParams(self._analysis_params) + self._analysis_params.iSamplingRate = self.sampling_rate + self._analysis_params.fHighestFreq = 20000 + self._analysis_params.iMaxDelayFrames = 4 # libsms minimum + self._analysis_params.analDelay = 0 + self._analysis_params.minGoodFrames = 1 + self._analysis_params.iCleanTracks = 0 + self._analysis_params.iFormat = simplsms.SMS_FORMAT_HP + self._analysis_params.nTracks = self._max_partials + self._analysis_params.nGuides = self._max_partials + self._analysis_params.preEmphasis = 0 + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + self._sms_header = simplsms.SMS_Header() + simplsms.sms_fillHeader(self._sms_header, self._analysis_params, "simpl") + self._analysis_frame = simplsms.SMS_Data() + simplsms.sms_allocFrameH(self._sms_header, self._analysis_frame) + + def __del__(self): + simplsms.sms_freeAnalysis(self._analysis_params) + simplsms.sms_freeFrame(self._analysis_frame) + simplsms.sms_free() + + # properties + max_frequency = property(lambda self: self.get_max_frequency(), + lambda self, x: self.set_max_frequency(x)) + default_fundamental = property(lambda self: self.get_default_fundamental(), + lambda self, x: self.set_default_fundamental(x)) + max_frame_delay = property(lambda self: self.get_max_frame_delay(), + lambda self, x: self.set_max_frame_delay(x)) + analysis_delay = property(lambda self: self.get_analysis_delay(), + lambda self, x: self.set_analysis_delay(x)) + min_good_frames = property(lambda self: self.get_min_good_frames(), + lambda self, x: self.set_min_good_frames(x)) + clean_tracks = property(lambda self: self.get_clean_tracks(), + lambda self, x: self.set_clean_tracks(x)) + format = property(lambda self: self.get_format(), + lambda self, x: self.set_format(x)) + pre_emphasis = property(lambda self: self.get_pre_emphasis(), + lambda self, x: self.set_pre_emphasis(x)) + + def get_max_frequency(self): + return self._analysis_params.fHighestFreq + + def set_max_frequency(self, max_frequency): + self._analysis_params.fHighestFreq = max_frequency + + def get_default_fundamental(self): + return self._analysis_params.fDefaultFundamental + + def set_default_fundamental(self, default_fundamental): + self._analysis_params.fDefaultFundamental = default_fundamental + + def get_max_frame_delay(self): + return self._analysis_params.iMaxDelayFrames + + def set_max_frame_delay(self, max_frame_delay): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.iMaxDelayFrames = max_frame_delay + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_analysis_delay(self): + return self._analysis_params.analDelay + + def set_analysis_delay(self, x): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.analDelay = x + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_min_good_frames(self): + return self._analysis_params.minGoodFrames + + def set_min_good_frames(self, x): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.minGoodFrames = x + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_clean_tracks(self): + return self._analysis_params.iCleanTracks + + def set_clean_tracks(self, x): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.iCleanTracks = x + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_format(self): + return self._analysis_params.iFormat + + def set_format(self, x): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.iFormat = x + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_pre_emphasis(self): + return self._analysis_params.preEmphasis + + def set_pre_emphasis(self, x): + simplsms.sms_freeAnalysis(self._analysis_params) + self._analysis_params.preEmphasis = x + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + + def get_max_partials(self): + return self._analysis_params.nTracks + + def set_max_partials(self, max_partials): + simplsms.sms_freeAnalysis(self._analysis_params) + simplsms.sms_freeFrame(self._analysis_frame) + self._max_partials = max_partials + self._analysis_params.maxPeaks = max_partials + self._analysis_params.nTracks = max_partials + self._analysis_params.nGuides = max_partials + if simplsms.sms_initAnalysis(self._analysis_params) != 0: + raise Exception("Error allocating memory for analysis_params") + simplsms.sms_fillHeader(self._sms_header, self._analysis_params, "simpl") + simplsms.sms_allocFrameH(self._sms_header, self._analysis_frame) + + def update_partials(self, frame): + "Streamable (real-time) partial-tracking." + # load Peak amplitudes, frequencies and phases into arrays + num_peaks = len(frame.peaks) + amps = np.zeros(num_peaks, dtype=simpl.dtype) + freqs = np.zeros(num_peaks, dtype=simpl.dtype) + phases = np.zeros(num_peaks, dtype=simpl.dtype) + for i in range(num_peaks): + peak = frame.peaks[i] + amps[i] = peak.amplitude + freqs[i] = peak.frequency + phases[i] = peak.phase + # set peaks in SMS_AnalParams structure + simplsms.sms_setPeaks(self._analysis_params, amps, freqs, phases) + # SMS partial tracking + simplsms.sms_findPartials(self._analysis_frame, self._analysis_params) + # read values back into amps, freqs, phases + amps = np.zeros(self.max_partials, dtype=simpl.dtype) + freqs = np.zeros(self.max_partials, dtype=simpl.dtype) + phases = np.zeros(self.max_partials, dtype=simpl.dtype) + self._analysis_frame.getSinAmp(amps) + self._analysis_frame.getSinFreq(freqs) + self._analysis_frame.getSinPhase(phases) + peaks = [] + for i in range(self.max_partials): + p = simpl.Peak() + p.amplitude = amps[i] + p.frequency = freqs[i] + p.phase = phases[i] + peaks.append(p) + return peaks + + def find_partials(self, frames): + """Find partials from the sinusoidal peaks in a list of Frames""" + self.frames = [] + for frame in frames: + frame.partials = self.update_partials(frame) + self.frames.append(frame) + # account for SMS analysis delay + # the first extra (max_frame_delay) frames are blank + if len(self.frames) > (self.max_frame_delay): + self.frames = self.frames[self.max_frame_delay:] + return self.frames + + +class SMSSynthesis(simpl.Synthesis): + "Sinusoidal resynthesis using SMS" + + def __init__(self): + simpl.Synthesis.__init__(self) + simplsms.sms_init() + self._synth_params = simplsms.SMS_SynthParams() + simplsms.sms_initSynthParams(self._synth_params) + self._synth_params.iSamplingRate = self._sampling_rate + self._synth_params.iDetSynthType = simplsms.SMS_DET_SIN + self._synth_params.iSynthesisType = simplsms.SMS_STYPE_DET + self._synth_params.iStochasticType = simplsms.SMS_STOC_NONE + self._synth_params.sizeHop = self._hop_size + self._synth_params.nTracks = self._max_partials + self._synth_params.deEmphasis = 0 + simplsms.sms_initSynth(self._synth_params) + self._current_frame = np.zeros(self._hop_size, dtype=simpl.dtype) + self._analysis_frame = simplsms.SMS_Data() + simplsms.sms_allocFrame(self._analysis_frame, self.max_partials, + self.num_stochastic_coeffs, 1, + self.stochastic_type, 0) + + def __del__(self): + simplsms.sms_freeFrame(self._analysis_frame) + simplsms.sms_freeSynth(self._synth_params) + simplsms.sms_free() + + # properties + synthesis_type = property(lambda self: self.get_synthesis_type(), + lambda self, x: self.set_synthesis_type(x)) + det_synthesis_type = property(lambda self: self.get_det_synthesis_type(), + lambda self, x: self.set_det_synthesis_type(x)) + num_stochastic_coeffs = property(lambda self: self.get_num_stochastic_coeffs(), + lambda self, x: self.set_num_stochastic_coeffs(x)) + stochastic_type = property(lambda self: self.get_stochastic_type(), + lambda self, x: self.set_stochastic_type(x)) + original_sampling_rate = property(lambda self: self.get_original_sampling_rate(), + lambda self, x: self.set_original_sampling_rate(x)) + original_hop_size = property(lambda self: self.get_original_hop_size(), + lambda self, x: self.set_original_hop_size(x)) + + def get_hop_size(self): + return self._synth_params.sizeHop + + def set_hop_size(self, hop_size): + simplsms.sms_freeSynth(self._synth_params) + self._synth_params.sizeHop = hop_size + simplsms.sms_initSynth(self._synth_params) + self._current_frame = np.zeros(hop_size, dtype=simpl.dtype) + + def get_max_partials(self): + return self._synth_params.nTracks + + def set_max_partials(self, max_partials): + simplsms.sms_freeSynth(self._synth_params) + simplsms.sms_freeFrame(self._analysis_frame) + self._synth_params.nTracks = max_partials + simplsms.sms_initSynth(self._synth_params) + simplsms.sms_allocFrame(self._analysis_frame, max_partials, + self.num_stochastic_coeffs, 1, + self.stochastic_type, 0) + + def get_sampling_rate(self): + return self._synth_params.iSamplingRate + + def set_sampling_rate(self, sampling_rate): + self._synth_params.iSamplingRate = sampling_rate + + def get_synthesis_type(self): + return self._synth_params.iSynthesisType + + def set_synthesis_type(self, synthesis_type): + self._synth_params.iSynthesisType = synthesis_type + + def get_det_synthesis_type(self): + return self._synth_params.iDetSynthesisType + + def set_det_synthesis_type(self, det_synthesis_type): + self._synth_params.iDetSynthType = det_synthesis_type + + def get_num_stochastic_coeffs(self): + return self._synth_params.nStochasticCoeff + + def set_num_stochastic_coeffs(self, num_stochastic_coeffs): + self._synth_params.nStochasticCoeff = num_stochastic_coeffs + simplsms.sms_freeFrame(self._analysis_frame) + simplsms.sms_allocFrame(self._analysis_frame, self.max_partials, + num_stochastic_coeffs, 1, + self.stochastic_type, 0) + + def get_stochastic_type(self): + return self._synth_params.iStochasticType + + def set_stochastic_type(self, stochastic_type): + simplsms.sms_freeSynth(self._synth_params) + simplsms.sms_freeFrame(self._analysis_frame) + self._synth_params.iStochasticType = stochastic_type + simplsms.sms_initSynth(self._synth_params) + simplsms.sms_allocFrame(self._analysis_frame, self.max_partials, + self.num_stochastic_coeffs, 1, + stochastic_type, 0) + + def get_original_sampling_rate(self): + return self._synth_params.iOriginalSRate + + def set_original_sampling_rate(self, sampling_rate): + self._synth_params.iOriginalSRate = sampling_rate + + def get_original_hop_size(self): + return self._synth_params.origSizeHop + + def set_original_hop_size(self, hop_size): + self._synth_params.origSizeHop = hop_size + + def synth_frame(self, frame): + "Synthesises a frame of audio" + amps = np.zeros(self.max_partials, dtype=simpl.dtype) + freqs = np.zeros(self.max_partials, dtype=simpl.dtype) + phases = np.zeros(self.max_partials, dtype=simpl.dtype) + num_partials = min(self.max_partials, len(frame.partials)) + for i in range(num_partials): + amps[i] = frame.partials[i].amplitude + freqs[i] = frame.partials[i].frequency + phases[i] = frame.partials[i].phase + self._analysis_frame.setSinAmp(amps) + self._analysis_frame.setSinFreq(freqs) + self._analysis_frame.setSinPha(phases) + simplsms.sms_synthesize(self._analysis_frame, + self._current_frame, + self._synth_params) + return self._current_frame + + +class SMSResidual(simpl.Residual): + "SMS residual component" + + def __init__(self): + simpl.Residual.__init__(self) + simplsms.sms_init() + self._residual_params = simplsms.SMS_ResidualParams() + simplsms.sms_initResidualParams(self._residual_params) + self._residual_params.hopSize = self._hop_size + simplsms.sms_initResidual(self._residual_params) + + def __del__(self): + simplsms.sms_freeResidual(self._residual_params) + simplsms.sms_free() + + def get_hop_size(self): + return self._residual_params.hopSize + + def set_hop_size(self, hop_size): + simplsms.sms_freeResidual(self._residual_params) + self._residual_params.hopSize = hop_size + simplsms.sms_initResidual(self._residual_params) + + def residual_frame(self, synth, original): + "Computes the residual signal for a frame of audio" + simplsms.sms_findResidual(synth, original, self._residual_params) + residual = np.zeros(self._residual_params.hopSize, dtype=simpl.dtype) + self._residual_params.getResidual(residual) + return residual + + def find_residual(self, synth, original): + "Calculate and return the residual signal" + num_frames = len(original) / self.hop_size + residual = np.array([], dtype=simpl.dtype) + sample_offset = 0 + + for i in range(num_frames): + synth_frame = synth[sample_offset:sample_offset + self.hop_size] + original_frame = original[sample_offset:sample_offset + self.hop_size] + residual = np.hstack(( + residual, self.residual_frame(synth_frame, original_frame) + )) + sample_offset += self.hop_size + return residual + + def synth_frame(self, synth, original): + "Calculate and return one frame of the synthesised residual signal" + residual = self.residual_frame(synth, original) + approx = np.zeros(self._residual_params.hopSize, dtype=simpl.dtype) + simplsms.sms_approxResidual(residual, approx, self._residual_params) + return approx diff --git a/simpl/sms.py b/simpl/sms.py deleted file mode 100644 index e683ac2..0000000 --- a/simpl/sms.py +++ /dev/null @@ -1,601 +0,0 @@ -import numpy as np -import simpl -import simpl.simplsms as simplsms - - -class SMSPeakDetection(simpl.PeakDetection): - "Sinusoidal peak detection using SMS" - - def __init__(self): - simpl.PeakDetection.__init__(self) - simplsms.sms_init() - # analysis parameters - self._analysis_params = simplsms.SMS_AnalParams() - simplsms.sms_initAnalParams(self._analysis_params) - self._analysis_params.iSamplingRate = self._sampling_rate - # set default hop and frame sizes to match those in the parent class - self._analysis_params.iFrameRate = self.sampling_rate / self._hop_size - self._analysis_params.iWindowType = simplsms.SMS_WIN_HAMMING - self._analysis_params.fHighestFreq = 20000 - self._analysis_params.iMaxDelayFrames = 4 - self._analysis_params.analDelay = 0 - self._analysis_params.minGoodFrames = 1 - self._analysis_params.iCleanTracks = 0 - self._analysis_params.iFormat = simplsms.SMS_FORMAT_HP - self._analysis_params.nTracks = self._max_peaks - self._analysis_params.maxPeaks = self._max_peaks - self._analysis_params.nGuides = self._max_peaks - self._analysis_params.preEmphasis = 0 - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - self._peaks = simplsms.SMS_SpectralPeaks(self._max_peaks) - # By default, SMS will change the size of the frames being read - # depending on the detected fundamental frequency (if any) of the - # input sound. To prevent this behaviour (useful when comparing - # different analysis algorithms), set the - # _static_frame_size variable to True - self._static_frame_size = False - - def __del__(self): - simplsms.sms_freeAnalysis(self._analysis_params) - simplsms.sms_freeSpectralPeaks(self._peaks) - simplsms.sms_free() - - # properties - max_frequency = property(lambda self: self.get_max_frequency(), - lambda self, x: self.set_max_frequency(x)) - default_fundamental = property(lambda self: self.get_default_fundamental(), - lambda self, x: self.set_default_fundamental(x)) - max_frame_delay = property(lambda self: self.get_max_frame_delay(), - lambda self, x: self.set_max_frame_delay(x)) - analysis_delay = property(lambda self: self.get_analysis_delay(), - lambda self, x: self.set_analysis_delay(x)) - min_good_frames = property(lambda self: self.get_min_good_frames(), - lambda self, x: self.set_min_good_frames(x)) - min_frequency = property(lambda self: self.get_min_frequency(), - lambda self, x: self.set_min_frequency(x)) - min_peak_amp = property(lambda self: self.get_min_peak_amp(), - lambda self, x: self.set_min_peak_amp(x)) - clean_tracks = property(lambda self: self.get_clean_tracks(), - lambda self, x: self.set_clean_tracks(x)) - format = property(lambda self: self.get_format(), - lambda self, x: self.set_format(x)) - pre_emphasis = property(lambda self: self.get_pre_emphasis(), - lambda self, x: self.set_pre_emphasis(x)) - - def get_max_frequency(self): - return self._analysis_params.fHighestFreq - - def set_max_frequency(self, max_frequency): - self._analysis_params.fHighestFreq = max_frequency - - def get_default_fundamental(self): - return self._analysis_params.fDefaultFundamental - - def set_default_fundamental(self, default_fundamental): - self._analysis_params.fDefaultFundamental = default_fundamental - - def get_max_frame_delay(self): - return self._analysis_params.iMaxDelayFrames - - def set_max_frame_delay(self, max_frame_delay): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.iMaxDelayFrames = max_frame_delay - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_analysis_delay(self): - return self._analysis_params.analDelay - - def set_analysis_delay(self, analysis_delay): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.analDelay = analysis_delay - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_min_good_frames(self): - return self._analysis_params.minGoodFrames - - def set_min_good_frames(self, min_good_frames): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.minGoodFrames = min_good_frames - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_min_frequency(self): - return self._analysis_params.fLowestFundamental - - def set_min_frequency(self, min_frequency): - self._analysis_params.fLowestFundamental = min_frequency - self._analysis_params.fLowestFreq = min_frequency - - def get_min_peak_amp(self): - return self._analysis_params.fMinPeakMag - - def set_min_peak_amp(self, min_peak_amp): - self._analysis_params.fMinPeakMag = min_peak_amp - - def get_clean_tracks(self): - return self._analysis_params.iCleanTracks - - def set_clean_tracks(self, x): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.iCleanTracks = x - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_format(self): - return self._analysis_params.iFormat - - def set_format(self, x): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.iFormat = x - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_pre_emphasis(self): - return self._analysis_params.preEmphasis - - def set_pre_emphasis(self, x): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.preEmphasis = x - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_hop_size(self): - return self._analysis_params.sizeHop - - def set_hop_size(self, hop_size): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.iFrameRate = self.sampling_rate / hop_size - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_max_peaks(self): - return self._analysis_params.maxPeaks - - def set_max_peaks(self, max_peaks): - simplsms.sms_freeAnalysis(self._analysis_params) - simplsms.sms_freeSpectralPeaks(self._peaks) - # make sure the new max is less than SMS_MAX_NPEAKS - if max_peaks > simplsms.SMS_MAX_NPEAKS: - print "Warning: max peaks (" + str(max_peaks) + ")", - print "set to more than the max. no. peaks possible in libsms." - print " Setting to", simplsms.SMS_MAX_NPEAKS, "instead." - max_peaks = simplsms.SMS_MAX_NPEAKS - # set analysis params - self._max_peaks = max_peaks - self._analysis_params.nTracks = max_peaks - self._analysis_params.maxPeaks = max_peaks - self._analysis_params.nGuides = max_peaks - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - # set peaks list - self._peaks = simplsms.SMS_SpectralPeaks(max_peaks) - - def get_sampling_rate(self): - return self._analysis_params.iSamplingRate - - def set_sampling_rate(self, sampling_rate): - self._analysis_params.iSamplingRate = sampling_rate - simplsms.sms_freeAnalysis(self._analysis_params) - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def set_window_size(self, window_size): - self._window_size = window_size - self._analysis_params.iDefaultSizeWindow = window_size - - def get_next_frame_size(self): - return self._analysis_params.sizeNextRead - - def find_peaks_in_frame(self, frame): - "Find and return all spectral peaks in a given frame of audio" - current_peaks = [] - num_peaks = simplsms.sms_findPeaks(frame.audio, - self._analysis_params, - self._peaks) - if num_peaks > 0: - amps = np.zeros(num_peaks, dtype=simpl.dtype) - freqs = np.zeros(num_peaks, dtype=simpl.dtype) - phases = np.zeros(num_peaks, dtype=simpl.dtype) - self._peaks.getFreq(freqs) - self._peaks.getMag(amps) - self._peaks.getPhase(phases) - for i in range(num_peaks): - p = simpl.Peak() - p.amplitude = amps[i] - p.frequency = freqs[i] - p.phase = phases[i] - current_peaks.append(p) - return current_peaks - - def find_peaks(self, audio): - """ - Find and return all spectral peaks in a given audio signal. - If the signal contains more than 1 frame worth of audio, - it will be broken up into separate frames, with a list of - peaks returned for each frame. - """ - # TODO: This hops by frame size rather than hop size in order to - # make sure the results are the same as with libsms. Make sure - # we have the same number of frames as the other algorithms. - self._analysis_params.iSizeSound = len(audio) - self.frames = [] - pos = 0 - # account for SMS analysis delay - # need an extra (max_frame_delay - 1) frames - num_samples = (len(audio) - self.hop_size) + ((self.max_frame_delay - 1) * self.hop_size) - while pos < num_samples: - # get the next frame size - if not self._static_frame_size: - self.frame_size = self.get_next_frame_size() - # get the next frame - frame = simpl.Frame() - frame.size = self.frame_size - frame.audio = audio[pos:pos + self.frame_size] - # find peaks - frame.peaks = self.find_peaks_in_frame(frame) - self.frames.append(frame) - pos += self.frame_size - return self.frames - - -class SMSPartialTracking(simpl.PartialTracking): - "Partial tracking using SMS" - - def __init__(self): - simpl.PartialTracking.__init__(self) - simplsms.sms_init() - self._analysis_params = simplsms.SMS_AnalParams() - simplsms.sms_initAnalParams(self._analysis_params) - self._analysis_params.iSamplingRate = self.sampling_rate - self._analysis_params.fHighestFreq = 20000 - self._analysis_params.iMaxDelayFrames = 4 # libsms minimum - self._analysis_params.analDelay = 0 - self._analysis_params.minGoodFrames = 1 - self._analysis_params.iCleanTracks = 0 - self._analysis_params.iFormat = simplsms.SMS_FORMAT_HP - self._analysis_params.nTracks = self._max_partials - self._analysis_params.nGuides = self._max_partials - self._analysis_params.preEmphasis = 0 - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - self._sms_header = simplsms.SMS_Header() - simplsms.sms_fillHeader(self._sms_header, self._analysis_params, "simpl") - self._analysis_frame = simplsms.SMS_Data() - simplsms.sms_allocFrameH(self._sms_header, self._analysis_frame) - - def __del__(self): - simplsms.sms_freeAnalysis(self._analysis_params) - simplsms.sms_freeFrame(self._analysis_frame) - simplsms.sms_free() - - # properties - max_frequency = property(lambda self: self.get_max_frequency(), - lambda self, x: self.set_max_frequency(x)) - default_fundamental = property(lambda self: self.get_default_fundamental(), - lambda self, x: self.set_default_fundamental(x)) - max_frame_delay = property(lambda self: self.get_max_frame_delay(), - lambda self, x: self.set_max_frame_delay(x)) - analysis_delay = property(lambda self: self.get_analysis_delay(), - lambda self, x: self.set_analysis_delay(x)) - min_good_frames = property(lambda self: self.get_min_good_frames(), - lambda self, x: self.set_min_good_frames(x)) - clean_tracks = property(lambda self: self.get_clean_tracks(), - lambda self, x: self.set_clean_tracks(x)) - format = property(lambda self: self.get_format(), - lambda self, x: self.set_format(x)) - pre_emphasis = property(lambda self: self.get_pre_emphasis(), - lambda self, x: self.set_pre_emphasis(x)) - - def get_max_frequency(self): - return self._analysis_params.fHighestFreq - - def set_max_frequency(self, max_frequency): - self._analysis_params.fHighestFreq = max_frequency - - def get_default_fundamental(self): - return self._analysis_params.fDefaultFundamental - - def set_default_fundamental(self, default_fundamental): - self._analysis_params.fDefaultFundamental = default_fundamental - - def get_max_frame_delay(self): - return self._analysis_params.iMaxDelayFrames - - def set_max_frame_delay(self, max_frame_delay): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.iMaxDelayFrames = max_frame_delay - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_analysis_delay(self): - return self._analysis_params.analDelay - - def set_analysis_delay(self, x): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.analDelay = x - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_min_good_frames(self): - return self._analysis_params.minGoodFrames - - def set_min_good_frames(self, x): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.minGoodFrames = x - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_clean_tracks(self): - return self._analysis_params.iCleanTracks - - def set_clean_tracks(self, x): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.iCleanTracks = x - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_format(self): - return self._analysis_params.iFormat - - def set_format(self, x): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.iFormat = x - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_pre_emphasis(self): - return self._analysis_params.preEmphasis - - def set_pre_emphasis(self, x): - simplsms.sms_freeAnalysis(self._analysis_params) - self._analysis_params.preEmphasis = x - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - - def get_max_partials(self): - return self._analysis_params.nTracks - - def set_max_partials(self, max_partials): - simplsms.sms_freeAnalysis(self._analysis_params) - simplsms.sms_freeFrame(self._analysis_frame) - self._max_partials = max_partials - self._analysis_params.maxPeaks = max_partials - self._analysis_params.nTracks = max_partials - self._analysis_params.nGuides = max_partials - if simplsms.sms_initAnalysis(self._analysis_params) != 0: - raise Exception("Error allocating memory for analysis_params") - simplsms.sms_fillHeader(self._sms_header, self._analysis_params, "simpl") - simplsms.sms_allocFrameH(self._sms_header, self._analysis_frame) - - def update_partials(self, frame): - "Streamable (real-time) partial-tracking." - # load Peak amplitudes, frequencies and phases into arrays - num_peaks = len(frame.peaks) - amps = np.zeros(num_peaks, dtype=simpl.dtype) - freqs = np.zeros(num_peaks, dtype=simpl.dtype) - phases = np.zeros(num_peaks, dtype=simpl.dtype) - for i in range(num_peaks): - peak = frame.peaks[i] - amps[i] = peak.amplitude - freqs[i] = peak.frequency - phases[i] = peak.phase - # set peaks in SMS_AnalParams structure - simplsms.sms_setPeaks(self._analysis_params, amps, freqs, phases) - # SMS partial tracking - simplsms.sms_findPartials(self._analysis_frame, self._analysis_params) - # read values back into amps, freqs, phases - amps = np.zeros(self.max_partials, dtype=simpl.dtype) - freqs = np.zeros(self.max_partials, dtype=simpl.dtype) - phases = np.zeros(self.max_partials, dtype=simpl.dtype) - self._analysis_frame.getSinAmp(amps) - self._analysis_frame.getSinFreq(freqs) - self._analysis_frame.getSinPhase(phases) - peaks = [] - for i in range(self.max_partials): - p = simpl.Peak() - p.amplitude = amps[i] - p.frequency = freqs[i] - p.phase = phases[i] - peaks.append(p) - return peaks - - def find_partials(self, frames): - """Find partials from the sinusoidal peaks in a list of Frames""" - self.frames = [] - for frame in frames: - frame.partials = self.update_partials(frame) - self.frames.append(frame) - # account for SMS analysis delay - # the first extra (max_frame_delay) frames are blank - if len(self.frames) > (self.max_frame_delay): - self.frames = self.frames[self.max_frame_delay:] - return self.frames - - -class SMSSynthesis(simpl.Synthesis): - "Sinusoidal resynthesis using SMS" - - def __init__(self): - simpl.Synthesis.__init__(self) - simplsms.sms_init() - self._synth_params = simplsms.SMS_SynthParams() - simplsms.sms_initSynthParams(self._synth_params) - self._synth_params.iSamplingRate = self._sampling_rate - self._synth_params.iDetSynthType = simplsms.SMS_DET_SIN - self._synth_params.iSynthesisType = simplsms.SMS_STYPE_DET - self._synth_params.iStochasticType = simplsms.SMS_STOC_NONE - self._synth_params.sizeHop = self._hop_size - self._synth_params.nTracks = self._max_partials - self._synth_params.deEmphasis = 0 - simplsms.sms_initSynth(self._synth_params) - self._current_frame = np.zeros(self._hop_size, dtype=simpl.dtype) - self._analysis_frame = simplsms.SMS_Data() - simplsms.sms_allocFrame(self._analysis_frame, self.max_partials, - self.num_stochastic_coeffs, 1, - self.stochastic_type, 0) - - def __del__(self): - simplsms.sms_freeFrame(self._analysis_frame) - simplsms.sms_freeSynth(self._synth_params) - simplsms.sms_free() - - # properties - synthesis_type = property(lambda self: self.get_synthesis_type(), - lambda self, x: self.set_synthesis_type(x)) - det_synthesis_type = property(lambda self: self.get_det_synthesis_type(), - lambda self, x: self.set_det_synthesis_type(x)) - num_stochastic_coeffs = property(lambda self: self.get_num_stochastic_coeffs(), - lambda self, x: self.set_num_stochastic_coeffs(x)) - stochastic_type = property(lambda self: self.get_stochastic_type(), - lambda self, x: self.set_stochastic_type(x)) - original_sampling_rate = property(lambda self: self.get_original_sampling_rate(), - lambda self, x: self.set_original_sampling_rate(x)) - original_hop_size = property(lambda self: self.get_original_hop_size(), - lambda self, x: self.set_original_hop_size(x)) - - def get_hop_size(self): - return self._synth_params.sizeHop - - def set_hop_size(self, hop_size): - simplsms.sms_freeSynth(self._synth_params) - self._synth_params.sizeHop = hop_size - simplsms.sms_initSynth(self._synth_params) - self._current_frame = np.zeros(hop_size, dtype=simpl.dtype) - - def get_max_partials(self): - return self._synth_params.nTracks - - def set_max_partials(self, max_partials): - simplsms.sms_freeSynth(self._synth_params) - simplsms.sms_freeFrame(self._analysis_frame) - self._synth_params.nTracks = max_partials - simplsms.sms_initSynth(self._synth_params) - simplsms.sms_allocFrame(self._analysis_frame, max_partials, - self.num_stochastic_coeffs, 1, - self.stochastic_type, 0) - - def get_sampling_rate(self): - return self._synth_params.iSamplingRate - - def set_sampling_rate(self, sampling_rate): - self._synth_params.iSamplingRate = sampling_rate - - def get_synthesis_type(self): - return self._synth_params.iSynthesisType - - def set_synthesis_type(self, synthesis_type): - self._synth_params.iSynthesisType = synthesis_type - - def get_det_synthesis_type(self): - return self._synth_params.iDetSynthesisType - - def set_det_synthesis_type(self, det_synthesis_type): - self._synth_params.iDetSynthType = det_synthesis_type - - def get_num_stochastic_coeffs(self): - return self._synth_params.nStochasticCoeff - - def set_num_stochastic_coeffs(self, num_stochastic_coeffs): - self._synth_params.nStochasticCoeff = num_stochastic_coeffs - simplsms.sms_freeFrame(self._analysis_frame) - simplsms.sms_allocFrame(self._analysis_frame, self.max_partials, - num_stochastic_coeffs, 1, - self.stochastic_type, 0) - - def get_stochastic_type(self): - return self._synth_params.iStochasticType - - def set_stochastic_type(self, stochastic_type): - simplsms.sms_freeSynth(self._synth_params) - simplsms.sms_freeFrame(self._analysis_frame) - self._synth_params.iStochasticType = stochastic_type - simplsms.sms_initSynth(self._synth_params) - simplsms.sms_allocFrame(self._analysis_frame, self.max_partials, - self.num_stochastic_coeffs, 1, - stochastic_type, 0) - - def get_original_sampling_rate(self): - return self._synth_params.iOriginalSRate - - def set_original_sampling_rate(self, sampling_rate): - self._synth_params.iOriginalSRate = sampling_rate - - def get_original_hop_size(self): - return self._synth_params.origSizeHop - - def set_original_hop_size(self, hop_size): - self._synth_params.origSizeHop = hop_size - - def synth_frame(self, frame): - "Synthesises a frame of audio" - amps = np.zeros(self.max_partials, dtype=simpl.dtype) - freqs = np.zeros(self.max_partials, dtype=simpl.dtype) - phases = np.zeros(self.max_partials, dtype=simpl.dtype) - num_partials = min(self.max_partials, len(frame.partials)) - for i in range(num_partials): - amps[i] = frame.partials[i].amplitude - freqs[i] = frame.partials[i].frequency - phases[i] = frame.partials[i].phase - self._analysis_frame.setSinAmp(amps) - self._analysis_frame.setSinFreq(freqs) - self._analysis_frame.setSinPha(phases) - simplsms.sms_synthesize(self._analysis_frame, - self._current_frame, - self._synth_params) - return self._current_frame - - -class SMSResidual(simpl.Residual): - "SMS residual component" - - def __init__(self): - simpl.Residual.__init__(self) - simplsms.sms_init() - self._residual_params = simplsms.SMS_ResidualParams() - simplsms.sms_initResidualParams(self._residual_params) - self._residual_params.hopSize = self._hop_size - simplsms.sms_initResidual(self._residual_params) - - def __del__(self): - simplsms.sms_freeResidual(self._residual_params) - simplsms.sms_free() - - def get_hop_size(self): - return self._residual_params.hopSize - - def set_hop_size(self, hop_size): - simplsms.sms_freeResidual(self._residual_params) - self._residual_params.hopSize = hop_size - simplsms.sms_initResidual(self._residual_params) - - def residual_frame(self, synth, original): - "Computes the residual signal for a frame of audio" - simplsms.sms_findResidual(synth, original, self._residual_params) - residual = np.zeros(self._residual_params.hopSize, dtype=simpl.dtype) - self._residual_params.getResidual(residual) - return residual - - def find_residual(self, synth, original): - "Calculate and return the residual signal" - num_frames = len(original) / self.hop_size - residual = np.array([], dtype=simpl.dtype) - sample_offset = 0 - - for i in range(num_frames): - synth_frame = synth[sample_offset:sample_offset + self.hop_size] - original_frame = original[sample_offset:sample_offset + self.hop_size] - residual = np.hstack(( - residual, self.residual_frame(synth_frame, original_frame) - )) - sample_offset += self.hop_size - return residual - - def synth_frame(self, synth, original): - "Calculate and return one frame of the synthesised residual signal" - residual = self.residual_frame(synth, original) - approx = np.zeros(self._residual_params.hopSize, dtype=simpl.dtype) - simplsms.sms_approxResidual(residual, approx, self._residual_params) - return approx diff --git a/tests/test_base.py b/tests/test_base.py index ce4297e..1fe5881 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,7 +1,7 @@ import os import numpy as np -import scipy.io.wavfile as wavfile from nose.tools import assert_almost_equals +import simpl import simpl.base as base float_precision = 5 @@ -74,9 +74,7 @@ class TestFrame(object): class TestPeakDetection(object): @classmethod def setup_class(cls): - cls.audio = wavfile.read(audio_path)[1] - cls.audio = np.asarray(cls.audio, dtype=np.double) - cls.audio /= np.max(cls.audio) + cls.audio = simpl.read_wav(audio_path)[0] def test_peak_detection(self): pd = base.PeakDetection() @@ -89,9 +87,7 @@ class TestPeakDetection(object): class TestPartialTracking(object): @classmethod def setup_class(cls): - cls.audio = wavfile.read(audio_path)[1] - cls.audio = np.asarray(cls.audio, dtype=np.double) - cls.audio /= np.max(cls.audio) + cls.audio = simpl.read_wav(audio_path)[0] def test_partial_tracking(self): pd = base.PeakDetection() @@ -107,9 +103,7 @@ class TestPartialTracking(object): class TestSynthesis(object): @classmethod def setup_class(cls): - cls.audio = wavfile.read(audio_path)[1] - cls.audio = np.asarray(cls.audio, dtype=np.double) - cls.audio /= np.max(cls.audio) + cls.audio = simpl.read_wav(audio_path)[0] def test_synthesis(self): pd = base.PeakDetection() @@ -127,9 +121,7 @@ class TestSynthesis(object): class TestResidual(object): @classmethod def setup_class(cls): - cls.audio = wavfile.read(audio_path)[1] - cls.audio = np.asarray(cls.audio, dtype=np.double) - cls.audio /= np.max(cls.audio) + cls.audio = simpl.read_wav(audio_path)[0] def test_synthesis(self): pd = base.PeakDetection() diff --git a/tests/test_sms.py b/tests/test_sms.py index 5b4cc4d..514ead4 100644 --- a/tests/test_sms.py +++ b/tests/test_sms.py @@ -1,13 +1,19 @@ -import simpl -from simpl import simplsms -import pysms +import os import numpy as np -from scipy.io.wavfile import read +import pysms from nose.tools import assert_almost_equals +import simpl +import simpl.simplsms as simplsms + +float_precision = 2 +frame_size = 512 +hop_size = 512 +audio_path = os.path.join( + os.path.dirname(__file__), 'audio/flute.wav' +) + class TestSimplSMS(object): - FLOAT_PRECISION = 2 # number of decimal places to check for accuracy - input_file = 'audio/flute.wav' hop_size = 512 num_frames = 50 num_samples = num_frames * hop_size @@ -15,9 +21,7 @@ class TestSimplSMS(object): max_partials = 10 def get_audio(self): - audio_data = read(self.input_file) - audio = simpl.asarray(audio_data[1]) / 32768.0 - sampling_rate = audio_data[0] + audio, sampling_rate = simpl.read_wav(audio_path) return audio[0:self.num_samples], sampling_rate def pysms_analysis_params(self, sampling_rate): @@ -61,25 +65,25 @@ class TestSimplSMS(object): return analysis_params def pysms_synthesis_params(self, sampling_rate): - synth_params = pysms.SMS_SynthParams() + synth_params = pysms.SMS_SynthParams() pysms.sms_initSynthParams(synth_params) synth_params.iSamplingRate = sampling_rate synth_params.iSynthesisType = pysms.SMS_STYPE_DET synth_params.iStochasticType = pysms.SMS_STOC_NONE - synth_params.sizeHop = self.hop_size + synth_params.sizeHop = self.hop_size synth_params.nTracks = self.max_peaks synth_params.deEmphasis = 0 return synth_params def test_size_next_read(self): """test_size_next_read - Make sure pysms PeakDetection is calculating + Make sure pysms PeakDetection is calculating the correct value for the size of the next frame.""" audio, sampling_rate = self.get_audio() pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) analysis_params.iMaxDelayFrames = self.num_frames + 1 @@ -106,10 +110,10 @@ class TestSimplSMS(object): dtype=np.float32))) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) - status = pysms.sms_analyze(frame, analysis_data, analysis_params) + status = pysms.sms_analyze(frame, analysis_data, analysis_params) # as the no. of frames of delay is > num_frames, sms_analyze should - # never get around to performing partial tracking, and so the return - # value should be 0 + # never get around to performing partial tracking, and so the + # return value should be 0 assert status == 0 pysms.sms_freeFrame(analysis_data) current_frame += 1 @@ -126,7 +130,6 @@ class TestSimplSMS(object): while current_frame < self.num_frames: pd.frame_size = pd.get_next_frame_size() - #print current_frame, sms_next_read_sizes[current_frame], pd.frame_size assert sms_next_read_sizes[current_frame] == pd.frame_size frame = simpl.Frame() frame.size = pd.frame_size @@ -143,7 +146,7 @@ class TestSimplSMS(object): pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: @@ -172,7 +175,7 @@ class TestSimplSMS(object): dtype=np.float32))) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) - status = pysms.sms_analyze(frame.audio, analysis_data, analysis_params) + status = pysms.sms_analyze(frame.audio, analysis_data, analysis_params) num_partials = analysis_data.nTracks peaks = [] @@ -232,17 +235,19 @@ class TestSimplSMS(object): frame.size = size_new_data frame.audio = audio[sample_offset:sample_offset + size_new_data] if len(frame.audio) < size_new_data: - frame.audio = np.hstack((frame.audio, simpl.zeros(size_new_data - len(frame.audio)))) + frame.audio = np.hstack(( + frame.audio, np.zeros(size_new_data - len(frame.audio), dtype=simpl.dtype) + )) analysis_data = simplsms.SMS_Data() simplsms.sms_allocFrameH(simpl_sms_header, analysis_data) - status = simplsms.sms_analyze(frame.audio, analysis_data, simpl_analysis_params) + status = simplsms.sms_analyze(frame.audio, analysis_data, simpl_analysis_params) num_partials = analysis_data.nTracks peaks = [] if status == 1: - freqs = simpl.zeros(num_partials) - amps = simpl.zeros(num_partials) - phases = simpl.zeros(num_partials) + freqs = np.zeros(num_partials, dtype=simpl.dtype) + amps = np.zeros(num_partials, dtype=simpl.dtype) + phases = np.zeros(num_partials, dtype=simpl.dtype) analysis_data.getSinAmp(amps) analysis_data.getSinFreq(freqs) analysis_data.getSinPhase(phases) @@ -280,15 +285,15 @@ class TestSimplSMS(object): for p in range(len(sms_frames[i].partials)): assert_almost_equals(sms_frames[i].partials[p].amplitude, simplsms_frames[i].partials[p].amplitude, - self.FLOAT_PRECISION) + float_precision) assert_almost_equals(sms_frames[i].partials[p].frequency, simplsms_frames[i].partials[p].frequency, - self.FLOAT_PRECISION) + float_precision) assert_almost_equals(sms_frames[i].partials[p].phase, simplsms_frames[i].partials[p].phase, - self.FLOAT_PRECISION) + float_precision) - def test_multi_sms_peak_detection(self): + def test_multi_sms_peak_detection(self): """test_multi_sms_peak_detection Test that running the same peak detection process twice in a row produces the same results each time. This makes sure that results @@ -314,16 +319,16 @@ class TestSimplSMS(object): frame = audio[sample_offset:sample_offset + size_new_data] analysis_data = simplsms.SMS_Data() simplsms.sms_allocFrameH(sms_header, analysis_data) - status = simplsms.sms_analyze(frame, analysis_data, analysis_params) + status = simplsms.sms_analyze(frame, analysis_data, analysis_params) # as the no. of frames of delay is > num_frames, sms_analyze should - # never get around to performing partial tracking, and so the return - # value should be 0 + # never get around to performing partial tracking, and so the + # return value should be 0 assert status == 0 num_peaks = analysis_data.nTracks frame_peaks = [] - simplsms_freqs = simpl.zeros(num_peaks) - simplsms_amps = simpl.zeros(num_peaks) - simplsms_phases = simpl.zeros(num_peaks) + simplsms_freqs = np.zeros(num_peaks, dtype=simpl.dtype) + simplsms_amps = np.zeros(num_peaks, dtype=simpl.dtype) + simplsms_phases = np.zeros(num_peaks, dtype=simpl.dtype) analysis_data.getSinFreq(simplsms_freqs) analysis_data.getSinAmp(simplsms_amps) analysis_data.getSinPhase(simplsms_phases) @@ -331,7 +336,7 @@ class TestSimplSMS(object): if simplsms_amps[i]: p = simpl.Peak() # convert amplitude back to linear - p.amplitude = 10**(simplsms_amps[i]/20.0) + p.amplitude = 10 ** (simplsms_amps[i] / 20.0) p.frequency = simplsms_freqs[i] p.phase = simplsms_phases[i] frame_peaks.append(p) @@ -364,16 +369,16 @@ class TestSimplSMS(object): frame = audio[sample_offset:sample_offset + size_new_data] analysis_data = simplsms.SMS_Data() simplsms.sms_allocFrameH(sms_header, analysis_data) - status = simplsms.sms_analyze(frame, analysis_data, analysis_params) + status = simplsms.sms_analyze(frame, analysis_data, analysis_params) # as the no. of frames of delay is > num_frames, sms_analyze should - # never get around to performing partial tracking, and so the return - # value should be 0 + # never get around to performing partial tracking, and so the + # return value should be 0 assert status == 0 num_peaks = analysis_data.nTracks frame_peaks = [] - simplsms_freqs = simpl.zeros(num_peaks) - simplsms_amps = simpl.zeros(num_peaks) - simplsms_phases = simpl.zeros(num_peaks) + simplsms_freqs = np.zeros(num_peaks, dtype=simpl.dtype) + simplsms_amps = np.zeros(num_peaks, dtype=simpl.dtype) + simplsms_phases = np.zeros(num_peaks, dtype=simpl.dtype) analysis_data.getSinFreq(simplsms_freqs) analysis_data.getSinAmp(simplsms_amps) analysis_data.getSinPhase(simplsms_phases) @@ -381,7 +386,7 @@ class TestSimplSMS(object): if simplsms_amps[i]: p = simpl.Peak() # convert amplitude back to linear - p.amplitude = 10**(simplsms_amps[i]/20.0) + p.amplitude = 10 ** (simplsms_amps[i] / 20.0) p.frequency = simplsms_freqs[i] p.phase = simplsms_phases[i] frame_peaks.append(p) @@ -399,17 +404,17 @@ class TestSimplSMS(object): assert len(peaks1[f]) == len(peaks2[f]) # make sure that each peak has the same value for p in range(len(peaks1[f])): - assert_almost_equals(peaks1[f][p].frequency, + assert_almost_equals(peaks1[f][p].frequency, peaks2[f][p].frequency, - self.FLOAT_PRECISION) - assert_almost_equals(peaks1[f][p].amplitude, + float_precision) + assert_almost_equals(peaks1[f][p].amplitude, peaks2[f][p].amplitude, - self.FLOAT_PRECISION) - assert_almost_equals(peaks1[f][p].phase, + float_precision) + assert_almost_equals(peaks1[f][p].phase, peaks2[f][p].phase, - self.FLOAT_PRECISION) + float_precision) - def test_multi_simpl_peak_detection(self): + def test_multi_simpl_peak_detection(self): """test_multi_simpl_peak_detection Test that running the simpl peak detection process twice in a row produces the same results each time. This makes sure that results @@ -417,14 +422,14 @@ class TestSimplSMS(object): audio, sampling_rate = self.get_audio() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks - pd.hop_size = self.hop_size + pd.hop_size = self.hop_size frames1 = pd.find_peaks(audio)[0:self.num_frames] del pd # second run audio, sampling_rate = self.get_audio() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks - pd.hop_size = self.hop_size + pd.hop_size = self.hop_size frames2 = pd.find_peaks(audio)[0:self.num_frames] # make sure we have the same number of frames in each run @@ -434,25 +439,25 @@ class TestSimplSMS(object): assert len(frames1[f].peaks) == len(frames2[f].peaks) # make sure that each peak has the same value for p in range(len(frames1[f].peaks)): - assert_almost_equals(frames1[f].peaks[p].frequency, + assert_almost_equals(frames1[f].peaks[p].frequency, frames2[f].peaks[p].frequency, - self.FLOAT_PRECISION) - assert_almost_equals(frames1[f].peaks[p].amplitude, + float_precision) + assert_almost_equals(frames1[f].peaks[p].amplitude, frames2[f].peaks[p].amplitude, - self.FLOAT_PRECISION) - assert_almost_equals(frames1[f].peaks[p].phase, + float_precision) + assert_almost_equals(frames1[f].peaks[p].phase, frames2[f].peaks[p].phase, - self.FLOAT_PRECISION) + float_precision) - def test_peak_detection(self): + def test_peak_detection(self): """test_peak_detection Compare simplsms Peaks with SMS peaks. Exact peak information cannot be retrieved using libsms. Basic peak detection is performed by sms_detectPeaks, but this is called multiple times with different frame sizes by sms_analyze. This peak data cannot be returned from sms_analyze without modifying it, so here - we compare the peaks to a slightly modified version of sms_analyze - from simplsms. The peak values should be the same as those found by + we compare the peaks to a slightly modified version of sms_analyze + from simplsms. The peak values should be the same as those found by the simplsms find_peaks function. Analyses have to be performed separately due to libsms implementation issues.""" audio, sampling_rate = self.get_audio() @@ -475,19 +480,21 @@ class TestSimplSMS(object): size_new_data = analysis_params.sizeNextRead frame = audio[sample_offset:sample_offset + size_new_data] if len(frame) < size_new_data: - frame = np.hstack((frame, simpl.zeros(size_new_data - len(frame)))) + frame = np.hstack(( + frame, np.zeros(size_new_data - len(frame), dtype=simpl.dtype) + )) analysis_data = simplsms.SMS_Data() simplsms.sms_allocFrameH(sms_header, analysis_data) - status = simplsms.sms_analyze(frame, analysis_data, analysis_params) + status = simplsms.sms_analyze(frame, analysis_data, analysis_params) # as the no. of frames of delay is > num_frames, sms_analyze should - # never get around to performing partial tracking, and so the return - # value should be 0 + # never get around to performing partial tracking, and so the + # return value should be 0 assert status == 0 num_peaks = analysis_data.nTracks frame_peaks = [] - simplsms_freqs = simpl.zeros(num_peaks) - simplsms_amps = simpl.zeros(num_peaks) - simplsms_phases = simpl.zeros(num_peaks) + simplsms_freqs = np.zeros(num_peaks, dtype=simpl.dtype) + simplsms_amps = np.zeros(num_peaks, dtype=simpl.dtype) + simplsms_phases = np.zeros(num_peaks, dtype=simpl.dtype) analysis_data.getSinFreq(simplsms_freqs) analysis_data.getSinAmp(simplsms_amps) analysis_data.getSinPhase(simplsms_phases) @@ -508,7 +515,7 @@ class TestSimplSMS(object): # get simpl peaks pd = simpl.SMSPeakDetection() - pd.hop_size = self.hop_size + pd.hop_size = self.hop_size pd.max_peaks = self.max_peaks current_frame = 0 sample_offset = 0 @@ -520,7 +527,9 @@ class TestSimplSMS(object): frame.size = pd.frame_size frame.audio = audio[sample_offset:sample_offset + pd.frame_size] if len(frame.audio) < pd.frame_size: - frame.audio = np.hstack((frame.audio, simpl.zeros(pd.frame_size - len(frame.audio)))) + frame.audio = np.hstack(( + frame.audio, np.zeros(pd.frame_size - len(frame.audio), dtype=simpl.dtype) + )) simpl_peaks.append(pd.find_peaks_in_frame(frame)) sample_offset += pd.frame_size current_frame += 1 @@ -539,13 +548,13 @@ class TestSimplSMS(object): sms_peak = sms_frame[peak_number] simpl_peak = simpl_frame[peak_number] assert_almost_equals(sms_peak.amplitude, simpl_peak.amplitude, - self.FLOAT_PRECISION) + float_precision) assert_almost_equals(sms_peak.frequency, simpl_peak.frequency, - self.FLOAT_PRECISION) + float_precision) assert_almost_equals(sms_peak.phase, simpl_peak.phase, - self.FLOAT_PRECISION) + float_precision) - def test_multi_pysms_analyze(self): + def test_multi_pysms_analyze(self): """test_multi_pysms_analyze Test that running the pysms sms_analyze function twice in a row produces the same results each time. This makes sure that results @@ -554,7 +563,7 @@ class TestSimplSMS(object): pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: @@ -579,7 +588,7 @@ class TestSimplSMS(object): frame = np.array(frame, dtype=np.float32) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) - status = pysms.sms_analyze(frame, analysis_data, analysis_params) + status = pysms.sms_analyze(frame, analysis_data, analysis_params) if status == 1: num_partials = analysis_data.nTracks freqs = np.zeros(num_partials, dtype=np.float32) @@ -605,7 +614,7 @@ class TestSimplSMS(object): pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: @@ -630,7 +639,7 @@ class TestSimplSMS(object): frame = np.array(frame, dtype=np.float32) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) - status = pysms.sms_analyze(frame, analysis_data, analysis_params) + status = pysms.sms_analyze(frame, analysis_data, analysis_params) if status == 1: num_partials = analysis_data.nTracks freqs = np.zeros(num_partials, dtype=np.float32) @@ -657,17 +666,18 @@ class TestSimplSMS(object): assert len(phases1) == len(phases2) for r in range(len(freqs1)): - # in each result, make sure that we have the same number amps, freqs and phases - assert len(freqs1[r]) == len(freqs2[r]) - assert len(amps1[r]) == len(amps2[r]) - assert len(phases1[r]) == len(phases2[r]) - # make sure that each partial has the same value - for p in range(len(freqs1[r])): - assert_almost_equals(freqs1[r][p], freqs2[r][p], self.FLOAT_PRECISION) - assert_almost_equals(amps1[r][p], amps2[r][p], self.FLOAT_PRECISION) - assert_almost_equals(phases1[r][p], phases2[r][p], self.FLOAT_PRECISION) - - def test_multi_simpl_partial_tracking(self): + # in each result, make sure that we have the same number amps, + # freqs and phases + assert len(freqs1[r]) == len(freqs2[r]) + assert len(amps1[r]) == len(amps2[r]) + assert len(phases1[r]) == len(phases2[r]) + # make sure that each partial has the same value + for p in range(len(freqs1[r])): + assert_almost_equals(freqs1[r][p], freqs2[r][p], float_precision) + assert_almost_equals(amps1[r][p], amps2[r][p], float_precision) + assert_almost_equals(phases1[r][p], phases2[r][p], float_precision) + + def test_multi_simpl_partial_tracking(self): """test_multi_simpl_partial_tracking Test that running the simpl peak detection process twice in a row produces the same results each time. This makes sure that results @@ -675,7 +685,7 @@ class TestSimplSMS(object): audio, sampling_rate = self.get_audio() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks - pd.hop_size = self.hop_size + pd.hop_size = self.hop_size peaks = pd.find_peaks(audio)[0:self.num_frames] pt = simpl.SMSPartialTracking() pt.max_partials = self.max_peaks @@ -686,7 +696,7 @@ class TestSimplSMS(object): audio, sampling_rate = self.get_audio() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks - pd.hop_size = self.hop_size + pd.hop_size = self.hop_size peaks = pd.find_peaks(audio)[0:self.num_frames] pt = simpl.SMSPartialTracking() pt.max_partials = self.max_peaks @@ -699,24 +709,24 @@ class TestSimplSMS(object): assert len(frames1[i].partials) == len(frames2[i].partials) # make sure that the peaks in each partial have the same values for p in range(len(frames1[i].partials)): - assert_almost_equals(frames1[i].partials[p].frequency, - frames2[i].partials[p].frequency, - self.FLOAT_PRECISION) - assert_almost_equals(frames1[i].partials[p].amplitude, - frames2[i].partials[p].amplitude, - self.FLOAT_PRECISION) - assert_almost_equals(frames1[i].partials[p].phase, - frames2[i].partials[p].phase, - self.FLOAT_PRECISION) + assert_almost_equals(frames1[i].partials[p].frequency, + frames2[i].partials[p].frequency, + float_precision) + assert_almost_equals(frames1[i].partials[p].amplitude, + frames2[i].partials[p].amplitude, + float_precision) + assert_almost_equals(frames1[i].partials[p].phase, + frames2[i].partials[p].phase, + float_precision) def test_partial_tracking(self): """test_partial_tracking - Compare pysms Partials with SMS partials.""" + Compare pysms Partials with SMS partials.""" audio, sampling_rate = self.get_audio() pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: @@ -744,7 +754,7 @@ class TestSimplSMS(object): pysms.sms_allocFrameH(sms_header, analysis_data) num_partials = analysis_data.nTracks peaks = [] - status = pysms.sms_analyze(frame.audio, analysis_data, analysis_params) + status = pysms.sms_analyze(frame.audio, analysis_data, analysis_params) if status == 1: sms_freqs = np.zeros(num_partials, dtype=np.float32) @@ -793,13 +803,13 @@ class TestSimplSMS(object): for p in range(len(sms_frames[i].partials)): assert_almost_equals(sms_frames[i].partials[p].amplitude, simpl_frames[i].partials[p].amplitude, - self.FLOAT_PRECISION) + float_precision) assert_almost_equals(sms_frames[i].partials[p].frequency, simpl_frames[i].partials[p].frequency, - self.FLOAT_PRECISION) + float_precision) assert_almost_equals(sms_frames[i].partials[p].phase, simpl_frames[i].partials[p].phase, - self.FLOAT_PRECISION) + float_precision) def test_sms_interpolate_frames(self): """test_sms_interpolate_frames @@ -809,7 +819,7 @@ class TestSimplSMS(object): pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) analysis_params.nFrames = self.num_frames @@ -836,7 +846,7 @@ class TestSimplSMS(object): frame = np.array(frame, dtype=np.float32) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) - status = pysms.sms_analyze(frame, analysis_data, analysis_params) + status = pysms.sms_analyze(frame, analysis_data, analysis_params) if status == 1: analysis_frames.append(analysis_data) @@ -861,13 +871,13 @@ class TestSimplSMS(object): interp_frame.getSinFreq(interp_freqs) for i in range(self.max_partials): assert_almost_equals(left_amps[i], interp_amps[i], - self.FLOAT_PRECISION) + float_precision) if left_freqs[i] != 0: assert_almost_equals(left_freqs[i], interp_freqs[i], - self.FLOAT_PRECISION) + float_precision) else: assert_almost_equals(right_freqs[i], interp_freqs[i], - self.FLOAT_PRECISION) + float_precision) pysms.sms_interpolateFrames(left_frame, right_frame, interp_frame, 1) interp_amps = np.zeros(self.max_partials, dtype=np.float32) interp_freqs = np.zeros(self.max_partials, dtype=np.float32) @@ -875,13 +885,13 @@ class TestSimplSMS(object): interp_frame.getSinFreq(interp_freqs) for i in range(self.max_partials): assert_almost_equals(right_amps[i], interp_amps[i], - self.FLOAT_PRECISION) + float_precision) if right_freqs[i] != 0: assert_almost_equals(right_freqs[i], interp_freqs[i], - self.FLOAT_PRECISION) + float_precision) else: assert_almost_equals(left_freqs[i], interp_freqs[i], - self.FLOAT_PRECISION) + float_precision) elif status == -1: raise Exception("AnalysisStoppedEarly") else: @@ -924,7 +934,7 @@ class TestSimplSMS(object): frame = audio[sample_offset:sample_offset + size_new_data] analysis_data = simplsms.SMS_Data() simplsms.sms_allocFrameH(sms_header, analysis_data) - status = simplsms.sms_analyze(frame, analysis_data, analysis_params) + status = simplsms.sms_analyze(frame, analysis_data, analysis_params) if status == 1: analysis_frames.append(analysis_data) @@ -935,41 +945,41 @@ class TestSimplSMS(object): simplsms.sms_interpolateFrames(left_frame, right_frame, interp_frame, 0) # make sure that interp_frame == left_frame # interpolateFrames doesn't interpolate phases so ignore - left_amps = simpl.zeros(self.max_partials) - left_freqs = simpl.zeros(self.max_partials) + left_amps = np.zeros(self.max_partials, dtype=simpl.dtype) + left_freqs = np.zeros(self.max_partials, dtype=simpl.dtype) left_frame.getSinAmp(left_amps) left_frame.getSinFreq(left_freqs) - right_amps = simpl.zeros(self.max_partials) - right_freqs = simpl.zeros(self.max_partials) + right_amps = np.zeros(self.max_partials, dtype=simpl.dtype) + right_freqs = np.zeros(self.max_partials, dtype=simpl.dtype) right_frame.getSinAmp(right_amps) right_frame.getSinFreq(right_freqs) - interp_amps = simpl.zeros(self.max_partials) - interp_freqs = simpl.zeros(self.max_partials) + interp_amps = np.zeros(self.max_partials, dtype=simpl.dtype) + interp_freqs = np.zeros(self.max_partials, dtype=simpl.dtype) interp_frame.getSinAmp(interp_amps) interp_frame.getSinFreq(interp_freqs) for i in range(self.max_partials): assert_almost_equals(left_amps[i], interp_amps[i], - self.FLOAT_PRECISION) + float_precision) if left_freqs[i] != 0: assert_almost_equals(left_freqs[i], interp_freqs[i], - self.FLOAT_PRECISION) + float_precision) else: assert_almost_equals(right_freqs[i], interp_freqs[i], - self.FLOAT_PRECISION) + float_precision) simplsms.sms_interpolateFrames(left_frame, right_frame, interp_frame, 1) - interp_amps = simpl.zeros(self.max_partials) - interp_freqs = simpl.zeros(self.max_partials) + interp_amps = np.zeros(self.max_partials, dtype=simpl.dtype) + interp_freqs = np.zeros(self.max_partials, dtype=simpl.dtype) interp_frame.getSinAmp(interp_amps) interp_frame.getSinFreq(interp_freqs) for i in range(self.max_partials): assert_almost_equals(right_amps[i], interp_amps[i], - self.FLOAT_PRECISION) + float_precision) if right_freqs[i] != 0: assert_almost_equals(right_freqs[i], interp_freqs[i], - self.FLOAT_PRECISION) + float_precision) else: assert_almost_equals(left_freqs[i], interp_freqs[i], - self.FLOAT_PRECISION) + float_precision) elif status == -1: raise Exception("AnalysisStoppedEarly") else: @@ -984,13 +994,13 @@ class TestSimplSMS(object): def test_harmonic_synthesis(self): """test_harmonic_synthesis - Compare pysms synthesised harmonic component with SMS synthesised + Compare pysms synthesised harmonic component with SMS synthesised harmonic component.""" audio, sampling_rate = self.get_audio() pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) analysis_params.nFrames = self.num_frames @@ -1014,7 +1024,7 @@ class TestSimplSMS(object): frame = np.array(frame, dtype=np.float32) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) - status = pysms.sms_analyze(frame, analysis_data, analysis_params) + status = pysms.sms_analyze(frame, analysis_data, analysis_params) if status == 1: analysis_frames.append(analysis_data) current_frame += 1 @@ -1050,7 +1060,7 @@ class TestSimplSMS(object): pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks - pd.hop_size = self.hop_size + pd.hop_size = self.hop_size peaks = pd.find_peaks(audio) pt = simpl.SMSPartialTracking() pt.max_partials = self.max_partials @@ -1063,17 +1073,17 @@ class TestSimplSMS(object): assert len(sms_audio) == len(simpl_audio) for i in range(simpl_audio.size): - assert_almost_equals(sms_audio[i], simpl_audio[i], self.FLOAT_PRECISION) + assert_almost_equals(sms_audio[i], simpl_audio[i], float_precision) def test_harmonic_synthesis_sin(self): """test_harmonic_synthesis_sin - Compare pysms synthesised harmonic component with SMS synthesised + Compare pysms synthesised harmonic component with SMS synthesised harmonic component.""" audio, sampling_rate = self.get_audio() pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: @@ -1100,7 +1110,7 @@ class TestSimplSMS(object): dtype=np.float32))) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) - status = pysms.sms_analyze(frame, analysis_data, analysis_params) + status = pysms.sms_analyze(frame, analysis_data, analysis_params) if status == 1: analysis_frames.append(analysis_data) current_frame += 1 @@ -1137,7 +1147,7 @@ class TestSimplSMS(object): pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks - pd.hop_size = self.hop_size + pd.hop_size = self.hop_size peaks = pd.find_peaks(audio) pt = simpl.SMSPartialTracking() pt.max_partials = self.max_partials @@ -1150,11 +1160,11 @@ class TestSimplSMS(object): assert len(sms_audio) == len(simpl_audio) for i in range(simpl_audio.size): - assert_almost_equals(sms_audio[i], simpl_audio[i], self.FLOAT_PRECISION) + assert_almost_equals(sms_audio[i], simpl_audio[i], float_precision) def test_residual_synthesis(self): """test_residual_synthesis - Compare pysms residual signal with SMS residual""" + Compare pysms residual signal with SMS residual""" # ------------------------------------------- # This test is not finished yet. Skip for now @@ -1166,7 +1176,7 @@ class TestSimplSMS(object): pysms.sms_init() snd_header = pysms.SMS_SndHeader() # Try to open the input file to fill snd_header - if(pysms.sms_openSF(self.input_file, snd_header)): + if(pysms.sms_openSF(audio_path, snd_header)): raise NameError("error opening sound file: " + pysms.sms_errorString()) analysis_params = self.pysms_analysis_params(sampling_rate) analysis_params.nFrames = self.num_frames @@ -1192,10 +1202,10 @@ class TestSimplSMS(object): frame = np.array(frame, dtype=np.float32) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) - status = pysms.sms_analyze(frame, analysis_data, analysis_params) + status = pysms.sms_analyze(frame, analysis_data, analysis_params) analysis_frames.append(analysis_data) if status == -1: - do_analysis = False + do_analysis = False current_frame += 1 sms_header.nFrames = len(analysis_frames) @@ -1235,16 +1245,5 @@ class TestSimplSMS(object): assert len(simpl_residual) == len(sms_residual) for i in range(len(simpl_residual)): - assert_almost_equals(simpl_residual[i], sms_residual[i], - self.FLOAT_PRECISION) - - -if __name__ == "__main__": - # run individual tests programatically - # useful for debugging, particularly with GDB - import nose - argv = [__file__, - "--nocapture", - #__file__ + ":TestSimplSMS.test_residual_synthesis"] - __file__ + ":TestSimplSMS.test_harmonic_synthesis_sin"] - nose.run(argv=argv) + assert_almost_equals(simpl_residual[i], sms_residual[i], + float_precision) -- cgit v1.2.3