"""
Set of objects to manage triggers streams.

A trigger is an audio signal with a value of 1 surrounded by 0s.

TrigXXX objects use this kind of signal to generate different
processes with sampling rate time accuracy.

"""

"""
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 createGraphWindow
import weakref


class Trig(PyoObject):
    """
    Sends one trigger.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    Trig sends a trigger each time it's play() method is called.

    :Parent: :py:class:`PyoObject`

    .. note::

        The out() method is bypassed. Trig's signal can not be sent to audio outs.

        Trig has no `mul` and `add` attributes.

    >>> s = Server().boot()
    >>> s.start()
    >>> a = Trig()
    >>> env = HannTable()
    >>> tenv = TrigEnv(a, table=env, dur=5, mul=.3)
    >>> n = Noise(tenv).out()

    """

    def __init__(self):
        PyoObject.__init__(self)
        self._base_objs = [Trig_base()]
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass


class Metro(PyoObject):
    """
    Generates isochronous trigger signals.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    The play() method starts the metro and is not called at the object
    creation time.

    :Parent: :py:class:`PyoObject`

    :Args:

        time: float or PyoObject, optional
            Time between each trigger in seconds. Defaults to 1.
        poly: int, optional
            Metronome polyphony. Denotes how many independent streams are
            generated by the metronome, allowing overlapping processes.

            Available only at initialization. Defaults to 1.

    .. note::

        The out() method is bypassed. Metro's signal can not be sent to audio outs.

        Metro has no `mul` and `add` attributes.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(time=.125, poly=2).play()
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> freq = TrigRand(met, min=400, max=1000)
    >>> a = Sine(freq=freq, mul=amp).out()

    """

    def __init__(self, time=1, poly=1):
        pyoArgsAssert(self, "OI", time, poly)
        PyoObject.__init__(self)
        self._time = time
        self._poly = poly
        time, lmax = convertArgsToLists(time)
        self._base_objs = [
            Metro_base(wrap(time, i) * poly, (float(j) / poly)) for i in range(lmax) for j in range(poly)
        ]

    def setTime(self, x):
        """
        Replace the `time` attribute.

        :Args:

            x: float or PyoObject
                New `time` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._time = x
        x, lmax = convertArgsToLists(x)
        [obj.setTime(wrap(x, i) * self._poly) for i, obj in enumerate(self._base_objs)]

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.001, 1.0, "log", "time", self._time)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def time(self):
        """float or PyoObject. Time between each trigger in seconds."""
        return self._time

    @time.setter
    def time(self, x):
        self.setTime(x)


class Seq(PyoObject):
    """
    Generates a rhythmic sequence of trigger signals.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    The play() method starts the sequence and is not called at the object
    creation time.

    :Parent: :py:class:`PyoObject`

    :Args:

        time: float or PyoObject, optional
            Base time between each trigger in seconds. Defaults to 1.
        seq: list of floats, optional
            Sequence of beat durations in time's unit. Defaults to [1].
        poly: int, optional
            Seq polyphony. Denotes how many independent streams are
            generated by the metronome, allowing overlapping processes.

            Available only at initialization. Defaults to 1.
        onlyonce: boolean, optional
            If True, the sequence will play only once and automatically stop.
            Defaults to False.
        speed: float or PyoObject, optional
            Continuous speed factor. This factor multiplies the speed of the
            internal timer continuously. It can be useful to create time
            deceleration or acceleration. Defaults to 1.

    .. note::

        The out() method is bypassed. Seq's signal can not be sent to audio outs.

        Seq has no `mul` and `add` attributes.

    >>> s = Server().boot()
    >>> s.start()
    >>> env = CosTable([(0,0),(300,1),(1000,.3),(8191,0)])
    >>> seq = Seq(time=.125, seq=[2,1,1,2], poly=2).play()
    >>> tr = TrigRand(seq, min=250, max=500, port=.005)
    >>> amp = TrigEnv(seq, table=env, dur=.25, mul=.25)
    >>> a = SineLoop(tr, feedback=0.07, mul=amp).out()

    """

    def __init__(self, time=1, seq=[1], poly=1, onlyonce=False, speed=1):
        pyoArgsAssert(self, "OlIBO", time, seq, poly, onlyonce, speed)
        PyoObject.__init__(self)
        self._time = time
        self._seq = seq
        self._poly = poly
        self._onlyonce = onlyonce
        self._speed = speed
        time, speed, lmax = convertArgsToLists(time, speed)
        if type(seq[0]) != list:
            self._base_players = [Seqer_base(wrap(time, i), seq, poly, onlyonce, wrap(speed, i)) for i in range(lmax)]
        else:
            seqlen = len(seq)
            lmax = max(seqlen, lmax)
            self._base_players = [
                Seqer_base(wrap(time, i), wrap(seq, i), poly, onlyonce, wrap(speed, i)) for i in range(lmax)
            ]
        self._base_objs = [Seq_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]

    def setTime(self, x):
        """
        Replace the `time` attribute.

        :Args:

            x: float or PyoObject
                New `time` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._time = x
        x, lmax = convertArgsToLists(x)
        [obj.setTime(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setSpeed(self, x):
        """
        Replace the `speed` attribute.

        :Args:

            x: float or PyoObject
                New `speed` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._speed = x
        x, lmax = convertArgsToLists(x)
        [obj.setSpeed(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setSeq(self, x):
        """
        Replace the `seq` attribute.

        :Args:

            x: list of floats
                New `seq` attribute.

        """
        pyoArgsAssert(self, "l", x)
        self._seq = x
        if type(x[0]) != list:
            [obj.setSeq(x) for i, obj in enumerate(self._base_players)]
        else:
            [obj.setSeq(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setOnlyonce(self, x):
        """
        Replace the `onlyonce` attribute.

        :Args:

            x: boolean
                New `onlyonce` attribute.

        """
        pyoArgsAssert(self, "B", x)
        self._onlyonce = x
        [obj.setOnlyonce(x) for obj in self._base_players]

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.001, 10.0, "log", "time", self._time)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def time(self):
        """float or PyoObject. Base time between each trigger in seconds."""
        return self._time

    @time.setter
    def time(self, x):
        self.setTime(x)

    @property
    def speed(self):
        """float or PyoObject. Continuous speed factor."""
        return self._speed

    @speed.setter
    def speed(self, x):
        self.setSpeed(x)

    @property
    def seq(self):
        """List of floats. Sequence of beat durations in time's unit."""
        return self._seq

    @seq.setter
    def seq(self, x):
        self.setSeq(x)

    @property
    def onlyonce(self):
        """boolean. Trigger the sequence only once."""
        return self._onlyonce

    @onlyonce.setter
    def onlyonce(self, x):
        self.setOnlyonce(x)


class Cloud(PyoObject):
    """
    Generates random triggers.

    Generates random triggers with control over the generation density.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    The play() method starts the Cloud and is not called at the object
    creation time.

    :Parent: :py:class:`PyoObject`

    :Args:

        density: float or PyoObject, optional
            Average number of triggers per second. Defaults to 10.
        poly: int, optional
            Cloud polyphony. Denotes how many independent streams are
            generated by the object, allowing overlapping processes.

            Available only at initialization. Defaults to 1.

    .. note::

        The out() method is bypassed. Cloud's signal can not be sent to audio outs.

        Cloud has no `mul` and `add` attributes.

    >>> s = Server().boot()
    >>> s.start()
    >>> dens = Expseg([(0,1),(5,50)], loop=True, exp=5, initToFirstVal=True).play()
    >>> m = Cloud(density=dens, poly=2).play()
    >>> tr = TrigRand(m, min=300, max=1000)
    >>> tr_p = Port(tr, risetime=0.001, falltime=0.001)
    >>> a = Sine(freq=tr, mul=0.2).out()

    """

    def __init__(self, density=10, poly=1):
        pyoArgsAssert(self, "OI", density, poly)
        PyoObject.__init__(self)
        self._density = density
        self._poly = poly
        density, lmax = convertArgsToLists(density)
        self._base_players = [Clouder_base(wrap(density, i), poly) for i in range(lmax)]
        self._base_objs = [Cloud_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]

    def setDensity(self, x):
        """
        Replace the `density` attribute.

        :Args:

            x: float or PyoObject
                New `density` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._density = x
        x, lmax = convertArgsToLists(x)
        [obj.setDensity(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0, 100.0, "lin", "density", self._density)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def density(self):
        """float or PyoObject. Average density of triggers generation."""
        return self._density

    @density.setter
    def density(self, x):
        self.setDensity(x)


class Beat(PyoObject):
    """
    Generates algorithmic trigger patterns.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    Beat generates measures of length `taps` and uses weight parameters
    (`w1`, `w2` and `w3`) to compute the chances of a beat to be present
    in the generated measure.

    User can store the current pattern in one of the 32 preset slots with
    the store() method and recall it later with recall(x).

    A preset is a list where the first value is the number of beats in the
    measure, followed by 1s and 0s. For a 4/4 measure with only down beats:

    [16, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]

    The play() method starts the Beat and is not called at the object
    creation time.

    :Parent: :py:class:`PyoObject`

    :Args:

        time: float or PyoObject, optional
            Time, in seconds, between each beat of the pattern. Defaults to 0.125.
        taps: int, optional
            Number of beats in the generated pattern, max = 64. Defaults to 16.
        w1: int {0 -> 100}, optional
            Probability for down beats. Defaults to 80.
        w2: int {0 -> 100}, optional
            Probability for up beats. Defaults to 50.
        w3: int {0 -> 100}, optional
            Probability for the weakest beats. Defaults to 30.
        poly: int, optional
            Beat polyphony. Denotes how many independent streams are
            generated by the object, allowing overlapping processes.

            Available only at initialization. Defaults to 1.
        onlyonce: boolean, optional
            If True, the sequence will play only once and automatically stop.
            Defaults to False.

    .. note::

        Beat outputs many signals identified with a string between brackets:

        |  obj['tap'] returns audio stream of the current tap of the measure.
        |  obj['amp'] returns audio stream of the current beat amplitude.
        |  obj['dur'] returns audio stream of the current beat duration in seconds.
        |  obj['end'] returns audio stream with a trigger just before the end of the measure.

        obj without brackets returns the generated trigger stream of the measure.

        The out() method is bypassed. Beat's signal can not be sent to audio outs.

        Beat has no `mul` and `add` attributes.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> beat = Beat(time=.125, taps=16, w1=[90,80], w2=50, w3=35, poly=1).play()
    >>> trmid = TrigXnoiseMidi(beat, dist=12, mrange=(60, 96))
    >>> trhz = Snap(trmid, choice=[0,2,3,5,7,8,10], scale=1)
    >>> tr2 = TrigEnv(beat, table=t, dur=beat['dur'], mul=beat['amp'])
    >>> a = Sine(freq=trhz, mul=tr2*0.3).out()

    """

    def __init__(self, time=0.125, taps=16, w1=80, w2=50, w3=30, poly=1, onlyonce=False):
        pyoArgsAssert(self, "OinnnIB", time, taps, w1, w2, w3, poly, onlyonce)
        PyoObject.__init__(self)
        self._tap_dummy = []
        self._amp_dummy = []
        self._dur_dummy = []
        self._end_dummy = []
        self._time = time
        self._taps = taps
        self._w1 = w1
        self._w2 = w2
        self._w3 = w3
        self._poly = poly
        self._onlyonce = onlyonce
        time, taps, w1, w2, w3, lmax = convertArgsToLists(time, taps, w1, w2, w3)
        self._base_players = [
            Beater_base(wrap(time, i), wrap(taps, i), wrap(w1, i), wrap(w2, i), wrap(w3, i), poly, onlyonce)
            for i in range(lmax)
        ]
        self._base_objs = [Beat_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._tap_objs = [BeatTapStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._amp_objs = [BeatAmpStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._dur_objs = [BeatDurStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._end_objs = [BeatEndStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]

    def __getitem__(self, i):
        if i == "tap":
            self._tap_dummy.append(Dummy([obj for obj in self._tap_objs]))
            return self._tap_dummy[-1]
        if i == "amp":
            self._amp_dummy.append(Dummy([obj for obj in self._amp_objs]))
            return self._amp_dummy[-1]
        if i == "dur":
            self._dur_dummy.append(Dummy([obj for obj in self._dur_objs]))
            return self._dur_dummy[-1]
        if i == "end":
            self._end_dummy.append(Dummy([obj for obj in self._end_objs]))
            return self._end_dummy[-1]
        if type(i) == slice:
            return self._base_objs[i]
        if i < len(self._base_objs):
            return self._base_objs[i]
        else:
            print("'i' too large!")

    def get(self, identifier="amp", all=False):
        """
        Return the first sample of the current buffer as a float.

        Can be used to convert audio stream to usable Python data.

        "tap", "amp" or "dur" must be given to `identifier` to specify
        which stream to get value from.

        :Args:

            identifier: string {"tap", "amp", "dur"}
                Address string parameter identifying audio stream.
                Defaults to "amp".
            all: boolean, optional
                If True, the first value of each object's stream
                will be returned as a list.

                If False, only the value of the first object's
                stream will be returned as a float.

        """
        if not all:
            return self.__getitem__(identifier)[0]._getStream().getValue()
        else:
            return [obj._getStream().getValue() for obj in self.__getitem__(identifier).getBaseObjects()]

    def reset(self):
        """
        Reset internal counters to initialization values.

        """
        [obj.reset() for obj in self._base_players]

    def new(self, now=False):
        """
        Generates a new pattern with the current parameters.

        :Args:

            now: boolean
                If True, the new sequence is immediately generated,
                otherwise (the default), the new sequence is generated
                after the current sequence is completed.

        """
        [obj.new(now) for i, obj in enumerate(self._base_players)]

    def fill(self):
        """
        Generates a fill-in pattern and then restore the current one.

        """
        [obj.fill() for i, obj in enumerate(self._base_players)]

    def store(self, x):
        """
        Store the current pattern in memory `x`.

        :Args:

            x: int
                Memory number. 0 <= x < 32.

        """
        pyoArgsAssert(self, "I", x)
        [obj.store(x) for i, obj in enumerate(self._base_players)]

    def recall(self, x):
        """
        Recall the pattern previously stored in memory `x`.

        :Args:

            x: int
                Memory number. 0 <= x < 32.

        """
        pyoArgsAssert(self, "I", x)
        [obj.recall(x) for i, obj in enumerate(self._base_players)]

    def getPresets(self):
        """
        Returns the list of stored presets.

        """
        if len(self._base_players) == 1:
            return self._base_players[0].getPresets()
        else:
            return [obj.getPresets() for obj in self._base_players]

    def setPresets(self, x):
        """
        Store a list presets.

        :Args:

            x: list
                List of presets.

        """
        pyoArgsAssert(self, "l", x)
        if len(self._base_players) == 1:
            return self._base_players[0].setPresets(x)
        else:
            return [obj.setPresets(x[i]) for i, obj in enumerate(self._base_players)]

    def setTime(self, x):
        """
        Replace the `time` attribute.

        :Args:

            x: float or PyoObject
                New `time` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._time = x
        x, lmax = convertArgsToLists(x)
        [obj.setTime(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setTaps(self, x):
        """
        Replace the `taps` attribute.

        :Args:

            x: int
                New `taps` attribute.

        """
        pyoArgsAssert(self, "I", x)
        self._taps = x
        x, lmax = convertArgsToLists(x)
        [obj.setTaps(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setW1(self, x):
        """
        Replace the `w1` attribute.

        :Args:

            x: int
                New `w1` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self.setWeights(w1=x)

    def setW2(self, x):
        """
        Replace the `w2` attribute.

        :Args:

            x: int
                New `w2` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self.setWeights(w2=x)

    def setW3(self, x):
        """
        Replace the `w3` attribute.

        :Args:

            x: int
                New `w3` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self.setWeights(w3=x)

    def setWeights(self, w1=None, w2=None, w3=None):
        """
        Replace the weight attributes.

        Arguments set to `None` remain unchanged.

        :Args:

            w1: int, optional
                New `w1` attribute. Defaults to None.
            w2: int, optional
                New `w2` attribute. Defaults to None.
            w3: int, optional
                New `w3` attribute. Defaults to None.

        """
        if w1 is not None:
            self._w1 = w1
        if w2 is not None:
            self._w2 = w2
        if w3 is not None:
            self._w3 = w3
        w1, w2, w3, lmax = convertArgsToLists(w1, w2, w3)
        [obj.setWeights(wrap(w1, i), wrap(w2, i), wrap(w3, i)) for i, obj in enumerate(self._base_players)]

    def setOnlyonce(self, x):
        """
        Replace the `onlyonce` attribute.

        :Args:

            x: boolean
                New `onlyonce` attribute.

        """
        pyoArgsAssert(self, "B", x)
        self._onlyonce = x
        [obj.setOnlyonce(x) for obj in self._base_players]

    def play(self, dur=0, delay=0):
        dur, delay, lmax = convertArgsToLists(dur, delay)
        self._tap_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._tap_objs)]
        self._amp_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._amp_objs)]
        self._dur_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._dur_objs)]
        self._end_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._end_objs)]
        return PyoObject.play(self, dur, delay)

    def stop(self, wait=0):
        [obj.stop(wait) for obj in self._tap_objs]
        [obj.stop(wait) for obj in self._amp_objs]
        [obj.stop(wait) for obj in self._dur_objs]
        [obj.stop(wait) for obj in self._end_objs]
        return PyoObject.stop(self, wait)

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [
            SLMap(0.001, 1.0, "lin", "time", self._time),
            SLMap(2, 64, "lin", "taps", self._taps, res="int", dataOnly=True),
            SLMap(0, 100, "lin", "w1", self._w1, res="int", dataOnly=True),
            SLMap(0, 100, "lin", "w2", self._w2, res="int", dataOnly=True),
            SLMap(0, 100, "lin", "w3", self._w3, res="int", dataOnly=True),
        ]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def time(self):
        """float or PyoObject. Time, in seconds, between each beat."""
        return self._time

    @time.setter
    def time(self, x):
        self.setTime(x)

    @property
    def taps(self):
        """int. Number of beats in the generated pattern."""
        return self._taps

    @taps.setter
    def taps(self, x):
        self.setTaps(x)

    @property
    def w1(self):
        """int. Probability for down beats."""
        return self._w1

    @w1.setter
    def w1(self, x):
        self.setW1(x)

    @property
    def w2(self):
        """int. Probability for up beats."""
        return self._w2

    @w2.setter
    def w2(self, x):
        self.setW2(x)

    @property
    def w3(self):
        """int. Probability for other beats."""
        return self._w3

    @w3.setter
    def w3(self, x):
        self.setW3(x)

    @property
    def onlyonce(self):
        """boolean. Trigger the sequence only once."""
        return self._onlyonce

    @onlyonce.setter
    def onlyonce(self, x):
        self.setOnlyonce(x)


class TrigRandInt(PyoObject):
    """
    Pseudo-random integer generator.

    TrigRandInt generates a pseudo-random number integer number between
    0 and `max` values each time it receives a trigger in its `input`
    parameter. The value is kept until the next trigger.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        max: float or PyoObject, optional
            Maximum value for the random generation. Defaults to 100.

    .. note::

        The out() method is bypassed. TrigRandInt's signal can not be sent
        to audio outs.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(.125, poly=2).play()
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> tr = TrigRandInt(met, max=10, mul=100, add=200)
    >>> a = Sine(tr, mul=amp).out()

    """

    def __init__(self, input, max=100.0, mul=1, add=0):
        pyoArgsAssert(self, "oOOO", input, max, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._max = max
        self._in_fader = InputFader(input)
        in_fader, max, mul, add, lmax = convertArgsToLists(self._in_fader, max, mul, add)
        self._base_objs = [
            TrigRandInt_base(wrap(in_fader, i), wrap(max, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
        ]
        self._init_play()

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setMax(self, x):
        """
        Replace the `max` attribute.

        :Args:

            x: float or PyoObject
                new `max` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._max = x
        x, lmax = convertArgsToLists(x)
        [obj.setMax(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(1.0, 200.0, "lin", "max", self._max), SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def max(self):
        """float or PyoObject. Maximum value."""
        return self._max

    @max.setter
    def max(self, x):
        self.setMax(x)


class TrigRand(PyoObject):
    """
    Pseudo-random number generator.

    TrigRand generates a pseudo-random number between `min` and `max`
    values each time it receives a trigger in its `input` parameter.
    The value is kept until the next trigger.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        min: float or PyoObject, optional
            Minimum value for the random generation. Defaults to 0.
        max: float or PyoObject, optional
            Maximum value for the random generation. Defaults to 1.
        port: float, optional
            Portamento. Time to reach a new value. Defaults to 0.
        init: float, optional
            Initial value. Available at initialization time only.
            Defaults to 0.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(.125, poly=2).play()
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> tr = TrigRand(met, 400, 600)
    >>> a = Sine(tr, mul=amp).out()

    """

    def __init__(self, input, min=0.0, max=1.0, port=0.0, init=0.0, mul=1, add=0):
        pyoArgsAssert(self, "oOOnnOO", input, min, max, port, init, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._min = min
        self._max = max
        self._port = port
        self._in_fader = InputFader(input)
        in_fader, min, max, port, init, mul, add, lmax = convertArgsToLists(
            self._in_fader, min, max, port, init, mul, add
        )
        self._base_objs = [
            TrigRand_base(
                wrap(in_fader, i), wrap(min, i), wrap(max, i), wrap(port, i), wrap(init, i), wrap(mul, i), wrap(add, i)
            )
            for i in range(lmax)
        ]
        self._init_play()

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setMin(self, x):
        """
        Replace the `min` attribute.

        :Args:

            x: float or PyoObject
                new `min` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._min = x
        x, lmax = convertArgsToLists(x)
        [obj.setMin(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setMax(self, x):
        """
        Replace the `max` attribute.

        :Args:

            x: float or PyoObject
                new `max` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._max = x
        x, lmax = convertArgsToLists(x)
        [obj.setMax(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setPort(self, x):
        """
        Replace the `port` attribute.

        :Args:

            x: float
                new `port` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self._port = x
        x, lmax = convertArgsToLists(x)
        [obj.setPort(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [
            SLMap(0.0, 1.0, "lin", "min", self._min),
            SLMap(1.0, 2.0, "lin", "max", self._max),
            SLMapMul(self._mul),
        ]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def min(self):
        """float or PyoObject. Minimum value."""
        return self._min

    @min.setter
    def min(self, x):
        self.setMin(x)

    @property
    def max(self):
        """float or PyoObject. Maximum value."""
        return self._max

    @max.setter
    def max(self, x):
        self.setMax(x)

    @property
    def port(self):
        """float. Ramp time."""
        return self._port

    @port.setter
    def port(self, x):
        self.setPort(x)


class TrigChoice(PyoObject):
    """
    Random generator from user's defined values.

    TrigChoice chooses randomly a new value in list `choice` each
    time it receives a trigger in its `input` parameter. The value
    is kept until the next trigger.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        choice: list of floats
            Possible values for the random generation.
        port: float, optional
            Portamento. Time to reach a new value. Defaults to 0.
        init: float, optional
            Initial value. Available at initialization time only.
            Defaults to 0.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(.125, poly=2).play()
    >>> freq = TrigChoice(met, [300, 350, 400, 450, 500, 550])
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> a = Sine(freq=freq, mul=amp).out()

    """

    def __init__(self, input, choice, port=0.0, init=0.0, mul=1, add=0):
        pyoArgsAssert(self, "olnnOO", input, choice, port, init, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._choice = choice
        self._port = port
        self._in_fader = InputFader(input)
        in_fader, port, init, mul, add, lmax = convertArgsToLists(self._in_fader, port, init, mul, add)
        if type(choice[0]) != list:
            self._base_objs = [
                TrigChoice_base(wrap(in_fader, i), choice, wrap(port, i), wrap(init, i), wrap(mul, i), wrap(add, i))
                for i in range(lmax)
            ]
        else:
            choicelen = len(choice)
            lmax = max(choicelen, lmax)
            self._base_objs = [
                TrigChoice_base(
                    wrap(in_fader, i), wrap(choice, i), wrap(port, i), wrap(init, i), wrap(mul, i), wrap(add, i)
                )
                for i in range(lmax)
            ]
        self._init_play()

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setChoice(self, x):
        """
        Replace the `choice` attribute.

        :Args:

            x: list of floats
                new `choice` attribute.

        """
        pyoArgsAssert(self, "l", x)
        self._choice = x
        if type(x[0]) != list:
            [obj.setChoice(self._choice) for i, obj in enumerate(self._base_objs)]
        else:
            [obj.setChoice(wrap(self._choice, i)) for i, obj in enumerate(self._base_objs)]

    def setPort(self, x):
        """
        Replace the `port` attribute.

        :Args:

            x: float
                new `port` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self._port = x
        x, lmax = convertArgsToLists(x)
        [obj.setPort(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def choice(self):
        """list of floats. Possible values."""
        return self._choice

    @choice.setter
    def choice(self, x):
        self.setChoice(x)

    @property
    def port(self):
        """float. Ramp time."""
        return self._port

    @port.setter
    def port(self, x):
        self.setPort(x)


class TrigFunc(PyoObject):
    """
    Python function callback.

    TrigFunc calls the function given at parameter `function` each
    time it receives a trigger in its `input` parameter.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        function: Python callable (function or method)
            Function to be called.
        arg: anything, optional
            Argument sent to the function's call. If None, the function
            will be called without argument. Defaults to None.

    .. note::

        The out() method is bypassed. TrigFunc's signal can not be sent
        to audio outs.

        TrigFunc has no `mul` and `add` attributes.

    >>> s = Server().boot()
    >>> s.start()
    >>> f = Fader(fadein=.005, fadeout=.1, dur=.12, mul=.2)
    >>> a = SineLoop(midiToHz([60,60]), feedback=0.05, mul=f).out()
    >>> c = 0.0
    >>> def count():
    ...     global c
    ...     freq = midiToHz(round(c) + 60)
    ...     a.freq = [freq, freq*0.995]
    ...     c += 1.77
    ...     if c > 13: c = 0
    ...     f.play()
    >>> m = Metro(.125).play()
    >>> tf = TrigFunc(m, count)

    """

    def __init__(self, input, function, arg=None):
        pyoArgsAssert(self, "oc", input, function)
        PyoObject.__init__(self)
        self._input = input
        self._function = getWeakMethodRef(function)
        self._arg = arg
        self._in_fader = InputFader(input)
        in_fader, function, arg, lmax = convertArgsToLists(self._in_fader, function, arg)
        self._base_objs = [
            TrigFunc_base(wrap(in_fader, i), WeakMethod(wrap(function, i)), wrap(arg, i)) for i in range(lmax)
        ]
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setFunction(self, x):
        """
        Replace the `function` attribute.

        :Args:

            x: Python callable (function or method)
                new `function` attribute.

        """
        pyoArgsAssert(self, "c", x)
        self._function = getWeakMethodRef(x)
        x, lmax = convertArgsToLists(x)
        [obj.setFunction(WeakMethod(wrap(x, i))) for i, obj in enumerate(self._base_objs)]

    def setArg(self, x):
        """
        Replace the `arg` attribute.

        :Args:

            x: Anything
                new `arg` attribute.

        """
        self._arg = x
        x, lmax = convertArgsToLists(x)
        [obj.setArg(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def function(self):
        """Python callable. Function to be called."""
        return self._function

    @function.setter
    def function(self, x):
        self.setFunction(x)

    @property
    def arg(self):
        """Anything. Callable's argument."""
        return self._arg

    @arg.setter
    def arg(self, x):
        self.setArg(x)


class TrigEnv(PyoObject):
    """
    Envelope reader generator.

    TrigEnv starts reading an envelope in `dur` seconds each time it
    receives a trigger in its `input` parameter.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        table: PyoTableObject
            Table containing the envelope.
        dur: float or PyoObject, optional
            Duration in seconds of the envelope. Defaults to 1.
        interp: int, optional
            Choice of the interpolation method. Defaults to 2.
                1. no interpolation
                2. linear
                3. cosinus
                4. cubic

    .. note::

        TrigEnv will send a trigger signal at the end of the playback.
        User can retreive the trigger streams by calling obj['trig'].
        Useful to synchronize other processes.

    >>> s = Server().boot()
    >>> s.start()
    >>> env = HannTable()
    >>> m = Metro(.125, poly=2).play()
    >>> tr = TrigRand(m, 400, 600)
    >>> te = TrigEnv(m, table=env, dur=.25, mul=.2)
    >>> a = Sine(tr, mul=te).out()

    """

    def __init__(self, input, table, dur=1, interp=2, mul=1, add=0):
        pyoArgsAssert(self, "otOiOO", input, table, dur, interp, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._table = table
        self._dur = dur
        self._interp = interp
        self._in_fader = InputFader(input)
        in_fader, table, dur, interp, mul, add, lmax = convertArgsToLists(self._in_fader, table, dur, interp, mul, add)
        self._base_objs = [
            TrigEnv_base(wrap(in_fader, i), wrap(table, i), wrap(dur, i), wrap(interp, i), wrap(mul, i), wrap(add, i))
            for i in range(lmax)
        ]
        self._trig_objs = Dummy([TriggerDummy_base(obj) for obj in self._base_objs])
        self._init_play()

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    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)]

    def setDur(self, x):
        """
        Replace the `dur` attribute.

        :Args:

            x: float or PyoObject
                new `dur` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._dur = x
        x, lmax = convertArgsToLists(x)
        [obj.setDur(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setInterp(self, x):
        """
        Replace the `interp` attribute.

        :Args:

            x: int {1, 2, 3, 4}
                new `interp` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._interp = x
        x, lmax = convertArgsToLists(x)
        [obj.setInterp(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.01, 10.0, "lin", "dur", self._dur), SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def table(self):
        """PyoTableObject. Envelope table."""
        return self._table

    @table.setter
    def table(self, x):
        self.setTable(x)

    @property
    def dur(self):
        """float or PyoObject. Duration in seconds."""
        return self._dur

    @dur.setter
    def dur(self, x):
        self.setDur(x)

    @property
    def interp(self):
        """int {1, 2, 3, 4}, Interpolation method."""
        return self._interp

    @interp.setter
    def interp(self, x):
        self.setInterp(x)


class TrigLinseg(PyoObject):
    """
    Line segments trigger.

    TrigLinseg starts reading a break-points line segments each time it
    receives a trigger in its `input` parameter.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        list: list of tuples
            Points used to construct the line segments. Each tuple is a
            new point in the form (time, value).

            Times are given in seconds and must be in increasing order.

    .. note::

        TrigLinseg will send a trigger signal at the end of the playback.
        User can retreive the trigger streams by calling obj['trig'].
        Useful to synchronize other processes.

        The out() method is bypassed. TrigLinseg's signal can not be sent
        to audio outs.

    >>> s = Server().boot()
    >>> s.start()
    >>> m = Metro(time=1, poly=2).play()
    >>> pit = TrigLinseg(m, [(0,1000),(.1,1300),(.2,900),(.3,1000),(2,1000)])
    >>> a = Sine(pit, mul=.2).out()

    """

    def __init__(self, input, list, mul=1, add=0):
        pyoArgsAssert(self, "olOO", input, list, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._list = list
        self._in_fader = InputFader(input)
        in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add)
        self._base_objs = [TrigLinseg_base(wrap(in_fader, i), list, wrap(mul, i), wrap(add, i)) for i in range(lmax)]
        self._trig_objs = Dummy([TriggerDummy_base(obj) for obj in self._base_objs])
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setList(self, x):
        """
        Replace the `list` attribute.

        :Args:

            x: list of tuples
                new `list` attribute.

        """
        pyoArgsAssert(self, "l", x)
        self._list = x
        [obj.setList(x) for i, obj in enumerate(self._base_objs)]

    def replace(self, x):
        """
        Alias for `setList` method.

        :Args:

            x: list of tuples
                new `list` attribute.

        """
        self.setList(x)

    def getPoints(self):
        return self._list

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    def graph(self, xlen=None, yrange=None, title=None, wxnoserver=False):
        """
        Opens a grapher window to control the shape of the envelope.

        When editing the grapher with the mouse, the new set of points
        will be send to the object on mouse up.

        Ctrl+C with focus on the grapher will copy the list of points to the
        clipboard, giving an easy way to insert the new shape in a script.

        :Args:

            xlen: float, optional
                Set the maximum value of the X axis of the graph. If None, the
                maximum value is retrieve from the current list of points.
                Defaults to None.
            yrange: tuple, optional
                Set the min and max values of the Y axis of the graph. If
                None, min and max are retrieve from the current list of points.
                Defaults to None.
            title: string, optional
                Title of the window. If none is provided, the name of the
                class is used.
            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.

        """
        if xlen is None:
            xlen = float(self._list[-1][0])
        else:
            xlen = float(xlen)
        if yrange is None:
            ymin = float(min([x[1] for x in self._list]))
            ymax = float(max([x[1] for x in self._list]))
            if ymin == ymax:
                yrange = (0, ymax)
            else:
                yrange = (ymin, ymax)
        createGraphWindow(self, 0, xlen, yrange, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def list(self):
        """list of tuples. Points used to construct the line segments."""
        return self._list

    @list.setter
    def list(self, x):
        self.setList(x)


class TrigExpseg(PyoObject):
    """
    Exponential segments trigger.

    TrigExpseg starts reading break-points exponential segments each time
    it receives a trigger in its `input` parameter.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        list: list of tuples
            Points used to construct the line segments. Each tuple is a
            new point in the form (time, value).

            Times are given in seconds and must be in increasing order.
        exp: float, optional
            Exponent factor. Used to control the slope of the curves.
            Defaults to 10.
        inverse: boolean, optional
            If True, downward slope will be inversed. Useful to create
            biexponential curves. Defaults to True.

    .. note::

        TrigExpseg will send a trigger signal at the end of the playback.
        User can retreive the trigger streams by calling obj['trig'].
        Useful to synchronize other processes.

        The out() method is bypassed. TrigExpseg's signal can not be sent
        to audio outs.

    >>> s = Server().boot()
    >>> s.start()
    >>> m = Metro(time=0.5, poly=2).play()
    >>> pit = TrigExpseg(m, [(0,1000),(.25,1300),(.5,1000),(1,1000)])
    >>> a = Sine(pit, mul=.2).out()

    """

    def __init__(self, input, list, exp=10, inverse=True, mul=1, add=0):
        pyoArgsAssert(self, "olnbOO", input, list, exp, inverse, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._list = list
        self._exp = exp
        self._inverse = inverse
        self._in_fader = InputFader(input)
        in_fader, exp, inverse, mul, add, lmax = convertArgsToLists(self._in_fader, exp, inverse, mul, add)
        self._base_objs = [
            TrigExpseg_base(wrap(in_fader, i), list, wrap(exp, i), wrap(inverse, i), wrap(mul, i), wrap(add, i))
            for i in range(lmax)
        ]
        self._trig_objs = Dummy([TriggerDummy_base(obj) for obj in self._base_objs])
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setList(self, x):
        """
        Replace the `list` attribute.

        :Args:

            x: list of tuples
                new `list` attribute.

        """
        pyoArgsAssert(self, "l", x)
        self._list = x
        [obj.setList(x) for i, obj in enumerate(self._base_objs)]

    def setExp(self, x):
        """
        Replace the `exp` attribute.

        :Args:

            x: float
                new `exp` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self._exp = x
        x, lmax = convertArgsToLists(x)
        [obj.setExp(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    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)]

    def replace(self, x):
        """
        Alias for `setList` method.

        :Args:

            x: list of tuples
                new `list` attribute.

        """
        self.setList(x)

    def getPoints(self):
        return self._list

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    def graph(self, xlen=None, yrange=None, title=None, wxnoserver=False):
        """
        Opens a grapher window to control the shape of the envelope.

        When editing the grapher with the mouse, the new set of points
        will be send to the object on mouse up.

        Ctrl+C with focus on the grapher will copy the list of points to the
        clipboard, giving an easy way to insert the new shape in a script.

        :Args:

            xlen: float, optional
                Set the maximum value of the X axis of the graph. If None, the
                maximum value is retrieve from the current list of points.
                Defaults to None.
            yrange: tuple, optional
                Set the min and max values of the Y axis of the graph. If
                None, min and max are retrieve from the current list of points.
                Defaults to None.
            title: string, optional
                Title of the window. If none is provided, the name of the
                class is used.
            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.

        """
        if xlen is None:
            xlen = float(self._list[-1][0])
        else:
            xlen = float(xlen)
        if yrange is None:
            ymin = float(min([x[1] for x in self._list]))
            ymax = float(max([x[1] for x in self._list]))
            if ymin == ymax:
                yrange = (0, ymax)
            else:
                yrange = (ymin, ymax)
        createGraphWindow(self, 2, xlen, yrange, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def list(self):
        """list of tuples. Points used to construct the line segments."""
        return self._list

    @list.setter
    def list(self, x):
        self.setList(x)

    @property
    def exp(self):
        """float. Exponent factor."""
        return self._exp

    @exp.setter
    def exp(self, x):
        self.setExp(x)

    @property
    def inverse(self):
        """boolean. Inversion of downward slope."""
        return self._inverse

    @inverse.setter
    def inverse(self, x):
        self.setInverse(x)


class TrigXnoise(PyoObject):
    """
    Triggered X-class pseudo-random generator.

    Xnoise implements a few of the most common noise distributions.
    A new value is generated each time the object receive a trigger
    in input. Each distribution generates values in the range 0 and 1.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        dist: string or int, optional
            Distribution type. Defaults to 0.
        x1: float or PyoObject, optional
            First parameter. Defaults to 0.5.
        x2: float or PyoObject, optional
            Second parameter. Defaults to 0.5.

    .. note::

        Available distributions are:
            0. uniform
            1. linear minimum
            2. linear maximum
            3. triangular
            4. exponential minimum
            5. exponential maximum
            6. double (bi)exponential
            7. cauchy
            8. weibull
            9. gaussian
            10. poisson
            11. walker (drunk)
            12. loopseg (drunk with looped segments)

        Depending on the distribution, `x1` and `x2` parameters are applied
        as follow (names as string, or associated number can be used as `dist`
        parameter):

            0. uniform
                - x1: not used
                - x2: not used
            1. linear_min
                - x1: not used
                - x2: not used
            2. linear_max
                - x1: not used
                - x2: not used
            3. triangle
                - x1: not used
                - x2: not used
            4. expon_min
                - x1: slope {0 = no slope -> 10 = sharp slope}
                - x2: not used
            5. expon_max
                - x1: slope {0 = no slope -> 10 = sharp slope}
                - x2: not used
            6. biexpon
                - x1: bandwidth {0 = huge bandwidth -> 10 = narrow bandwidth}
                - x2: not used
            7. cauchy
                - x1: bandwidth {0 = narrow bandwidth -> 10 = huge bandwidth}
                - x2: not used
            8. weibull
                - x1: mean location {0 -> 1}
                - x2: shape {0.5 = linear min, 1.5 = expon min, 3.5 = gaussian}
            9. gaussian
                - x1: mean location {0 -> 1}
                - x2: bandwidth {0 =  narrow bandwidth -> 10 = huge bandwidth}
            10. poisson
                 - x1: gravity center {0 = low values -> 10 = high values}
                 - x2: compress/expand range {0.1 = full compress -> 4 full expand}
            11. walker
                 - x1: maximum value {0.1 -> 1}
                 - x2: maximum step {0.1 -> 1}
            12. loopseg
                 - x1: maximum value {0.1 -> 1}
                 - x2: maximum step {0.1 -> 1}

    >>> s = Server().boot()
    >>> s.start()
    >>> wav = SquareTable()
    >>> env = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> met = Metro(.125, 12).play()
    >>> amp = TrigEnv(met, table=env, mul=.2)
    >>> pit = TrigXnoise(met, dist=4, x1=10, mul=1000, add=200)
    >>> a = Osc(table=wav, freq=pit, mul=amp).out()

    """

    def __init__(self, input, dist=0, x1=0.5, x2=0.5, mul=1, add=0):
        pyoArgsAssert(self, "oOOOO", input, x1, x2, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._dist = dist
        self._x1 = x1
        self._x2 = x2
        self._in_fader = InputFader(input)
        in_fader, dist, x1, x2, mul, add, lmax = convertArgsToLists(self._in_fader, dist, x1, x2, mul, add)
        for i, t in enumerate(dist):
            if type(t) in [bytes, str]:
                dist[i] = XNOISE_DICT.get(t, 0)
        self._base_objs = [
            TrigXnoise_base(wrap(in_fader, i), wrap(dist, i), wrap(x1, i), wrap(x2, i), wrap(mul, i), wrap(add, i))
            for i in range(lmax)
        ]
        self._init_play()

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setDist(self, x):
        """
        Replace the `dist` attribute.

        :Args:

            x: int
                new `dist` attribute.

        """
        self._dist = x
        x, lmax = convertArgsToLists(x)
        for i, t in enumerate(x):
            if type(t) in [bytes, str]:
                x[i] = XNOISE_DICT.get(t, 0)
        [obj.setType(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setX1(self, x):
        """
        Replace the `x1` attribute.

        :Args:

            x: float or PyoObject
                new `x1` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._x1 = x
        x, lmax = convertArgsToLists(x)
        [obj.setX1(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setX2(self, x):
        """
        Replace the `x2` attribute.

        :Args:

            x: float or PyoObject
                new `x2` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._x2 = x
        x, lmax = convertArgsToLists(x)
        [obj.setX2(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [
            SLMap(0, 12, "lin", "dist", self._dist, res="int", dataOnly=True),
            SLMap(0.01, 10.0, "log", "x1", self._x1, dataOnly=True),
            SLMap(0.01, 10.0, "log", "x2", self._x2, dataOnly=True),
            SLMapMul(self._mul),
        ]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def dist(self):
        """string or int. Distribution type."""
        return self._dist

    @dist.setter
    def dist(self, x):
        self.setDist(x)

    @property
    def x1(self):
        """float or PyoObject. First parameter."""
        return self._x1

    @x1.setter
    def x1(self, x):
        self.setX1(x)

    @property
    def x2(self):
        """float or PyoObject. Second parameter."""
        return self._x2

    @x2.setter
    def x2(self, x):
        self.setX2(x)


class TrigXnoiseMidi(PyoObject):
    """
    Triggered X-class midi notes pseudo-random generator.

    Xnoise implements a few of the most common noise distributions.
    A new value is generated each time the object receive a trigger
    in input. Each distribution generates integer values in the range
    defined with `mrange` parameter and output can be scaled on midi
    notes, hertz or transposition factor.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        dist: string of int, optional
            Distribution type. Defaults to 0.
        x1: float or PyoObject, optional
            First parameter. Defaults to 0.5.
        x2: float or PyoObject, optional
            Second parameter. Defaults to 0.5.
        scale: int {0, 1, 2}, optional
            Output format. 0 = MIDI, 1 = Hertz, 2 = transposition factor.
            Defaults to 0.

            In the transposition mode, the central key (the key where there
            is no transposition) is (`minrange` + `maxrange`) / 2.
        mrange: tuple of int, optional
            Minimum and maximum possible values, in Midi notes. Available
            only at initialization time. Defaults to (0, 127).

    .. note::

        Available distributions are:
            0. uniform
            1. linear minimum
            2. linear maximum
            3. triangular
            4. exponential minimum
            5. exponential maximum
            6. double (bi)exponential
            7. cauchy
            8. weibull
            9. gaussian
            10. poisson
            11. walker (drunk)
            12. loopseg (drunk with looped segments)

        Depending on the distribution, `x1` and `x2` parameters are applied
        as follow (names as string, or associated number can be used as `dist`
        parameter):

            0. uniform
                - x1: not used
                - x2: not used
            1. linear_min
                - x1: not used
                - x2: not used
            2. linear_max
                - x1: not used
                - x2: not used
            3. triangle
                - x1: not used
                - x2: not used
            4. expon_min
                - x1: slope {0 = no slope -> 10 = sharp slope}
                - x2: not used
            5. expon_max
                - x1: slope {0 = no slope -> 10 = sharp slope}
                - x2: not used
            6. biexpon
                - x1: bandwidth {0 = huge bandwidth -> 10 = narrow bandwidth}
                - x2: not used
            7. cauchy
                - x1: bandwidth {0 = narrow bandwidth -> 10 = huge bandwidth}
                - x2: not used
            8. weibull
                - x1: mean location {0 -> 1}
                - x2: shape {0.5 = linear min, 1.5 = expon min, 3.5 = gaussian}
            9. gaussian
                - x1: mean location {0 -> 1}
                - x2: bandwidth {0 =  narrow bandwidth -> 10 = huge bandwidth}
            10. poisson
                 - x1: gravity center {0 = low values -> 10 = high values}
                 - x2: compress/expand range {0.1 = full compress -> 4 full expand}
            11. walker
                 - x1: maximum value {0.1 -> 1}
                 - x2: maximum step {0.1 -> 1}
            12. loopseg
                 - x1: maximum value {0.1 -> 1}
                 - x2: maximum step {0.1 -> 1}

    >>> s = Server().boot()
    >>> s.start()
    >>> wav = SquareTable()
    >>> env = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> met = Metro(.125, 12).play()
    >>> amp = TrigEnv(met, table=env, mul=.2)
    >>> pit = TrigXnoiseMidi(met, dist=4, x1=10, scale=1, mrange=(48,84))
    >>> a = Osc(table=wav, freq=pit, mul=amp).out()

    """

    def __init__(self, input, dist=0, x1=0.5, x2=0.5, scale=0, mrange=(0, 127), mul=1, add=0):
        pyoArgsAssert(self, "oOOixOO", input, x1, x2, scale, mrange, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._dist = dist
        self._x1 = x1
        self._x2 = x2
        self._scale = scale
        self._mrange = mrange
        self._in_fader = InputFader(input)
        in_fader, dist, x1, x2, scale, mrange, mul, add, lmax = convertArgsToLists(
            self._in_fader, dist, x1, x2, scale, mrange, mul, add
        )
        for i, t in enumerate(dist):
            if type(t) in [bytes, str]:
                dist[i] = XNOISE_DICT.get(t, 0)
        self._base_objs = [
            TrigXnoiseMidi_base(
                wrap(in_fader, i),
                wrap(dist, i),
                wrap(x1, i),
                wrap(x2, i),
                wrap(scale, i),
                wrap(mrange, i),
                wrap(mul, i),
                wrap(add, i),
            )
            for i in range(lmax)
        ]
        self._init_play()

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setDist(self, x):
        """
        Replace the `dist` attribute.

        :Args:

            x: int
                new `dist` attribute.

        """
        self._dist = x
        x, lmax = convertArgsToLists(x)
        for i, t in enumerate(x):
            if type(t) in [bytes, str]:
                x[i] = XNOISE_DICT.get(t, 0)
        [obj.setType(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setScale(self, x):
        """
        Replace the `scale` attribute.

        Possible values are:
            0. Midi notes
            1. Hertz
            2. transposition factor (centralkey is (`minrange` + `maxrange`) / 2

        :Args:

            x: int {0, 1, 2}
                new `scale` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._scale = x
        x, lmax = convertArgsToLists(x)
        [obj.setScale(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setRange(self, mini, maxi):
        """
        Replace the `mrange` attribute.

        :Args:

            mini: int
                minimum output midi range.
            maxi: int
                maximum output midi range.

        """
        pyoArgsAssert(self, "ii", mini, maxi)
        self._mrange = (mini, maxi)
        mini, maxi, lmax = convertArgsToLists(mini, maxi)
        [obj.setRange(wrap(mini, i), wrap(maxi, i)) for i, obj in enumerate(self._base_objs)]

    def setX1(self, x):
        """
        Replace the `x1` attribute.

        :Args:

            x: float or PyoObject
                new `x1` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._x1 = x
        x, lmax = convertArgsToLists(x)
        [obj.setX1(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setX2(self, x):
        """
        Replace the `x2` attribute.

        :Args:

            x: float or PyoObject
                new `x2` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._x2 = x
        x, lmax = convertArgsToLists(x)
        [obj.setX2(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [
            SLMap(0, 12, "lin", "dist", self._dist, res="int", dataOnly=True),
            SLMap(0.01, 10.0, "log", "x1", self._x1, dataOnly=True),
            SLMap(0.01, 10.0, "log", "x2", self._x2, dataOnly=True),
            SLMapMul(self._mul),
        ]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def dist(self):
        """string or int. Distribution type."""
        return self._dist

    @dist.setter
    def dist(self, x):
        self.setDist(x)

    @property
    def x1(self):
        """float or PyoObject. First parameter."""
        return self._x1

    @x1.setter
    def x1(self, x):
        self.setX1(x)

    @property
    def x2(self):
        """float or PyoObject. Second parameter."""
        return self._x2

    @x2.setter
    def x2(self, x):
        self.setX2(x)

    @property
    def scale(self):
        """int. Output format."""
        return self._scale

    @scale.setter
    def scale(self, x):
        self.setScale(x)


class Counter(PyoObject):
    """
    Integer count generator.

    Counter keeps track of all triggers received, outputs the current
    count constrained within `min` and `max` range, and can be set to
    count up, down, or up-and-down.


    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        min: int, optional
            Minimum value of the count, included in the count. Defaults to 0.
        max: int, optional
            Maximum value of the count. excluded of the count.
            The counter will count up to max - 1. Defaults to 100.
        dir: int {0, 1, 2}, optional
            Direction of the count. Defaults to 0. Three possible values:
                0. up
                1. down
                2. up-and-down

    .. note::

        The out() method is bypassed. Counter's signal can not be sent
        to audio outs.

    .. seealso::

        :py:class:`Select`

    >>> s = Server().boot()
    >>> s.start()
    >>> m = Metro(.125).play()
    >>> c = Counter(m, min=3, max=8, dir=2, mul=100)
    >>> a = Sine(freq=c, mul=.2).mix(2).out()

    """

    def __init__(self, input, min=0, max=100, dir=0, mul=1, add=0):
        pyoArgsAssert(self, "oiiiOO", input, min, max, dir, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._min = min
        self._max = max
        self._dir = dir
        self._in_fader = InputFader(input)
        in_fader, min, max, dir, mul, add, lmax = convertArgsToLists(self._in_fader, min, max, dir, mul, add)
        self._base_objs = [
            Counter_base(wrap(in_fader, i), wrap(min, i), wrap(max, i), wrap(dir, i), wrap(mul, i), wrap(add, i))
            for i in range(lmax)
        ]
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setMin(self, x):
        """
        Replace the `min` attribute.

        :Args:

            x: int
                new `min` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._min = x
        x, lmax = convertArgsToLists(x)
        [obj.setMin(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setMax(self, x):
        """
        Replace the `max` attribute.

        :Args:

            x: int
                new `max` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._max = x
        x, lmax = convertArgsToLists(x)
        [obj.setMax(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setDir(self, x):
        """
        Replace the `dir` attribute.

        :Args:

            x: int {0, 1, 2}
                new `dir` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._dir = x
        x, lmax = convertArgsToLists(x)
        [obj.setDir(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def reset(self, value=None):
        """
        Reset the current count of the counter. If `value` is None, the counter
        resets to the beginning of the count.

        :Args:

            value: int, optional
                Value where to reset the count. Defaults to None.

        """
        if value is not None:
            pyoArgsAssert(self, "i", value)
        value, lmax = convertArgsToLists(value)
        [obj.reset(wrap(value, i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [
            SLMap(0, 100, "lin", "min", self._min, res="int", dataOnly=True),
            SLMap(0, 1000, "lin", "max", self._max, res="int", dataOnly=True),
            SLMap(0, 2, "lin", "dir", self._dir, res="int", dataOnly=True),
            SLMap(0, 1000, "lin", "mul", self._mul),
            SLMap(0, 1000, "lin", "add", self._add),
        ]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def min(self):
        """int. Minimum value."""
        return self._min

    @min.setter
    def min(self, x):
        self.setMin(x)

    @property
    def max(self):
        """int. Maximum value."""
        return self._max

    @max.setter
    def max(self, x):
        self.setMax(x)

    @property
    def dir(self):
        """int. Direction of the count."""
        return self._dir

    @dir.setter
    def dir(self, x):
        self.setDir(x)


class Select(PyoObject):
    """
    Sends trigger on matching integer values.

    Select takes in input an audio signal containing integer numbers
    and sends a trigger when the input matches `value` parameter. This
    object is especially designed to be used with Counter object.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal. Must contains integer numbers.
        value: int, optional
            Value to be matched to send a trigger. Defaults to 0.

    .. note::

        The out() method is bypassed. Select's signal can not be sent
        to audio outs.

    .. seealso::

        :py:class:`Counter`

    >>> s = Server().boot()
    >>> s.start()
    >>> env = HannTable()
    >>> m = Metro(.125, poly=2).play()
    >>> te = TrigEnv(m, table=env, dur=.2, mul=.2)
    >>> c = Counter(m, min=0, max=4)
    >>> se = Select(c, 0)
    >>> tr = TrigRand(se, 400, 600)
    >>> a = Sine(freq=tr, mul=te).out()

    """

    def __init__(self, input, value=0, mul=1, add=0):
        pyoArgsAssert(self, "oiOO", input, value, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._value = value
        self._in_fader = InputFader(input)
        in_fader, value, mul, add, lmax = convertArgsToLists(self._in_fader, value, mul, add)
        self._base_objs = [
            Select_base(wrap(in_fader, i), wrap(value, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
        ]
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setValue(self, x):
        """
        Replace the `value` attribute.

        :Args:

            x: int
                new `value` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._value = x
        x, lmax = convertArgsToLists(x)
        [obj.setValue(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0, 100, "lin", "value", self._value, res="int", dataOnly=True)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def value(self):
        """int. Matching value."""
        return self._value

    @value.setter
    def value(self, x):
        self.setValue(x)


class Change(PyoObject):
    """
    Sends trigger that informs when input value has changed.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal. Must contains integer numbers.

    .. note::

        The out() method is bypassed. Change's signal can not be sent
        to audio outs.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> a = XnoiseMidi(dist="loopseg", freq=[2, 3], x1=1, scale=1, mrange=(60,73))
    >>> b = Change(a)
    >>> amp = TrigEnv(b, table=t, dur=[.5,.333], mul=.3)
    >>> out = SineLoop(freq=a, feedback=.05, mul=amp).out()

    """

    def __init__(self, input, mul=1, add=0):
        pyoArgsAssert(self, "oOO", input, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._in_fader = InputFader(input)
        in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add)
        self._base_objs = [Change_base(wrap(in_fader, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)]
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    @property
    def input(self):
        """PyoObject. Audio signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)


class Thresh(PyoObject):
    """
    Informs when a signal crosses a threshold.

    Thresh sends a trigger when a signal crosses a threshold. The `dir`
    parameter can be used to set the crossing mode, down-up, up-down, or
    both.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        threshold: float or PyoObject, optional
            Threshold value. Defaults to 0.
        dir: int {0, 1, 2}, optional
            There are three modes of using Thresh:
                0. down-up (default)
                    sends a trigger when current value is higher than the
                    threshold, while old value was equal to or lower than
                    the threshold.
                1. up-down
                    sends a trigger when current value is lower than the
                    threshold, while old value was equal to or higher than
                    the threshold.
                2. both direction
                    sends a trigger in both the two previous cases.

    .. note::

        The out() method is bypassed. Thresh's signal can not be sent
        to audio outs.

    >>> s = Server().boot()
    >>> s.start()
    >>> a = Phasor(1)
    >>> b = Thresh(a, threshold=[0.25, 0.5, 0.66], dir=0)
    >>> t = LinTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> env = TrigEnv(b, table=t, dur=.5, mul=.3)
    >>> sine = Sine(freq=[500,600,700], mul=env).out()

    """

    def __init__(self, input, threshold=0.0, dir=0, mul=1, add=0):
        pyoArgsAssert(self, "oOiOO", input, threshold, dir, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._threshold = threshold
        self._dir = dir
        self._in_fader = InputFader(input)
        in_fader, threshold, dir, mul, add, lmax = convertArgsToLists(self._in_fader, threshold, dir, mul, add)
        self._base_objs = [
            Thresh_base(wrap(in_fader, i), wrap(threshold, i), wrap(dir, i), wrap(mul, i), wrap(add, i))
            for i in range(lmax)
        ]
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setThreshold(self, x):
        """
        Replace the `threshold` attribute.

        :Args:

            x: float or PyoObject
                new `threshold` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._threshold = x
        x, lmax = convertArgsToLists(x)
        [obj.setThreshold(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setDir(self, x):
        """
        Replace the `dir` attribute.

        :Args:

            x: int {0, 1, 2}
                new `dir` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._dir = x
        x, lmax = convertArgsToLists(x)
        [obj.setDir(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    @property
    def input(self):
        """PyoObject. Audio signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def threshold(self):
        """float or PyoObject. Threshold value."""
        return self._threshold

    @threshold.setter
    def threshold(self, x):
        self.setThreshold(x)

    @property
    def dir(self):
        """int. User mode."""
        return self._dir

    @dir.setter
    def dir(self, x):
        self.setDir(x)


class Percent(PyoObject):
    """
    Lets pass a certain percentage of the input triggers.

    Percent looks at the triggers received in `input` and
    lets them pass `percent` of the time.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        percent: float or PyoObject, optional
            How much percentage of triggers to let pass,
            between 0 and 100. Defaults to 50.

    .. note::

        The out() method is bypassed. Percent's signal can not
        be sent to audio outs.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(time=.125, poly=2).play()
    >>> trig = Percent(met, percent=50)
    >>> amp = TrigEnv(trig, table=t, dur=.25, mul=.3)
    >>> fr = TrigRand(trig, min=400, max=1000)
    >>> freq = Port(fr, risetime=0.001, falltime=0.001)
    >>> a = Sine(freq=freq, mul=amp).out()

    """

    def __init__(self, input, percent=50.0, mul=1, add=0):
        pyoArgsAssert(self, "oOOO", input, percent, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._percent = percent
        self._in_fader = InputFader(input)
        in_fader, percent, mul, add, lmax = convertArgsToLists(self._in_fader, percent, mul, add)
        self._base_objs = [
            Percent_base(wrap(in_fader, i), wrap(percent, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
        ]
        self._init_play()

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setPercent(self, x):
        """
        Replace the `percent` attribute.

        :Args:

            x: float or PyoObject
                new `percent` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._percent = x
        x, lmax = convertArgsToLists(x)
        [obj.setPercent(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.0, 100.0, "lin", "percent", self._percent)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def percent(self):
        """float or PyoObject. Percentage value."""
        return self._percent

    @percent.setter
    def percent(self, x):
        self.setPercent(x)


class Timer(PyoObject):
    """
    Reports elapsed time between two trigs.

    A trigger in `input2` signal starts an internal timer. The next trigger
    in `input` signal stops it and reports the elapsed time between the two
    triggers. Useful for filtering triggers that are too close to each other.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Trigger signal. Stops the timer and reports elapsed time.
        input2: PyoObject
            Trigger signal. Starts the timer if not already started.

    .. note::

        The `input` signal is evaluated before the `input2` signal, so it's
        safe to stop and start the timer with the same trigger signal.

    >>> s = Server().boot()
    >>> s.start()
    >>> cl = Cloud(density=20, poly=2).play()
    >>> ti = Timer(cl, cl)
    >>> # Minimum waiting time before a new trig
    >>> cp = Compare(ti, comp=.05, mode=">")
    >>> trig = cl * cp
    >>> amp = TrigEnv(trig, table=HannTable(), dur=.05, mul=.25)
    >>> freq = TrigChoice(trig, choice=[100,150,200,250,300,350,400])
    >>> a = LFO(freq=freq, type=2, mul=amp).out()

    """

    def __init__(self, input, input2, mul=1, add=0):
        pyoArgsAssert(self, "ooOO", input, input2, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._input2 = input2
        self._in_fader = InputFader(input)
        self._in_fader2 = InputFader(input2)
        in_fader, in_fader2, mul, add, lmax = convertArgsToLists(self._in_fader, self._in_fader2, mul, add)
        self._base_objs = [
            Timer_base(wrap(in_fader, i), wrap(in_fader2, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
        ]
        self._init_play()

    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)

    def setInput2(self, x, fadetime=0.05):
        """
        Replace the `input2` 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._input2 = x
        self._in_fader2.setInput(x, fadetime)

    @property
    def input(self):
        """PyoObject. Timer stop signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def input2(self):
        """PyoObject. Timer start signal."""
        return self._input2

    @input2.setter
    def input2(self, x):
        self.setInput2(x)


class Iter(PyoObject):
    """
    Triggers iterate over a list of values.

    Iter loops over a list of user-defined values. When a trigger is received
    in `input`, Iter moves up to the next value in the list, with wrap-around.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        choice: list of floats or PyoObjects
            Sequence of values over which to iterate. If a PyoObject with
            more than one audio streams is given, the streams will be
            flattened and inserted in the main list. See setChoice method
            for more details.
        init: float, optional
            Initial value. Available at initialization time only.
            Defaults to 0.

    .. note::

        Iter will send a trigger signal when the iterator hits the
        last value of the list `choice`. User can retreive the trigger
        streams by calling obj['trig']. Useful to synchronize other
        processes.

    >>> s = Server().boot()
    >>> s.start()
    >>> l1 = [300, 350, 400, 450, 500, 550]
    >>> l2 = [300, 350, 450, 500, 550]
    >>> t = CosTable([(0,0), (50,1), (250,.3), (8191,0)])
    >>> met = Metro(time=.125, poly=2).play()
    >>> amp = TrigEnv(met, table=t, dur=.25, mul=.3)
    >>> it = Iter(met, choice=[l1, l2])
    >>> si = Sine(freq=it, mul=amp).out()

    """

    def __init__(self, input, choice, init=0.0, mul=1, add=0):
        pyoArgsAssert(self, "olnOO", input, choice, init, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._choice = choice
        self._in_fader = InputFader(input)
        in_fader, init, mul, add, lmax = convertArgsToLists(self._in_fader, init, mul, add)
        x = self._flatten(choice)
        if type(x[0]) != list:
            self._base_objs = [
                Iter_base(wrap(in_fader, i), x, wrap(init, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
            ]
        else:
            choicelen = len(x)
            lmax = max(choicelen, lmax)
            self._base_objs = [
                Iter_base(wrap(in_fader, i), wrap(x, i), wrap(init, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
            ]
        self._trig_objs = Dummy([TriggerDummy_base(obj) for obj in self._base_objs])
        self._init_play()

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def _flatten(self, x):
        if type(x[0]) != list:
            lst = []
            for ob in x:
                if isinstance(ob, PyoObject):
                    lst.extend(ob.getBaseObjects())
                else:
                    lst.append(ob)
        else:
            lst = []
            for sub in x:
                sublst = []
                for ob in sub:
                    if isinstance(ob, PyoObject):
                        sublst.extend(ob.getBaseObjects())
                    else:
                        sublst.append(ob)
                lst.append(sublst)
        return lst

    def setChoice(self, x):
        """
        Replace the `choice` attribute.

        `x` is a sequence of values over which to iterate. If a PyoObject
        with more than one audio streams is given, the streams will be
        flattened and inserted in the main list. For example, the choices:

            [100, Randi(100,200,4), 200, Sig(250, mul=[1, 2])]

        will expand to:

            [100, rand_val, 200, 250, 500] # the last two are audio streams.

        :Args:

            x: list of floats or PyoObjects
                new `choice` attribute.

        """
        pyoArgsAssert(self, "l", x)
        self._choice = x
        x = self._flatten(x)
        if type(x[0]) != list:
            [obj.setChoice(x) for i, obj in enumerate(self._base_objs)]
        else:
            [obj.setChoice(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def reset(self, x=0):
        """
        Resets the current count.

        :Args:

            x: int, optional
                Value where to reset the count. Defaults to 0.

        """
        pyoArgsAssert(self, "I", x)
        [obj.reset(x) for obj in self._base_objs]

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def choice(self):
        """list of floats or PyoObjects. Possible values."""
        return self._choice

    @choice.setter
    def choice(self, x):
        self.setChoice(x)


class Count(PyoObject):
    """
    Counts integers at audio rate.

    Count generates a signal increasing by 1 each sample when it receives a
    trigger. It can be used to do sample playback using TableIndex.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Trigger signal. Start or Restart the count.
        min: int, optional
            Minimum value of the count, included in the count. Defaults to 0.
        max: int, optional
            Maximum value of the count. excluded of the count. Defaults to 0.

            A value of 0 eliminates the maximum, and the count continues
            increasing without resetting.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = SndTable(SNDS_PATH+'/accord.aif')
    >>> ind = Count(Trig().play(), [0,100], t.getSize())
    >>> read = TableIndex(t, ind).out()

    """

    def __init__(self, input, min=0, max=0, mul=1, add=0):
        pyoArgsAssert(self, "oiiOO", input, min, max, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._min = min
        self._max = max
        self._in_fader = InputFader(input)
        in_fader, min, max, mul, add, lmax = convertArgsToLists(self._in_fader, min, max, mul, add)
        self._base_objs = [
            Count_base(wrap(in_fader, i), wrap(min, i), wrap(max, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
        ]
        self._init_play()

    def setInput(self, x, fadetime=0.05):
        """
        Replace the `input` attribute.

        :Args:

            x: PyoObject
                New input signal.
            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)

    def setMin(self, x):
        """
        Replace the `min` attribute.

        :Args:

            x: int
                new `min` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._min = x
        x, lmax = convertArgsToLists(x)
        [obj.setMin(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def setMax(self, x):
        """
        Replace the `max` attribute.

        :Args:

            x: int
                new `max` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._max = x
        x, lmax = convertArgsToLists(x)
        [obj.setMax(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [
            SLMap(0, 10000, "lin", "min", self._min, res="int", dataOnly=True),
            SLMap(10000, 1000000, "lin", "max", self._max, res="int", dataOnly=True),
            SLMapMul(self._mul),
        ]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Trigger signal. Start/Restart the count."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def min(self):
        """int. Minimum value."""
        return self._min

    @min.setter
    def min(self, x):
        self.setMin(x)

    @property
    def max(self):
        """int. Maximum value."""
        return self._max

    @max.setter
    def max(self, x):
        self.setMax(x)


class NextTrig(PyoObject):
    """
    A trigger in the second stream opens a gate only for the next one in the first stream.

    When the gate is opened by a trigger in `input2` signal, the next trigger
    in `input` signal is allowed to pass and automatically closes the gate.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Trigger signal. Trigger stream waiting for the gate to be opened.
        input2: PyoObject
            Trigger signal. Trigger stream opening the gate.

    .. note::

        The `input` signal is evaluated before the `input2` signal, so it's
        safe to send triggers in both inputs at the same time and wait for the
        next one.

    >>> s = Server().boot()
    >>> s.start()
    >>> mid = Urn(max=4, freq=4, add=60)
    >>> sigL = SineLoop(freq=MToF(mid), feedback=.08, mul=0.3).out()
    >>> first = NextTrig(Change(mid), mid["trig"])
    >>> amp = TrigExpseg(first, [(0,0),(.01,.25),(1,0)])
    >>> sigR = SineLoop(midiToHz(84), feedback=0.05, mul=amp).out(1)

    """

    def __init__(self, input, input2, mul=1, add=0):
        pyoArgsAssert(self, "ooOO", input, input2, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._input2 = input2
        self._in_fader = InputFader(input)
        self._in_fader2 = InputFader(input2)
        in_fader, in_fader2, mul, add, lmax = convertArgsToLists(self._in_fader, self._in_fader2, mul, add)
        self._base_objs = [
            NextTrig_base(wrap(in_fader, i), wrap(in_fader2, i), wrap(mul, i), wrap(add, i)) for i in range(lmax)
        ]
        self._init_play()

    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)

    def setInput2(self, x, fadetime=0.05):
        """
        Replace the `input2` 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._input2 = x
        self._in_fader2.setInput(x, fadetime)

    @property
    def input(self):
        """PyoObject. Incoming trigger stream signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def input2(self):
        """PyoObject. Trigger stream opening the gate."""
        return self._input2

    @input2.setter
    def input2(self, x):
        self.setInput2(x)


class TrigVal(PyoObject):
    """
    Outputs a previously defined value on a trigger signal.

    Value defined at `value` argument is sent when a trigger signal
    is detected in input.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Audio signal sending triggers.
        value: float or PyoObject, optional
            Next value. Defaults to 0.
        init: float, optional
            Initial value. Defaults to 0.

    .. note::

        The out() method is bypassed. TrigVal's signal can not be sent
        to audio outs.

    >>> s = Server().boot()
    >>> s.start()
    >>> def newfreq():
    ...     val.value = (val.value + 50) % 500 + 100
    >>> tr = Metro(1).play()
    >>> val = TrigVal(tr, value=250)
    >>> a = SineLoop(val, feedback=.1, mul=.3).out()
    >>> trfunc = TrigFunc(tr, newfreq)

    """

    def __init__(self, input, value=0.0, init=0.0, mul=1, add=0):
        pyoArgsAssert(self, "oOnOO", input, value, init, mul, add)
        PyoObject.__init__(self, mul, add)
        self._input = input
        self._value = value
        self._in_fader = InputFader(input)
        in_fader, value, init, mul, add, lmax = convertArgsToLists(self._in_fader, value, init, mul, add)
        self._base_objs = [
            TrigVal_base(wrap(in_fader, i), wrap(value, i), wrap(init, i), wrap(mul, i), wrap(add, i))
            for i in range(lmax)
        ]
        self._init_play()

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setValue(self, x):
        """
        Replace the `value` attribute.

        :Args:

            x: float or PyoObject
                new `value` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._value = x
        x, lmax = convertArgsToLists(x)
        [obj.setValue(wrap(x, i)) for i, obj in enumerate(self._base_objs)]

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [SLMap(0.0, 1.0, "lin", "value", self._value), SLMapMul(self._mul)]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def value(self):
        """float or PyoObject. Next value."""
        return self._value

    @value.setter
    def value(self, x):
        self.setValue(x)


class Euclide(PyoObject):
    """
    Euclidean rhythm generator.

    This object generates euclidean trigger patterns, resulting in onsets
    in the rhythm to be as equidistant as possible.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    The play() method starts the Euclide and is not called at the object
    creation time.

    :Parent: :py:class:`PyoObject`

    :Args:

        time: float or PyoObject, optional
            Time, in seconds, between each beat of the pattern. Defaults to 0.125.
        taps: int, optional
            Number of beats in the generated pattern (measure length), max = 64.
            Defaults to 16.
        onsets: int, optional
            Number of onsets (a positive tap) in the generated pattern.
            Defaults to 10.
        poly: int, optional
            Beat polyphony. Denotes how many independent streams are
            generated by the object, allowing overlapping processes.

            Available only at initialization. Defaults to 1.

    .. note::

        Euclide outputs many signals identified with a string between brackets:

        |  obj['tap'] returns audio stream of the current tap of the measure.
        |  obj['amp'] returns audio stream of the current beat amplitude.
        |  obj['dur'] returns audio stream of the current beat duration in seconds.
        |  obj['end'] returns audio stream with a trigger just before the end of the measure.

        obj without brackets returns the generated trigger stream of the measure.

        The out() method is bypassed. Euclide's signal can not be sent to audio outs.

        Euclide has no `mul` and `add` attributes.

    >>> s = Server().boot()
    >>> s.start()
    >>> t = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
    >>> beat = Euclide(time=.125, taps=16, onsets=[8,7], poly=1).play()
    >>> trmid = TrigXnoiseMidi(beat, dist=12, mrange=(60, 96))
    >>> trhz = Snap(trmid, choice=[0,2,3,5,7,8,10], scale=1)
    >>> tr2 = TrigEnv(beat, table=t, dur=beat['dur'], mul=beat['amp'])
    >>> a = Sine(freq=trhz, mul=tr2*0.3).out()

    """

    def __init__(self, time=0.125, taps=16, onsets=10, poly=1):
        pyoArgsAssert(self, "OiiI", time, taps, onsets, poly)
        PyoObject.__init__(self)
        self._tap_dummy = []
        self._amp_dummy = []
        self._dur_dummy = []
        self._end_dummy = []
        self._time = time
        self._taps = taps
        self._onsets = onsets
        self._poly = poly
        time, taps, onsets, lmax = convertArgsToLists(time, taps, onsets)
        self._base_players = [
            Beater_base(wrap(time, i), wrap(taps, i), wrap([100] * lmax, i), poly) for i in range(lmax)
        ]
        self._base_objs = [Beat_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._tap_objs = [BeatTapStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._amp_objs = [BeatAmpStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._dur_objs = [BeatDurStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._end_objs = [BeatEndStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        for i in range(lmax):
            preset = [wrap(taps, i)] + self.__generate__(wrap(onsets, i), wrap(taps, i))
            self._base_players[i].setPresets([preset])
            self._base_players[i].recall(0)

    def __generate__(self, m, k):
        """
        Generates the euclidean rhythm for `m` onsets
        in a measure of length `k` (number of taps).
        Looping implementation, faster than recursive.
        """
        if m < 1:
            m = 1
        if k < 1:
            k = 1
        if m > k:
            m = k
        k -= m
        mv, kv = [1], [0]
        while k > 1:
            if m > k:
                m, k = k, m - k
                mv, kv = mv + kv, mv
            else:
                m, k = m, k - m
                mv, kv = mv + kv, kv
        return mv * m + kv * k

    def __getitem__(self, i):
        if i == "tap":
            self._tap_dummy.append(Dummy([obj for obj in self._tap_objs]))
            return self._tap_dummy[-1]
        if i == "amp":
            self._amp_dummy.append(Dummy([obj for obj in self._amp_objs]))
            return self._amp_dummy[-1]
        if i == "dur":
            self._dur_dummy.append(Dummy([obj for obj in self._dur_objs]))
            return self._dur_dummy[-1]
        if i == "end":
            self._end_dummy.append(Dummy([obj for obj in self._end_objs]))
            return self._end_dummy[-1]
        if type(i) == slice:
            return self._base_objs[i]
        if i < len(self._base_objs):
            return self._base_objs[i]
        else:
            print("'i' too large!")

    def get(self, identifier="amp", all=False):
        """
        Return the first sample of the current buffer as a float.

        Can be used to convert audio stream to usable Python data.

        "tap", "amp" or "dur" must be given to `identifier` to specify
        which stream to get value from.

        :Args:

            identifier: string {"tap", "amp", "dur"}
                Address string parameter identifying audio stream.
                Defaults to "amp".
            all: boolean, optional
                If True, the first value of each object's stream
                will be returned as a list.

                If False, only the value of the first object's
                stream will be returned as a float.

        """
        if not all:
            return self.__getitem__(identifier)[0]._getStream().getValue()
        else:
            return [obj._getStream().getValue() for obj in self.__getitem__(identifier).getBaseObjects()]

    def setTime(self, x):
        """
        Replace the `time` attribute.

        :Args:

            x: float or PyoObject
                New `time` attribute.

        """
        pyoArgsAssert(self, "O", x)
        self._time = x
        x, lmax = convertArgsToLists(x)
        [obj.setTime(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setTaps(self, x):
        """
        Replace the `taps` attribute.

        :Args:

            x: int
                New `taps` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._taps = x
        x, onsets, lmax = convertArgsToLists(x, self._onsets)
        for i in range(len(self._base_players)):
            preset = [wrap(x, i)] + self.__generate__(wrap(onsets, i), wrap(x, i))
            self._base_players[i].setPresets([preset])
            self._base_players[i].recall(0)

    def setOnsets(self, x):
        """
        Replace the `onsets` attribute.

        :Args:

            x: int
                New `onsets` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._onsets = x
        x, taps, lmax = convertArgsToLists(x, self._taps)
        for i in range(len(self._base_players)):
            preset = [wrap(taps, i)] + self.__generate__(wrap(x, i), wrap(taps, i))
            self._base_players[i].setPresets([preset])
            self._base_players[i].recall(0)

    def reset(self):
        """
        Reset internal counters to initialization values.

        """
        [obj.reset() for obj in self._base_players]

    def play(self, dur=0, delay=0):
        dur, delay, lmax = convertArgsToLists(dur, delay)
        self._tap_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._tap_objs)]
        self._amp_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._amp_objs)]
        self._dur_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._dur_objs)]
        self._end_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._end_objs)]
        return PyoObject.play(self, dur, delay)

    def stop(self, wait=0):
        [obj.stop(wait) for obj in self._tap_objs]
        [obj.stop(wait) for obj in self._amp_objs]
        [obj.stop(wait) for obj in self._dur_objs]
        [obj.stop(wait) for obj in self._end_objs]
        return PyoObject.stop(self, wait)

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [
            SLMap(0.01, 1.0, "lin", "time", self._time),
            SLMap(2, 64, "lin", "taps", self._taps, res="int", dataOnly=True),
            SLMap(0, 64, "lin", "onsets", self._onsets, res="int", dataOnly=True),
        ]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def time(self):
        """float or PyoObject. Time, in seconds, between each beat."""
        return self._time

    @time.setter
    def time(self, x):
        self.setTime(x)

    @property
    def taps(self):
        """int. Number of beats in the generated pattern."""
        return self._taps

    @taps.setter
    def taps(self, x):
        self.setTaps(x)

    @property
    def onsets(self):
        """int. Number of onsets in the generated pattern."""
        return self._onsets

    @onsets.setter
    def onsets(self, x):
        self.setOnsets(x)


class TrigBurst(PyoObject):
    """
    Generates a time/amplitude expandable trigger pattern.

    A trigger is an audio signal with a value of 1 surrounded by 0s.

    When TrigBurst receives a trigger in its `input` argument, it starts
    to output `count` triggers with a variable delay between each trigger
    of the pattern. If `expand` is less than 1.0, the delay becomes shorter,
    if it is greater than 1.0, the delay becomes longer.

    :Parent: :py:class:`PyoObject`

    :Args:

        input: PyoObject
            Input signal sending triggers.
        time: float, optional
            Base time, in seconds, between each trig of the serie. Defaults to 0.25.
        count: int, optional
            Number of trigs generated (length of the serie). Defaults to 10.
        expand: float, optional
            Timing power serie factor. Each delay before the next trig is the
            current delay (starting with `time`) times `expand` factor. Defaults to 1.0.
        ampfade: float, optional
            Amplitude power serie factor. Each amplitude in the serie is the
            current amplitude (starting at 1) times `ampfade` factor. Defaults to 1.0.
        poly: int, optional
            Voice polyphony. Denotes how many independent streams are
            generated by the object, allowing overlapping processes.

            Available only at initialization. Defaults to 1.

    .. note::

        TrigBurst outputs many signals identified with a string between brackets:

        |  obj['tap'] returns audio stream of the current tap of the serie.
        |  obj['amp'] returns audio stream of the current beat amplitude.
        |  obj['dur'] returns audio stream of the current beat duration in seconds.
        |  obj['end'] returns audio stream with a trigger just before the end of the serie.

        obj without brackets returns the generated trigger stream of the serie.

        The out() method is bypassed. TrigBurst's signal can not be sent to audio outs.

        TrigBurst has no `mul` and `add` attributes.

    >>> s = Server().boot()
    >>> s.start()
    >>> env = CosTable([(0,0), (100,0.5), (500, 0.3), (4096,0.3), (8192,0)])
    >>> m = Metro(2).play()
    >>> tb = TrigBurst(m, time=0.15, count=[15,20], expand=[0.92,0.9], ampfade=0.85)
    >>> amp = TrigEnv(tb, env, dur=tb["dur"], mul=tb["amp"]*0.3)
    >>> a = Sine([800,600], mul=amp)
    >>> rev = STRev(a, inpos=[0,1], revtime=1.5, cutoff=5000, bal=0.1).out()

    """

    def __init__(self, input, time=0.25, count=10, expand=1.0, ampfade=1.0, poly=1):
        pyoArgsAssert(self, "oOinnI", input, time, count, expand, ampfade, poly)
        PyoObject.__init__(self)
        self._tap_dummy = []
        self._amp_dummy = []
        self._dur_dummy = []
        self._end_dummy = []
        self._input = input
        self._time = time
        self._count = count
        self._expand = expand
        self._ampfade = ampfade
        self._poly = poly
        self._in_fader = InputFader(input)
        in_fader, time, count, expand, ampfade, lmax = convertArgsToLists(self._in_fader, time, count, expand, ampfade)
        self._base_players = [
            TrigBurster_base(wrap(in_fader, i), wrap(time, i), wrap(count, i), wrap(expand, i), wrap(ampfade, i), poly)
            for i in range(lmax)
        ]
        self._base_objs = [TrigBurst_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)]
        self._tap_objs = [
            TrigBurstTapStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)
        ]
        self._amp_objs = [
            TrigBurstAmpStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)
        ]
        self._dur_objs = [
            TrigBurstDurStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)
        ]
        self._end_objs = [
            TrigBurstEndStream_base(wrap(self._base_players, j), i) for i in range(poly) for j in range(lmax)
        ]
        self._init_play()

    def __getitem__(self, i):
        if i == "tap":
            self._tap_dummy.append(Dummy([obj for obj in self._tap_objs]))
            return self._tap_dummy[-1]
        if i == "amp":
            self._amp_dummy.append(Dummy([obj for obj in self._amp_objs]))
            return self._amp_dummy[-1]
        if i == "dur":
            self._dur_dummy.append(Dummy([obj for obj in self._dur_objs]))
            return self._dur_dummy[-1]
        if i == "end":
            self._end_dummy.append(Dummy([obj for obj in self._end_objs]))
            return self._end_dummy[-1]
        if type(i) == slice:
            return self._base_objs[i]
        if i < len(self._base_objs):
            return self._base_objs[i]
        else:
            print("'i' too large!")

    def get(self, identifier="amp", all=False):
        """
        Return the first sample of the current buffer as a float.

        Can be used to convert audio stream to usable Python data.

        "tap", "amp" or "dur" must be given to `identifier` to specify
        which stream to get value from.

        :Args:

            identifier: string {"tap", "amp", "dur"}
                Address string parameter identifying audio stream.
                Defaults to "amp".
            all: boolean, optional
                If True, the first value of each object's stream
                will be returned as a list.

                If False, only the value of the first object's
                stream will be returned as a float.

        """
        if not all:
            return self.__getitem__(identifier)[0]._getStream().getValue()
        else:
            return [obj._getStream().getValue() for obj in self.__getitem__(identifier).getBaseObjects()]

    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. Defaults to 0.05.

        """
        pyoArgsAssert(self, "oN", x, fadetime)
        self._input = x
        self._in_fader.setInput(x, fadetime)

    def setTime(self, x):
        """
        Replace the `time` attribute.

        :Args:

            x: float
                New `time` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self._time = x
        x, lmax = convertArgsToLists(x)
        [obj.setTime(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setCount(self, x):
        """
        Replace the `count` attribute.

        :Args:

            x: int
                New `count` attribute.

        """
        pyoArgsAssert(self, "i", x)
        self._count = x
        x, lmax = convertArgsToLists(x)
        [obj.setCount(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setExpand(self, x):
        """
        Replace the `expand` attribute.

        :Args:

            x: float
                New `expand` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self._expand = x
        x, lmax = convertArgsToLists(x)
        [obj.setExpand(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def setAmpfade(self, x):
        """
        Replace the `ampfade` attribute.

        :Args:

            x: float
                New `ampfade` attribute.

        """
        pyoArgsAssert(self, "n", x)
        self._ampfade = x
        x, lmax = convertArgsToLists(x)
        [obj.setAmpfade(wrap(x, i)) for i, obj in enumerate(self._base_players)]

    def play(self, dur=0, delay=0):
        dur, delay, lmax = convertArgsToLists(dur, delay)
        self._tap_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._tap_objs)]
        self._amp_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._amp_objs)]
        self._dur_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._dur_objs)]
        self._end_objs = [obj.play(wrap(dur, i), wrap(delay, i)) for i, obj in enumerate(self._end_objs)]
        return PyoObject.play(self, dur, delay)

    def stop(self, wait=0):
        [obj.stop(wait) for obj in self._tap_objs]
        [obj.stop(wait) for obj in self._amp_objs]
        [obj.stop(wait) for obj in self._dur_objs]
        [obj.stop(wait) for obj in self._end_objs]
        return PyoObject.stop(self, wait)

    def out(self, chnl=0, inc=1, dur=0, delay=0):
        return self.play(dur, delay)

    def setMul(self, x):
        pass

    def setAdd(self, x):
        pass

    def setSub(self, x):
        pass

    def setDiv(self, x):
        pass

    def ctrl(self, map_list=None, title=None, wxnoserver=False):
        self._map_list = [
            SLMap(0.1, 1.0, "lin", "time", self._time, dataOnly=True),
            SLMap(2, 128, "lin", "count", self._count, res="int", dataOnly=True),
            SLMap(0.5, 2.0, "lin", "expand", self._expand, dataOnly=True),
            SLMap(0.5, 1.0, "lin", "ampfade", self._ampfade, dataOnly=True),
        ]
        PyoObject.ctrl(self, map_list, title, wxnoserver)

    @property
    def input(self):
        """PyoObject. Audio trigger signal."""
        return self._input

    @input.setter
    def input(self, x):
        self.setInput(x)

    @property
    def time(self):
        """float. Base time, in seconds, between each trig."""
        return self._time

    @time.setter
    def time(self, x):
        self.setTime(x)

    @property
    def count(self):
        """int. Number of triggers in the generated serie."""
        return self._count

    @count.setter
    def count(self, x):
        self.setCount(x)

    @property
    def expand(self):
        """float. Time's power expansion factor."""
        return self._expand

    @expand.setter
    def expand(self, x):
        self.setExpand(x)

    @property
    def ampfade(self):
        """float. Amplitude's power expansion factor."""
        return self._ampfade

    @ampfade.setter
    def ampfade(self, x):
        self.setAmpfade(x)
