summaryrefslogtreecommitdiff
path: root/basetypes.py
diff options
context:
space:
mode:
authorJohn Glover <glover.john@gmail.com>2011-06-24 18:17:23 +0100
committerJohn Glover <glover.john@gmail.com>2011-06-24 18:17:23 +0100
commit416bd737074a287ea47106c73ea6bcfde40a75a8 (patch)
tree74562303d4f4f2f2e010f7e13cba41dc4852b50c /basetypes.py
parentd26519464dcbf8c3682348167c29454961facefe (diff)
downloadsimpl-416bd737074a287ea47106c73ea6bcfde40a75a8.tar.gz
simpl-416bd737074a287ea47106c73ea6bcfde40a75a8.tar.bz2
simpl-416bd737074a287ea47106c73ea6bcfde40a75a8.zip
Change to using distutils.
Currently only builds the simplsndobj module
Diffstat (limited to 'basetypes.py')
-rw-r--r--basetypes.py420
1 files changed, 0 insertions, 420 deletions
diff --git a/basetypes.py b/basetypes.py
deleted file mode 100644
index c12091d..0000000
--- a/basetypes.py
+++ /dev/null
@@ -1,420 +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
-
-class Peak(object):
- "A spectral peak"
- def __init__(self):
- self.amplitude = 0.0
- self.frequency = 0.0
- self.phase = 0.0
- self.next_peak = None
- self.previous_peak = None
- self.partial_id = None
- self.partial_position = None
- self.frame_number = None
-
- def is_start_of_partial(self):
- return self.previous_peak is None
-
- def is_free(self, direction='forwards'):
- "Returns true iff this peak is unmatched in the given direction, and has positive amplitude"
- if self.amplitude <= 0:
- return False
- if direction == 'forwards':
- if self.next_peak:
- return False
- elif direction == 'backwards':
- if self.previous_peak:
- return False
- else:
- return False
- return True
-
-
-def compare_peak_amps(peak_x, peak_y):
- """Compares two peaks, and returns 1, 0 or -1 if the first has a greater
- amplitude than the second, they have the same amplitude, or the second has
- a greater amplitude than the first respectively.
- Can be used to sort lists of peaks."""
- if peak_x.amplitude > peak_y.amplitude:
- return 1
- elif peak_x.amplitude < peak_y.amplitude:
- return -1
- else:
- return 0
-
-def compare_peak_freqs(peak_x, peak_y):
- """Compares two peaks, and returns 1, 0 or -1 if the first has a greater
- frequency than the second, they have the same frequency, or the second has
- a greater frequency than the first respectively.
- Can be used to sort lists of peaks."""
- if peak_x.frequency > peak_y.frequency:
- return 1
- elif peak_x.frequency < peak_y.frequency:
- return -1
- else:
- return 0
-
-
-class Partial(object):
- "Represents a sinuoidal partial or track, an ordered sequence of Peaks"
- _num_partials = 0
-
- def __init__(self):
- "Initialise peaks list and increment partial_id"
- self.peaks = []
- self.starting_frame = 0
- self.partial_number = -1
- self.partial_id = Partial._num_partials
- Partial._num_partials += 1
-
- def add_peak(self, peak):
- "Add peak to this partial, setting its id and partial_id."
- partial_position = len(self.peaks)
- last_peak = self.get_last_peak()
- self.peaks.append(peak)
- if last_peak:
- last_peak.next_peak = peak
- peak.previous_peak = last_peak
- peak.partial_position = partial_position
- peak.partial_id = self.partial_id
- peak.partial_number = self.partial_number
-
- def get_length(self):
- "Return the length of this partial (as a number of frames)"
- return len(self.peaks)
-
- def get_last_frame(self):
- "Return the frame number of the last frame in this partial"
- return self.starting_frame + self.get_length()
-
- def get_last_peak(self):
- "Return the last peak of this partial"
- if self.peaks:
- return self.peaks[-1]
- return None
-
- def list_peaks(self):
- "A generator that returns the peaks in this partial"
- for peak in self.peaks:
- 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"
-
- def __init__(self):
- self._sampling_rate = 44100
- self._frame_size = 2048
- self._static_frame_size = True
- self._hop_size = 512
- self._max_peaks = 100
- self._window_type = "hamming"
- self._window_size = 2048
- self._min_peak_separation = 1.0 # in Hz
- self.frames = []
-
- # properties
- sampling_rate = property(lambda self: self.get_sampling_rate(),
- lambda self, x: self.set_sampling_rate(x))
- frame_size = property(lambda self: self.get_frame_size(),
- lambda self, x: self.set_frame_size(x))
- hop_size = property(lambda self: self.get_hop_size(),
- lambda self, x: self.set_hop_size(x))
- max_peaks = property(lambda self: self.get_max_peaks(),
- lambda self, x: self.set_max_peaks(x))
- window_type = property(lambda self: self.get_window_type(),
- lambda self, x: self.set_window_type(x))
- window_size = property(lambda self: self.get_window_size(),
- lambda self, x: self.set_window_size(x))
-
- def get_sampling_rate(self):
- return self._sampling_rate
-
- def set_sampling_rate(self, sampling_rate):
- self._sampling_rate = sampling_rate
-
- def get_frame_size(self):
- return self._frame_size
-
- def set_frame_size(self, frame_size):
- self._frame_size = frame_size
-
- def get_hop_size(self):
- return self._hop_size
-
- def set_hop_size(self, hop_size):
- self._hop_size = hop_size
-
- def get_max_peaks(self):
- return self._max_peaks
-
- def set_max_peaks(self, max_peaks):
- self._max_peaks = max_peaks
-
- def get_window_type(self):
- return self._window_type
-
- def set_window_type(self, window_type):
- self._window_type = window_type
-
- def get_window_size(self):
- return self._window_size
-
- def set_window_size(self, window_size):
- self._window_size = window_size
-
- def get_next_frame_size(self):
- return self._frame_size
-
- def find_peaks_in_frame(self, frame):
- "Find and return all spectral peaks in a given frame of audio"
- 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.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 = Frame()
- frame.size = self.frame_size
- frame.audio = audio[pos:pos+self.frame_size]
- # pad if necessary
- if len(frame.audio) < self.frame_size:
- frame.audio = np.hstack((frame.audio,
- simpl.zeros(self.frame_size - len(frame.audio))))
- # find peaks
- frame.peaks = self.find_peaks_in_frame(frame)
- self.frames.append(frame)
- pos += self.hop_size
- return self.frames
-
-
-class PartialTracking(object):
- "Link spectral peaks from consecutive frames to form partials"
- def __init__(self):
- self._sampling_rate = 44100
- self._max_partials = 100
- self._min_partial_length = 0
- self._max_gap = 2
- self.frames = []
-
- # properties
- sampling_rate = property(lambda self: self.get_sampling_rate(),
- lambda self, x: self.set_sampling_rate(x))
- max_partials = property(lambda self: self.get_max_partials(),
- lambda self, x: self.set_max_partials(x))
- min_partial_length = property(lambda self: self.get_min_partial_length(),
- lambda self, x: self.set_min_partial_length(x))
- max_gap = property(lambda self: self.get_max_gap(),
- lambda self, x: self.set_max_gap(x))
-
- def get_sampling_rate(self):
- return self._sampling_rate
-
- def set_sampling_rate(self, sampling_rate):
- self._sampling_rate = sampling_rate
-
- def get_max_partials(self):
- return self._max_partials
-
- def set_max_partials(self, num_partials):
- self._max_partials = num_partials
-
- def get_min_partial_length(self):
- return self._min_partial_length
-
- def set_min_partial_length(self, length):
- self._min_partial_length = length
-
- def get_max_gap(self):
- return self._max_gap
-
- def set_max_gap(self, gap):
- self._max_gap = gap
-
- def update_partials(self, frame):
- "Streamable (real-time) partial-tracking."
- peaks = [None for i in range(self.max_partials)]
- return peaks
-
- def find_partials(self, frames):
- """Find partials from the sinusoidal peaks in a list of Frames"""
- self.frames = []
- for frame in frames:
- frame.partials = self.update_partials(frame)
- self.frames.append(frame)
- return self.frames
-
-
-class Synthesis(object):
- "Synthesise audio from spectral analysis data"
- def __init__(self):
- self._frame_size = 512
- self._hop_size = 512
- self._max_partials = 100
- self._sampling_rate = 44100
-
- # properties
- frame_size = property(lambda self: self.get_frame_size(),
- lambda self, x: self.set_frame_size(x))
- hop_size = property(lambda self: self.get_hop_size(),
- lambda self, x: self.set_hop_size(x))
- max_partials = property(lambda self: self.get_max_partials(),
- lambda self, x: self.set_max_partials(x))
- max_partials = property(lambda self: self.get_max_partials(),
- lambda self, x: self.set_max_partials(x))
- sampling_rate = property(lambda self: self.get_sampling_rate(),
- lambda self, x: self.set_sampling_rate(x))
-
- def get_frame_size(self):
- return self._frame_size
-
- def set_frame_size(self, frame_size):
- self._frame_size = frame_size
-
- def get_hop_size(self):
- return self._hop_size
-
- def set_hop_size(self, hop_size):
- self._hop_size = hop_size
-
- def get_max_partials(self):
- return self._max_partials
-
- def set_max_partials(self, num_partials):
- self._max_partials = num_partials
-
- def get_sampling_rate(self):
- return self._sampling_rate
-
- def set_sampling_rate(self, sampling_rate):
- self._sampling_rate = sampling_rate
-
- def synth_frame(self, frame):
- "Synthesises a frame of audio, given a list of peaks from tracks"
- raise Exception("NotYetImplemented")
-
- def synth(self, frames):
- "Synthesise audio from the given partials"
- audio_out = simpl.array([])
- for frame in frames:
- audio_out = np.hstack((audio_out, self.synth_frame(frame)))
- return audio_out
-
-
-class Residual(object):
- "Calculate a residual signal"
-
- def __init__(self):
- self._hop_size = 512
- self._frame_size = 512
-
- frame_size = property(lambda self: self.get_frame_size(),
- lambda self, x: self.set_frame_size(x))
- hop_size = property(lambda self: self.get_hop_size(),
- lambda self, x: self.set_hop_size(x))
-
- def get_frame_size(self):
- return self._frame_size
-
- def set_frame_size(self, frame_size):
- self._frame_size = frame_size
-
- def get_hop_size(self):
- return self._hop_size
-
- def set_hop_size(self, hop_size):
- self._hop_size = hop_size
-
- def residual_frame(self, synth, original):
- "Computes the residual signal for a frame of audio"
- raise Exception("NotYetImplemented")
-
- def find_residual(self, synth, original):
- "Calculate and return the residual signal"
- # pad the signals if necessary
- if len(synth) % self.hop_size != 0:
- synth = np.hstack((synth, np.zeros(self.hop_size - (len(synth) % self.hop_size))))
- if len(original) % self.hop_size != 0:
- original = np.hstack((original, np.zeros(self.hop_size - (len(original) % self.hop_size))))
-
- num_frames = len(original) / self.hop_size
- residual = simpl.array([])
- sample_offset = 0
-
- for i in range(num_frames):
- synth_frame = synth[sample_offset:sample_offset+self.hop_size]
- original_frame = original[sample_offset:sample_offset+self.hop_size]
- residual = np.hstack((residual,
- self.residual_frame(synth_frame, original_frame)))
- sample_offset += self.hop_size
- return residual
-
- def synth_frame(self, synth, original):
- "Calculate and return one frame of the synthesised residual signal"
- raise Exception("NotYetImplemented")
-
- def synth(self, synth, original):
- "Calculate and return a synthesised residual signal"
- # pad the signals if necessary
- if len(synth) % self.hop_size != 0:
- synth = np.hstack((synth, np.zeros(self.hop_size - (len(synth) % self.hop_size))))
- if len(original) % self.hop_size != 0:
- original = np.hstack((original, np.zeros(self.hop_size - (len(original) % self.hop_size))))
-
- num_frames = len(original) / self.hop_size
- residual = simpl.array([])
- sample_offset = 0
-
- for i in range(num_frames):
- synth_frame = synth[sample_offset:sample_offset+self.hop_size]
- original_frame = original[sample_offset:sample_offset+self.hop_size]
- residual = np.hstack((residual,
- self.synth_frame(synth_frame, original_frame)))
- sample_offset += self.hop_size
- return residual
-