summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--__init__.py3
-rw-r--r--basetypes.py97
-rw-r--r--sms.py87
-rw-r--r--tests/sms.py217
4 files changed, 236 insertions, 168 deletions
diff --git a/__init__.py b/__init__.py
index 182226e..82e693e 100644
--- a/__init__.py
+++ b/__init__.py
@@ -14,7 +14,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-from basetypes import Peak, PeakDetection, Partial, PartialTracking, Synthesis, Residual
+from basetypes import Frame, Peak, Partial
+from basetypes import PeakDetection, PartialTracking, Synthesis, Residual
from basetypes import compare_peak_amps, compare_peak_freqs
from sndobj import SndObjPeakDetection, SndObjPartialTracking, SndObjSynthesis
from sms import SMSPeakDetection, SMSPartialTracking, SMSSynthesis, SMSResidual
diff --git a/basetypes.py b/basetypes.py
index b58da34..0564697 100644
--- a/basetypes.py
+++ b/basetypes.py
@@ -116,6 +116,26 @@ class Partial(object):
yield peak
+class Frame(object):
+ """Represents a frame of audio information.
+ This can be: - raw audio samples
+ - an unordered list of sinusoidal peaks
+ - an ordered list of partials
+ - synthesised audio samples
+ - residual samples
+ - synthesised residual samples"""
+
+ def __init__(self):
+ self._size = 512
+ self._max_partials = 100
+ self.audio = None
+ self.peaks = None
+ self.partials = None
+ self.synth = None
+ self.residual = None
+ self.synth_residual = None
+
+
class PeakDetection(object):
"Detect spectral peaks"
@@ -128,7 +148,7 @@ class PeakDetection(object):
self._window_type = "hamming"
self._window_size = 2048
self._min_peak_separation = 1.0 # in Hz
- self.peaks = []
+ self.frames = []
# properties
sampling_rate = property(lambda self: self.get_sampling_rate(),
@@ -185,28 +205,32 @@ class PeakDetection(object):
def find_peaks_in_frame(self, frame):
"Find and return all spectral peaks in a given frame of audio"
- current_peaks = []
- return current_peaks
+ peaks = []
+ return peaks
def find_peaks(self, audio):
"""Find and return all spectral peaks in a given audio signal.
If the signal contains more than 1 frame worth of audio, it will be broken
up into separate frames, with a list of peaks returned for each frame."""
- self.peaks = []
+ self.frames = []
pos = 0
while pos < len(audio):
# get the next frame size
if not self._static_frame_size:
self.frame_size = self.get_next_frame_size()
# get the next frame
- frame = audio[pos:pos+self.frame_size]
+ frame = Frame()
+ frame.size = self.frame_size
+ frame.audio = audio[pos:pos+self.frame_size]
# pad if necessary
- if len(frame) < self.frame_size:
- frame = np.hstack((frame, simpl.zeros(self.frame_size - len(frame))))
+ if len(frame.audio) < self.frame_size:
+ frame.audio = np.hstack((frame.audio,
+ simpl.zeros(self.frame_size - len(frame.audio))))
# find peaks
- self.peaks.append(self.find_peaks_in_frame(frame))
+ frame.peaks = self.find_peaks_in_frame(frame)
+ self.frames.append(frame)
pos += self.hop_size
- return self.peaks
+ return self.frames
class PartialTracking(object):
@@ -216,7 +240,7 @@ class PartialTracking(object):
self._max_partials = 100
self._min_partial_length = 0
self._max_gap = 2
- self.partials = [] # list of Partials
+ self.frames = []
# properties
sampling_rate = property(lambda self: self.get_sampling_rate(),
@@ -252,25 +276,18 @@ class PartialTracking(object):
def set_max_gap(self, gap):
self._max_gap = gap
- def get_partial(self, id):
- """Return the partial with partial_id = id. Returns None if no such
- partial exists"""
- for p in self.partials:
- if p.partial_id == id:
- return p
- return None
-
- def update_partials(self, frame, frame_number):
+ def update_partials(self, frame):
"Streamable (real-time) partial-tracking."
- frame_partials = []
- return frame_partials
+ peaks = [None for i in range(self.max_partials)]
+ return peaks
def find_partials(self, frames):
- """Creates tracks from the frames of peaks in self.peak_frames,
- stored in self.track_frames"""
- for frame_number, frame in enumerate(frames):
- self.update_partials(frame, frame_number)
- return self.partials
+ """Find partials from the sinusoidal peaks in a list of Frames"""
+ self.frames = []
+ for frame in frames:
+ frame.partials = self.update_partials(frame)
+ self.frames.append(frame)
+ return self.frames
class Synthesis(object):
@@ -317,34 +334,15 @@ class Synthesis(object):
def set_sampling_rate(self, sampling_rate):
self._sampling_rate = sampling_rate
- def synth_frame(self, partials):
+ def synth_frame(self, frame):
"Synthesises a frame of audio, given a list of peaks from tracks"
raise Exception("NotYetImplemented")
- def synth(self, partials):
+ def synth(self, frames):
"Synthesise audio from the given partials"
audio_out = simpl.array([])
- # return an empty frame if there are no partials
- if not partials:
- return audio_out
- current_partials = []
- num_frames = max([partial.get_last_frame() for partial in partials])
- # for each frame of audio
- for frame_number in range(num_frames):
- # get all partials that start on this frame, append to list of continuing partials
- current_partials.extend([partial.list_peaks() for partial in partials if partial.starting_frame == frame_number])
- # get all peaks to be synthesised for this frame
- current_peaks = []
- for partial_number, partial in enumerate(current_partials):
- try:
- current_peaks.append(partial.next())
- except StopIteration:
- # End of partial. Set this partial to None, remove it from the list later
- current_partials[partial_number] = None
- # synth frame
- audio_out = np.hstack((audio_out, self.synth_frame(current_peaks)))
- # remove any finished partials
- current_partials = [partial for partial in current_partials if partial]
+ for frame in frames:
+ audio_out = np.hstack((audio_out, self.synth_frame(frame)))
return audio_out
@@ -402,3 +400,4 @@ class Residual(object):
self.synth_frame(synth_frame, original_frame)))
sample_offset += self._hop_size
return residual
+
diff --git a/sms.py b/sms.py
index 8dbcd1c..625c933 100644
--- a/sms.py
+++ b/sms.py
@@ -171,7 +171,7 @@ class SMSPeakDetection(simpl.PeakDetection):
def find_peaks_in_frame(self, frame):
"Find and return all spectral peaks in a given frame of audio"
current_peaks = []
- num_peaks = simplsms.sms_findPeaks(frame,
+ num_peaks = simplsms.sms_findPeaks(frame.audio,
self._analysis_params,
self._peaks)
if num_peaks > 0:
@@ -197,18 +197,21 @@ class SMSPeakDetection(simpl.PeakDetection):
# make sure the results are the same as with libsms. Make sure
# we have the same number of frames as the other algorithms.
self._analysis_params.iSizeSound = len(audio)
- self.peaks = []
+ self.frames = []
pos = 0
while pos < len(audio):
# get the next frame size
if not self._static_frame_size:
self.frame_size = self.get_next_frame_size()
# get the next frame
- frame = audio[pos:pos+self.frame_size]
+ frame = simpl.Frame()
+ frame.size = self.frame_size
+ frame.audio = audio[pos:pos+self.frame_size]
# find peaks
- self.peaks.append(self.find_peaks_in_frame(frame))
+ frame.peaks = self.find_peaks_in_frame(frame)
+ self.frames.append(frame)
pos += self.frame_size
- return self.peaks
+ return self.frames
class SMSPartialTracking(simpl.PartialTracking):
@@ -226,20 +229,22 @@ class SMSPartialTracking(simpl.PartialTracking):
self._analysis_params.minGoodFrames = 1
self._analysis_params.iCleanTracks = 0
self._analysis_params.iFormat = simplsms.SMS_FORMAT_HP
- self._analysis_params.nTracks = self.max_partials
- self._analysis_params.nGuides = self.max_partials
+ self._analysis_params.nTracks = self._max_partials
+ self._analysis_params.nGuides = self._max_partials
if simplsms.sms_initAnalysis(self._analysis_params) != 0:
raise Exception("Error allocating memory for analysis_params")
self._sms_header = simplsms.SMS_Header()
simplsms.sms_fillHeader(self._sms_header, self._analysis_params, "simpl")
self._analysis_frame = simplsms.SMS_Data()
simplsms.sms_allocFrameH(self._sms_header, self._analysis_frame)
- self.live_partials = [None for i in range(self.max_partials)]
def __del__(self):
simplsms.sms_freeAnalysis(self._analysis_params)
simplsms.sms_freeFrame(self._analysis_frame)
simplsms.sms_free()
+
+ def get_max_partials(self):
+ return self._analysis_params.nTracks
def set_max_partials(self, max_partials):
simplsms.sms_freeAnalysis(self._analysis_params)
@@ -253,16 +258,15 @@ class SMSPartialTracking(simpl.PartialTracking):
simplsms.sms_fillHeader(self._sms_header, self._analysis_params, "simpl")
simplsms.sms_allocFrameH(self._sms_header, self._analysis_frame)
- def update_partials(self, frame, frame_number):
+ def update_partials(self, frame):
"Streamable (real-time) partial-tracking."
- frame_partials = []
# load Peak amplitudes, frequencies and phases into arrays
- num_peaks = len(frame)
+ num_peaks = len(frame.peaks)
amps = simpl.zeros(num_peaks)
freqs = simpl.zeros(num_peaks)
phases = simpl.zeros(num_peaks)
for i in range(num_peaks):
- peak = frame[i]
+ peak = frame.peaks[i]
amps[i] = peak.amplitude
freqs[i] = peak.frequency
phases[i] = peak.phase
@@ -271,34 +275,20 @@ class SMSPartialTracking(simpl.PartialTracking):
# SMS partial tracking
simplsms.sms_findPartials(self._analysis_frame, self._analysis_params)
# read values back into amps, freqs, phases
- num_partials = self._analysis_frame.nTracks
- amps = simpl.zeros(num_partials)
- freqs = simpl.zeros(num_partials)
- phases = simpl.zeros(num_partials)
+ amps = simpl.zeros(self.max_partials)
+ freqs = simpl.zeros(self.max_partials)
+ phases = simpl.zeros(self.max_partials)
self._analysis_frame.getSinAmp(amps)
self._analysis_frame.getSinFreq(freqs)
self._analysis_frame.getSinPhase(phases)
- # form simpl Partial objects
- for i in range(num_partials):
- # for each partial, if the mag is > 0, this partial is alive
- if amps[i] > 0:
- # create a peak object
- p = simpl.Peak()
- p.amplitude = amps[i]
- p.frequency = freqs[i]
- p.phase = phases[i]
- # add this peak to the appropriate partial
- if not self.live_partials[i]:
- self.live_partials[i] = simpl.Partial()
- self.live_partials[i].starting_frame = frame_number
- self.live_partials[i].partial_number = i
- self.partials.append(self.live_partials[i])
- self.live_partials[i].add_peak(p)
- # if the mag is 0 and this partial was alive, kill it
- else:
- if self.live_partials[i]:
- self.live_partials[i] = None
- return frame_partials
+ peaks = []
+ for i in range(self.max_partials):
+ p = simpl.Peak()
+ p.amplitude = amps[i]
+ p.frequency = freqs[i]
+ p.phase = phases[i]
+ peaks.append(p)
+ return peaks
class SMSSynthesis(simpl.Synthesis):
@@ -328,6 +318,8 @@ class SMSSynthesis(simpl.Synthesis):
# properties
synthesis_type = property(lambda self: self.get_synthesis_type(),
lambda self, x: self.set_synthesis_type(x))
+ det_synthesis_type = property(lambda self: self.get_det_synthesis_type(),
+ lambda self, x: self.set_det_synthesis_type(x))
num_stochastic_coeffs = property(lambda self: self.get_num_stochastic_coeffs(),
lambda self, x: self.set_num_stochastic_coeffs(x))
stochastic_type = property(lambda self: self.get_stochastic_type(),
@@ -369,6 +361,12 @@ class SMSSynthesis(simpl.Synthesis):
def set_synthesis_type(self, synthesis_type):
self._synth_params.iSynthesisType = synthesis_type
+ def get_det_synthesis_type(self):
+ return self._synth_params.iDetSynthesisType
+
+ def set_det_synthesis_type(self, det_synthesis_type):
+ self._synth_params.iDetSynthesisType = det_synthesis_type
+
def get_num_stochastic_coeffs(self):
return self._synth_params.nStochasticCoeff
@@ -401,18 +399,15 @@ class SMSSynthesis(simpl.Synthesis):
def set_original_hop_size(self, hop_size):
self._synth_params.origSizeHop = hop_size
- def synth_frame(self, peaks):
- "Synthesises a frame of audio, given a list of peaks from tracks"
+ def synth_frame(self, frame):
+ "Synthesises a frame of audio"
amps = simpl.zeros(self.max_partials)
freqs = simpl.zeros(self.max_partials)
phases = simpl.zeros(self.max_partials)
- for i in range(len(peaks)):
- p = peaks[i].partial_number
- if p < 0:
- p = i
- amps[p] = peaks[i].amplitude
- freqs[p] = peaks[i].frequency
- phases[p] = peaks[i].phase
+ for i in range(len(frame.partials)):
+ amps[i] = frame.partials[i].amplitude
+ freqs[i] = frame.partials[i].frequency
+ phases[i] = frame.partials[i].phase
self._analysis_frame.setSinAmp(amps)
self._analysis_frame.setSinFreq(freqs)
self._analysis_frame.setSinPha(phases)
diff --git a/tests/sms.py b/tests/sms.py
index f292e22..d85f27a 100644
--- a/tests/sms.py
+++ b/tests/sms.py
@@ -141,7 +141,10 @@ class TestSimplSMS(object):
while current_frame < self.num_frames:
pd.frame_size = pd.get_next_frame_size()
assert sms_next_read_sizes[current_frame] == pd.frame_size
- pd.find_peaks_in_frame(audio[sample_offset:sample_offset + 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
@@ -424,30 +427,30 @@ class TestSimplSMS(object):
pd = simpl.SMSPeakDetection()
pd.max_peaks = self.max_peaks
pd.hop_size = self.hop_size
- peaks1 = pd.find_peaks(audio)[0:self.num_frames]
+ 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
- peaks2 = pd.find_peaks(audio)[0:self.num_frames]
+ frames2 = pd.find_peaks(audio)[0:self.num_frames]
# make sure we have the same number of frames in each run
- assert len(peaks1) == len(peaks2)
- for f in range(len(peaks1)):
+ 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(peaks1[f]) == len(peaks2[f])
+ assert len(frames1[f].peaks) == len(frames2[f].peaks)
# 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,
+ 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(peaks1[f][p].amplitude,
- peaks2[f][p].amplitude,
+ assert_almost_equals(frames1[f].peaks[p].amplitude,
+ frames2[f].peaks[p].amplitude,
self.FLOAT_PRECISION)
- assert_almost_equals(peaks1[f][p].phase,
- peaks2[f][p].phase,
+ assert_almost_equals(frames1[f].peaks[p].phase,
+ frames2[f].peaks[p].phase,
self.FLOAT_PRECISION)
def test_peak_detection(self):
@@ -520,8 +523,10 @@ class TestSimplSMS(object):
while current_frame < self.num_frames:
pd.frame_size = pd.get_next_frame_size()
- simpl_peaks.append(
- pd.find_peaks_in_frame(audio[sample_offset:sample_offset + pd.frame_size]))
+ frame = simpl.Frame()
+ frame.size = pd.frame_size
+ frame.audio = audio[sample_offset:sample_offset + pd.frame_size]
+ simpl_peaks.append(pd.find_peaks_in_frame(frame))
sample_offset += pd.frame_size
current_frame += 1
@@ -679,7 +684,7 @@ class TestSimplSMS(object):
peaks = pd.find_peaks(audio)[0:self.num_frames]
pt = simpl.SMSPartialTracking()
pt.max_partials = self.max_peaks
- partials1 = pt.find_partials(peaks)
+ frames1 = pt.find_partials(peaks)
del pd
del pt
# second run
@@ -690,24 +695,23 @@ class TestSimplSMS(object):
peaks = pd.find_peaks(audio)[0:self.num_frames]
pt = simpl.SMSPartialTracking()
pt.max_partials = self.max_peaks
- partials2 = pt.find_partials(peaks)
+ frames2 = pt.find_partials(peaks)
# make sure we have the same number of partials in each run
- print len(partials1), len(partials2)
- assert len(partials1) == len(partials2)
- for p in range(len(partials1)):
+ assert len(frames1) == len(frames2)
+ for i in range(len(frames1)):
# make sure each partial is the same length
- assert partials1[p].get_length() == partials2[p].get_length()
+ assert len(frames1[i].partials) == len(frames2[i].partials)
# make sure that the peaks in each partial have the same values
- for i in range(partials1[p].get_length()):
- assert_almost_equals(partials1[p].peaks[i].frequency,
- partials2[p].peaks[i].frequency,
+ 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(partials1[p].peaks[i].amplitude,
- partials2[p].peaks[i].amplitude,
+ assert_almost_equals(frames1[i].partials[p].amplitude,
+ frames2[i].partials[p].amplitude,
self.FLOAT_PRECISION)
- assert_almost_equals(partials1[p].peaks[i].phase,
- partials2[p].peaks[i].phase,
+ assert_almost_equals(frames1[i].partials[p].phase,
+ frames2[i].partials[p].phase,
self.FLOAT_PRECISION)
def test_partial_tracking(self):
@@ -730,50 +734,49 @@ class TestSimplSMS(object):
sample_offset = 0
size_new_data = 0
current_frame = 0
- sms_partials = []
- live_partials = [None for i in range(self.max_peaks)]
+ 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 = audio[sample_offset:sample_offset + size_new_data]
- frame = np.array(frame, dtype=np.float32)
+ 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)
- status = pysms.sms_analyze(frame, analysis_data, analysis_params)
+ num_partials = analysis_data.nTracks
+ peaks = []
+ status = pysms.sms_analyze(frame.audio, analysis_data, analysis_params)
if status == 1:
- num_partials = analysis_data.nTracks
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)
- # make partial objects
for i in range(num_partials):
- # for each partial, if the mag is > 0, this partial is alive
- if sms_amps[i] > 0:
- # create a peak object
- p = simpl.Peak()
- p.amplitude = sms_amps[i]
- p.frequency = sms_freqs[i]
- p.phase = sms_phases[i]
- # add this peak to the appropriate partial
- if not live_partials[i]:
- live_partials[i] = simpl.Partial()
- live_partials[i].starting_frame = current_frame
- live_partials[i].partial_number = i
- sms_partials.append(live_partials[i])
- live_partials[i].add_peak(p)
- # if the mag is 0 and this partial was alive, kill it
- else:
- if live_partials[i]:
- live_partials[i] = None
- elif status == -1:
+ 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
@@ -787,23 +790,23 @@ class TestSimplSMS(object):
peaks = pd.find_peaks(audio)[0:self.num_frames]
pt = simpl.SMSPartialTracking()
pt.max_partials = self.max_partials
- partials = pt.find_partials(peaks)
+ simpl_frames = pt.find_partials(peaks)
# make sure both have the same number of partials
- assert len(sms_partials) == len(partials)
+ assert len(sms_frames) == len(simpl_frames)
# make sure each partial is the same
- for i in range(len(sms_partials)):
- assert sms_partials[i].get_length() == partials[i].get_length()
- for peak_number in range(sms_partials[i].get_length()):
- assert_almost_equals(sms_partials[i].peaks[peak_number].amplitude,
- partials[i].peaks[peak_number].amplitude,
+ 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_partials[i].peaks[peak_number].frequency,
- partials[i].peaks[peak_number].frequency,
+ assert_almost_equals(sms_frames[i].partials[p].frequency,
+ simpl_frames[i].partials[p].frequency,
self.FLOAT_PRECISION)
- assert_almost_equals(sms_partials[i].peaks[peak_number].phase,
- partials[i].peaks[peak_number].phase,
+ assert_almost_equals(sms_frames[i].partials[p].phase,
+ simpl_frames[i].partials[p].phase,
self.FLOAT_PRECISION)
def test_sms_interpolate_frames(self):
@@ -1062,6 +1065,82 @@ class TestSimplSMS(object):
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
+ 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)
+ analysis_frames.append(analysis_data)
+ if status == -1:
+ do_analysis = False
+ current_frame += 1
+
+ synth_params = self.pysms_synthesis_params(sampling_rate)
+ synth_params.iDetSynthesisType = 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)[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
+ synth.stochastic_type = simplsms.SMS_STOC_NONE
+ 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"""
@@ -1146,11 +1225,6 @@ class TestSimplSMS(object):
res = simpl.SMSResidual()
simpl_residual = res.synth(simpl_harmonic, audio[0:simpl_harmonic.size])
- #import matplotlib.pyplot as plt
- #plt.plot(sms_residual)
- #plt.plot(simpl_residual)
- #plt.show()
-
assert len(simpl_residual) == len(sms_residual)
for i in range(len(simpl_residual)):
assert_almost_equals(simpl_residual[i], sms_residual[i],
@@ -1162,7 +1236,6 @@ if __name__ == "__main__":
# useful for debugging, particularly with GDB
import nose
argv = [__file__,
- #__file__ + ":TestSimplSMS.test_residual_synthesis"]
- __file__ + ":TestSimplSMS.test_harmonic_synthesis"]
+ __file__ + ":TestSimplSMS.test_residual_synthesis"]
nose.run(argv=argv)