From 0ecf55c21718ce97384f0c44d797549fce29db12 Mon Sep 17 00:00:00 2001 From: John Glover Date: Fri, 24 Jun 2011 18:21:52 +0100 Subject: Update test file names --- tests/debug.py | 1 - tests/lp.py | 28 - tests/peakdetection.py | 25 - tests/signals.py | 1 - tests/sms.py | 1266 ------------------------------------------- tests/sms_old.py | 137 ----- tests/sndobj.py | 389 ------------- tests/test_lp.py | 28 + tests/test_peakdetection.py | 24 + tests/test_sms.py | 1266 +++++++++++++++++++++++++++++++++++++++++++ tests/test_sms_old.py | 126 +++++ tests/test_sndobj.py | 389 +++++++++++++ 12 files changed, 1833 insertions(+), 1847 deletions(-) delete mode 100644 tests/lp.py delete mode 100644 tests/peakdetection.py delete mode 100644 tests/sms.py delete mode 100644 tests/sms_old.py delete mode 100644 tests/sndobj.py create mode 100644 tests/test_lp.py create mode 100644 tests/test_peakdetection.py create mode 100644 tests/test_sms.py create mode 100644 tests/test_sms_old.py create mode 100644 tests/test_sndobj.py (limited to 'tests') diff --git a/tests/debug.py b/tests/debug.py index 62f3c48..084df72 100644 --- a/tests/debug.py +++ b/tests/debug.py @@ -27,4 +27,3 @@ def print_partials(partials): for peak_number, peak in enumerate(partial.peaks): print peak.frequency, print - diff --git a/tests/lp.py b/tests/lp.py deleted file mode 100644 index 8d80ba2..0000000 --- a/tests/lp.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) 2010 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 - -from simpl import lp -import numpy as np - -class TestLP(object): - - def test_predict(self): - """test_predict""" - coefs = np.array([1,2,3,4,5]) - test_signal = np.ones(5) - predictions = lp.predict(test_signal, coefs, 2) - assert predictions[0] == -sum(coefs) - assert predictions[1] == -sum(coefs[1:])-predictions[0] diff --git a/tests/peakdetection.py b/tests/peakdetection.py deleted file mode 100644 index d98b2b0..0000000 --- a/tests/peakdetection.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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 -import numpy as np -from scipy.io.wavfile import read - -class TestPeakDetection(object): - frame_size = 2048 - hop_size = 512 - max_peaks = 10 - diff --git a/tests/signals.py b/tests/signals.py index 1ebf44e..5b04c03 100644 --- a/tests/signals.py +++ b/tests/signals.py @@ -47,4 +47,3 @@ def sinechirpsine(): audio[i+(section_length*sampling_rate*2)] = amp * np.sin(2 * np.pi * final_freq * t) return audio - diff --git a/tests/sms.py b/tests/sms.py deleted file mode 100644 index ca51f3f..0000000 --- a/tests/sms.py +++ /dev/null @@ -1,1266 +0,0 @@ -# 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) diff --git a/tests/sms_old.py b/tests/sms_old.py deleted file mode 100644 index 00e778d..0000000 --- a/tests/sms_old.py +++ /dev/null @@ -1,137 +0,0 @@ -# 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, M 02111-1307 USA - -import unittest -from pysms import SMS_Header, SMS_Data, SMS_SndHeader, SMS_AnalParams, \ - sms_openSF, sms_errorString, sms_getSound, \ - sms_fillHeader, sms_init, sms_initAnalysis, sms_allocFrameH, \ - sms_freeFrame, sms_freeAnalysis, sms_free -from scipy import zeros, sin, pi, asarray, int16 -from scipy.io.wavfile import read, write -import os -import random -from pylab import plot, show - -TEST_AUDIO_FILE = "Tests.wav" - -# Create a test audio file (1 second of a sine wave at 220 Hz) -test_audio = zeros(44100) -for sample_number in range(test_audio.size): - test_audio[sample_number] = sin(2 * pi * 220 * sample_number / 44100.0) -# convert to int values -test_audio *= 32767 -test_audio = asarray(test_audio, int16) - -def create_test_audio_file(): - "Create a test audio file in the current directory" - write(TEST_AUDIO_FILE, 44100, test_audio) - -def delete_test_audio_file(): - "Delete the test audio file created by the function create_test_audio_file" - os.remove(TEST_AUDIO_FILE) - -class TestSoundIO(unittest.TestCase): - def setUp(self): - self.snd_header = SMS_SndHeader() - - def test_sms_openSF_file_exists(self): - "sms_openSF returns True when trying to open an existing file" - create_test_audio_file() - self.assert_(sms_openSF(TEST_AUDIO_FILE, self.snd_header) == 0) - delete_test_audio_file() - - def test_sms_openSF_file_missing(self): - "sms_openSF returns False when trying to open a file that doesn't exist" - file_path = "" - max_file_names = 1000 - count = 0 - class MaxFilesReached(Exception): pass - # create a path to a non-existent file - while True: - file_path = str(random.randint(0, max_file_names)) + ".wav" - if not os.path.isfile(file_path): - break - if count > max_file_names: - raise MaxFilesReached - count += 1 - # call sms_openSF, should return an error - self.assertRaises(IndexError, sms_openSF, file_path, self.snd_header) - - def test_sms_getSound(self): - "sms_getSound" - create_test_audio_file() - self.assert_(sms_openSF(TEST_AUDIO_FILE, self.snd_header) == 0) - frame_size = 512 - frame = zeros(frame_size).astype('float32') - self.assert_(sms_getSound(self.snd_header, frame, 0) == 0) - # test that values read in are the same as those written (allowing for some rounding errors) - class SampleMismatch(Exception): pass - for sample_number in range(frame_size): - if abs((test_audio[sample_number] / 32768.0) - frame[sample_number] > 0.000001): - raise SampleMismatch - delete_test_audio_file() - -class TestInit(unittest.TestCase): - def setUp(self): - self.snd_header = SMS_SndHeader() - self.sms_header = SMS_Header() - self.data = SMS_Data() - self.analysis_params = SMS_AnalParams() - - def tearDown(self): - sms_freeFrame(self.data) - - def test_sms_fillHeader(self): - "sms_fillHeader copies data from an SMS_AnalParams to an SMS_Header" - data_fields = ["nFrames", "iFormat", "iFrameRate", "iStochasticType", \ - "nTracks", "iSamplingRate", "nStochasticCoeff"] - sms_fillHeader(self.sms_header, self.analysis_params, "") - for field in data_fields: - self.assert_(eval("self.sms_header."+field) == eval("self.analysis_params."+field)) - - def test_sms_init(self): - "sms_init" - self.assert_(sms_init() == 0) - - def test_sms_initAnalysis(self): - "sms_initAnalysis" - create_test_audio_file() - if(sms_openSF(TEST_AUDIO_FILE, self.snd_header)): - raise NameError("error opening sound file: " + sms_errorString()) - self.assert_(sms_initAnalysis(self.analysis_params, self.snd_header) == 0) - delete_test_audio_file() - - def test_sms_allocFrameH(self): - "sms_allocFrameH" - create_test_audio_file() - if(sms_openSF(TEST_AUDIO_FILE, self.snd_header)): - raise NameError("error opening sound file: " + sms_errorString()) - self.assert_(sms_allocFrameH(self.sms_header, self.data) == 0) - delete_test_audio_file() - -class TestAnalysis(unittest.TestCase): - pass -# sms_analyze: -# if called less than delay times should return 0 -# sms_fundDeviation -# sms_peakContinuation -# sms_cleanTracks -# sms_getWindow -# sms_residual -# sms_stocAnalysis - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/tests/sndobj.py b/tests/sndobj.py deleted file mode 100644 index 527a9d7..0000000 --- a/tests/sndobj.py +++ /dev/null @@ -1,389 +0,0 @@ -# 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 unittest -import sndobj -import simpl -from simpl import pysndobj -from scipy.io.wavfile import read -import numpy as np - -FLOAT_PRECISION = 2 # number of decimal places to check for accuracy - -class TestSimplSndObj(unittest.TestCase): - def setUp(self): - self.input_file = 'audio/flute.wav' - - def test_sndobj_numpy(self): - "Test reading and writing numpy data in SndObjs" - frame_size = 2048 - hop_size = 2048 - num_frames = 4 - num_samples = frame_size + (num_frames * hop_size) - - audio_in_data = read(self.input_file) - audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 - audio_in = audio_in[0:num_samples] - frame = simpl.zeros(frame_size) - frame_out = simpl.zeros(hop_size) - audio_out = simpl.array([]) - - input = pysndobj.SndObj() - input.SetVectorSize(frame_size) - - i = 0 - while (i + frame_size) <= num_samples: - frame = audio_in[i:i+frame_size] - input.PushIn(frame) - input.PopOut(frame_out) - audio_out = np.hstack((audio_out, frame_out)) - i += hop_size - - self.assertEqual(audio_in.size, audio_out.size) - for i in range(audio_out.size): - self.assertEqual(audio_in[i], audio_out[i]) - - def test_hammingtable(self): - "Compare sndobj.HammingTable with simplsndobj.HammingTable" - frame_size = 2048 - window1 = sndobj.HammingTable(frame_size, 0.5) - window2 = pysndobj.HammingTable(frame_size, 0.5) - for i in range(frame_size): - self.assertEqual(window1.Lookup(i), window2.Lookup(i)) - - def test_ifgram(self): - "Compare sndobj.IFGram with simplsndobj.IFGram" - frame_size = 2048 - hop_size = 512 - num_frames = 4 - num_samples = frame_size + ((num_frames - 1) * hop_size) - - audio_in_data = read(self.input_file) - audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 - audio_in = audio_in[0:num_samples] - frame = simpl.zeros(frame_size) - - sndobj_input = sndobj.SndObj() - simpl_input = pysndobj.SndObj() - sndobj_input.SetVectorSize(frame_size) - simpl_input.SetVectorSize(frame_size) - sndobj_window = sndobj.HammingTable(frame_size, 0.5) - simpl_window = pysndobj.HammingTable(frame_size, 0.5) - sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) - simpl_ifgram = pysndobj.IFGram(simpl_window, simpl_input, 1, frame_size, hop_size) - - i = 0 - while (i + frame_size) <= num_samples: - frame = audio_in[i:i+frame_size] - sndobj_input.PushIn(frame) - simpl_input.PushIn(frame) - sndobj_ifgram.DoProcess() - simpl_ifgram.DoProcess() - for j in range(frame_size): - self.assertAlmostEquals(sndobj_ifgram.Output(j), simpl_ifgram.Output(j), - places = FLOAT_PRECISION) - i += hop_size - - def test_sinanal(self): - "Compare sndobj.SinAnal with simplsndobj.SinAnal" - frame_size = 2048 - hop_size = 512 - max_tracks = 20 - num_frames = 4 - num_samples = frame_size + ((num_frames - 1) * hop_size) - - audio_in_data = read(self.input_file) - audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 - audio_in = audio_in[0:num_samples] - frame = simpl.zeros(frame_size) - - sndobj_input = sndobj.SndObj() - simpl_input = pysndobj.SndObj() - sndobj_input.SetVectorSize(frame_size) - simpl_input.SetVectorSize(frame_size) - sndobj_window = sndobj.HammingTable(frame_size, 0.5) - simpl_window = pysndobj.HammingTable(frame_size, 0.5) - sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) - simpl_ifgram = pysndobj.IFGram(simpl_window, simpl_input, 1, frame_size, hop_size) - sndobj_sinmod = sndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) - simpl_sinmod = pysndobj.SinAnal(simpl_ifgram, 0.003, max_tracks, 1, 3) - - i = 0 - while (i + frame_size) <= num_samples: - frame = audio_in[i:i+frame_size] - sndobj_input.PushIn(frame) - simpl_input.PushIn(frame) - sndobj_ifgram.DoProcess() - simpl_ifgram.DoProcess() - sndobj_sinmod.DoProcess() - simpl_sinmod.DoProcess() - for j in range(max_tracks * 3): - self.assertAlmostEquals(sndobj_sinmod.Output(j), simpl_sinmod.Output(j), - places = FLOAT_PRECISION) - i += hop_size - - def test_adsyn_doprocess(self): - "Compare sndobj.AdSyn with simplsndobj.AdSyn" - frame_size = 2048 - hop_size = 512 - max_tracks = 20 - num_frames = 4 - num_samples = frame_size + ((num_frames - 1) * hop_size) - - audio_in_data = read(self.input_file) - audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 - audio_in = audio_in[0:num_samples] - frame = simpl.zeros(frame_size) - sndobj_frame_out = simpl.zeros(hop_size) - simpl_frame_out = simpl.zeros(hop_size) - sndobj_audio_out = simpl.array([]) - simpl_audio_out = simpl.array([]) - - sndobj_input = sndobj.SndObj() - simpl_input = pysndobj.SndObj() - sndobj_input.SetVectorSize(frame_size) - simpl_input.SetVectorSize(frame_size) - sndobj_window = sndobj.HammingTable(frame_size, 0.5) - simpl_window = pysndobj.HammingTable(frame_size, 0.5) - sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) - simpl_ifgram = pysndobj.IFGram(simpl_window, simpl_input, 1, frame_size, hop_size) - sndobj_sinmod = sndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) - simpl_sinmod = pysndobj.SinAnal(simpl_ifgram, 0.003, max_tracks, 1, 3) - sndobj_table = sndobj.HarmTable(10000, 1, 1, 0.25) - simpl_table = pysndobj.HarmTable(10000, 1, 1, 0.25) - sndobj_synth = sndobj.AdSyn(sndobj_sinmod, max_tracks, sndobj_table, 1, 1, hop_size) - simpl_synth = pysndobj.AdSyn(simpl_sinmod, max_tracks, simpl_table, 1, 1, hop_size) - - i = 0 - while (i + frame_size) <= num_samples: - frame = audio_in[i:i+frame_size] - sndobj_input.PushIn(frame) - simpl_input.PushIn(frame) - sndobj_ifgram.DoProcess() - simpl_ifgram.DoProcess() - sndobj_sinmod.DoProcess() - simpl_sinmod.DoProcess() - sndobj_synth.DoProcess() - simpl_synth.DoProcess() - sndobj_synth.PopOut(sndobj_frame_out) - simpl_synth.PopOut(simpl_frame_out) - sndobj_audio_out = np.hstack((sndobj_audio_out, sndobj_frame_out)) - simpl_audio_out = np.hstack((simpl_audio_out, simpl_frame_out)) - i += hop_size - - self.assertEqual(sndobj_audio_out.size, simpl_audio_out.size) - for i in range(sndobj_audio_out.size): - self.assertAlmostEquals(sndobj_audio_out[i], simpl_audio_out[i], - places = FLOAT_PRECISION) - - def test_sinsyn_doprocess(self): - "Compare sndobj.SinSyn with pysndobj.SinSyn" - frame_size = 2048 - hop_size = 512 - max_tracks = 20 - num_frames = 4 - num_samples = frame_size + ((num_frames - 1) * hop_size) - - audio_in_data = read(self.input_file) - audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 - audio_in = audio_in[0:num_samples] - frame = simpl.zeros(frame_size) - sndobj_frame_out = simpl.zeros(hop_size) - simpl_frame_out = simpl.zeros(hop_size) - sndobj_audio_out = simpl.array([]) - simpl_audio_out = simpl.array([]) - - sndobj_input = sndobj.SndObj() - simpl_input = pysndobj.SndObj() - sndobj_input.SetVectorSize(frame_size) - simpl_input.SetVectorSize(frame_size) - sndobj_window = sndobj.HammingTable(frame_size, 0.5) - simpl_window = pysndobj.HammingTable(frame_size, 0.5) - sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) - simpl_ifgram = pysndobj.IFGram(simpl_window, simpl_input, 1, frame_size, hop_size) - sndobj_sinmod = sndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) - simpl_sinmod = pysndobj.SinAnal(simpl_ifgram, 0.003, max_tracks, 1, 3) - sndobj_table = sndobj.HarmTable(10000, 1, 1, 0.25) - simpl_table = pysndobj.HarmTable(10000, 1, 1, 0.25) - sndobj_synth = sndobj.SinSyn(sndobj_sinmod, max_tracks, sndobj_table, 1, hop_size) - simpl_synth = pysndobj.SinSyn(simpl_sinmod, max_tracks, simpl_table, 1, hop_size) - - i = 0 - while (i + frame_size) <= num_samples: - frame = audio_in[i:i+frame_size] - sndobj_input.PushIn(frame) - simpl_input.PushIn(frame) - sndobj_ifgram.DoProcess() - simpl_ifgram.DoProcess() - sndobj_sinmod.DoProcess() - simpl_sinmod.DoProcess() - sndobj_synth.DoProcess() - simpl_synth.DoProcess() - sndobj_synth.PopOut(sndobj_frame_out) - simpl_synth.PopOut(simpl_frame_out) - sndobj_audio_out = np.hstack((sndobj_audio_out, sndobj_frame_out)) - simpl_audio_out = np.hstack((simpl_audio_out, simpl_frame_out)) - i += hop_size - - self.assertEqual(sndobj_audio_out.size, simpl_audio_out.size) - for i in range(sndobj_audio_out.size): - self.assertAlmostEquals(sndobj_audio_out[i], simpl_audio_out[i], - places = FLOAT_PRECISION) - - def test_peak_detection(self): - "Compare pysndobj Peaks with SndObj peaks" - frame_size = 2048 - hop_size = 512 - num_frames = 4 - max_peaks = 20 - max_tracks = 20 - num_samples = frame_size + ((num_frames - 1) * hop_size) - - audio_in_data = read(self.input_file) - audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 - audio_in = audio_in[0:num_samples] - frame = simpl.zeros(frame_size) - - sndobj_input = sndobj.SndObj() - sndobj_input.SetVectorSize(frame_size) - sndobj_window = sndobj.HammingTable(frame_size, 0.5) - sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) - simpl_sinmod = pysndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) - - pd = simpl.SndObjPeakDetection() - pd.max_peaks = max_peaks - - i = 0 - while (i + frame_size) <= num_samples: - frame = audio_in[i:i+frame_size] - sndobj_input.PushIn(frame) - sndobj_ifgram.DoProcess() - num_peaks_found = simpl_sinmod.FindPeaks() - - frame = audio_in[i:i+frame_size] - peaks = pd.find_peaks(frame) - self.assertEquals(len(peaks), 1) - peaks = peaks[0] - - self.assertEquals(num_peaks_found, len(peaks)) - for j in range(num_peaks_found): - self.assertAlmostEquals(peaks[j].amplitude, simpl_sinmod.Output(j*3), - places=FLOAT_PRECISION) - self.assertAlmostEquals(peaks[j].frequency, simpl_sinmod.Output((j*3)+1), - places=FLOAT_PRECISION) - self.assertAlmostEquals(peaks[j].phase, simpl_sinmod.Output((j*3)+2), - places=FLOAT_PRECISION) - i += hop_size - - def test_partial_tracking(self): - "Compare pysndobj Partials with SndObj tracks" - frame_size = 2048 - hop_size = 512 - num_frames = 4 - max_tracks = 20 - max_peaks = 20 - num_samples = frame_size + ((num_frames - 1) * hop_size) - - audio_in_data = read(self.input_file) - audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 - audio_in = audio_in[0:num_samples] - frame = simpl.zeros(frame_size) - - sndobj_input = sndobj.SndObj() - sndobj_input.SetVectorSize(frame_size) - sndobj_window = sndobj.HammingTable(frame_size, 0.5) - sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) - sndobj_sinmod = pysndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) - - pd = simpl.SndObjPeakDetection() - pd.max_peaks = max_peaks - pt = simpl.SndObjPartialTracking() - pt.max_partials = max_tracks - - i = 0 - while (i + frame_size) <= num_samples: - frame = audio_in[i:i+frame_size] - sndobj_input.PushIn(frame) - sndobj_ifgram.DoProcess() - sndobj_sinmod.DoProcess() - - frame = audio_in[i:i+frame_size] - peaks = pd.find_peaks(frame)[0] - partials = pt.update_partials(peaks, i/hop_size) - - num_sndobj_partials = sndobj_sinmod.GetTracks() - num_simpl_partials = len(partials) - self.assertEquals(num_sndobj_partials, num_simpl_partials) - - for j in range(num_simpl_partials): - self.assertAlmostEquals(partials[j].amplitude, sndobj_sinmod.Output(j*3), - places=FLOAT_PRECISION) - self.assertAlmostEquals(partials[j].frequency, sndobj_sinmod.Output((j*3)+1), - places=FLOAT_PRECISION) - self.assertAlmostEquals(partials[j].phase, sndobj_sinmod.Output((j*3)+2), - places=FLOAT_PRECISION) - i += hop_size - - def test_synthesis(self): - "Compare pysndobj synthesised audio with SndObj synthesised audio" - frame_size = 2048 - hop_size = 512 - num_frames = 4 - max_tracks = 20 - max_peaks = 20 - num_samples = frame_size + ((num_frames - 1) * hop_size) - - audio_in_data = read(self.input_file) - audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 - audio_in = audio_in[0:num_samples] - frame = simpl.zeros(frame_size) - sndobj_frame_out = simpl.zeros(hop_size) - sndobj_audio_out = simpl.array([]) - - sndobj_input = sndobj.SndObj() - sndobj_input.SetVectorSize(frame_size) - sndobj_window = sndobj.HammingTable(frame_size, 0.5) - sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) - sndobj_sinmod = pysndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) - sndobj_table = sndobj.HarmTable(10000, 1, 1, 0.25) - sndobj_synth = sndobj.AdSyn(sndobj_sinmod, max_tracks, sndobj_table, 1, 1, hop_size) - - i = 0 - while (i + frame_size) <= num_samples: - frame = audio_in[i:i+frame_size] - sndobj_input.PushIn(frame) - sndobj_ifgram.DoProcess() - sndobj_sinmod.DoProcess() - sndobj_synth.DoProcess() - sndobj_synth.PopOut(sndobj_frame_out) - sndobj_audio_out = np.hstack((sndobj_audio_out, sndobj_frame_out)) - i += hop_size - - pd = simpl.SndObjPeakDetection() - pd.max_peaks = max_peaks - pt = simpl.SndObjPartialTracking() - pt.max_partials = max_tracks - peaks = pd.find_peaks(audio_in) - partials = pt.find_partials(peaks) - synth = simpl.SndObjSynthesis() - simpl_audio_out = synth.synth(partials) - self.assertEquals(sndobj_audio_out.size, simpl_audio_out.size) - for i in range(simpl_audio_out.size): - self.assertAlmostEquals(sndobj_audio_out[i], simpl_audio_out[i], - places = FLOAT_PRECISION) - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_lp.py b/tests/test_lp.py new file mode 100644 index 0000000..8d80ba2 --- /dev/null +++ b/tests/test_lp.py @@ -0,0 +1,28 @@ +# Copyright (c) 2010 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 + +from simpl import lp +import numpy as np + +class TestLP(object): + + def test_predict(self): + """test_predict""" + coefs = np.array([1,2,3,4,5]) + test_signal = np.ones(5) + predictions = lp.predict(test_signal, coefs, 2) + assert predictions[0] == -sum(coefs) + assert predictions[1] == -sum(coefs[1:])-predictions[0] diff --git a/tests/test_peakdetection.py b/tests/test_peakdetection.py new file mode 100644 index 0000000..1257f02 --- /dev/null +++ b/tests/test_peakdetection.py @@ -0,0 +1,24 @@ +# 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 +import numpy as np +from scipy.io.wavfile import read + +class TestPeakDetection(object): + frame_size = 2048 + hop_size = 512 + max_peaks = 10 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) diff --git a/tests/test_sms_old.py b/tests/test_sms_old.py new file mode 100644 index 0000000..7ed8724 --- /dev/null +++ b/tests/test_sms_old.py @@ -0,0 +1,126 @@ +# 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, M 02111-1307 USA + +import unittest +from pysms import SMS_Header, SMS_Data, SMS_SndHeader, SMS_AnalParams, \ + sms_openSF, sms_errorString, sms_getSound, \ + sms_fillHeader, sms_init, sms_initAnalysis, sms_allocFrameH, \ + sms_freeFrame, sms_freeAnalysis, sms_free +from scipy import zeros, sin, pi, asarray, int16 +from scipy.io.wavfile import read, write +import os +import random +from pylab import plot, show + +TEST_AUDIO_FILE = "Tests.wav" + +# Create a test audio file (1 second of a sine wave at 220 Hz) +test_audio = zeros(44100) +for sample_number in range(test_audio.size): + test_audio[sample_number] = sin(2 * pi * 220 * sample_number / 44100.0) +# convert to int values +test_audio *= 32767 +test_audio = asarray(test_audio, int16) + +def create_test_audio_file(): + "Create a test audio file in the current directory" + write(TEST_AUDIO_FILE, 44100, test_audio) + +def delete_test_audio_file(): + "Delete the test audio file created by the function create_test_audio_file" + os.remove(TEST_AUDIO_FILE) + +class TestSoundIO(unittest.TestCase): + def setUp(self): + self.snd_header = SMS_SndHeader() + + def test_sms_openSF_file_exists(self): + "sms_openSF returns True when trying to open an existing file" + create_test_audio_file() + self.assert_(sms_openSF(TEST_AUDIO_FILE, self.snd_header) == 0) + delete_test_audio_file() + + def test_sms_openSF_file_missing(self): + "sms_openSF returns False when trying to open a file that doesn't exist" + file_path = "" + max_file_names = 1000 + count = 0 + class MaxFilesReached(Exception): pass + # create a path to a non-existent file + while True: + file_path = str(random.randint(0, max_file_names)) + ".wav" + if not os.path.isfile(file_path): + break + if count > max_file_names: + raise MaxFilesReached + count += 1 + # call sms_openSF, should return an error + self.assertRaises(IndexError, sms_openSF, file_path, self.snd_header) + + def test_sms_getSound(self): + "sms_getSound" + create_test_audio_file() + self.assert_(sms_openSF(TEST_AUDIO_FILE, self.snd_header) == 0) + frame_size = 512 + frame = zeros(frame_size).astype('float32') + self.assert_(sms_getSound(self.snd_header, frame, 0) == 0) + # test that values read in are the same as those written (allowing for some rounding errors) + class SampleMismatch(Exception): pass + for sample_number in range(frame_size): + if abs((test_audio[sample_number] / 32768.0) - frame[sample_number] > 0.000001): + raise SampleMismatch + delete_test_audio_file() + +class TestInit(unittest.TestCase): + def setUp(self): + self.snd_header = SMS_SndHeader() + self.sms_header = SMS_Header() + self.data = SMS_Data() + self.analysis_params = SMS_AnalParams() + + def tearDown(self): + sms_freeFrame(self.data) + + def test_sms_fillHeader(self): + "sms_fillHeader copies data from an SMS_AnalParams to an SMS_Header" + data_fields = ["nFrames", "iFormat", "iFrameRate", "iStochasticType", \ + "nTracks", "iSamplingRate", "nStochasticCoeff"] + sms_fillHeader(self.sms_header, self.analysis_params, "") + for field in data_fields: + self.assert_(eval("self.sms_header."+field) == eval("self.analysis_params."+field)) + + def test_sms_init(self): + "sms_init" + self.assert_(sms_init() == 0) + + def test_sms_initAnalysis(self): + "sms_initAnalysis" + create_test_audio_file() + if(sms_openSF(TEST_AUDIO_FILE, self.snd_header)): + raise NameError("error opening sound file: " + sms_errorString()) + self.assert_(sms_initAnalysis(self.analysis_params, self.snd_header) == 0) + delete_test_audio_file() + + def test_sms_allocFrameH(self): + "sms_allocFrameH" + create_test_audio_file() + if(sms_openSF(TEST_AUDIO_FILE, self.snd_header)): + raise NameError("error opening sound file: " + sms_errorString()) + self.assert_(sms_allocFrameH(self.sms_header, self.data) == 0) + delete_test_audio_file() + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_sndobj.py b/tests/test_sndobj.py new file mode 100644 index 0000000..527a9d7 --- /dev/null +++ b/tests/test_sndobj.py @@ -0,0 +1,389 @@ +# 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 unittest +import sndobj +import simpl +from simpl import pysndobj +from scipy.io.wavfile import read +import numpy as np + +FLOAT_PRECISION = 2 # number of decimal places to check for accuracy + +class TestSimplSndObj(unittest.TestCase): + def setUp(self): + self.input_file = 'audio/flute.wav' + + def test_sndobj_numpy(self): + "Test reading and writing numpy data in SndObjs" + frame_size = 2048 + hop_size = 2048 + num_frames = 4 + num_samples = frame_size + (num_frames * hop_size) + + audio_in_data = read(self.input_file) + audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 + audio_in = audio_in[0:num_samples] + frame = simpl.zeros(frame_size) + frame_out = simpl.zeros(hop_size) + audio_out = simpl.array([]) + + input = pysndobj.SndObj() + input.SetVectorSize(frame_size) + + i = 0 + while (i + frame_size) <= num_samples: + frame = audio_in[i:i+frame_size] + input.PushIn(frame) + input.PopOut(frame_out) + audio_out = np.hstack((audio_out, frame_out)) + i += hop_size + + self.assertEqual(audio_in.size, audio_out.size) + for i in range(audio_out.size): + self.assertEqual(audio_in[i], audio_out[i]) + + def test_hammingtable(self): + "Compare sndobj.HammingTable with simplsndobj.HammingTable" + frame_size = 2048 + window1 = sndobj.HammingTable(frame_size, 0.5) + window2 = pysndobj.HammingTable(frame_size, 0.5) + for i in range(frame_size): + self.assertEqual(window1.Lookup(i), window2.Lookup(i)) + + def test_ifgram(self): + "Compare sndobj.IFGram with simplsndobj.IFGram" + frame_size = 2048 + hop_size = 512 + num_frames = 4 + num_samples = frame_size + ((num_frames - 1) * hop_size) + + audio_in_data = read(self.input_file) + audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 + audio_in = audio_in[0:num_samples] + frame = simpl.zeros(frame_size) + + sndobj_input = sndobj.SndObj() + simpl_input = pysndobj.SndObj() + sndobj_input.SetVectorSize(frame_size) + simpl_input.SetVectorSize(frame_size) + sndobj_window = sndobj.HammingTable(frame_size, 0.5) + simpl_window = pysndobj.HammingTable(frame_size, 0.5) + sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) + simpl_ifgram = pysndobj.IFGram(simpl_window, simpl_input, 1, frame_size, hop_size) + + i = 0 + while (i + frame_size) <= num_samples: + frame = audio_in[i:i+frame_size] + sndobj_input.PushIn(frame) + simpl_input.PushIn(frame) + sndobj_ifgram.DoProcess() + simpl_ifgram.DoProcess() + for j in range(frame_size): + self.assertAlmostEquals(sndobj_ifgram.Output(j), simpl_ifgram.Output(j), + places = FLOAT_PRECISION) + i += hop_size + + def test_sinanal(self): + "Compare sndobj.SinAnal with simplsndobj.SinAnal" + frame_size = 2048 + hop_size = 512 + max_tracks = 20 + num_frames = 4 + num_samples = frame_size + ((num_frames - 1) * hop_size) + + audio_in_data = read(self.input_file) + audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 + audio_in = audio_in[0:num_samples] + frame = simpl.zeros(frame_size) + + sndobj_input = sndobj.SndObj() + simpl_input = pysndobj.SndObj() + sndobj_input.SetVectorSize(frame_size) + simpl_input.SetVectorSize(frame_size) + sndobj_window = sndobj.HammingTable(frame_size, 0.5) + simpl_window = pysndobj.HammingTable(frame_size, 0.5) + sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) + simpl_ifgram = pysndobj.IFGram(simpl_window, simpl_input, 1, frame_size, hop_size) + sndobj_sinmod = sndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) + simpl_sinmod = pysndobj.SinAnal(simpl_ifgram, 0.003, max_tracks, 1, 3) + + i = 0 + while (i + frame_size) <= num_samples: + frame = audio_in[i:i+frame_size] + sndobj_input.PushIn(frame) + simpl_input.PushIn(frame) + sndobj_ifgram.DoProcess() + simpl_ifgram.DoProcess() + sndobj_sinmod.DoProcess() + simpl_sinmod.DoProcess() + for j in range(max_tracks * 3): + self.assertAlmostEquals(sndobj_sinmod.Output(j), simpl_sinmod.Output(j), + places = FLOAT_PRECISION) + i += hop_size + + def test_adsyn_doprocess(self): + "Compare sndobj.AdSyn with simplsndobj.AdSyn" + frame_size = 2048 + hop_size = 512 + max_tracks = 20 + num_frames = 4 + num_samples = frame_size + ((num_frames - 1) * hop_size) + + audio_in_data = read(self.input_file) + audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 + audio_in = audio_in[0:num_samples] + frame = simpl.zeros(frame_size) + sndobj_frame_out = simpl.zeros(hop_size) + simpl_frame_out = simpl.zeros(hop_size) + sndobj_audio_out = simpl.array([]) + simpl_audio_out = simpl.array([]) + + sndobj_input = sndobj.SndObj() + simpl_input = pysndobj.SndObj() + sndobj_input.SetVectorSize(frame_size) + simpl_input.SetVectorSize(frame_size) + sndobj_window = sndobj.HammingTable(frame_size, 0.5) + simpl_window = pysndobj.HammingTable(frame_size, 0.5) + sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) + simpl_ifgram = pysndobj.IFGram(simpl_window, simpl_input, 1, frame_size, hop_size) + sndobj_sinmod = sndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) + simpl_sinmod = pysndobj.SinAnal(simpl_ifgram, 0.003, max_tracks, 1, 3) + sndobj_table = sndobj.HarmTable(10000, 1, 1, 0.25) + simpl_table = pysndobj.HarmTable(10000, 1, 1, 0.25) + sndobj_synth = sndobj.AdSyn(sndobj_sinmod, max_tracks, sndobj_table, 1, 1, hop_size) + simpl_synth = pysndobj.AdSyn(simpl_sinmod, max_tracks, simpl_table, 1, 1, hop_size) + + i = 0 + while (i + frame_size) <= num_samples: + frame = audio_in[i:i+frame_size] + sndobj_input.PushIn(frame) + simpl_input.PushIn(frame) + sndobj_ifgram.DoProcess() + simpl_ifgram.DoProcess() + sndobj_sinmod.DoProcess() + simpl_sinmod.DoProcess() + sndobj_synth.DoProcess() + simpl_synth.DoProcess() + sndobj_synth.PopOut(sndobj_frame_out) + simpl_synth.PopOut(simpl_frame_out) + sndobj_audio_out = np.hstack((sndobj_audio_out, sndobj_frame_out)) + simpl_audio_out = np.hstack((simpl_audio_out, simpl_frame_out)) + i += hop_size + + self.assertEqual(sndobj_audio_out.size, simpl_audio_out.size) + for i in range(sndobj_audio_out.size): + self.assertAlmostEquals(sndobj_audio_out[i], simpl_audio_out[i], + places = FLOAT_PRECISION) + + def test_sinsyn_doprocess(self): + "Compare sndobj.SinSyn with pysndobj.SinSyn" + frame_size = 2048 + hop_size = 512 + max_tracks = 20 + num_frames = 4 + num_samples = frame_size + ((num_frames - 1) * hop_size) + + audio_in_data = read(self.input_file) + audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 + audio_in = audio_in[0:num_samples] + frame = simpl.zeros(frame_size) + sndobj_frame_out = simpl.zeros(hop_size) + simpl_frame_out = simpl.zeros(hop_size) + sndobj_audio_out = simpl.array([]) + simpl_audio_out = simpl.array([]) + + sndobj_input = sndobj.SndObj() + simpl_input = pysndobj.SndObj() + sndobj_input.SetVectorSize(frame_size) + simpl_input.SetVectorSize(frame_size) + sndobj_window = sndobj.HammingTable(frame_size, 0.5) + simpl_window = pysndobj.HammingTable(frame_size, 0.5) + sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) + simpl_ifgram = pysndobj.IFGram(simpl_window, simpl_input, 1, frame_size, hop_size) + sndobj_sinmod = sndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) + simpl_sinmod = pysndobj.SinAnal(simpl_ifgram, 0.003, max_tracks, 1, 3) + sndobj_table = sndobj.HarmTable(10000, 1, 1, 0.25) + simpl_table = pysndobj.HarmTable(10000, 1, 1, 0.25) + sndobj_synth = sndobj.SinSyn(sndobj_sinmod, max_tracks, sndobj_table, 1, hop_size) + simpl_synth = pysndobj.SinSyn(simpl_sinmod, max_tracks, simpl_table, 1, hop_size) + + i = 0 + while (i + frame_size) <= num_samples: + frame = audio_in[i:i+frame_size] + sndobj_input.PushIn(frame) + simpl_input.PushIn(frame) + sndobj_ifgram.DoProcess() + simpl_ifgram.DoProcess() + sndobj_sinmod.DoProcess() + simpl_sinmod.DoProcess() + sndobj_synth.DoProcess() + simpl_synth.DoProcess() + sndobj_synth.PopOut(sndobj_frame_out) + simpl_synth.PopOut(simpl_frame_out) + sndobj_audio_out = np.hstack((sndobj_audio_out, sndobj_frame_out)) + simpl_audio_out = np.hstack((simpl_audio_out, simpl_frame_out)) + i += hop_size + + self.assertEqual(sndobj_audio_out.size, simpl_audio_out.size) + for i in range(sndobj_audio_out.size): + self.assertAlmostEquals(sndobj_audio_out[i], simpl_audio_out[i], + places = FLOAT_PRECISION) + + def test_peak_detection(self): + "Compare pysndobj Peaks with SndObj peaks" + frame_size = 2048 + hop_size = 512 + num_frames = 4 + max_peaks = 20 + max_tracks = 20 + num_samples = frame_size + ((num_frames - 1) * hop_size) + + audio_in_data = read(self.input_file) + audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 + audio_in = audio_in[0:num_samples] + frame = simpl.zeros(frame_size) + + sndobj_input = sndobj.SndObj() + sndobj_input.SetVectorSize(frame_size) + sndobj_window = sndobj.HammingTable(frame_size, 0.5) + sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) + simpl_sinmod = pysndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) + + pd = simpl.SndObjPeakDetection() + pd.max_peaks = max_peaks + + i = 0 + while (i + frame_size) <= num_samples: + frame = audio_in[i:i+frame_size] + sndobj_input.PushIn(frame) + sndobj_ifgram.DoProcess() + num_peaks_found = simpl_sinmod.FindPeaks() + + frame = audio_in[i:i+frame_size] + peaks = pd.find_peaks(frame) + self.assertEquals(len(peaks), 1) + peaks = peaks[0] + + self.assertEquals(num_peaks_found, len(peaks)) + for j in range(num_peaks_found): + self.assertAlmostEquals(peaks[j].amplitude, simpl_sinmod.Output(j*3), + places=FLOAT_PRECISION) + self.assertAlmostEquals(peaks[j].frequency, simpl_sinmod.Output((j*3)+1), + places=FLOAT_PRECISION) + self.assertAlmostEquals(peaks[j].phase, simpl_sinmod.Output((j*3)+2), + places=FLOAT_PRECISION) + i += hop_size + + def test_partial_tracking(self): + "Compare pysndobj Partials with SndObj tracks" + frame_size = 2048 + hop_size = 512 + num_frames = 4 + max_tracks = 20 + max_peaks = 20 + num_samples = frame_size + ((num_frames - 1) * hop_size) + + audio_in_data = read(self.input_file) + audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 + audio_in = audio_in[0:num_samples] + frame = simpl.zeros(frame_size) + + sndobj_input = sndobj.SndObj() + sndobj_input.SetVectorSize(frame_size) + sndobj_window = sndobj.HammingTable(frame_size, 0.5) + sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) + sndobj_sinmod = pysndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) + + pd = simpl.SndObjPeakDetection() + pd.max_peaks = max_peaks + pt = simpl.SndObjPartialTracking() + pt.max_partials = max_tracks + + i = 0 + while (i + frame_size) <= num_samples: + frame = audio_in[i:i+frame_size] + sndobj_input.PushIn(frame) + sndobj_ifgram.DoProcess() + sndobj_sinmod.DoProcess() + + frame = audio_in[i:i+frame_size] + peaks = pd.find_peaks(frame)[0] + partials = pt.update_partials(peaks, i/hop_size) + + num_sndobj_partials = sndobj_sinmod.GetTracks() + num_simpl_partials = len(partials) + self.assertEquals(num_sndobj_partials, num_simpl_partials) + + for j in range(num_simpl_partials): + self.assertAlmostEquals(partials[j].amplitude, sndobj_sinmod.Output(j*3), + places=FLOAT_PRECISION) + self.assertAlmostEquals(partials[j].frequency, sndobj_sinmod.Output((j*3)+1), + places=FLOAT_PRECISION) + self.assertAlmostEquals(partials[j].phase, sndobj_sinmod.Output((j*3)+2), + places=FLOAT_PRECISION) + i += hop_size + + def test_synthesis(self): + "Compare pysndobj synthesised audio with SndObj synthesised audio" + frame_size = 2048 + hop_size = 512 + num_frames = 4 + max_tracks = 20 + max_peaks = 20 + num_samples = frame_size + ((num_frames - 1) * hop_size) + + audio_in_data = read(self.input_file) + audio_in = simpl.asarray(audio_in_data[1]) / 32768.0 + audio_in = audio_in[0:num_samples] + frame = simpl.zeros(frame_size) + sndobj_frame_out = simpl.zeros(hop_size) + sndobj_audio_out = simpl.array([]) + + sndobj_input = sndobj.SndObj() + sndobj_input.SetVectorSize(frame_size) + sndobj_window = sndobj.HammingTable(frame_size, 0.5) + sndobj_ifgram = sndobj.IFGram(sndobj_window, sndobj_input, 1, frame_size, hop_size) + sndobj_sinmod = pysndobj.SinAnal(sndobj_ifgram, 0.003, max_tracks, 1, 3) + sndobj_table = sndobj.HarmTable(10000, 1, 1, 0.25) + sndobj_synth = sndobj.AdSyn(sndobj_sinmod, max_tracks, sndobj_table, 1, 1, hop_size) + + i = 0 + while (i + frame_size) <= num_samples: + frame = audio_in[i:i+frame_size] + sndobj_input.PushIn(frame) + sndobj_ifgram.DoProcess() + sndobj_sinmod.DoProcess() + sndobj_synth.DoProcess() + sndobj_synth.PopOut(sndobj_frame_out) + sndobj_audio_out = np.hstack((sndobj_audio_out, sndobj_frame_out)) + i += hop_size + + pd = simpl.SndObjPeakDetection() + pd.max_peaks = max_peaks + pt = simpl.SndObjPartialTracking() + pt.max_partials = max_tracks + peaks = pd.find_peaks(audio_in) + partials = pt.find_partials(peaks) + synth = simpl.SndObjSynthesis() + simpl_audio_out = synth.synth(partials) + self.assertEquals(sndobj_audio_out.size, simpl_audio_out.size) + for i in range(simpl_audio_out.size): + self.assertAlmostEquals(sndobj_audio_out[i], simpl_audio_out[i], + places = FLOAT_PRECISION) + +if __name__ == '__main__': + unittest.main() -- cgit v1.2.3