Source code for pyo.lib.analysis

"""
Tools to analyze audio signals.

These objects are designed to retrieve specific informations
from an audio stream. Analysis are sent at audio rate, user
can use them for controlling parameters of others objects.

"""

"""
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, createScopeWindow
from .pattern import Pattern


[docs]class Follower(PyoObject): """ Envelope follower. Output signal is the continuous mean amplitude of an input signal. :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. freq: float or PyoObject, optional Cutoff frequency of the filter in hertz. Default to 20. .. note:: The out() method is bypassed. Follower's signal can not be sent to audio outs. .. seealso:: :py:class:`Follower2`, :py:class:`Balance`, :py:class:`RMS`, :py:class:`PeakAmp` >>> s = Server().boot() >>> s.start() >>> sf = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out() >>> fol = Follower(sf, freq=30) >>> n = Noise(mul=fol).out(1) """ def __init__(self, input, freq=20, mul=1, add=0): pyoArgsAssert(self, "oOOO", input, freq, mul, add) PyoObject.__init__(self, mul, add) self._input = input self._freq = freq self._in_fader = InputFader(input) in_fader, freq, mul, add, lmax = convertArgsToLists(self._in_fader, freq, mul, add) self._base_objs = [ Follower_base(wrap(in_fader, i), wrap(freq, i), wrap(mul, i), wrap(add, i)) for i in range(lmax) ] self._init_play()
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def setFreq(self, x): """ Replace the `freq` attribute. :Args: x: float or PyoObject New `freq` attribute. """ pyoArgsAssert(self, "O", x) self._freq = x x, lmax = convertArgsToLists(x) [obj.setFreq(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False): self._map_list = [SLMap(1.0, 500.0, "log", "freq", self._freq)] PyoObject.ctrl(self, map_list, title, wxnoserver)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x) @property def freq(self): """float or PyoObject. Cutoff frequency of the filter.""" return self._freq @freq.setter def freq(self, x): self.setFreq(x)
[docs]class Follower2(PyoObject): """ Envelope follower with different attack and release times. Output signal is the continuous mean amplitude of an input signal. :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. risetime: float or PyoObject, optional Time to reach upward value in seconds. Default to 0.01. falltime: float or PyoObject, optional Time to reach downward value in seconds. Default to 0.1. .. note:: The out() method is bypassed. Follower's signal can not be sent to audio outs. .. seealso:: :py:class:`Follower`, :py:class:`Balance`, :py:class:`RMS`, :py:class:`PeakAmp` >>> s = Server().boot() >>> s.start() >>> sf = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out() >>> fol2 = Follower2(sf, risetime=0.002, falltime=.1, mul=.5) >>> n = Noise(fol2).out(1) """ def __init__(self, input, risetime=0.01, falltime=0.1, mul=1, add=0): pyoArgsAssert(self, "oOOOO", input, risetime, falltime, mul, add) PyoObject.__init__(self, mul, add) self._input = input self._risetime = risetime self._falltime = falltime self._in_fader = InputFader(input) in_fader, risetime, falltime, mul, add, lmax = convertArgsToLists(self._in_fader, risetime, falltime, mul, add) self._base_objs = [ Follower2_base(wrap(in_fader, i), wrap(risetime, i), wrap(falltime, i), wrap(mul, i), wrap(add, i)) for i in range(lmax) ] self._init_play()
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def setRisetime(self, x): """ Replace the `risetime` attribute. :Args: x: float or PyoObject New `risetime` attribute. """ pyoArgsAssert(self, "O", x) self._risetime = x x, lmax = convertArgsToLists(x) [obj.setRisetime(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setFalltime(self, x): """ Replace the `falltime` attribute. :Args: x: float or PyoObject New `falltime` attribute. """ pyoArgsAssert(self, "O", x) self._falltime = x x, lmax = convertArgsToLists(x) [obj.setFalltime(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False): self._map_list = [SLMap(0.001, 1.0, "log", "risetime", self._risetime)] PyoObject.ctrl(self, map_list, title, wxnoserver)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x) @property def risetime(self): """float or PyoObject. Time to reach upward value in seconds.""" return self._risetime @risetime.setter def risetime(self, x): self.setRisetime(x) @property def falltime(self): """float or PyoObject. Time to reach downward value in seconds.""" return self._falltime @falltime.setter def falltime(self, x): self.setFalltime(x)
[docs]class ZCross(PyoObject): """ Zero-crossing counter. Output signal is the number of zero-crossing occured during each buffer size, normalized between 0 and 1. :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. thresh: float, optional Minimum amplitude difference allowed between adjacent samples to be included in the zeros count. Defaults to 0. .. note:: The out() method is bypassed. ZCross's signal can not be sent to audio outs. >>> s = Server().boot() >>> s.start() >>> a = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out() >>> b = ZCross(a, thresh=.02) >>> n = Noise(b).out(1) """ def __init__(self, input, thresh=0.0, mul=1, add=0): pyoArgsAssert(self, "onOO", input, thresh, mul, add) PyoObject.__init__(self, mul, add) self._input = input self._thresh = thresh self._in_fader = InputFader(input) in_fader, thresh, mul, add, lmax = convertArgsToLists(self._in_fader, thresh, mul, add) self._base_objs = [ ZCross_base(wrap(in_fader, i), wrap(thresh, i), wrap(mul, i), wrap(add, i)) for i in range(lmax) ] self._init_play()
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def setThresh(self, x): """ Replace the `thresh` attribute. :Args: x: float New amplitude difference threshold. """ pyoArgsAssert(self, "n", x) self._thresh = x x, lmax = convertArgsToLists(x) [obj.setThresh(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False): self._map_list = [SLMap(0.0, 0.5, "lin", "thresh", self._thresh)] PyoObject.ctrl(self, map_list, title, wxnoserver)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x) @property def thresh(self): """float. Amplitude difference threshold.""" return self._thresh @thresh.setter def thresh(self, x): self.setThresh(x)
[docs]class Yin(PyoObject): """ Pitch tracker using the Yin algorithm. Pitch tracker using the Yin algorithm based on the implementation in C of aubio. This algorithm was developped by A. de Cheveigne and H. Kawahara and published in de Cheveigne, A., Kawahara, H. (2002) 'YIN, a fundamental frequency estimator for speech and music', J. Acoust. Soc. Am. 111, 1917-1930. The audio output of the object is the estimated frequency, in Hz, of the input sound. :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. tolerance: float, optional Parameter for minima selection, between 0 and 1. Defaults to 0.2. minfreq: float, optional Minimum estimated frequency in Hz. Frequency below this threshold will be ignored. Defaults to 40. maxfreq: float, optional Maximum estimated frequency in Hz. Frequency above this threshold will be ignored. Defaults to 1000. cutoff: float, optional Cutoff frequency, in Hz, of the lowpass filter applied on the input sound. Defaults to 1000. The lowpass filter helps the algorithm to detect the fundamental frequency by filtering higher harmonics. winsize: int, optional Size, in samples, of the analysis window. Must be higher that two period of the lowest desired frequency. Available at initialization time only. Defaults to 1024. >>> s = Server(duplex=1).boot() >>> s.start() >>> lfo = Randh(min=100, max=500, freq=3) >>> src = SineLoop(freq=lfo, feedback=0.1, mul=.3).out() >>> pit = Yin(src, tolerance=0.2, winsize=1024) >>> freq = Tone(pit, freq=10) >>> # fifth above >>> a = LFO(freq*1.5, type=2, mul=0.2).out(1) """ def __init__(self, input, tolerance=0.2, minfreq=40, maxfreq=1000, cutoff=1000, winsize=1024, mul=1, add=0): pyoArgsAssert(self, "onnnniOO", input, tolerance, minfreq, maxfreq, cutoff, winsize, mul, add) PyoObject.__init__(self, mul, add) self._input = input self._tolerance = tolerance self._minfreq = minfreq self._maxfreq = maxfreq self._cutoff = cutoff self._in_fader = InputFader(input) in_fader, tolerance, minfreq, maxfreq, cutoff, winsize, mul, add, lmax = convertArgsToLists( self._in_fader, tolerance, minfreq, maxfreq, cutoff, winsize, mul, add ) self._base_objs = [ Yin_base( wrap(in_fader, i), wrap(tolerance, i), wrap(minfreq, i), wrap(maxfreq, i), wrap(cutoff, i), wrap(winsize, i), wrap(mul, i), wrap(add, i), ) for i in range(lmax) ] self._init_play()
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def setTolerance(self, x): """ Replace the `tolerance` attribute. :Args: x: float New parameter for minima selection, between 0 and 1. """ pyoArgsAssert(self, "n", x) self._tolerance = x x, lmax = convertArgsToLists(x) [obj.setTolerance(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setMinfreq(self, x): """ Replace the `minfreq` attribute. :Args: x: float New minimum frequency detected. """ pyoArgsAssert(self, "n", x) self._minfreq = x x, lmax = convertArgsToLists(x) [obj.setMinfreq(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setMaxfreq(self, x): """ Replace the `maxfreq` attribute. :Args: x: float New maximum frequency detected. """ pyoArgsAssert(self, "n", x) self._maxfreq = x x, lmax = convertArgsToLists(x) [obj.setMaxfreq(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setCutoff(self, x): """ Replace the `cutoff` attribute. :Args: x: float New input lowpass filter cutoff frequency. """ pyoArgsAssert(self, "n", x) self._cutoff = x x, lmax = convertArgsToLists(x) [obj.setCutoff(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False): self._map_list = [ SLMap(0, 1, "lin", "tolerance", self._tolerance, dataOnly=True), SLMap(20, 400, "log", "minfreq", self._minfreq, dataOnly=True), SLMap(500, 5000, "log", "maxfreq", self._maxfreq, dataOnly=True), SLMap(200, 15000, "log", "cutoff", self._cutoff, dataOnly=True), ] PyoObject.ctrl(self, map_list, title, wxnoserver)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x) @property def tolerance(self): """float. Parameter for minima selection.""" return self._tolerance @tolerance.setter def tolerance(self, x): self.setTolerance(x) @property def minfreq(self): """float. Minimum frequency detected.""" return self._minfreq @minfreq.setter def minfreq(self, x): self.setMinfreq(x) @property def maxfreq(self): """float. Maximum frequency detected.""" return self._maxfreq @maxfreq.setter def maxfreq(self, x): self.setMaxfreq(x) @property def cutoff(self): """float. Input lowpass filter cutoff frequency.""" return self._cutoff @cutoff.setter def cutoff(self, x): self.setCutoff(x)
[docs]class Centroid(PyoObject): """ Computes the spectral centroid of an input signal. Output signal is the spectral centroid, in Hz, of the input signal. It indicates where the "center of mass" of the spectrum is. Perceptually, it has a robust connection with the impression of "brightness" of a sound. Centroid does its computation with two overlaps, so a new output value comes every half of the FFT window size. :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. size: int, optional Size, as a power-of-two, of the FFT used to compute the centroid. Available at initialization time only. Defaults to 1024. .. note:: The out() method is bypassed. Centroid's signal can not be sent to audio outs. >>> s = Server().boot() >>> s.start() >>> a = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out() >>> b = Centroid(a, 1024) >>> c = Port(b, 0.05, 0.05) >>> d = ButBP(Noise(0.2), freq=c, q=5).out(1) """ def __init__(self, input, size=1024, mul=1, add=0): pyoArgsAssert(self, "oiOO", input, size, mul, add) PyoObject.__init__(self, mul, add) self._input = input self._size = size self._in_fader = InputFader(input) in_fader, size, mul, add, lmax = convertArgsToLists(self._in_fader, size, mul, add) self._base_objs = [ Centroid_base(wrap(in_fader, i), wrap(size, i), wrap(mul, i), wrap(add, i)) for i in range(lmax) ] self._init_play()
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False): self._map_list = [] PyoObject.ctrl(self, map_list, title, wxnoserver)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x)
[docs]class AttackDetector(PyoObject): """ Audio signal onset detection. AttackDetector analyses an audio signal in input and output a trigger each time an onset is detected. An onset is a sharp amplitude rising while the signal had previously fall below a minimum threshold. Parameters must be carefully tuned depending on the nature of the analysed signal and the level of the background noise. :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. deltime: float, optional Delay time, in seconds, between previous and current rms analysis to compare. Defaults to 0.005. cutoff: float, optional Cutoff frequency, in Hz, of the amplitude follower's lowpass filter. Defaults to 10. Higher values are more responsive and also more likely to give false onsets. maxthresh: float, optional Attack threshold in positive dB (current rms must be higher than previous rms + maxthresh to be reported as an attack). Defaults to 3.0. minthresh: float, optional Minimum threshold in dB (signal must fall below this threshold to allow a new attack to be detected). Defaults to -30.0. reltime: float, optional Time, in seconds, to wait before reporting a new attack. Defaults to 0.1. >>> s = Server(duplex=1).boot() >>> s.start() >>> a = Input() >>> d = AttackDetector(a, deltime=0.005, cutoff=10, maxthresh=4, minthresh=-20, reltime=0.05) >>> exc = TrigEnv(d, HannTable(), dur=0.005, mul=BrownNoise(0.3)) >>> wgs = Waveguide(exc, freq=[100,200.1,300.3,400.5], dur=30).out() """ def __init__(self, input, deltime=0.005, cutoff=10, maxthresh=3, minthresh=-30, reltime=0.1, mul=1, add=0): pyoArgsAssert(self, "onnnnnOO", input, deltime, cutoff, maxthresh, minthresh, reltime, mul, add) PyoObject.__init__(self, mul, add) self._input = input self._deltime = deltime self._cutoff = cutoff self._maxthresh = maxthresh self._minthresh = minthresh self._reltime = reltime self._in_fader = InputFader(input) in_fader, deltime, cutoff, maxthresh, minthresh, reltime, mul, add, lmax = convertArgsToLists( self._in_fader, deltime, cutoff, maxthresh, minthresh, reltime, mul, add ) self._base_objs = [ AttackDetector_base( wrap(in_fader, i), wrap(deltime, i), wrap(cutoff, i), wrap(maxthresh, i), wrap(minthresh, i), wrap(reltime, i), wrap(mul, i), wrap(add, i), ) for i in range(lmax) ] self._init_play()
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def setDeltime(self, x): """ Replace the `deltime` attribute. :Args: x: float New delay between rms analysis. """ pyoArgsAssert(self, "n", x) self._deltime = x x, lmax = convertArgsToLists(x) [obj.setDeltime(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setCutoff(self, x): """ Replace the `cutoff` attribute. :Args: x: float New cutoff for the follower lowpass filter. """ pyoArgsAssert(self, "n", x) self._cutoff = x x, lmax = convertArgsToLists(x) [obj.setCutoff(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setMaxthresh(self, x): """ Replace the `maxthresh` attribute. :Args: x: float New attack threshold in dB. """ pyoArgsAssert(self, "n", x) self._maxthresh = x x, lmax = convertArgsToLists(x) [obj.setMaxthresh(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setMinthresh(self, x): """ Replace the `minthresh` attribute. :Args: x: float New minimum threshold in dB. """ pyoArgsAssert(self, "n", x) self._minthresh = x x, lmax = convertArgsToLists(x) [obj.setMinthresh(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setReltime(self, x): """ Replace the `reltime` attribute. :Args: x: float Time, in seconds, to wait before reporting a new attack. """ pyoArgsAssert(self, "n", x) self._reltime = x x, lmax = convertArgsToLists(x) [obj.setReltime(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def readyToDetect(self): """ Initializes variables in the ready state to detect an attack. """ [obj.readyToDetect() for obj in self._base_objs]
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False): self._map_list = [ SLMap(0.001, 0.05, "lin", "deltime", self._deltime, dataOnly=True), SLMap(1.0, 1000.0, "log", "cutoff", self._cutoff, dataOnly=True), SLMap(0.0, 18.0, "lin", "maxthresh", self._maxthresh, dataOnly=True), SLMap(-90.0, 0.0, "lin", "minthresh", self._minthresh, dataOnly=True), SLMap(0.001, 1.0, "log", "reltime", self._reltime, dataOnly=True), ] PyoObject.ctrl(self, map_list, title, wxnoserver)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x) @property def deltime(self): """float. Delay between rms analysis.""" return self._deltime @deltime.setter def deltime(self, x): self.setDeltime(x) @property def cutoff(self): """float. Cutoff for the follower lowpass filter.""" return self._cutoff @cutoff.setter def cutoff(self, x): self.setCutoff(x) @property def maxthresh(self): """float. Attack threshold in dB.""" return self._maxthresh @maxthresh.setter def maxthresh(self, x): self.setMaxthresh(x) @property def minthresh(self): """float. Minimum threshold in dB.""" return self._minthresh @minthresh.setter def minthresh(self, x): self.setMinthresh(x) @property def reltime(self): """float. Time to wait before reporting a new attack.""" return self._reltime @reltime.setter def reltime(self, x): self.setReltime(x)
[docs]class Spectrum(PyoObject): """ Spectrum analyzer and display. Spectrum measures the magnitude of an input signal versus frequency within a user defined range. It can show both magnitude and frequency on linear or logarithmic scale. :Parent: :py:class:`PyoObject` :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. The FFT size is the number of samples used in each analysis frame. Defaults to 1024. wintype: int, optional Shape of the envelope used to filter each input frame. Possible shapes are : 0. rectangular (no windowing) 1. Hamming 2. Hanning 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) function: python callable, optional If set, this function will be called with magnitudes (as list of lists, one list per channel). Useful if someone wants to save the analysis data into a text file. Defaults to None. wintitle: string, optional GUI window title. Defaults to "Spectrum". .. note:: Spectrum has no `out` method. Spectrum has no `mul` and `add` attributes. >>> s = Server().boot() >>> s.start() >>> a = SuperSaw(freq=[500,750], detune=0.6, bal=0.7, mul=0.5).out() >>> spec = Spectrum(a, size=1024) """ def __init__(self, input, size=1024, wintype=2, function=None, wintitle="Spectrum"): pyoArgsAssert(self, "oiiCS", input, size, wintype, function, wintitle) PyoObject.__init__(self) self.points = None self.viewFrame = None self.channelNamesVisible = True self.channelNames = [] self._input = input self._size = size self._wintype = wintype self._function = getWeakMethodRef(function) self._fscaling = 0 self._mscaling = 1 self._lowbound = 0 self._highbound = 0.5 self._width = 500 self._height = 400 self._gain = 1 self._in_fader = InputFader(input) in_fader, size, wintype, lmax = convertArgsToLists(self._in_fader, size, wintype) self._base_objs = [Spectrum_base(wrap(in_fader, i), wrap(size, i), wrap(wintype, i)) for i in range(lmax)] self._timer = Pattern(self.refreshView, 0.05).play() if function is None: self.view(wintitle) self._init_play()
[docs] def play(self, dur=0, delay=0): self._timer.play(dur, delay) return PyoObject.play(self, dur, delay)
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def stop(self, wait=0): self._timer.stop(wait) return PyoObject.stop(self, wait)
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[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 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 setFunction(self, function): """ Sets the function to be called to retrieve the analysis data. :Args: function: python callable The function called by the internal timer to retrieve the analysis data. The function must be created with one argument and will receive the data as a list of lists (one list per channel). """ pyoArgsAssert(self, "C", function) self._function = getWeakMethodRef(function)
[docs] def poll(self, active): """ Turns on and off the analysis polling. :Args: active: boolean If True, starts the analysis polling, False to stop it. defaults to True. """ pyoArgsAssert(self, "B", active) if active: self._timer.play() else: self._timer.stop()
[docs] def polltime(self, time): """ Sets the polling time in seconds. :Args: time: float Adjusts the frequency of the internal timer used to retrieve the current analysis frame. defaults to 0.05. """ pyoArgsAssert(self, "N", time) self._timer.time = time
[docs] def setLowFreq(self, x): """ Sets the lower frequency, in Hz, returned by the analysis. :Args: x: float New low frequency in Hz. Adjusts the `lowbound` attribute, as `x / sr`. """ pyoArgsAssert(self, "n", x) x /= self.getServer().getSamplingRate() self._lowbound = x x, lmax = convertArgsToLists(x) tmp = [obj.setLowbound(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setHighFreq(self, x): """ Sets the higher frequency, in Hz, returned by the analysis. :Args: x: float New high frequency in Hz. Adjusts the `highbound` attribute, as `x / sr`. """ pyoArgsAssert(self, "n", x) x /= self.getServer().getSamplingRate() self._highbound = x x, lmax = convertArgsToLists(x) tmp = [obj.setHighbound(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setLowbound(self, x): """ Sets the lower frequency, as multiplier of sr, returned by the analysis. Returns the real low frequency in Hz. :Args: x: float {0 <= x <= 0.5} new `lowbound` attribute. """ pyoArgsAssert(self, "n", x) self._lowbound = x x, lmax = convertArgsToLists(x) tmp = [obj.setLowbound(wrap(x, i)) for i, obj in enumerate(self._base_objs)] return tmp[0]
[docs] def setHighbound(self, x): """ Sets the higher frequency, as multiplier of sr, returned by the analysis. Returns the real high frequency in Hz. :Args: x: float {0 <= x <= 0.5} new `highbound` attribute. """ pyoArgsAssert(self, "n", x) self._highbound = x x, lmax = convertArgsToLists(x) tmp = [obj.setHighbound(wrap(x, i)) for i, obj in enumerate(self._base_objs)] return tmp[0]
[docs] def getLowfreq(self): """ Returns the current lower frequency, in Hz, used by the analysis. """ return self._base_objs[0].getLowfreq()
[docs] def getHighfreq(self): """ Returns the current higher frequency, in Hz, used by the analysis. """ return self._base_objs[0].getHighfreq()
[docs] def setWidth(self, x): """ Sets the width, in pixels, of the current display. Used internally to build the list of points to draw. :Args: x: int new `width` attribute. """ pyoArgsAssert(self, "i", x) self._width = x x, lmax = convertArgsToLists(x) [obj.setWidth(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setHeight(self, x): """ Sets the height, in pixels, of the current display. Used internally to build the list of points to draw. :Args: x: int new `height` attribute. """ pyoArgsAssert(self, "i", x) self._height = x x, lmax = convertArgsToLists(x) [obj.setHeight(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def setFscaling(self, x): """ Sets the frequency display to linear or logarithmic. :Args: x: boolean If True, the frequency display is logarithmic. False turns it back to linear. Defaults to False. """ pyoArgsAssert(self, "b", x) self._fscaling = x x, lmax = convertArgsToLists(x) [obj.setFscaling(wrap(x, i)) for i, obj in enumerate(self._base_objs)] if self.viewFrame is not None: self.viewFrame.setFscaling(self._fscaling)
[docs] def setMscaling(self, x): """ Sets the magnitude display to linear or logarithmic. :Args: x: boolean If True, the magnitude display is logarithmic (which means in dB). False turns it back to linear. Defaults to True. """ pyoArgsAssert(self, "b", x) self._mscaling = x x, lmax = convertArgsToLists(x) [obj.setMscaling(wrap(x, i)) for i, obj in enumerate(self._base_objs)] if self.viewFrame is not None: self.viewFrame.setMscaling(self._mscaling)
[docs] def getFscaling(self): """ Returns the scaling of the frequency display. Returns True for logarithmic or False for linear. """ return self._fscaling
[docs] def getMscaling(self): """ Returns the scaling of the magnitude display. Returns True for logarithmic or False for linear. """ return self._mscaling
[docs] def setGain(self, x): """ Set the gain of the analysis data. For drawing purpose. :Args: x: float new `gain` attribute, as linear values. """ pyoArgsAssert(self, "n", x) self._gain = x x, lmax = convertArgsToLists(x) [obj.setGain(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def view(self, title="Spectrum", wxnoserver=False): """ Opens a window showing the result of the analysis. :Args: title: string, optional Window title. Defaults to "Spectrum". wxnoserver: boolean, optional With wxPython graphical toolkit, if True, tells the interpreter that there will be no server window. If `wxnoserver` is set to True, the interpreter will not wait for the server GUI before showing the controller window. """ pyoArgsAssert(self, "SB", title, wxnoserver) createSpectrumWindow(self, title, wxnoserver)
[docs] def showChannelNames(self, visible=True): """ If True (the default), channel names will be displayed in the window. """ self.channelNamesVisible = visible if self.viewFrame is not None: self.viewFrame.showChannelNames(visible)
[docs] def setChannelNames(self, names): """ Change the stream names displayed in the spectrum window. If given a list of strings, these will be displayed as the name of the consecutive audio streams instead of the generic 'chan X' names. """ self.channelNames = names if self.viewFrame is not None: self.viewFrame.setChannelNames(names)
def _setViewFrame(self, frame): self.viewFrame = frame
[docs] def refreshView(self): """ Updates the graphical display of the spectrum. Called automatically by the internal timer. """ self.points = [obj.display() for obj in self._base_objs] if self._function is not None: self._function(self.points) if self.viewFrame is not None: self.viewFrame.update(self.points)
@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 wintype(self): """int. Windowing method.""" return self._wintype @wintype.setter def wintype(self, x): self.setWinType(x) @property def gain(self): """float. Sets the gain of the analysis data.""" return self._gain @gain.setter def gain(self, x): self.setGain(x) @property def lowbound(self): """float. Lowest frequency (multiplier of sr) to output.""" return self._lowbound @lowbound.setter def lowbound(self, x): self.setLowbound(x) @property def highbound(self): """float. Highest frequency (multiplier of sr) to output.""" return self._highbound @highbound.setter def highbound(self, x): self.setHighbound(x) @property def width(self): """int. Width, in pixels, of the current display.""" return self._width @width.setter def width(self, x): self.setWidth(x) @property def height(self): """int. Height, in pixels, of the current display.""" return self._height @height.setter def height(self, x): self.setHeight(x) @property def fscaling(self): """boolean. Scaling of the frequency display.""" return self._fscaling @fscaling.setter def fscaling(self, x): self.setFscaling(x) @property def mscaling(self): """boolean. Scaling of the magnitude display.""" return self._mscaling @mscaling.setter def mscaling(self, x): self.setMscaling(x)
[docs]class Scope(PyoObject): """ Oscilloscope - audio waveform display. Oscilloscopes are used to observe the change of an electrical signal over time. :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. length: float, optional Length, in seconds, of the displayed window. Can't be a list. Defaults to 0.05. gain: float, optional Linear gain applied to the signal to be displayed. Can't be a list. Defaults to 0.67. function: python callable, optional If set, this function will be called with samples (as list of lists, one list per channel). Useful if someone wants to save the analysis data into a text file. Defaults to None. wintitle: string, optional GUI window title. Defaults to "Scope". .. note:: Scope has no `out` method. Scope has no `mul` and `add` attributes. >>> s = Server().boot() >>> s.start() >>> a = Sine([100,100.2], mul=0.7) >>> b = Noise(0.1) >>> scope = Scope(a+b) """ def __init__(self, input, length=0.05, gain=0.67, function=None, wintitle="Scope"): pyoArgsAssert(self, "oNNCS", input, length, gain, function, wintitle) PyoObject.__init__(self) self.points = None self.viewFrame = None self._input = input self._length = length self._gain = gain self._function = function self._width = 500 self._height = 400 self.channelNamesVisible = True self.channelNames = [] self._in_fader = InputFader(input) in_fader, lmax = convertArgsToLists(self._in_fader) self._base_objs = [Scope_base(wrap(in_fader, i), length) for i in range(lmax)] self._base_objs[0].setFunc(self.refreshView) if function is None: self.view(wintitle) self._init_play()
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def setLength(self, x): """ Replace the `length` attribute. :Args: x: float new `length` attribute. """ pyoArgsAssert(self, "N", x) self._length = x [obj.setLength(x) for obj in self._base_objs]
[docs] def setGain(self, x): """ Set the gain boost applied to the analysed data. For drawing purpose. :Args: x: float new `gain` attribute, as linear values. """ pyoArgsAssert(self, "n", x) self._gain = x x, lmax = convertArgsToLists(x) [obj.setGain(wrap(x, i)) for i, obj in enumerate(self._base_objs)]
[docs] def poll(self, active): """ Turns on and off the analysis polling. :Args: active: boolean If True, starts the analysis polling, False to stop it. defaults to True. """ pyoArgsAssert(self, "B", active) [obj.setPoll(active) for obj in self._base_objs]
[docs] def setWidth(self, x): """ Gives the width of the display to the analyzer. The analyzer needs this value to construct the list of points to draw on the display. :Args: x: int Width of the display in pixel value. The default width is 500. """ pyoArgsAssert(self, "I", x) self._width = x [obj.setWidth(x) for obj in self._base_objs]
[docs] def setHeight(self, x): """ Gives the height of the display to the analyzer. The analyzer needs this value to construct the list of points to draw on the display. :Args: x: int Height of the display in pixel value. The default height is 400. """ pyoArgsAssert(self, "I", x) self._height = x [obj.setHeight(x) for obj in self._base_objs]
[docs] def view(self, title="Scope", wxnoserver=False): """ Opens a window showing the incoming waveform. :Args: title: string, optional Window title. Defaults to "Scope". wxnoserver: boolean, optional With wxPython graphical toolkit, if True, tells the interpreter that there will be no server window. If `wxnoserver` is set to True, the interpreter will not wait for the server GUI before showing the controller window. """ pyoArgsAssert(self, "SB", title, wxnoserver) createScopeWindow(self, title, wxnoserver)
[docs] def setFunction(self, function): """ Sets the function to be called to retrieve the analysis data. :Args: function: python callable The function called by the internal timer to retrieve the analysis data. The function must be created with one argument and will receive the data as a list of lists (one list per channel). """ pyoArgsAssert(self, "C", function) self._function = getWeakMethodRef(function)
[docs] def showChannelNames(self, visible=True): """ If True (the default), channel names will be displayed in the window. """ self.channelNamesVisible = visible if self.viewFrame is not None: self.viewFrame.showChannelNames(visible)
[docs] def setChannelNames(self, names): """ Change the stream names displayed in the spectrum window. If given a list of strings, these will be displayed as the name of the consecutive audio streams instead of the generic 'chan X' names. """ self.channelNames = names if self.viewFrame is not None: self.viewFrame.setChannelNames(names)
def _setViewFrame(self, frame): self.viewFrame = frame
[docs] def refreshView(self): """ Updates the graphical display of the scope. Called automatically by the internal timer. """ self.points = [obj.display() for obj in self._base_objs] if self.viewFrame is not None: self.viewFrame.update(self.points) if self._function is not None: self._function(self.points)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x) @property def length(self): """float. Window length.""" return self._length @length.setter def length(self, x): self.setLength(x) @property def gain(self): """float. Sets the gain of the analysis data.""" return self._gain @gain.setter def gain(self, x): self.setGain(x)
[docs]class PeakAmp(PyoObject): """ Peak amplitude follower. Output signal is the continuous peak amplitude of an input signal. A new peaking value is computed every buffer size. If `function` argument is not None, it should be a function that will be called periodically with a variable-length argument list containing the peaking values of all object's streams. Useful for meter drawing. Function definition must look like this: >>> def getValues(*args): ... print(args) :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. function: callable, optional Function that will be called with amplitude values in arguments. Default to None. .. note:: The out() method is bypassed. PeakAmp's signal can not be sent to audio outs. .. seealso:: :py:class:`Follower`, :py:class:`Follower2`, :py:class:`Balance`, :py:class:`RMS` >>> s = Server().boot() >>> s.start() >>> sf = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out() >>> amp = PeakAmp(sf) >>> n = Noise(mul=Port(amp)).out(1) """ def __init__(self, input, function=None, mul=1, add=0): pyoArgsAssert(self, "oCOO", input, function, mul, add) PyoObject.__init__(self, mul, add) self._input = input if callable(function): self._function = getWeakMethodRef(function) else: self._function = None self._in_fader = InputFader(input) in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add) self._base_objs = [PeakAmp_base(wrap(in_fader, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)] sr = self.getSamplingRate() bs = self.getBufferSize() self._timer = Pattern(self._buildList, 0.06).play() self._init_play()
[docs] def play(self, dur=0, delay=0): self._timer.play(dur, delay) return PyoObject.play(self, dur, delay)
def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def stop(self, wait=0): self._timer.stop(wait) return PyoObject.stop(self, wait)
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def setFunction(self, x): """ Replace the `function` attribute. :Args: x: callable New function to call with amplitude values in arguments. """ pyoArgsAssert(self, "C", x) if callable(x): self._function = getWeakMethodRef(x)
[docs] def polltime(self, x): """ Sets the delay, in seconds, between each call of the function. :Args: x: float New polling time in seconds. """ pyoArgsAssert(self, "N", x) self._timer.time = x
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
def _buildList(self): if self._function is not None: values = [obj.getValue() for obj in self._base_objs] self._function(*values)
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False): self._map_list = [] PyoObject.ctrl(self, map_list, title, wxnoserver)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x) @property def function(self): """PyoObject. function signal to process.""" return self._function @function.setter def function(self, x): self.setFunction(x)
[docs]class RMS(PyoObject): """ Returns the RMS (Root-Mean-Square) value of a signal. Output signal is the continuous rms of an input signal. A new rms value is computed every buffer size. If `function` argument is not None, it should be a function that will be called periodically with a variable-length argument list containing the rms values of all object's streams. Useful for meter drawing. Function definition must look like this: >>> def getValues(*args): ... print(args) :Parent: :py:class:`PyoObject` :Args: input: PyoObject Input signal to process. function: callable, optional Function that will be called with amplitude values in arguments. Default to None. .. note:: The out() method is bypassed. RMS's signal can not be sent to audio outs. .. seealso:: :py:class:`Follower`, :py:class:`Follower2`, :py:class:`Balance`, :py:class:`PeakAmp` >>> s = Server().boot() >>> s.start() >>> sf = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out() >>> amp = RMS(sf) >>> n = Noise(mul=Port(amp)).out(1) """ def __init__(self, input, function=None, mul=1, add=0): pyoArgsAssert(self, "oCOO", input, function, mul, add) PyoObject.__init__(self, mul, add) self._input = input if callable(function): self._function = getWeakMethodRef(function) else: self._function = None self._in_fader = InputFader(input) in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add) self._base_objs = [RMS_base(wrap(in_fader, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)] sr = self.getSamplingRate() bs = self.getBufferSize() self._timer = Pattern(self._buildList, 0.06).play() self._init_play()
[docs] def play(self, dur=0, delay=0): self._timer.play(dur, delay) return PyoObject.play(self, dur, delay)
def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
[docs] def stop(self, wait=0): self._timer.stop(wait) return PyoObject.stop(self, wait)
[docs] def setInput(self, x, fadetime=0.05): """ Replace the `input` attribute. :Args: x: PyoObject New signal to process. fadetime: float, optional Crossfade time between old and new input. Default to 0.05. """ pyoArgsAssert(self, "oN", x, fadetime) self._input = x self._in_fader.setInput(x, fadetime)
[docs] def setFunction(self, x): """ Replace the `function` attribute. :Args: x: callable New function to call with amplitude values in arguments. """ pyoArgsAssert(self, "C", x) if callable(x): self._function = getWeakMethodRef(x)
[docs] def polltime(self, x): """ Sets the delay, in seconds, between each call of the function. :Args: x: float New polling time in seconds. """ pyoArgsAssert(self, "N", x) self._timer.time = x
[docs] def out(self, chnl=0, inc=1, dur=0, delay=0): return self.play(dur, delay)
def _buildList(self): if self._function is not None: values = [obj.getValue() for obj in self._base_objs] self._function(*values)
[docs] def ctrl(self, map_list=None, title=None, wxnoserver=False): self._map_list = [] PyoObject.ctrl(self, map_list, title, wxnoserver)
@property def input(self): """PyoObject. Input signal to process.""" return self._input @input.setter def input(self, x): self.setInput(x) @property def function(self): """PyoObject. function signal to process.""" return self._function @function.setter def function(self, x): self.setFunction(x)