"""
Phase vocoder.
The phase vocoder is a digital signal processing technique of potentially
great musical significance. It can be used to perform very high fidelity
time scaling, pitch transposition, and myriad other modifications of sounds.
"""
"""
Copyright 2009-2015 Olivier Belanger
This file is part of pyo, a python module to help digital signal
processing script creation.
pyo is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
pyo 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with pyo. If not, see <http://www.gnu.org/licenses/>.
"""
from ._core import *
from ._maps import *
from ._widgets import createSpectrumWindow
from .pattern import Pattern
[docs]class PVAnal(PyoPVObject):
"""
Phase Vocoder analysis object.
PVAnal takes an input sound and performs the phase vocoder
analysis on it. This results in two streams, one for the bin's
magnitudes and the other for the bin's true frequencies. These
two streams are used by the PVxxx object family to transform
the input signal using spectral domain algorithms. The last
object in the phase vocoder chain must be a PVSynth to perform
the spectral to time domain conversion.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoObject
Input signal to process.
size: int {pow-of-two > 4}, optional
FFT size. Must be a power of two greater than 4.
Defaults to 1024.
The FFT size is the number of samples used in each
analysis frame.
overlaps: int, optional
The number of overlaped analysis block. Must be a
power of two. Defaults to 4.
More overlaps can greatly improved sound quality
synthesis but it is also more CPU expensive.
wintype: int, optional
Shape of the envelope used to filter each input frame.
Possible shapes are:
0. rectangular (no windowing)
1. Hamming
2. Hanning (default)
3. Bartlett (triangular)
4. Blackman 3-term
5. Blackman-Harris 4-term
6. Blackman-Harris 7-term
7. Tuckey (alpha = 0.66)
8. Sine (half-sine window)
callback: callable, optional
If not None (default), this function will be called with the result
of the analysis at the end of every overlap. The function will
receive two arguments, a list of floats for both the magnitudes
and the frequencies. The signature is:
callback(magnitudes, frequencies)
If you analyse a multi-channel signal, you should pass a list
of callables, one per channel to analyse.
>>> s = Server().boot()
>>> s.start()
>>> a = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=0.7)
>>> pva = PVAnal(a, size=1024, overlaps=4, wintype=2)
>>> pvs = PVSynth(pva).mix(2).out()
"""
def __init__(self, input, size=1024, overlaps=4, wintype=2, callback=None):
pyoArgsAssert(self, "oiiic", input, size, overlaps, wintype, callback)
PyoPVObject.__init__(self)
self._input = input
self._size = size
self._overlaps = overlaps
self._wintype = wintype
self._callback = callback
self._in_fader = InputFader(input)
in_fader, size, overlaps, wintype, callback, lmax = convertArgsToLists(
self._in_fader, size, overlaps, wintype, callback
)
self._base_objs = [
PVAnal_base(wrap(in_fader, i), wrap(size, i), wrap(overlaps, i), wrap(wintype, i), wrap(callback, i))
for i in range(lmax)
]
self._init_play()
[docs] def setSize(self, x):
"""
Replace the `size` attribute.
:Args:
x: int
new `size` attribute.
"""
pyoArgsAssert(self, "i", x)
self._size = x
x, lmax = convertArgsToLists(x)
[obj.setSize(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setOverlaps(self, x):
"""
Replace the `overlaps` attribute.
:Args:
x: int
new `overlaps` attribute.
"""
pyoArgsAssert(self, "i", x)
self._overlaps = x
x, lmax = convertArgsToLists(x)
[obj.setOverlaps(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setWinType(self, x):
"""
Replace the `wintype` attribute.
:Args:
x: int
new `wintype` attribute.
"""
pyoArgsAssert(self, "i", x)
self._wintype = x
x, lmax = convertArgsToLists(x)
[obj.setWinType(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setCallback(self, x):
"""
Replace the `callback` attribute.
:Args:
x: callable
new `callback` attribute.
"""
pyoArgsAssert(self, "c", x)
self._callback = x
x, lmax = convertArgsToLists(x)
[obj.setCallback(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
@property
def input(self):
"""PyoObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def size(self):
"""int. FFT size."""
return self._size
@size.setter
def size(self, x):
self.setSize(x)
@property
def overlaps(self):
"""int. FFT overlap factor."""
return self._overlaps
@overlaps.setter
def overlaps(self, x):
self.setOverlaps(x)
@property
def wintype(self):
"""int. Windowing method."""
return self._wintype
@wintype.setter
def wintype(self, x):
self.setWinType(x)
[docs]class PVSynth(PyoObject):
"""
Phase Vocoder synthesis object.
PVSynth takes a PyoPVObject as its input and performed
the spectral to time domain conversion on it. This step
converts phase vocoder magnitude and true frequency's
streams back to a real signal.
:Parent: :py:class:`PyoObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
wintype: int, optional
Shape of the envelope used to filter each input frame.
Possible shapes are:
0. rectangular (no windowing)
1. Hamming
2. Hanning (default)
3. Bartlett (triangular)
4. Blackman 3-term
5. Blackman-Harris 4-term
6. Blackman-Harris 7-term
7. Tuckey (alpha = 0.66)
8. Sine (half-sine window)
>>> s = Server().boot()
>>> s.start()
>>> a = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=0.7)
>>> pva = PVAnal(a, size=1024, overlaps=4, wintype=2)
>>> pvs = PVSynth(pva).mix(2).out()
"""
def __init__(self, input, wintype=2, mul=1, add=0):
pyoArgsAssert(self, "piOO", input, wintype, mul, add)
PyoObject.__init__(self, mul, add)
self._input = input
self._wintype = wintype
input, wintype, mul, add, lmax = convertArgsToLists(self._input, wintype, mul, add)
self._base_objs = [
PVSynth_base(wrap(input, i), wrap(wintype, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
]
self._init_play()
[docs] def setWinType(self, x):
"""
Replace the `wintype` attribute.
:Args:
x: int
new `wintype` attribute.
"""
pyoArgsAssert(self, "i", x)
self._wintype = x
x, lmax = convertArgsToLists(x)
[obj.setWinType(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def wintype(self):
"""int. Windowing method."""
return self._wintype
@wintype.setter
def wintype(self, x):
self.setWinType(x)
[docs]class PVAddSynth(PyoObject):
"""
Phase Vocoder additive synthesis object.
PVAddSynth takes a PyoPVObject as its input and resynthesize
the real signal using the magnitude and true frequency's
streams to control amplitude and frequency envelopes of an
oscillator bank.
:Parent: :py:class:`PyoObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
pitch: float or PyoObject, optional
Transposition factor. Defaults to 1.
num: int, optional
Number of oscillators used to synthesize the
output sound. Defaults to 100.
first: int, optional
The first bin to synthesize, starting from 0.
Defaults to 0.
inc: int, optional
Starting from bin `first`, resynthesize bins
`inc` apart. Defaults to 1.
>>> s = Server().boot()
>>> s.start()
>>> a = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=0.7)
>>> pva = PVAnal(a, size=1024, overlaps=4, wintype=2)
>>> pvs = PVAddSynth(pva, pitch=1.25, num=100, first=0, inc=2).out()
"""
def __init__(self, input, pitch=1, num=100, first=0, inc=1, mul=1, add=0):
pyoArgsAssert(self, "pOiiiOO", input, pitch, num, first, inc, mul, add)
PyoObject.__init__(self, mul, add)
self._input = input
self._pitch = pitch
self._num = num
self._first = first
self._inc = inc
input, pitch, num, first, inc, mul, add, lmax = convertArgsToLists(
self._input, pitch, num, first, inc, mul, add
)
self._base_objs = [
PVAddSynth_base(
wrap(input, i), wrap(pitch, i), wrap(num, i), wrap(first, i), wrap(inc, i), wrap(mul, i), wrap(add, i)
)
for i in range(lmax)
]
self._init_play()
[docs] def setPitch(self, x):
"""
Replace the `pitch` attribute.
:Args:
x: float or PyoObject
new `pitch` attribute.
"""
pyoArgsAssert(self, "O", x)
self._pitch = x
x, lmax = convertArgsToLists(x)
[obj.setPitch(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setNum(self, x):
"""
Replace the `num` attribute.
:Args:
x: int
new `num` attribute.
"""
pyoArgsAssert(self, "i", x)
self._num = x
x, lmax = convertArgsToLists(x)
[obj.setNum(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setFirst(self, x):
"""
Replace the `first` attribute.
:Args:
x: int
new `first` attribute.
"""
pyoArgsAssert(self, "i", x)
self._first = x
x, lmax = convertArgsToLists(x)
[obj.setFirst(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setInc(self, x):
"""
Replace the `inc` attribute.
:Args:
x: int
new `inc` attribute.
"""
pyoArgsAssert(self, "i", x)
self._inc = x
x, lmax = convertArgsToLists(x)
[obj.setInc(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0.25, 4, "lin", "pitch", self._pitch), SLMapMul(self._mul)]
PyoObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def pitch(self):
"""float or PyoObject. Transposition factor."""
return self._pitch
@pitch.setter
def pitch(self, x):
self.setPitch(x)
@property
def num(self):
"""int. Number of oscillators."""
return self._num
@num.setter
def num(self, x):
self.setNum(x)
@property
def first(self):
"""int. First bin to synthesize."""
return self._first
@first.setter
def first(self, x):
self.setFirst(x)
@property
def inc(self):
"""int. Synthesized bin increment."""
return self._inc
@inc.setter
def inc(self, x):
self.setInc(x)
[docs]class PVTranspose(PyoPVObject):
"""
Transpose the frequency components of a pv stream.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
transpo: float or PyoObject, optional
Transposition factor. Defaults to 1.
>>> s = Server().boot()
>>> s.start()
>>> sf = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=.7)
>>> pva = PVAnal(sf, size=1024)
>>> pvt = PVTranspose(pva, transpo=1.5)
>>> pvs = PVSynth(pvt).out()
>>> dry = Delay(sf, delay=1024./s.getSamplingRate(), mul=.7).out(1)
"""
def __init__(self, input, transpo=1):
pyoArgsAssert(self, "pO", input, transpo)
PyoPVObject.__init__(self)
self._input = input
self._transpo = transpo
input, transpo, lmax = convertArgsToLists(self._input, transpo)
self._base_objs = [PVTranspose_base(wrap(input, i), wrap(transpo, i)) for i in range(lmax)]
self._init_play()
[docs] def setTranspo(self, x):
"""
Replace the `transpo` attribute.
:Args:
x: int
new `transpo` attribute.
"""
pyoArgsAssert(self, "O", x)
self._transpo = x
x, lmax = convertArgsToLists(x)
[obj.setTranspo(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0.25, 4, "lin", "transpo", self._transpo)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def transpo(self):
"""float or PyoObject. Transposition factor."""
return self._transpo
@transpo.setter
def transpo(self, x):
self.setTranspo(x)
[docs]class PVVerb(PyoPVObject):
"""
Spectral domain reverberation.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
revtime: float or PyoObject, optional
Reverberation factor, between 0 and 1.
Defaults to 0.75.
damp: float or PyoObject, optional
High frequency damping factor, between 0 and 1.
1 means no damping and 0 is the most damping.
Defaults to 0.75.
>>> s = Server().boot()
>>> s.start()
>>> sf = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=.5)
>>> pva = PVAnal(sf, size=2048)
>>> pvg = PVGate(pva, thresh=-36, damp=0)
>>> pvv = PVVerb(pvg, revtime=0.95, damp=0.95)
>>> pvs = PVSynth(pvv).mix(2).out()
>>> dry = Delay(sf, delay=2048./s.getSamplingRate(), mul=.4).mix(2).out()
"""
def __init__(self, input, revtime=0.75, damp=0.75):
pyoArgsAssert(self, "pOO", input, revtime, damp)
PyoPVObject.__init__(self)
self._input = input
self._revtime = revtime
self._damp = damp
input, revtime, damp, lmax = convertArgsToLists(self._input, revtime, damp)
self._base_objs = [PVVerb_base(wrap(input, i), wrap(revtime, i), wrap(damp, i)) for i in range(lmax)]
self._init_play()
[docs] def setRevtime(self, x):
"""
Replace the `revtime` attribute.
:Args:
x: int
new `revtime` attribute.
"""
pyoArgsAssert(self, "O", x)
self._revtime = x
x, lmax = convertArgsToLists(x)
[obj.setRevtime(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setDamp(self, x):
"""
Replace the `damp` attribute.
:Args:
x: int
new `damp` attribute.
"""
pyoArgsAssert(self, "O", x)
self._damp = x
x, lmax = convertArgsToLists(x)
[obj.setDamp(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0, 1, "lin", "revtime", self._revtime), SLMap(0, 1, "lin", "damp", self._damp)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def revtime(self):
"""float or PyoObject. Reverberation factor."""
return self._revtime
@revtime.setter
def revtime(self, x):
self.setRevtime(x)
@property
def damp(self):
"""float or PyoObject. High frequency damping factor."""
return self._damp
@damp.setter
def damp(self, x):
self.setDamp(x)
[docs]class PVGate(PyoPVObject):
"""
Spectral gate.
:Parent: :py:class:`PyoObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
thresh: float or PyoObject, optional
Threshold factor in dB. Bins below that threshold
will be scaled by `damp` factor. Defaults to -20.
damp: float or PyoObject, optional
Damping factor for low amplitude bins. Defaults to 0.
inverse: boolean, optional
If True, the damping factor will be applied to the bins
with amplitude above the given threshold. If False, the
damping factor is applied to bins with amplitude below
the given threshold. Defaults to False.
>>> s = Server().boot()
>>> s.start()
>>> sf = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=.5)
>>> pva = PVAnal(sf, size=2048)
>>> pvg = PVGate(pva, thresh=-50, damp=0)
>>> pvs = PVSynth(pvg).mix(2).out()
"""
def __init__(self, input, thresh=-20, damp=0.0, inverse=False):
pyoArgsAssert(self, "pOOb", input, thresh, damp, inverse)
PyoPVObject.__init__(self)
self._input = input
self._thresh = thresh
self._damp = damp
self._inverse = inverse
input, thresh, damp, inverse, lmax = convertArgsToLists(self._input, thresh, damp, inverse)
self._base_objs = [
PVGate_base(wrap(input, i), wrap(thresh, i), wrap(damp, i), wrap(inverse, i)) for i in range(lmax)
]
self._init_play()
[docs] def setThresh(self, x):
"""
Replace the `thresh` attribute.
:Args:
x: int
new `thresh` attribute.
"""
pyoArgsAssert(self, "O", x)
self._thresh = x
x, lmax = convertArgsToLists(x)
[obj.setThresh(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setDamp(self, x):
"""
Replace the `damp` attribute.
:Args:
x: int
new `damp` attribute.
"""
pyoArgsAssert(self, "O", x)
self._damp = x
x, lmax = convertArgsToLists(x)
[obj.setDamp(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setInverse(self, x):
"""
Replace the `inverse` attribute.
:Args:
x: boolean
new `inverse` attribute.
"""
pyoArgsAssert(self, "b", x)
self._inverse = x
x, lmax = convertArgsToLists(x)
[obj.setInverse(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(-120, 18, "lin", "thresh", self._thresh), SLMap(0, 2, "lin", "damp", self._damp)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def thresh(self):
"""float or PyoObject. Threshold factor."""
return self._thresh
@thresh.setter
def thresh(self, x):
self.setThresh(x)
@property
def damp(self):
"""float or PyoObject. Damping factor for low amplitude bins."""
return self._damp
@damp.setter
def damp(self, x):
self.setDamp(x)
@property
def inverse(self):
"""boolean. If True, the gate is applied to high amplitude bins."""
return self._inverse
@inverse.setter
def inverse(self, x):
self.setInverse(x)
[docs]class PVCross(PyoPVObject):
"""
Performs cross-synthesis between two phase vocoder streaming object.
The amplitudes from `input` and `input2` (scaled by `fade` argument)
are applied to the frequencies of `input`.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process. Frequencies from
this pv stream are used to compute the output signal.
input2: PyoPVObject
Phase vocoder streaming object which gives the second set of
magnitudes. Frequencies from this pv stream are not used.
fade: float or PyoObject, optional
Scaling factor for the output amplitudes, between 0 and 1.
0 means amplitudes from `input` and 1 means amplitudes from `input2`.
Defaults to 1.
.. note::
The two input pv stream must have the same size and overlaps. It is
the responsibility of the user to be sure they are consistent. To change
the size (or the overlaps) of the phase vocoder process, one must
write a function to change both at the same time (see the example below).
Another possibility is to use channel expansion to analyse both sounds
with the same PVAnal object.
>>> s = Server().boot()
>>> s.start()
>>> sf = SineLoop(freq=[80,81], feedback=0.07, mul=.5)
>>> sf2 = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=.5)
>>> pva = PVAnal(sf)
>>> pva2 = PVAnal(sf2)
>>> pvc = PVCross(pva, pva2, fade=1)
>>> pvs = PVSynth(pvc).out()
>>> def size(x):
... pva.size = x
... pva2.size = x
>>> def olaps(x):
... pva.overlaps = x
... pva2.overlaps = x
"""
def __init__(self, input, input2, fade=1):
pyoArgsAssert(self, "ppO", input, input2, fade)
PyoPVObject.__init__(self)
self._input = input
self._input2 = input2
self._fade = fade
input, input2, fade, lmax = convertArgsToLists(self._input, self._input2, fade)
self._base_objs = [PVCross_base(wrap(input, i), wrap(input2, i), wrap(fade, i)) for i in range(lmax)]
self._init_play()
[docs] def setFade(self, x):
"""
Replace the `fade` attribute.
:Args:
x: float or PyoObject
new `fade` attribute.
"""
pyoArgsAssert(self, "O", x)
self._fade = x
x, lmax = convertArgsToLists(x)
[obj.setFade(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0, 1, "lin", "fade", self._fade)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def input2(self):
"""PyoPVObject. Second set of amplitudes."""
return self._input2
@input2.setter
def input2(self, x):
self.setInput2(x)
@property
def fade(self):
"""float or PyoObject. Scaling factor."""
return self._fade
@fade.setter
def fade(self, x):
self.setFade(x)
[docs]class PVMult(PyoPVObject):
"""
Multiply magnitudes from two phase vocoder streaming object.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process. Frequencies from
this pv stream are used to compute the output signal.
input2: PyoPVObject
Phase vocoder streaming object which gives the second set of
magnitudes. Frequencies from this pv stream are not used.
.. note::
The two input pv stream must have the same size and overlaps. It is
the responsibility of the user to be sure they are consistent. To change
the size (or the overlaps) of the phase vocoder process, one must
write a function to change both at the same time (see the example below).
Another possibility is to use channel expansion to analyse both sounds
with the same PVAnal object.
>>> s = Server().boot()
>>> s.start()
>>> sf = FM(carrier=[100,150], ratio=[.999,.5005], index=20, mul=.4)
>>> sf2 = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=.5)
>>> pva = PVAnal(sf)
>>> pva2 = PVAnal(sf2)
>>> pvc = PVMult(pva, pva2)
>>> pvs = PVSynth(pvc).out()
>>> def size(x):
... pva.size = x
... pva2.size = x
>>> def olaps(x):
... pva.overlaps = x
... pva2.overlaps = x
"""
def __init__(self, input, input2):
pyoArgsAssert(self, "pp", input, input2)
PyoPVObject.__init__(self)
self._input = input
self._input2 = input2
input, input2, lmax = convertArgsToLists(self._input, self._input2)
self._base_objs = [PVMult_base(wrap(input, i), wrap(input2, i)) for i in range(lmax)]
self._init_play()
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def input2(self):
"""PyoPVObject. Second set of magnitudes."""
return self._input2
@input2.setter
def input2(self, x):
self.setInput2(x)
[docs]class PVMorph(PyoPVObject):
"""
Performs spectral morphing between two phase vocoder streaming object.
According to `fade` argument, the amplitudes from `input` and `input2`
are interpolated linearly while the frequencies are interpolated
exponentially.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object which gives the first set of
magnitudes and frequencies.
input2: PyoPVObject
Phase vocoder streaming object which gives the second set of
magnitudes and frequencies.
fade: float or PyoObject, optional
Scaling factor for the output amplitudes and frequencies,
between 0 and 1. 0 is `input` and 1 in `input2`. Defaults to 0.5.
.. note::
The two input pv stream must have the same size and overlaps. It is
the responsibility of the user to be sure they are consistent. To change
the size (or the overlaps) of the phase vocoder process, one must
write a function to change both at the same time (see the example below).
Another possibility is to use channel expansion to analyse both sounds
with the same PVAnal object.
>>> s = Server().boot()
>>> s.start()
>>> sf = SineLoop(freq=[100,101], feedback=0.12, mul=.5)
>>> sf2 = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=.5)
>>> pva = PVAnal(sf)
>>> pva2 = PVAnal(sf2)
>>> pvc = PVMorph(pva, pva2, fade=0.5)
>>> pvs = PVSynth(pvc).out()
>>> def size(x):
... pva.size = x
... pva2.size = x
>>> def olaps(x):
... pva.overlaps = x
... pva2.overlaps = x
"""
def __init__(self, input, input2, fade=0.5):
pyoArgsAssert(self, "ppO", input, input2, fade)
PyoPVObject.__init__(self)
self._input = input
self._input2 = input2
self._fade = fade
input, input2, fade, lmax = convertArgsToLists(self._input, self._input2, fade)
self._base_objs = [PVMorph_base(wrap(input, i), wrap(input2, i), wrap(fade, i)) for i in range(lmax)]
self._init_play()
[docs] def setFade(self, x):
"""
Replace the `fade` attribute.
:Args:
x: float or PyoObject
new `fade` attribute.
"""
pyoArgsAssert(self, "O", x)
self._fade = x
x, lmax = convertArgsToLists(x)
[obj.setFade(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0, 1, "lin", "fade", self._fade)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. First input signal."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def input2(self):
"""PyoPVObject. Second input signal."""
return self._input2
@input2.setter
def input2(self, x):
self.setInput2(x)
@property
def fade(self):
"""float or PyoObject. Scaling factor."""
return self._fade
@fade.setter
def fade(self, x):
self.setFade(x)
[docs]class PVFilter(PyoPVObject):
"""
Spectral filter.
PVFilter filters frequency components of a pv stream
according to the shape drawn in the table given in
argument.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
table: PyoTableObject
Table containing the filter shape. If the
table length is smaller than fftsize/2,
remaining bins will be set to 0.
gain: float or PyoObject, optional
Gain of the filter applied to the input spectrum.
Defaults to 1.
mode: int, optional
Table scanning mode. Defaults to 0.
If 0, bin indexes outside table size are set to 0.
If 1, bin indexes are scaled over table length.
>>> s = Server().boot()
>>> s.start()
>>> t = ExpTable([(0,1),(61,1),(71,0),(131,1),(171,0),(511,0)], size=512)
>>> src = Noise(.4)
>>> pva = PVAnal(src, size=1024)
>>> pvf = PVFilter(pva, t)
>>> pvs = PVSynth(pvf).out()
"""
def __init__(self, input, table, gain=1, mode=0):
pyoArgsAssert(self, "ptOi", input, table, gain, mode)
PyoPVObject.__init__(self)
self._input = input
self._table = table
self._gain = gain
self._mode = mode
input, table, gain, mode, lmax = convertArgsToLists(self._input, table, gain, mode)
self._base_objs = [
PVFilter_base(wrap(input, i), wrap(table, i), wrap(gain, i), wrap(mode, i)) for i in range(lmax)
]
self._init_play()
[docs] def setTable(self, x):
"""
Replace the `table` attribute.
:Args:
x: PyoTableObject
new `table` attribute.
"""
pyoArgsAssert(self, "t", x)
self._table = x
x, lmax = convertArgsToLists(x)
[obj.setTable(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setGain(self, x):
"""
Replace the `gain` attribute.
:Args:
x: float or PyoObject
new `gain` attribute.
"""
pyoArgsAssert(self, "O", x)
self._gain = x
x, lmax = convertArgsToLists(x)
[obj.setGain(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setMode(self, x):
"""
Replace the `mode` attribute.
:Args:
x: int
new `mode` attribute.
"""
pyoArgsAssert(self, "i", x)
self._mode = x
x, lmax = convertArgsToLists(x)
[obj.setMode(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0, 1, "lin", "gain", self._gain)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def table(self):
"""PyoTableObject. Table containing the filter shape."""
return self._table
@table.setter
def table(self, x):
self.setTable(x)
@property
def gain(self):
"""float or PyoObject. Gain of the filter."""
return self._gain
@gain.setter
def gain(self, x):
self.setGain(x)
@property
def mode(self):
"""int. Table scanning mode."""
return self._mode
@mode.setter
def mode(self, x):
self.setMode(x)
[docs]class PVDelay(PyoPVObject):
"""
Spectral delays.
PVDelay applies different delay times and feedbacks for
each bin of a phase vocoder analysis. Delay times and
feedbacks are specified with PyoTableObjects.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
deltable: PyoTableObject
Table containing delay times, as integer multipliers
of the FFT hopsize (fftsize / overlaps).
If the table length is smaller than fftsize/2,
remaining bins will be set to 0.
feedtable: PyoTableObject
Table containing feedback values, between -1 and 1.
If the table length is smaller than fftsize/2,
remaining bins will be set to 0.
maxdelay: float, optional
Maximum delay time in seconds. Available at initialization
time only. Defaults to 1.0.
mode: int, optional
Tables scanning mode. Defaults to 0.
If 0, bin indexes outside table size are set to 0.
If 1, bin indexes are scaled over table length.
>>> s = Server().boot()
>>> s.start()
>>> SIZE = 1024
>>> SIZE2 = int(SIZE / 2)
>>> OLAPS = 4
>>> MAXDEL = 2.0 # two seconds delay memories
>>> FRAMES = int(MAXDEL * s.getSamplingRate() / (SIZE / OLAPS))
>>> # Edit tables with the graph() method. yrange=(0, FRAMES) for delays table
>>> dt = DataTable(size=SIZE2, init=[i / float(SIZE2) * FRAMES for i in range(SIZE2)])
>>> ft = DataTable(size=SIZE2, init=[0.5]*SIZE2)
>>> src = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=0.5)
>>> pva = PVAnal(src, size=SIZE, overlaps=OLAPS)
>>> pvd = PVDelay(pva, dt, ft, maxdelay=MAXDEL)
>>> pvs = PVSynth(pvd).out()
"""
def __init__(self, input, deltable, feedtable, maxdelay=1.0, mode=0):
pyoArgsAssert(self, "pttni", input, deltable, feedtable, maxdelay, mode)
PyoPVObject.__init__(self)
self._input = input
self._deltable = deltable
self._feedtable = feedtable
self._maxdelay = maxdelay
self._mode = mode
input, deltable, feedtable, maxdelay, mode, lmax = convertArgsToLists(
self._input, deltable, feedtable, maxdelay, mode
)
self._base_objs = [
PVDelay_base(wrap(input, i), wrap(deltable, i), wrap(feedtable, i), wrap(maxdelay, i), wrap(mode, i))
for i in range(lmax)
]
self._init_play()
[docs] def setDeltable(self, x):
"""
Replace the `deltable` attribute.
:Args:
x: PyoTableObject
new `deltable` attribute.
"""
pyoArgsAssert(self, "t", x)
self._deltable = x
x, lmax = convertArgsToLists(x)
[obj.setDeltable(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setFeedtable(self, x):
"""
Replace the `feedtable` attribute.
:Args:
x: PyoTableObject
new `feedtable` attribute.
"""
pyoArgsAssert(self, "t", x)
self._feedtable = x
x, lmax = convertArgsToLists(x)
[obj.setFeedtable(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setMode(self, x):
"""
Replace the `mode` attribute.
:Args:
x: int
new `mode` attribute.
"""
pyoArgsAssert(self, "i", x)
self._mode = x
x, lmax = convertArgsToLists(x)
[obj.setMode(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def deltable(self):
"""PyoTableObject. Table containing the delay times."""
return self._deltable
@deltable.setter
def deltable(self, x):
self.setDeltable(x)
@property
def feedtable(self):
"""PyoTableObject. Table containing feedback values."""
return self._feedtable
@feedtable.setter
def feedtable(self, x):
self.setFeedtable(x)
@property
def mode(self):
"""int. Table scanning mode."""
return self._mode
@mode.setter
def mode(self, x):
self.setMode(x)
[docs]class PVBuffer(PyoPVObject):
"""
Phase vocoder buffer and playback with transposition.
PVBuffer keeps `length` seconds of pv analysis in memory
and gives control on playback position and transposition.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
index: PyoObject
Playback position, as audio stream, normalized
between 0 and 1.
pitch: float or PyoObject, optional
Transposition factor. Defaults to 1.
length: float, optional
Memory length in seconds. Defaults to 1.0.
.. note::
The play() method can be called to start a new recording of
the current pv input.
>>> s = Server().boot()
>>> s.start()
>>> f = SNDS_PATH+'/transparent.aif'
>>> f_len = sndinfo(f)[1]
>>> src = SfPlayer(f, mul=0.5)
>>> index = Phasor(freq=1.0/f_len*0.25, phase=0.9)
>>> pva = PVAnal(src, size=1024, overlaps=8)
>>> pvb = PVBuffer(pva, index, pitch=1.25, length=f_len)
>>> pvs = PVSynth(pvb).out()
"""
def __init__(self, input, index, pitch=1.0, length=1.0):
pyoArgsAssert(self, "poOn", input, index, pitch, length)
PyoPVObject.__init__(self)
self._input = input
self._index = index
self._pitch = pitch
self._length = length
input, index, pitch, length, lmax = convertArgsToLists(self._input, index, pitch, length)
self._base_objs = [
PVBuffer_base(wrap(input, i), wrap(index, i), wrap(pitch, i), wrap(length, i)) for i in range(lmax)
]
self._init_play()
[docs] def setIndex(self, x):
"""
Replace the `index` attribute.
:Args:
x: PyoObject
new `index` attribute.
"""
pyoArgsAssert(self, "o", x)
self._index = x
x, lmax = convertArgsToLists(x)
[obj.setIndex(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setPitch(self, x):
"""
Replace the `pitch` attribute.
:Args:
x: float or PyoObject
new `pitch` attribute.
"""
pyoArgsAssert(self, "O", x)
self._pitch = x
x, lmax = convertArgsToLists(x)
[obj.setPitch(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setLength(self, x):
"""
Replace the `length` attribute.
:Args:
x: float
new `length` attribute.
"""
pyoArgsAssert(self, "n", x)
self._length = x
x, lmax = convertArgsToLists(x)
[obj.setLength(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(0.25, 4, "lin", "pitch", self._pitch)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def index(self):
"""PyoObject. Reader's normalized position."""
return self._index
@index.setter
def index(self, x):
self.setIndex(x)
@property
def pitch(self):
"""float or PyoObject. Transposition factor."""
return self._pitch
@pitch.setter
def pitch(self, x):
self.setPitch(x)
@property
def length(self):
"""float. Buffer length in seconds."""
return self._length
@length.setter
def length(self, x):
self.setLength(x)
[docs]class PVShift(PyoPVObject):
"""
Spectral domain frequency shifter.
PVShift linearly moves the analysis bins by the amount, in Hertz,
specified by the the `shift` argument.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
shift: float or PyoObject, optional
Frequency shift factor. Defaults to 0.
>>> s = Server().boot()
>>> s.start()
>>> sf = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=.7)
>>> pva = PVAnal(sf, size=1024)
>>> pvt = PVShift(pva, shift=500)
>>> pvs = PVSynth(pvt).out()
"""
def __init__(self, input, shift=0):
pyoArgsAssert(self, "pO", input, shift)
PyoPVObject.__init__(self)
self._input = input
self._shift = shift
input, shift, lmax = convertArgsToLists(self._input, shift)
self._base_objs = [PVShift_base(wrap(input, i), wrap(shift, i)) for i in range(lmax)]
self._init_play()
[docs] def setShift(self, x):
"""
Replace the `shift` attribute.
:Args:
x: float or PyoObject
new `shift` attribute.
"""
pyoArgsAssert(self, "O", x)
self._shift = x
x, lmax = convertArgsToLists(x)
[obj.setShift(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(-5000, 5000, "lin", "shift", self._shift)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def shift(self):
"""float or PyoObject. Frequency shift factor."""
return self._shift
@shift.setter
def shift(self, x):
self.setShift(x)
[docs]class PVAmpMod(PyoPVObject):
"""
Performs frequency independent amplitude modulations.
PVAmpMod modulates the magnitude of each bin of a pv
stream with an independent oscillator. `basefreq` and
`spread` are used to derive the frequency of each
modulating oscillator.
Internally, the following operations are applied to
derive oscillator frequencies (`i` is the bin number):
spread = spread * 0.001 + 1.0
f_i = basefreq * pow(spread, i)
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
basefreq: float or PyoObject, optional
Base modulation frequency, in Hertz.
Defaults to 1.
spread: float or PyoObject, optional
Spreading factor for oscillator frequencies, between
-1 and 1. 0 means every oscillator has the same frequency.
shape: int, optional
Modulation oscillator waveform. Possible shapes are:
0. Sine (default)
1. Sawtooth
2. Ramp (inverse sawtooth)
3. Square
4. Triangle
5. Brown Noise
6. Pink Noise
7. White Noise
>>> s = Server().boot()
>>> s.start()
>>> src = PinkNoise(.3)
>>> pva = PVAnal(src, size=1024, overlaps=4)
>>> pvm = PVAmpMod(pva, basefreq=4, spread=0.5)
>>> pvs = PVSynth(pvm).out()
"""
def __init__(self, input, basefreq=1, spread=0, shape=0):
pyoArgsAssert(self, "pOOi", input, basefreq, spread, shape)
PyoPVObject.__init__(self)
self._input = input
self._basefreq = basefreq
self._spread = spread
self._shape = shape
input, basefreq, spread, shape, lmax = convertArgsToLists(self._input, basefreq, spread, shape)
self._base_objs = [
PVAmpMod_base(wrap(input, i), wrap(basefreq, i), wrap(spread, i), wrap(shape, i)) for i in range(lmax)
]
self._init_play()
[docs] def setBasefreq(self, x):
"""
Replace the `basefreq` attribute.
:Args:
x: float or PyoObject
new `basefreq` attribute.
"""
pyoArgsAssert(self, "O", x)
self._basefreq = x
x, lmax = convertArgsToLists(x)
[obj.setBasefreq(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setSpread(self, x):
"""
Replace the `spread` attribute.
:Args:
x: float or PyoObject
new `spread` attribute.
"""
pyoArgsAssert(self, "O", x)
self._spread = x
x, lmax = convertArgsToLists(x)
[obj.setSpread(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setShape(self, x):
"""
Replace the `shape` attribute.
:Args:
x: int
new `shape` attribute. Possible shapes are:
0. Sine (default)
1. Sawtooth
2. Ramp (inverse sawtooth)
3. Square
4. Triangle
5. Brown Noise
6. Pink Noise
7. White Noise
"""
pyoArgsAssert(self, "i", x)
self._shape = x
x, lmax = convertArgsToLists(x)
[obj.setShape(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def reset(self):
"""
Resets modulation pointers to 0.
"""
[obj.reset() for obj in self._base_objs]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [
SLMap(0.1, 20, "log", "basefreq", self._basefreq),
SLMap(-1, 1, "lin", "spread", self._spread),
]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def basefreq(self):
"""float or PyoObject. Modulator's base frequency."""
return self._basefreq
@basefreq.setter
def basefreq(self, x):
self.setBasefreq(x)
@property
def spread(self):
"""float or PyoObject. Modulator's frequency spreading factor."""
return self._spread
@spread.setter
def spread(self, x):
self.setSpread(x)
@property
def shape(self):
"""int. Modulation oscillator waveform."""
return self._shape
@shape.setter
def shape(self, x):
self.setShape(x)
[docs]class PVFreqMod(PyoPVObject):
"""
Performs frequency independent frequency modulations.
PVFreqMod modulates the frequency of each bin of a pv
stream with an independent oscillator. `basefreq` and
`spread` are used to derive the frequency of each
modulating oscillator.
Internally, the following operations are applied to
derive oscillator frequencies (`i` is the bin number):
spread = spread * 0.001 + 1.0
f_i = basefreq * pow(spread, i)
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
basefreq: float or PyoObject, optional
Base modulation frequency, in Hertz.
Defaults to 1.
spread: float or PyoObject, optional
Spreading factor for oscillator frequencies, between
-1 and 1. 0 means every oscillator has the same frequency.
depth: float or PyoObject, optional
Amplitude of the modulating oscillators, between 0 and 1.
Defaults to 0.1.
shape: int, optional
Modulation oscillator waveform. Possible shapes are:
0. Sine (default)
1. Sawtooth
2. Ramp (inverse sawtooth)
3. Square
4. Triangle
5. Brown Noise
6. Pink Noise
7. White Noise
>>> s = Server().boot()
>>> s.start()
>>> src = SfPlayer(SNDS_PATH+"/accord.aif", loop=True, mul=0.5)
>>> pva = PVAnal(src, size=1024, overlaps=4)
>>> pvm = PVFreqMod(pva, basefreq=8, spread=0.75, depth=0.05)
>>> pvs = PVSynth(pvm).out()
"""
def __init__(self, input, basefreq=1, spread=0, depth=0.1, shape=0):
pyoArgsAssert(self, "pOOOi", input, basefreq, spread, depth, shape)
PyoPVObject.__init__(self)
self._input = input
self._basefreq = basefreq
self._spread = spread
self._depth = depth
self._shape = shape
input, basefreq, spread, depth, shape, lmax = convertArgsToLists(self._input, basefreq, spread, depth, shape)
self._base_objs = [
PVFreqMod_base(wrap(input, i), wrap(basefreq, i), wrap(spread, i), wrap(depth, i), wrap(shape, i))
for i in range(lmax)
]
self._init_play()
[docs] def setBasefreq(self, x):
"""
Replace the `basefreq` attribute.
:Args:
x: float or PyoObject
new `basefreq` attribute.
"""
pyoArgsAssert(self, "O", x)
self._basefreq = x
x, lmax = convertArgsToLists(x)
[obj.setBasefreq(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setSpread(self, x):
"""
Replace the `spread` attribute.
:Args:
x: float or PyoObject
new `spread` attribute.
"""
pyoArgsAssert(self, "O", x)
self._spread = x
x, lmax = convertArgsToLists(x)
[obj.setSpread(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setDepth(self, x):
"""
Replace the `depth` attribute.
:Args:
x: float or PyoObject
new `depth` attribute.
"""
pyoArgsAssert(self, "O", x)
self._depth = x
x, lmax = convertArgsToLists(x)
[obj.setDepth(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setShape(self, x):
"""
Replace the `shape` attribute.
:Args:
x: int
new `shape` attribute. Possible shapes are:
0. Sine (default)
1. Sawtooth
2. Ramp (inverse sawtooth)
3. Square
4. Triangle
5. Brown Noise
6. Pink Noise
7. White Noise
"""
pyoArgsAssert(self, "i", x)
self._shape = x
x, lmax = convertArgsToLists(x)
[obj.setShape(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def reset(self):
"""
Resets modulation pointers to 0.
"""
[obj.reset() for obj in self._base_objs]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [
SLMap(0.1, 20, "log", "basefreq", self._basefreq),
SLMap(-1, 1, "lin", "spread", self._spread),
SLMap(0, 1, "lin", "depth", self._depth),
]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def basefreq(self):
"""float or PyoObject. Modulator's base frequency."""
return self._basefreq
@basefreq.setter
def basefreq(self, x):
self.setBasefreq(x)
@property
def spread(self):
"""float or PyoObject. Modulator's frequencies spreading factor."""
return self._spread
@spread.setter
def spread(self, x):
self.setSpread(x)
@property
def depth(self):
"""float or PyoObject. Amplitude of the modulators."""
return self._depth
@depth.setter
def depth(self, x):
self.setDepth(x)
@property
def shape(self):
"""int. Modulation oscillator waveform."""
return self._shape
@shape.setter
def shape(self, x):
self.setShape(x)
[docs]class PVBufLoops(PyoPVObject):
"""
Phase vocoder buffer with bin independent speed playback.
PVBufLoops keeps `length` seconds of pv analysis in memory
and gives control on playback position independently for
every frequency bin.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
low: float or PyoObject, optional
Lowest bin speed factor. Defaults to 1.0.
high: float or PyoObject, optional
Highest bin speed factor. Defaults to 1.0.
mode: int, optional
Speed distribution algorithm. Available algorithms are:
0. linear, line between `low` and `high` (default)
1. exponential, exponential line between `low` and `high`
2. logarithmic, logarithmic line between `low` and `high`
3. random, uniform random between `low` and `high`
4. rand expon min, exponential random from `low` to `high`
5. rand expon max, exponential random from `high` to `low`
6. rand bi-expon, bipolar exponential random between `low` and `high`
length: float, optional
Memory length in seconds. Available at initialization
time only. Defaults to 1.0.
.. note::
The play() method can be called to start a new recording of
the current pv input.
>>> s = Server().boot()
>>> s.start()
>>> f = SNDS_PATH+'/transparent.aif'
>>> f_len = sndinfo(f)[1]
>>> src = SfPlayer(f, mul=0.5)
>>> pva = PVAnal(src, size=1024, overlaps=8)
>>> pvb = PVBufLoops(pva, low=0.9, high=1.1, mode=3, length=f_len)
>>> pvs = PVSynth(pvb).out()
"""
def __init__(self, input, low=1.0, high=1.0, mode=0, length=1.0):
pyoArgsAssert(self, "pOOin", input, low, high, mode, length)
PyoPVObject.__init__(self)
self._input = input
self._low = low
self._high = high
self._mode = mode
self._length = length
input, low, high, mode, length, lmax = convertArgsToLists(self._input, low, high, mode, length)
self._base_objs = [
PVBufLoops_base(wrap(input, i), wrap(low, i), wrap(high, i), wrap(mode, i), wrap(length, i))
for i in range(lmax)
]
self._init_play()
[docs] def setLow(self, x):
"""
Replace the `low` attribute.
:Args:
x: float or PyoObject
new `low` attribute.
"""
pyoArgsAssert(self, "O", x)
self._low = x
x, lmax = convertArgsToLists(x)
[obj.setLow(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setHigh(self, x):
"""
Replace the `high` attribute.
:Args:
x: float or PyoObject
new `high` attribute.
"""
pyoArgsAssert(self, "O", x)
self._high = x
x, lmax = convertArgsToLists(x)
[obj.setHigh(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setMode(self, x):
"""
Replace the `mode` attribute.
:Args:
x: int
new `mode` attribute.
"""
pyoArgsAssert(self, "i", x)
self._mode = x
x, lmax = convertArgsToLists(x)
[obj.setMode(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def reset(self):
"""
Reset pointer positions to 0.
"""
[obj.reset() for obj in self._base_objs]
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False):
self._map_list = [SLMap(-4, 4, "lin", "low", self._low), SLMap(-4, 4, "lin", "high", self._high)]
PyoPVObject.ctrl(self, map_list, title, wxnoserver)
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def low(self):
"""float or PyoObject. Lowest bin speed factor."""
return self._low
@low.setter
def low(self, x):
self.setLow(x)
@property
def high(self):
"""float or PyoObject. Highest bin speed factor."""
return self._high
@high.setter
def high(self, x):
self.setHigh(x)
@property
def mode(self):
"""int. Speed distribution algorithm."""
return self._mode
@mode.setter
def mode(self, x):
self.setMode(x)
[docs]class PVBufTabLoops(PyoPVObject):
"""
Phase vocoder buffer with bin independent speed playback.
PVBufTabLoops keeps `length` seconds of pv analysis in memory
and gives control on playback position, using a PyoTableObject,
independently for every frequency bin.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object to process.
speed: PyoTableObject
Table which specify the speed of bin playback readers.
length: float, optional
Memory length in seconds. Available at initialization
time only. Defaults to 1.0.
.. note::
The play() method can be called to start a new recording of
the current pv input.
>>> s = Server().boot()
>>> s.start()
>>> f = SNDS_PATH+'/transparent.aif'
>>> f_len = sndinfo(f)[1]
>>> src = SfPlayer(f, mul=0.5)
>>> spd = ExpTable([(0,1), (512,0.5)], exp=6, size=512)
>>> pva = PVAnal(src, size=1024, overlaps=8)
>>> pvb = PVBufTabLoops(pva, spd, length=f_len)
>>> pvs = PVSynth(pvb).out()
"""
def __init__(self, input, speed, length=1.0):
pyoArgsAssert(self, "ptn", input, speed, length)
PyoPVObject.__init__(self)
self._input = input
self._speed = speed
self._length = length
input, speed, length, lmax = convertArgsToLists(self._input, speed, length)
self._base_objs = [PVBufTabLoops_base(wrap(input, i), wrap(speed, i), wrap(length, i)) for i in range(lmax)]
self._init_play()
[docs] def setSpeed(self, x):
"""
Replace the `speed` attribute.
:Args:
x: PyoTableObject
new `speed` attribute.
"""
pyoArgsAssert(self, "t", x)
self._speed = x
x, lmax = convertArgsToLists(x)
[obj.setSpeed(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def reset(self):
"""
Reset pointer positions to 0.
"""
[obj.reset() for obj in self._base_objs]
@property
def input(self):
"""PyoPVObject. Input signal to process."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def speed(self):
"""PyoTableObject. Table which specify the speed of bin playback readers."""
return self._speed
@speed.setter
def speed(self, x):
self.setSpeed(x)
[docs]class PVMix(PyoPVObject):
"""
Mix the most prominent components from two phase vocoder streaming objects.
:Parent: :py:class:`PyoPVObject`
:Args:
input: PyoPVObject
Phase vocoder streaming object 1.
input2: PyoPVObject
Phase vocoder streaming object 2.
.. note::
The two input pv stream must have the same size and overlaps. It is
the responsibility of the user to be sure they are consistent. To change
the size (or the overlaps) of the phase vocoder process, one must
write a function to change both at the same time (see the example below).
Another possibility is to use channel expansion to analyse both sounds
with the same PVAnal object.
>>> s = Server().boot()
>>> s.start()
>>> sf = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=.5)
>>> sf2 = SfPlayer(SNDS_PATH+"/accord.aif", loop=True, mul=.5)
>>> pva = PVAnal(sf)
>>> pva2 = PVAnal(sf2)
>>> pvm = PVMix(pva, pva2)
>>> pvs = PVSynth(pvm).out()
>>> def size(x):
... pva.size = x
... pva2.size = x
>>> def olaps(x):
... pva.overlaps = x
... pva2.overlaps = x
"""
def __init__(self, input, input2):
pyoArgsAssert(self, "pp", input, input2)
PyoPVObject.__init__(self)
self._input = input
self._input2 = input2
input, input2, lmax = convertArgsToLists(self._input, self._input2)
self._base_objs = [PVMix_base(wrap(input, i), wrap(input2, i)) for i in range(lmax)]
self._init_play()
@property
def input(self):
"""PyoPVObject. Phase vocoder streaming object 1."""
return self._input
@input.setter
def input(self, x):
self.setInput(x)
@property
def input2(self):
"""PyoPVObject. Phase vocoder streaming object 2."""
return self._input2
@input2.setter
def input2(self, x):
self.setInput2(x)