summaryrefslogtreecommitdiff
path: root/tests/test_sms.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_sms.py')
-rw-r--r--tests/test_sms.py1266
1 files changed, 1266 insertions, 0 deletions
diff --git a/tests/test_sms.py b/tests/test_sms.py
new file mode 100644
index 0000000..ca51f3f
--- /dev/null
+++ b/tests/test_sms.py
@@ -0,0 +1,1266 @@
+# Copyright (c) 2009 John Glover, National University of Ireland, Maynooth
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import simpl
+from simpl import simplsms
+import pysms
+import numpy as np
+from scipy.io.wavfile import read
+from nose.tools import assert_almost_equals
+
+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
+ max_peaks = 10
+ 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]
+ 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(self.input_file, 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()
+ #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
+ 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(self.input_file, 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, simpl.zeros(size_new_data - len(frame.audio))))
+ 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 = simpl.zeros(num_partials)
+ amps = simpl.zeros(num_partials)
+ phases = simpl.zeros(num_partials)
+ 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,
+ self.FLOAT_PRECISION)
+ assert_almost_equals(sms_frames[i].partials[p].frequency,
+ simplsms_frames[i].partials[p].frequency,
+ self.FLOAT_PRECISION)
+ assert_almost_equals(sms_frames[i].partials[p].phase,
+ simplsms_frames[i].partials[p].phase,
+ self.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 = simpl.zeros(num_peaks)
+ simplsms_amps = simpl.zeros(num_peaks)
+ simplsms_phases = simpl.zeros(num_peaks)
+ 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 = simpl.zeros(num_peaks)
+ simplsms_amps = simpl.zeros(num_peaks)
+ simplsms_phases = simpl.zeros(num_peaks)
+ 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,
+ self.FLOAT_PRECISION)
+ assert_almost_equals(peaks1[f][p].amplitude,
+ peaks2[f][p].amplitude,
+ self.FLOAT_PRECISION)
+ assert_almost_equals(peaks1[f][p].phase,
+ peaks2[f][p].phase,
+ self.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,
+ self.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,
+ frames2[f].peaks[p].phase,
+ self.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, simpl.zeros(size_new_data - len(frame))))
+ 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 = simpl.zeros(num_peaks)
+ simplsms_amps = simpl.zeros(num_peaks)
+ simplsms_phases = simpl.zeros(num_peaks)
+ 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, simpl.zeros(pd.frame_size - len(frame.audio))))
+ 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,
+ self.FLOAT_PRECISION)
+ assert_almost_equals(sms_peak.frequency, simpl_peak.frequency,
+ self.FLOAT_PRECISION)
+ assert_almost_equals(sms_peak.phase, simpl_peak.phase,
+ self.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(self.input_file, 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(self.input_file, 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], 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):
+ """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,
+ 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)
+
+ 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(self.input_file, 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,
+ self.FLOAT_PRECISION)
+ assert_almost_equals(sms_frames[i].partials[p].frequency,
+ simpl_frames[i].partials[p].frequency,
+ self.FLOAT_PRECISION)
+ assert_almost_equals(sms_frames[i].partials[p].phase,
+ simpl_frames[i].partials[p].phase,
+ self.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(self.input_file, 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],
+ self.FLOAT_PRECISION)
+ if left_freqs[i] != 0:
+ assert_almost_equals(left_freqs[i], interp_freqs[i],
+ self.FLOAT_PRECISION)
+ else:
+ assert_almost_equals(right_freqs[i], interp_freqs[i],
+ self.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],
+ self.FLOAT_PRECISION)
+ if right_freqs[i] != 0:
+ assert_almost_equals(right_freqs[i], interp_freqs[i],
+ self.FLOAT_PRECISION)
+ else:
+ assert_almost_equals(left_freqs[i], interp_freqs[i],
+ self.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 = simpl.zeros(self.max_partials)
+ left_freqs = simpl.zeros(self.max_partials)
+ 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_frame.getSinAmp(right_amps)
+ right_frame.getSinFreq(right_freqs)
+ interp_amps = simpl.zeros(self.max_partials)
+ interp_freqs = simpl.zeros(self.max_partials)
+ 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)
+ if left_freqs[i] != 0:
+ assert_almost_equals(left_freqs[i], interp_freqs[i],
+ self.FLOAT_PRECISION)
+ else:
+ assert_almost_equals(right_freqs[i], interp_freqs[i],
+ self.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_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)
+ if right_freqs[i] != 0:
+ assert_almost_equals(right_freqs[i], interp_freqs[i],
+ self.FLOAT_PRECISION)
+ else:
+ assert_almost_equals(left_freqs[i], interp_freqs[i],
+ self.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(self.input_file, 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], self.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(self.input_file, 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], self.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(self.input_file, 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],
+ 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)