"""
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 2010 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 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with pyo.  If not, see <http://www.gnu.org/licenses/>.
"""
import sys
from _core import *
from _maps import *
from _widgets import createGraphWindow
from types import SliceType, ListType, TupleType

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

    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):
        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.
        
        """
        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., '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 ints, 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.

    .. 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):
        PyoObject.__init__(self)
        if type(seq) != ListType:
            print >> sys.stderr, 'TypeError: "seq" argument of %s must be a list.\n' % self.__class__.__name__
            exit()
        self._time = time
        self._seq = seq
        self._poly = poly
        time, lmax = convertArgsToLists(time)
        if type(seq[0]) != ListType:
            self._base_players = [Seqer_base(wrap(time,i), seq, poly) 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) 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.

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

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

        :Args:

            x : list of ints
                New `seq` attribute.

        """
        self._seq = x
        if type(x[0]) != ListType:
            [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 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., '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 seq(self):
        """List of ints. Sequence of beat durations in time's unit.""" 
        return self._seq
    @seq.setter
    def seq(self, x): self.setSeq(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):
        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.
        
        """
        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., '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.

    .. 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=.125, taps=16, w1=80, w2=50, w3=30, poly=1):
        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
        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) 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) == SliceType:
            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 new(self):
        """
        Generates a new pattern with the current parameters.
        
        """
        [obj.new() 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.

        """
        [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.

        """
        [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.

        """
        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.

        """
        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.

        """
        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.

        """
        self.setWeights(w1=x)

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

        :Args:

            x : int
                New `w2` attribute.

        """
        self.setWeights(w2=x)

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

        :Args:

            x : int
                New `w3` attribute.

        """
        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 != None: self._w1 = w1
        if w2 != None: self._w2 = w2
        if w3 != 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 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):
        [obj.stop() for obj in self._tap_objs]
        [obj.stop() for obj in self._amp_objs]
        [obj.stop() for obj in self._dur_objs]
        [obj.stop() for obj in self._end_objs]
        return PyoObject.stop(self)

    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., 'lin', 'time', self._time)]
        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)

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., mul=1, add=0):
        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)]

    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.

        """
        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.

        """
        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., 200., '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., max=1., port=0., init=0., mul=1, add=0):
        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)]

    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.

        """
        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.
        
        """
        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.
        
        """
        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.
        
        """
        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., 1., 'lin', 'min', self._min),
                          SLMap(1., 2., '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., init=0., mul=1, add=0):
        PyoObject.__init__(self, mul, add)
        if type(choice) != ListType:
            print >> sys.stderr, 'TypeError: "choice" argument of %s must be a list.\n' % self.__class__.__name__
            exit()
        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]) != ListType:
            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)]

    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.

        """
        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.
        
        """
        self._choice = x
        if type(x[0]) != ListType:
            [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.
        
        """
        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 function
            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):
        PyoObject.__init__(self)
        if type(function) == ListType or type(function) == TupleType:
            if not callable(function[0]):
                print >> sys.stderr, 'TypeError: "function" argument of %s must be callable.\n' % self.__class__.__name__
                exit()
        else:
            if not callable(function):
                print >> sys.stderr, 'TypeError: "function" argument of %s must be callable.\n' % self.__class__.__name__
                exit()
        self._input = input
        self._function = 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), wrap(function,i), wrap(arg,i)) for i in range(lmax)]

    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.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setFunction(self, x):
        """
        Replace the `function` attribute.
        
        :Args:

            x : Python function
                new `function` attribute.
        
        """
        self._function = x
        x, lmax = convertArgsToLists(x)
        [obj.setFunction(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 sends 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):
        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])

    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.

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

    def setTable(self, x):
        """
        Replace the `table` attribute.
        
        :Args:

            x : PyoTableObject
                new `table` attribute.
        
        """
        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.
        
        """
        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.
        
        """
        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., '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 sends 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):
        PyoObject.__init__(self, mul, add)
        if type(list) != ListType:
            print >> sys.stderr, 'TypeError: "list" argument of %s must be a list of tuples.\n' % self.__class__.__name__
            exit()
        if type(list[0]) != TupleType:
            print >> sys.stderr, 'TypeError: "list" argument of %s must be a list of tuples.\n' % self.__class__.__name__
            exit()
        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])

    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.

        """
        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.
        
        """
        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 == None:
            xlen = float(self._list[-1][0])
        else:
            xlen = float(xlen)
        if yrange == 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 sends 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):
        PyoObject.__init__(self, mul, add)
        if type(list) != ListType:
            print >> sys.stderr, 'TypeError: "list" argument of %s must be a list of tuples.\n' % self.__class__.__name__
            exit()
        if type(list[0]) != TupleType:
            print >> sys.stderr, 'TypeError: "list" argument of %s must be a list of tuples.\n' % self.__class__.__name__
            exit()
        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])

    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.

        """
        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.
        
        """
        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.

        """
        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.

        """
        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 == None:
            xlen = float(self._list[-1][0])
        else:
            xlen = float(xlen)
        if yrange == 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):
        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) == StringType: 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)]

    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.

        """
        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) == StringType: 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.

        """
        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.

        """
        self._x2= x
        x, lmax = convertArgsToLists(x)
        [obj.setX2(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 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):
        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) == StringType: 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)]

    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.

        """
        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) == StringType: 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.

        """
        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.

        """
        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.

        """
        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.

        """
        self._x2= x
        x, lmax = convertArgsToLists(x)
        [obj.setX2(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 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):
        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)]

    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.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setMin(self, x):
        """
        Replace the `min` attribute.
        
        :Args:

            x : int
                new `min` attribute.
        
        """
        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.
        
        """
        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.
        
        """
        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.

        """
        value, lmax = convertArgsToLists(value)
        [obj.reset(wrap(value,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 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):
        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)]

    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.

        """
        self._input = x
        self._in_fader.setInput(x, fadetime)
        
    def setValue(self, x):
        """
        Replace the `value` attribute.
        
        :Args:

            x : int
                new `value` attribute.
        
        """
        self._value = x
        x, lmax = convertArgsToLists(x)
        [obj.setValue(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 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):
        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)]

    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.

        """
        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., dir=0, mul=1, add=0):
        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)]

    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.

        """
        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.
        
        """
        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.
        
        """
        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., mul=1, add=0):
        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)]

    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.

        """
        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.

        """
        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., 100., '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):
        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)]

    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.

        """
        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.

        """
        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
            Sequence of values over which to iterate.
        init : float, optional
            Initial value. Available at initialization time only. 
            Defaults to 0.

    >>> 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., mul=1, add=0):
        PyoObject.__init__(self, mul, add)
        if type(choice) != ListType:
            print >> sys.stderr, 'TypeError: "choice" argument of %s must be a list.\n' % self.__class__.__name__
            exit()
        self._input = input
        self._choice = choice
        self._in_fader = InputFader(input)
        in_fader, init, mul, add, lmax = convertArgsToLists(self._in_fader, init, mul, add)
        if type(choice[0]) != ListType:
            self._base_objs = [Iter_base(wrap(in_fader,i), choice, 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 = [Iter_base(wrap(in_fader,i), wrap(choice,i), wrap(init,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]

    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.

        """
        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.

        """
        self._choice = x
        if type(x[0]) != ListType:
            [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 reset(self, x=0):
        """
        Resets the current count.
        
        :Args:
        
            x : int, optional
                Value where to reset the count. Defaults to 0.
        
        """
        [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. 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):
        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)]

    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.

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

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

        :Args:

            x : int
                new `min` attribute.

        """
        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.

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

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

    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.

        """
        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.

        """
        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., init=0., mul=1, add=0):
        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)]

    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.

        """
        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.

        """
        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., 1., '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)
