import os import numpy as np import pysms from nose.tools import assert_almost_equals import simpl import simpl.simplsms as simplsms float_precision = 2 audio_path = os.path.join( os.path.dirname(__file__), 'audio/flute.wav' ) class TestSimplSMS(object): hop_size = 512 num_frames = 50 num_samples = num_frames * hop_size max_peaks = 10 max_partials = 10 def get_audio(self): audio, sampling_rate = simpl.read_wav(audio_path) return audio[0:self.num_samples], sampling_rate def pysms_analysis_params(self, sampling_rate): analysis_params = pysms.SMS_AnalParams() pysms.sms_initAnalParams(analysis_params) analysis_params.iSamplingRate = sampling_rate analysis_params.iFrameRate = sampling_rate / self.hop_size analysis_params.iWindowType = pysms.SMS_WIN_HAMMING analysis_params.fDefaultFundamental = 100 analysis_params.fHighestFreq = 20000 analysis_params.iFormat = pysms.SMS_FORMAT_HP analysis_params.nTracks = self.max_peaks analysis_params.peakParams.iMaxPeaks = self.max_peaks analysis_params.nGuides = self.max_peaks analysis_params.iMaxDelayFrames = 4 analysis_params.analDelay = 0 analysis_params.minGoodFrames = 1 analysis_params.iCleanTracks = 0 analysis_params.iStochasticType = pysms.SMS_STOC_NONE analysis_params.preEmphasis = 0 return analysis_params def simplsms_analysis_params(self, sampling_rate): analysis_params = simplsms.SMS_AnalParams() simplsms.sms_initAnalParams(analysis_params) analysis_params.iSamplingRate = sampling_rate analysis_params.iFrameRate = sampling_rate / self.hop_size analysis_params.iWindowType = simplsms.SMS_WIN_HAMMING analysis_params.fDefaultFundamental = 100 analysis_params.fHighestFreq = 20000 analysis_params.iFormat = simplsms.SMS_FORMAT_HP analysis_params.nTracks = self.max_peaks analysis_params.maxPeaks = self.max_peaks analysis_params.nGuides = self.max_peaks analysis_params.iMaxDelayFrames = 4 analysis_params.analDelay = 0 analysis_params.minGoodFrames = 1 analysis_params.iCleanTracks = 0 analysis_params.iStochasticType = simplsms.SMS_STOC_NONE analysis_params.preEmphasis = 0 return analysis_params def pysms_synthesis_params(self, sampling_rate): 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.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 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(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 if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: raise Exception("Error allocating memory for analysis_params") analysis_params.nFrames = self.num_frames sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") sample_offset = 0 pysms_size_new_data = 0 current_frame = 0 sms_next_read_sizes = [] while current_frame < self.num_frames: sms_next_read_sizes.append(analysis_params.sizeNextRead) sample_offset += pysms_size_new_data pysms_size_new_data = analysis_params.sizeNextRead # convert frame to floats for libsms frame = audio[sample_offset:sample_offset + pysms_size_new_data] frame = np.array(frame, dtype=np.float32) if len(frame) < pysms_size_new_data: frame = np.hstack((frame, np.zeros(pysms_size_new_data - len(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) # 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 assert status == 0 pysms.sms_freeFrame(analysis_data) current_frame += 1 pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_free() pd = simpl.SMSPeakDetection() pd.hop_size = self.hop_size pd.max_peaks = self.max_peaks current_frame = 0 sample_offset = 0 while current_frame < self.num_frames: pd.frame_size = pd.get_next_frame_size() assert sms_next_read_sizes[current_frame] == pd.frame_size frame = simpl.Frame() frame.size = pd.frame_size frame.audio = audio[sample_offset:sample_offset + pd.frame_size] pd.find_peaks_in_frame(frame) sample_offset += pd.frame_size current_frame += 1 def test_sms_analyze(self): """test_sms_analyze Make sure that the simplsms.sms_analyze function does the same thing as the sms_analyze function from libsms.""" 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(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: raise Exception("Error allocating memory for analysis_params") analysis_params.nFrames = self.num_frames analysis_params.iSizeSound = self.num_samples sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") sample_offset = 0 size_new_data = 0 current_frame = 0 sms_frames = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead # convert frame to floats for libsms frame = simpl.Frame() frame.size = size_new_data frame.audio = np.array(audio[sample_offset:sample_offset + size_new_data], dtype=np.float32) if len(frame.audio) < size_new_data: frame.audio = np.hstack((frame.audio, np.zeros(size_new_data - len(frame.audio), 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) num_partials = analysis_data.nTracks peaks = [] if status == 1: sms_amps = np.zeros(num_partials, dtype=np.float32) sms_freqs = np.zeros(num_partials, dtype=np.float32) sms_phases = np.zeros(num_partials, dtype=np.float32) analysis_data.getSinFreq(sms_freqs) analysis_data.getSinAmp(sms_amps) analysis_data.getSinPhase(sms_phases) for i in range(num_partials): p = simpl.Peak() p.amplitude = sms_amps[i] p.frequency = sms_freqs[i] p.phase = sms_phases[i] peaks.append(p) else: for i in range(num_partials): p = simpl.Peak() p.amplitude = 0.0 p.frequency = 0.0 p.phase = 0.0 peaks.append(p) if status == -1: do_analysis = False frame.partials = peaks sms_frames.append(frame) pysms.sms_freeFrame(analysis_data) current_frame += 1 pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_free() audio, sampling_rate = self.get_audio() simplsms.sms_init() simpl_analysis_params = self.simplsms_analysis_params(sampling_rate) if simplsms.sms_initAnalysis(simpl_analysis_params) != 0: raise Exception("Error allocating memory for analysis_params") simpl_analysis_params.nFrames = self.num_frames simpl_analysis_params.iSizeSound = self.num_samples simpl_sms_header = simplsms.SMS_Header() simplsms.sms_fillHeader(simpl_sms_header, simpl_analysis_params, "simplsms") sample_offset = 0 size_new_data = 0 current_frame = 0 simplsms_frames = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = simpl_analysis_params.sizeNextRead frame = simpl.Frame() 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, 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) num_partials = analysis_data.nTracks peaks = [] if status == 1: 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) for i in range(num_partials): p = simpl.Peak() p.amplitude = amps[i] p.frequency = freqs[i] p.phase = phases[i] peaks.append(p) else: for i in range(num_partials): p = simpl.Peak() p.amplitude = 0.0 p.frequency = 0.0 p.phase = 0.0 peaks.append(p) if status == -1: do_analysis = False frame.partials = peaks simplsms_frames.append(frame) simplsms.sms_freeFrame(analysis_data) current_frame += 1 simplsms.sms_freeAnalysis(simpl_analysis_params) simplsms.sms_free() # make sure both have the same number of partials assert len(sms_frames) == len(simplsms_frames) # make sure each partial is the same for i in range(len(sms_frames)): assert len(sms_frames[i].partials) == len(simplsms_frames[i].partials) for p in range(len(sms_frames[i].partials)): assert_almost_equals(sms_frames[i].partials[p].amplitude, simplsms_frames[i].partials[p].amplitude, float_precision) assert_almost_equals(sms_frames[i].partials[p].frequency, simplsms_frames[i].partials[p].frequency, float_precision) assert_almost_equals(sms_frames[i].partials[p].phase, simplsms_frames[i].partials[p].phase, float_precision) 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 are independent, and also helps to highlight any memory errors.""" audio, sampling_rate = self.get_audio() simplsms.sms_init() analysis_params = self.simplsms_analysis_params(sampling_rate) analysis_params.iMaxDelayFrames = self.num_frames + 1 if simplsms.sms_initAnalysis(analysis_params) != 0: raise Exception("Error allocating memory for analysis_params") analysis_params.nFrames = self.num_frames sms_header = simplsms.SMS_Header() simplsms.sms_fillHeader(sms_header, analysis_params, "simplsms") sample_offset = 0 size_new_data = 0 current_frame = 0 peaks1 = [] while current_frame < self.num_frames: sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead 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) # 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 assert status == 0 num_peaks = analysis_data.nTracks frame_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) for i in range(num_peaks): if simplsms_amps[i]: p = simpl.Peak() # convert amplitude back to linear p.amplitude = 10 ** (simplsms_amps[i] / 20.0) p.frequency = simplsms_freqs[i] p.phase = simplsms_phases[i] frame_peaks.append(p) peaks1.append(frame_peaks) pysms.sms_freeFrame(analysis_data) current_frame += 1 simplsms.sms_freeAnalysis(analysis_params) simplsms.sms_free() # Second run audio, sampling_rate = self.get_audio() simplsms.sms_init() analysis_params = self.simplsms_analysis_params(sampling_rate) analysis_params.iMaxDelayFrames = self.num_frames + 1 if simplsms.sms_initAnalysis(analysis_params) != 0: raise Exception("Error allocating memory for analysis_params") analysis_params.nFrames = self.num_frames sms_header = simplsms.SMS_Header() simplsms.sms_fillHeader(sms_header, analysis_params, "simplsms") sample_offset = 0 size_new_data = 0 current_frame = 0 peaks2 = [] while current_frame < self.num_frames: sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead 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) # 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 assert status == 0 num_peaks = analysis_data.nTracks frame_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) for i in range(num_peaks): if simplsms_amps[i]: p = simpl.Peak() # convert amplitude back to linear p.amplitude = 10 ** (simplsms_amps[i] / 20.0) p.frequency = simplsms_freqs[i] p.phase = simplsms_phases[i] frame_peaks.append(p) peaks2.append(frame_peaks) pysms.sms_freeFrame(analysis_data) current_frame += 1 simplsms.sms_freeAnalysis(analysis_params) simplsms.sms_free() # make sure we have the same number of frames in each run assert len(peaks1) == len(peaks2) for f in range(len(peaks1)): # in each frame, make sure that we have the same number of peaks 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, peaks2[f][p].frequency, float_precision) assert_almost_equals(peaks1[f][p].amplitude, peaks2[f][p].amplitude, float_precision) assert_almost_equals(peaks1[f][p].phase, peaks2[f][p].phase, float_precision) 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 are independent, and also helps to highlight any memory errors.""" audio, sampling_rate = self.get_audio() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks 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 frames2 = pd.find_peaks(audio)[0:self.num_frames] # make sure we have the same number of frames in each run assert len(frames1) == len(frames2) for f in range(len(frames1)): # in each frame, make sure that we have the same number of peaks 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, frames2[f].peaks[p].frequency, float_precision) assert_almost_equals(frames1[f].peaks[p].amplitude, frames2[f].peaks[p].amplitude, float_precision) assert_almost_equals(frames1[f].peaks[p].phase, frames2[f].peaks[p].phase, float_precision) 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 the simplsms find_peaks function. Analyses have to be performed separately due to libsms implementation issues.""" audio, sampling_rate = self.get_audio() simplsms.sms_init() analysis_params = self.simplsms_analysis_params(sampling_rate) analysis_params.iMaxDelayFrames = self.num_frames + 1 if simplsms.sms_initAnalysis(analysis_params) != 0: raise Exception("Error allocating memory for analysis_params") analysis_params.nFrames = self.num_frames sms_header = simplsms.SMS_Header() simplsms.sms_fillHeader(sms_header, analysis_params, "simplsms") sample_offset = 0 size_new_data = 0 current_frame = 0 sms_peaks = [] while current_frame < self.num_frames: sample_offset += size_new_data 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, 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) # 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 assert status == 0 num_peaks = analysis_data.nTracks frame_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) for i in range(num_peaks): if simplsms_amps[i]: p = simpl.Peak() # convert amplitude back to linear p.amplitude = simplsms_amps[i] p.frequency = simplsms_freqs[i] p.phase = simplsms_phases[i] frame_peaks.append(p) sms_peaks.append(frame_peaks) pysms.sms_freeFrame(analysis_data) current_frame += 1 simplsms.sms_freeAnalysis(analysis_params) simplsms.sms_free() # get simpl peaks pd = simpl.SMSPeakDetection() pd.hop_size = self.hop_size pd.max_peaks = self.max_peaks current_frame = 0 sample_offset = 0 simpl_peaks = [] while current_frame < self.num_frames: pd.frame_size = pd.get_next_frame_size() frame = simpl.Frame() 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, 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 # make sure we have the same number of frames assert len(sms_peaks) == len(simpl_peaks) # compare data for each frame for frame_number in range(len(sms_peaks)): sms_frame = sms_peaks[frame_number] simpl_frame = simpl_peaks[frame_number] # make sure we have the same number of peaks in each frame assert len(sms_frame) == len(simpl_frame) # check peak values for peak_number in range(len(sms_frame)): sms_peak = sms_frame[peak_number] simpl_peak = simpl_frame[peak_number] assert_almost_equals(sms_peak.amplitude, simpl_peak.amplitude, float_precision) assert_almost_equals(sms_peak.frequency, simpl_peak.frequency, float_precision) assert_almost_equals(sms_peak.phase, simpl_peak.phase, float_precision) 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 are independent, and also helps to highlight any memory errors.""" 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(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: raise Exception("Error allocating memory for analysis_params") analysis_params.iSizeSound = self.num_samples sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") sample_offset = 0 size_new_data = 0 current_frame = 0 freqs1 = [] amps1 = [] phases1 = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead # convert frame to floats for libsms frame = audio[sample_offset:sample_offset + size_new_data] 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) if status == 1: num_partials = analysis_data.nTracks freqs = np.zeros(num_partials, dtype=np.float32) amps = np.zeros(num_partials, dtype=np.float32) phases = np.zeros(num_partials, dtype=np.float32) analysis_data.getSinFreq(freqs) analysis_data.getSinAmp(amps) analysis_data.getSinPhase(phases) amps1.append(amps) freqs1.append(freqs) phases1.append(phases) elif status == -1: do_analysis = False pysms.sms_freeFrame(analysis_data) current_frame += 1 pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_free() # second run 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(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: raise Exception("Error allocating memory for analysis_params") analysis_params.iSizeSound = self.num_samples sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") sample_offset = 0 size_new_data = 0 current_frame = 0 freqs2 = [] amps2 = [] phases2 = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead # convert frame to floats for libsms frame = audio[sample_offset:sample_offset + size_new_data] 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) if status == 1: num_partials = analysis_data.nTracks freqs = np.zeros(num_partials, dtype=np.float32) amps = np.zeros(num_partials, dtype=np.float32) phases = np.zeros(num_partials, dtype=np.float32) analysis_data.getSinFreq(freqs) analysis_data.getSinAmp(amps) analysis_data.getSinPhase(phases) amps2.append(amps) freqs2.append(freqs) phases2.append(phases) elif status == -1: do_analysis = False pysms.sms_freeFrame(analysis_data) current_frame += 1 pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_free() # make sure we have the same number of results in each run assert len(freqs1) == len(freqs2) assert len(amps1) == len(amps2) 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], 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 are independent, and also helps to highlight any memory errors.""" audio, sampling_rate = self.get_audio() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks pd.hop_size = self.hop_size peaks = pd.find_peaks(audio)[0:self.num_frames] pt = simpl.SMSPartialTracking() pt.max_partials = self.max_peaks frames1 = pt.find_partials(peaks) del pd del pt # second run audio, sampling_rate = self.get_audio() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks pd.hop_size = self.hop_size peaks = pd.find_peaks(audio)[0:self.num_frames] pt = simpl.SMSPartialTracking() pt.max_partials = self.max_peaks frames2 = pt.find_partials(peaks) # make sure we have the same number of partials in each run assert len(frames1) == len(frames2) for i in range(len(frames1)): # make sure each partial is the same length 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, 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.""" 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(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: raise Exception("Error allocating memory for analysis_params") analysis_params.iSizeSound = self.num_samples analysis_params.nFrames = self.num_frames sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") sample_offset = 0 size_new_data = 0 current_frame = 0 sms_frames = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead # convert frame to floats for libsms frame = simpl.Frame() frame.size = size_new_data frame.audio = np.array(audio[sample_offset:sample_offset + size_new_data], dtype=np.float32) analysis_data = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, analysis_data) num_partials = analysis_data.nTracks peaks = [] status = pysms.sms_analyze(frame.audio, analysis_data, analysis_params) if status == 1: sms_freqs = np.zeros(num_partials, dtype=np.float32) sms_amps = np.zeros(num_partials, dtype=np.float32) sms_phases = np.zeros(num_partials, dtype=np.float32) analysis_data.getSinFreq(sms_freqs) analysis_data.getSinAmp(sms_amps) analysis_data.getSinPhase(sms_phases) for i in range(num_partials): p = simpl.Peak() p.amplitude = sms_amps[i] p.frequency = sms_freqs[i] p.phase = sms_phases[i] peaks.append(p) frame.partials = peaks sms_frames.append(frame) current_frame += 1 if status == -1: do_analysis = False pysms.sms_freeFrame(analysis_data) # first frame is blank sms_frames = sms_frames[1:] # free sms memory pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_free() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks pd.hop_size = self.hop_size peaks = pd.find_peaks(audio) pt = simpl.SMSPartialTracking() pt.max_partials = self.max_partials simpl_frames = pt.find_partials(peaks) # make sure both have the same number of partials assert len(sms_frames) == len(simpl_frames) # make sure each partial is the same for i in range(len(sms_frames)): assert len(sms_frames[i].partials) == len(simpl_frames[i].partials) for p in range(len(sms_frames[i].partials)): assert_almost_equals(sms_frames[i].partials[p].amplitude, simpl_frames[i].partials[p].amplitude, float_precision) assert_almost_equals(sms_frames[i].partials[p].frequency, simpl_frames[i].partials[p].frequency, float_precision) assert_almost_equals(sms_frames[i].partials[p].phase, simpl_frames[i].partials[p].phase, float_precision) def test_sms_interpolate_frames(self): """test_sms_interpolate_frames Make sure that sms_interpolateFrames returns the expected values with interpolation factors of 0 and 1.""" 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(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 if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: raise Exception("Error allocating memory for analysis_params") analysis_params.iSizeSound = self.num_samples sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") interp_frame = pysms.SMS_Data() pysms.sms_allocFrameH(sms_header, interp_frame) sample_offset = 0 size_new_data = 0 current_frame = 0 analysis_frames = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead frame = audio[sample_offset:sample_offset + size_new_data] # convert frame to floats for libsms 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) if status == 1: analysis_frames.append(analysis_data) # test interpolateFrames on the last two analysis frames if current_frame == self.num_frames - 1: left_frame = analysis_frames[-2] right_frame = analysis_frames[-1] pysms.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 = np.zeros(self.max_partials, dtype=np.float32) left_freqs = np.zeros(self.max_partials, dtype=np.float32) left_frame.getSinAmp(left_amps) left_frame.getSinFreq(left_freqs) right_amps = np.zeros(self.max_partials, dtype=np.float32) right_freqs = np.zeros(self.max_partials, dtype=np.float32) right_frame.getSinAmp(right_amps) right_frame.getSinFreq(right_freqs) interp_amps = np.zeros(self.max_partials, dtype=np.float32) interp_freqs = np.zeros(self.max_partials, dtype=np.float32) 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], float_precision) if left_freqs[i] != 0: assert_almost_equals(left_freqs[i], interp_freqs[i], float_precision) else: assert_almost_equals(right_freqs[i], interp_freqs[i], 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) 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], float_precision) if right_freqs[i] != 0: assert_almost_equals(right_freqs[i], interp_freqs[i], float_precision) else: assert_almost_equals(left_freqs[i], interp_freqs[i], float_precision) elif status == -1: raise Exception("AnalysisStoppedEarly") else: pysms.sms_freeFrame(analysis_data) current_frame += 1 for frame in analysis_frames: pysms.sms_freeFrame(frame) pysms.sms_freeFrame(interp_frame) pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_free() def test_simplsms_interpolate_frames(self): """test_simplsms_interpolate_frames Make sure that sms_interpolateFrames returns the expected values with interpolation factors of 0 and 1.""" audio, sampling_rate = self.get_audio() simplsms.sms_init() analysis_params = self.simplsms_analysis_params(sampling_rate) analysis_params.nFrames = self.num_frames if simplsms.sms_initAnalysis(analysis_params) != 0: raise Exception("Error allocating memory for analysis_params") analysis_params.iSizeSound = self.num_samples sms_header = simplsms.SMS_Header() simplsms.sms_fillHeader(sms_header, analysis_params, "simplsms") interp_frame = simplsms.SMS_Data() simplsms.sms_allocFrameH(sms_header, interp_frame) sample_offset = 0 size_new_data = 0 current_frame = 0 analysis_frames = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead 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) if status == 1: analysis_frames.append(analysis_data) # test interpolateFrames on the last two analysis frames if current_frame == self.num_frames - 1: left_frame = analysis_frames[-2] right_frame = analysis_frames[-1] 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 = 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 = 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 = 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], float_precision) if left_freqs[i] != 0: assert_almost_equals(left_freqs[i], interp_freqs[i], float_precision) else: assert_almost_equals(right_freqs[i], interp_freqs[i], float_precision) simplsms.sms_interpolateFrames(left_frame, right_frame, interp_frame, 1) 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], float_precision) if right_freqs[i] != 0: assert_almost_equals(right_freqs[i], interp_freqs[i], float_precision) else: assert_almost_equals(left_freqs[i], interp_freqs[i], float_precision) elif status == -1: raise Exception("AnalysisStoppedEarly") else: simplsms.sms_freeFrame(analysis_data) current_frame += 1 for frame in analysis_frames: simplsms.sms_freeFrame(frame) simplsms.sms_freeFrame(interp_frame) simplsms.sms_freeAnalysis(analysis_params) simplsms.sms_free() def test_harmonic_synthesis(self): """test_harmonic_synthesis 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(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 if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: raise Exception("Error allocating memory for analysis_params") analysis_params.iSizeSound = self.num_samples sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") sample_offset = 0 size_new_data = 0 current_frame = 0 analysis_frames = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead frame = audio[sample_offset:sample_offset + size_new_data] # convert frame to floats for libsms 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) if status == 1: analysis_frames.append(analysis_data) current_frame += 1 elif status == 0: pysms.sms_freeFrame(analysis_data) elif status == -1: do_analysis = False pysms.sms_freeFrame(analysis_data) # remove the first frame, it's blank blank_frame = analysis_frames[0] analysis_frames = analysis_frames[1:] pysms.sms_freeFrame(blank_frame) synth_params = self.pysms_synthesis_params(sampling_rate) pysms.sms_initSynth(sms_header, synth_params) synth_samples = np.zeros(synth_params.sizeHop, dtype=np.float32) sms_audio = np.array([], dtype=np.float32) current_frame = 0 while current_frame < len(analysis_frames): pysms.sms_synthesize(analysis_frames[current_frame], synth_samples, synth_params) sms_audio = np.hstack((sms_audio, synth_samples)) current_frame += 1 for frame in analysis_frames: pysms.sms_freeFrame(frame) pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_freeSynth(synth_params) pysms.sms_free() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks pd.hop_size = self.hop_size peaks = pd.find_peaks(audio) pt = simpl.SMSPartialTracking() pt.max_partials = self.max_partials partials = pt.find_partials(peaks) synth = simpl.SMSSynthesis() synth.hop_size = self.hop_size synth.max_partials = self.max_partials synth.det_synthesis_type = simplsms.SMS_DET_IFFT simpl_audio = synth.synth(partials) assert len(sms_audio) == len(simpl_audio) for i in range(simpl_audio.size): 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 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(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: raise Exception("Error allocating memory for analysis_params") analysis_params.iSizeSound = self.num_samples analysis_params.nFrames = self.num_frames sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") sample_offset = 0 size_new_data = 0 current_frame = 0 analysis_frames = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead frame = audio[sample_offset:sample_offset + size_new_data] # convert frame to floats for libsms frame = np.array(frame, dtype=np.float32) if len(frame) < size_new_data: frame = np.hstack((frame, np.zeros(size_new_data - len(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) if status == 1: analysis_frames.append(analysis_data) current_frame += 1 elif status == 0: pysms.sms_freeFrame(analysis_data) elif status == -1: do_analysis = False pysms.sms_freeFrame(analysis_data) # remove the first frame, it's blank blank_frame = analysis_frames[0] analysis_frames = analysis_frames[1:] pysms.sms_freeFrame(blank_frame) synth_params = self.pysms_synthesis_params(sampling_rate) synth_params.iDetSynthType = pysms.SMS_DET_SIN pysms.sms_initSynth(sms_header, synth_params) synth_samples = np.zeros(synth_params.sizeHop, dtype=np.float32) sms_audio = np.array([], dtype=np.float32) current_frame = 0 while current_frame < len(analysis_frames): pysms.sms_synthesize(analysis_frames[current_frame], synth_samples, synth_params) sms_audio = np.hstack((sms_audio, synth_samples)) current_frame += 1 for frame in analysis_frames: pysms.sms_freeFrame(frame) pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_freeSynth(synth_params) pysms.sms_free() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks pd.hop_size = self.hop_size peaks = pd.find_peaks(audio) pt = simpl.SMSPartialTracking() pt.max_partials = self.max_partials partials = pt.find_partials(peaks) synth = simpl.SMSSynthesis() synth.hop_size = self.hop_size synth.max_partials = self.max_partials synth.det_synthesis_type = simplsms.SMS_DET_SIN simpl_audio = synth.synth(partials) assert len(sms_audio) == len(simpl_audio) for i in range(simpl_audio.size): 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""" # ------------------------------------------- # This test is not finished yet. Skip for now from nose.plugins.skip import SkipTest raise SkipTest # ------------------------------------------- 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(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 analysis_params.nStochasticCoeff = 128 analysis_params.iStochasticType = pysms.SMS_STOC_APPROX if pysms.sms_initAnalysis(analysis_params, snd_header) != 0: raise Exception("Error allocating memory for analysis_params") analysis_params.iSizeSound = self.num_samples sms_header = pysms.SMS_Header() pysms.sms_fillHeader(sms_header, analysis_params, "pysms") sample_offset = 0 size_new_data = 0 current_frame = 0 analysis_frames = [] do_analysis = True while do_analysis and (current_frame < self.num_frames): sample_offset += size_new_data size_new_data = analysis_params.sizeNextRead # convert frame to floats for libsms frame = audio[sample_offset:sample_offset + size_new_data] 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) analysis_frames.append(analysis_data) if status == -1: do_analysis = False current_frame += 1 sms_header.nFrames = len(analysis_frames) synth_params = self.pysms_synthesis_params(sampling_rate) synth_params.iStochasticType = pysms.SMS_STOC_APPROX synth_params.iSynthesisType = pysms.SMS_STYPE_STOC pysms.sms_initSynth(sms_header, synth_params) synth_samples = np.zeros(synth_params.sizeHop, dtype=np.float32) sms_residual = np.array([], dtype=np.float32) current_frame = 0 while current_frame < len(analysis_frames): pysms.sms_synthesize(analysis_frames[current_frame], synth_samples, synth_params) sms_residual = np.hstack((sms_residual, synth_samples)) current_frame += 1 for frame in analysis_frames: pysms.sms_freeFrame(frame) pysms.sms_freeAnalysis(analysis_params) pysms.sms_closeSF() pysms.sms_freeSynth(synth_params) pysms.sms_free() pd = simpl.SMSPeakDetection() pd.max_peaks = self.max_peaks pd.hop_size = self.hop_size peaks = pd.find_peaks(audio)[0:self.num_frames] pt = simpl.SMSPartialTracking() pt.max_partials = self.max_partials partials = pt.find_partials(peaks) synth = simpl.SMSSynthesis() synth.hop_size = self.hop_size synth.max_partials = self.max_partials simpl_harmonic = synth.synth(partials) res = simpl.SMSResidual() simpl_residual = res.synth(simpl_harmonic, audio[0:simpl_harmonic.size]) assert len(simpl_residual) == len(sms_residual) for i in range(len(simpl_residual)): assert_almost_equals(simpl_residual[i], sms_residual[i], float_precision)