[SCM] python-pyo/master: Imported Upstream version 0.7.4

tiago at users.alioth.debian.org tiago at users.alioth.debian.org
Fri Jan 30 04:34:08 UTC 2015


The following commit has been merged in the master branch:
commit 6d35ddffd63e8b1287e09c3f32e1c3636ac4cef3
Author: Tiago Bortoletto Vaz <tiago at debian.org>
Date:   Thu Jan 29 22:48:04 2015 -0500

    Imported Upstream version 0.7.4

diff --git a/pyolib/COPYING.txt b/COPYING.txt
similarity index 100%
copy from pyolib/COPYING.txt
copy to COPYING.txt
diff --git a/ChangeLog b/ChangeLog
index ef1d32f..1e01dd5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,242 @@
+2015-01-29 belangeo <belangeo at gmail.com>
+
+    * Release tag: 0.7.4
+    - rev 1284
+
+2015-01-29 belangeo <belangeo at gmail.com>
+
+    * Added new function: floatmap, 0-1 range mapper. Fixed bug in DataTable initialization 
+    and added an automatic refresh of the DataTable grapher window.
+    - rev 1282
+
+2015-01-26 belangeo <belangeo at gmail.com>
+
+    * Added new objet: Particle, a full control granular synthesis generator.
+    - rev 1281
+
+2015-01-24 belangeo <belangeo at gmail.com>
+
+    * Added setSync method to Granule object. Allow to toggle between synchronous 
+    and asynchronous granulation. Added noteon and noteoff trigger streams to Notein 
+    object.
+
+    - rev 1280
+
+2014-12-15 belangeo <belangeo at gmail.com>
+
+    * Added reset method to CtlScan and CtlScan2 objects.
+    - rev 1279
+
+2014-12-03 belangeo <belangeo at gmail.com>
+
+    * Added new objet: PeakAmp, a peak amplitude follower.
+    - rev 1277
+
+2014-11-27 belangeo <belangeo at gmail.com>
+
+    * Added reset method to Beat and Euclide objects.
+    - rev 1275
+
+-------------------------------------------------------------------------------------
+
+2014-10-17 belangeo <belangeo at gmail.com>
+
+    * Release tag: 0.7.3.
+    - rev 1273
+
+2014-11-15 belangeo <belangeo at gmail.com>
+
+    * Added new objet: Scope, an audio waveform display.
+    - rev 1270
+
+2014-11-12 belangeo <belangeo at gmail.com>
+
+    * E-Pyo: Fix marker's line numbering.
+    - rev 1267
+
+2014-11-08 belangeo <belangeo at gmail.com>
+
+    * E-Pyo: Added Save As Template... menu item.
+    - rev 1263
+
+2014-11-02 belangeo <belangeo at gmail.com>
+
+    * Fixed bug in Fader decreasing ramp.
+    - rev 1262
+
+2014-10-28 belangeo <belangeo at gmail.com>
+
+    * Added midi output methods to the Server object. noteout, afterout, ctlout, programout, pressout and bendout.
+    - rev 1261
+
+2014-10-28 belangeo <belangeo at gmail.com>
+
+    * Server.setMidiOutputDevice(idx) with `idx` greater than the higher portmidi devices index opens all available output devices.
+    - rev 1260
+
+2014-10-24 belangeo <belangeo at gmail.com>
+
+    * Added new object: FToM, converts an audio stream containning frequencies in hertz to a midi note audio stream.
+    - rev 1259
+
+2014-10-23 belangeo <belangeo at gmail.com>
+
+    * Added new function: hzToMidi, converts a frequency in hertz to a midi note value.
+    - rev 1258
+
+-------------------------------------------------------------------------------------
+
+2014-10-17 belangeo <belangeo at gmail.com>
+
+    * Release tag: 0.7.2.
+    - rev 1256
+
+2014-10-16 belangeo <belangeo at gmail.com>
+
+    * Server.setMidiInputDevice(idx) with `idx` greater than the higher portmidi input index opens all available devices.
+    - rev 1254
+
+2014-10-16 belangeo <belangeo at gmail.com>
+
+    * OSX installer: Also install pyo in anaconda site-packages directory if exist.
+    - rev 1253
+
+2014-10-16 belangeo <belangeo at gmail.com>
+
+    * Added new object : TrigBurst, generates a time/amplitude expandable trigger pattern.
+    - rev 1252
+
+2014-10-14 belangeo <belangeo at gmail.com>
+
+    * Added new object : Euclide, Euclidean rhythm generator.
+    - rev 1251
+
+2014-10-13 belangeo <belangeo at gmail.com>
+
+    * Windows installers now check for the current python installation directory before installing files.
+    - rev 1244 - 1250
+
+2014-10-10 belangeo <belangeo at gmail.com>
+
+    * E-Pyo: Fixed inconsistencies in Find/Replace behaviours.
+    - rev 1241
+
+2014-10-10 belangeo <belangeo at gmail.com>
+
+    * Added new object : SmoothDelay, a delay line that does not produce clicks or pitch shifting when the delay time is changing.
+    - rev 1239
+
+2014-10-08 belangeo <belangeo at gmail.com>
+
+    * Added new object : AttackDetector, audio signal onset detection.
+    - rev 1238
+
+2014-10-07 belangeo <belangeo at gmail.com>
+
+    * Added new object : Centroid, Computes the spectral centroid of an input signal.
+    - rev 1237
+
+-------------------------------------------------------------------------------------
+
+2014-08-29 belangeo <belangeo at gmail.com>
+
+    * Release tag: 0.7.1.
+    - rev 1236
+
+2014-09-12 belangeo <belangeo at gmail.com>
+
+    * E-Pyo: Added RadioPyo to the template choices.  
+    - rev 1234
+
+2014-09-09 belangeo <belangeo at gmail.com>
+
+    * Fixed Compare when used with None or a string. Print a warning and set 'comp' attribute to 0. 
+    - rev 1229
+
+2014-09-05 belangeo <belangeo at gmail.com>
+
+    * Fixed live interpreter of the server window when using arrow keys navigation.
+    - rev 1228
+
+2014-09-04 belangeo <belangeo at gmail.com>
+
+    * E-Pyo: Check if WxPython 3.0 is installed, otherwise uses 2.8.
+    - rev 1227
+
+2014-09-02 belangeo <belangeo at gmail.com>
+
+    * Added anti-aliasing to PyoTableObject's grapher widget. Fixed Ctrl+W on the grapher.
+    - rev 1225, 1226
+
+-------------------------------------------------------------------------------------
+
+2014-08-29 belangeo <belangeo at gmail.com>
+
+    * Release tag: 0.7.0.
+    - rev 1224
+
+2014-08-26 belangeo <belangeo at gmail.com>
+
+    * pyo can now be used without any GUI toolkit (WxPython or TKinter). Widgets are simply disabled.
+    - rev 1208
+
+2014-06-22 belangeo <belangeo at gmail.com>
+
+    * Added Server methods to auto-connect Jack ports to already opened ports.
+    - rev 1201
+
+2014-05-23 belangeo <belangeo at gmail.com>
+
+    * E-Pyo: output log now in realtime.
+    - rev 1197
+
+2014-04-24 belangeo <belangeo at gmail.com>
+
+    * Added new object: Tanh, hyperbolic tangent function on audio signal.
+    - rev 1188
+
+-------------------------------------------------------------------------------------
+
+2014-04-11 belangeo <belangeo at gmail.com>
+
+    * Release tag: 0.6.9.
+    - rev 1185
+
+2014-04-11 belangeo <belangeo at gmail.com>
+
+    * Added lot of methods to PyoTableObject (retify, bipolarGain, invert, lowpass, fadein, fadeout, pow).
+    - rev 1182
+
+2014-04-04 belangeo <belangeo at gmail.com>
+
+    * Added new object: PartialTable, generates waveforms made of inharmonic components.
+    - rev 1177
+
+2014-03-12 belangeo <belangeo at gmail.com>
+
+    * Added a Scope example in examples/utilities.
+    - rev 1168
+
+2013-12-24 belangeo <belangeo at gmail.com>
+
+    * Added new object: STRev, Stereo reverb.
+    - rev 1154
+
+2013-12-24 belangeo <belangeo at gmail.com>
+
+    * Added dataOnly argument to SLMap. User can now control parameters, in ctrl window, that do not accept audio signal but discreet values.
+    - rev 1153
+
+2013-12-10 belangeo <belangeo at gmail.com>
+
+    * Added new object: ComplexRes, Complex one-pole resonator filter.
+    - rev 1148
+
+2013-10-18 belangeo <belangeo at gmail.com>
+
+    * Added new object: TrackHold, Performs a 'thru' and hold on its input signal.
+    - rev 1143
+
 -------------------------------------------------------------------------------------
 
 2013-10-16 belangeo <belangeo at gmail.com>
diff --git a/doc-sphinx/build.py b/doc-sphinx/build.py
index fdcb309..50c9fe8 100644
--- a/doc-sphinx/build.py
+++ b/doc-sphinx/build.py
@@ -62,10 +62,8 @@ os.system("sphinx-build -a -b %s ./source %s" % (build_format, build_folder))
 
 if build_format == "latex":
     os.system("cd build_latex; pdflatex -interaction nonstopmode Pyo;  pdflatex -interaction nonstopmode Pyo")
-else:
-    # Upload on iACT server
-    print "Upload documentation (y/n)?"
-    ans = raw_input()
-    if (ans == 'y'):
-        os.system('scp -r %s/* sysop at 132.204.178.49:/Library/WebServer/Documents/pyo/manual-dev/' % build_folder)
+
+rep = raw_input("Do you want to upload to ajax server (y/n) ? ")
+if rep == "y":
+        os.system("scp -r build_html/* jeadum1 at ajaxsoundstudio.com:/home/jeadum1/ajaxsoundstudio.com/pyodoc")
 
diff --git a/doc-sphinx/source/about.rst b/doc-sphinx/source/about.rst
index 4add116..b7488f9 100644
--- a/doc-sphinx/source/about.rst
+++ b/doc-sphinx/source/about.rst
@@ -12,4 +12,4 @@ For questions and comments, please subscribe to the `pyo-discuss <http://groups.
 To report a bug or to request a feature, use the `issues tracker <http://code.google.com/p/pyo/issues/list>`_ on googlecode.
 
 Sources and binaries can be downloaded at:
-http://code.google.com/p/pyo/
+http://ajaxsoundstudio.com/software/pyo/
diff --git a/doc-sphinx/source/api/alphabetical.rst b/doc-sphinx/source/api/alphabetical.rst
index 3b2862b..a67b7d7 100644
--- a/doc-sphinx/source/api/alphabetical.rst
+++ b/doc-sphinx/source/api/alphabetical.rst
@@ -12,6 +12,7 @@ Alphabetical class reference
 - :py:class:`Allpass` :     Delay line based allpass filter.
 - :py:class:`Atan2` :     Computes the principal value of the arc tangent of b/a.
 - :py:class:`Atone` :     A first-order recursive high-pass filter with variable frequency response.
+- :py:class:`AttackDetector` :     Audio signal onset detection.
 - :py:class:`Average` :     Moving average filter.
 - :py:class:`Balance` :     Adjust rms power of an audio signal according to the rms power of another.
 - :py:class:`BandSplit` :     Splits an input signal into multiple frequency bands.
@@ -30,6 +31,7 @@ Alphabetical class reference
 - :py:class:`CallAfter` :     Calls a Python function after a given time.
 - :py:class:`CarToPol` :     Performs the cartesian to polar conversion.
 - :py:class:`Ceil` :     Rounds to smallest integral value greater than or equal to the input signal.
+- :py:class:`Centroid` :     Computes the spectral centroid of an input signal.
 - :py:class:`CentsToTranspo` :     Returns the transposition factor equivalent of a given cents value.
 - :py:class:`Change` :     Sends trigger that informs when input value has changed.
 - :py:class:`ChebyTable` :     Chebyshev polynomials of the first kind.
@@ -39,6 +41,7 @@ Alphabetical class reference
 - :py:class:`Clip` :     Clips a signal to a predefined limit.
 - :py:class:`Cloud` :     Generates random triggers.
 - :py:class:`Compare` :     Comparison object.
+- :py:class:`ComplexRes` :     Complex one-pole resonator filter. 
 - :py:class:`Compress` :     Reduces the dynamic range of an audio signal.
 - :py:class:`ControlRead` :     Reads control values previously stored in text files.
 - :py:class:`ControlRec` :     Records control values and writes them in a text file.
@@ -63,10 +66,12 @@ Alphabetical class reference
 - :py:class:`Disto` :     Arc tangent distortion.
 - :py:class:`Dummy` :     Dummy object used to perform arithmetics on PyoObject.
 - :py:class:`EQ` :     Equalizer filter. 
+- :py:class:`Euclide` :     Euclidean rhythm generator.
 - :py:class:`ExpTable` :     Construct a table from exponential interpolated segments.
 - :py:class:`Expseg` :     Trace a series of exponential segments between specified break-points. 
 - :py:class:`FFT` :     Fast Fourier Transform.
 - :py:class:`FM` :     A simple frequency modulation generator.
+- :py:class:`FToM` :     Returns the midi note equivalent to a frequency in Hz.
 - :py:class:`Fader` :     Fadein - fadeout envelope generator.
 - :py:class:`Floor` :     Rounds to largest integral value not greater than audio signal.
 - :py:class:`Follower2` :     Envelope follower with different attack and release times.
@@ -153,11 +158,15 @@ Alphabetical class reference
 - :py:class:`PVVerb` :     Spectral domain reverberation.
 - :py:class:`Pan` :     Cosinus panner with control on the spread factor.
 - :py:class:`ParaTable` :     Generates parabola window function. 
+- :py:class:`PartialTable` :     Inharmonic waveform generator.
+- :py:class:`Particle` :     A full control granular synthesis generator.
 - :py:class:`Pattern` :     Periodically calls a Python function.
+- :py:class:`PeakAmp` :     Peak amplitude follower.
 - :py:class:`Percent` :     Lets pass a certain percentage of the input triggers.
 - :py:class:`Phaser` :     Multi-stages second-order phase shifter allpass filters. 
 - :py:class:`Phasor` :     A simple phase incrementor.
 - :py:class:`PinkNoise` :     A pink noise generator.
+- :py:class:`Pointer2` :     High quality table reader with control on the pointer position.
 - :py:class:`Pointer` :     Table reader with control on the pointer position.
 - :py:class:`PolToCar` :     Performs the polar to cartesian conversion.
 - :py:class:`Port` :     Exponential portamento.
@@ -183,10 +192,12 @@ Alphabetical class reference
 - :py:class:`SLMapPhase` :     SLMap with normalized values for a 'phase' slider.
 - :py:class:`SLMapQ` :     SLMap with normalized values for a 'q' slider.
 - :py:class:`SPan` :     Simple equal power panner.
+- :py:class:`STRev` :     Stereo reverb.
 - :py:class:`SVF` :     Fourth-order state variable filter allowing continuous change of the filter type. 
 - :py:class:`SampHold` :     Performs a sample-and-hold operation on its input. 
 - :py:class:`SawTable` :     Sawtooth waveform generator.
 - :py:class:`Scale` :     Maps an input range of audio values to an output range.
+- :py:class:`Scope` :     Oscilloscope - audio waveform display.
 - :py:class:`Score` :     Calls functions by incrementation of a preformatted name.
 - :py:class:`Select` :     Sends trigger on matching integer values.
 - :py:class:`Selector` :     Audio selector.
@@ -200,6 +211,7 @@ Alphabetical class reference
 - :py:class:`SincTable` :     Generates sinc window function. 
 - :py:class:`SineLoop` :     A simple sine wave oscillator with feedback.
 - :py:class:`Sine` :     A simple sine wave oscillator.
+- :py:class:`SmoothDelay` :     Artifact free sweepable recursive delay.
 - :py:class:`Snap` :     Snap input values on a user's defined midi scale.
 - :py:class:`SndTable` :     Transfers data from a soundfile into a function table.
 - :py:class:`Spectrum` :     Spectrum analyzer and display.
@@ -215,11 +227,14 @@ Alphabetical class reference
 - :py:class:`TableRec` :     TableRec is for writing samples into a previously created NewTable.
 - :py:class:`TableScale` :     Scales all the values contained in a PyoTableObject.
 - :py:class:`Tan` :     Performs a tangent function on audio signal.
+- :py:class:`Tanh` :     Performs a hyperbolic tangent function on audio signal.
 - :py:class:`Thresh` :     Informs when a signal crosses a threshold.
 - :py:class:`Timer` :     Reports elapsed time between two trigs.
 - :py:class:`Tone` :     A first-order recursive low-pass filter with variable frequency response.
 - :py:class:`Touchin` :     Get the current value of an after-touch Midi controller.
+- :py:class:`TrackHold` :     Performs a track-and-hold operation on its input. 
 - :py:class:`TranspoToCents` :     Returns the cents value equivalent of a transposition factor.
+- :py:class:`TrigBurst` :     Generates a time/amplitude expandable trigger pattern.
 - :py:class:`TrigChoice` :     Random generator from user's defined values.
 - :py:class:`TrigEnv` :     Envelope reader generator.
 - :py:class:`TrigExpseg` :     Exponential segments trigger.
diff --git a/doc-sphinx/source/api/classes/analysis.rst b/doc-sphinx/source/api/classes/analysis.rst
index 233842a..6a94baa 100644
--- a/doc-sphinx/source/api/classes/analysis.rst
+++ b/doc-sphinx/source/api/classes/analysis.rst
@@ -33,3 +33,32 @@ can use them for controlling parameters of others objects.
 .. autoclass:: Yin
    :members:
 
+*Centroid*
+------------
+
+.. autoclass:: Centroid
+   :members:
+
+*AttackDetector*
+-----------------
+
+.. autoclass:: AttackDetector
+   :members:
+
+*Spectrum*
+-----------------------------------
+
+.. autoclass:: Spectrum
+   :members:
+
+*Scope*
+-----------------------------------
+
+.. autoclass:: Scope
+   :members:
+
+*PeakAmp*
+-----------------------------------
+
+.. autoclass:: PeakAmp
+   :members:
diff --git a/doc-sphinx/source/api/classes/arithmetic.rst b/doc-sphinx/source/api/classes/arithmetic.rst
index af5fc7f..757bdfc 100644
--- a/doc-sphinx/source/api/classes/arithmetic.rst
+++ b/doc-sphinx/source/api/classes/arithmetic.rst
@@ -23,6 +23,12 @@ Tools to perform arithmetic operations on audio signals.
 .. autoclass:: Tan
    :members:
 
+*Tanh*
+------------
+
+.. autoclass:: Tanh
+   :members:
+
 *Abs*
 ------------
 
diff --git a/doc-sphinx/source/api/classes/dynamics.rst b/doc-sphinx/source/api/classes/dynamics.rst
index 0ac8200..cb68212 100644
--- a/doc-sphinx/source/api/classes/dynamics.rst
+++ b/doc-sphinx/source/api/classes/dynamics.rst
@@ -11,6 +11,12 @@ Objects to modify the dynamic range and sample quality of audio signals.
 .. autoclass:: Clip
    :members:
 
+*Degrade*
+----------
+
+.. autoclass:: Degrade
+   :members:
+
 *Mirror*
 ------------
 
diff --git a/doc-sphinx/source/api/classes/effects.rst b/doc-sphinx/source/api/classes/effects.rst
index be32c61..25a3201 100644
--- a/doc-sphinx/source/api/classes/effects.rst
+++ b/doc-sphinx/source/api/classes/effects.rst
@@ -78,3 +78,15 @@ as distortions, delays, chorus and reverbs.
 .. autoclass:: FreqShift
    :members:
 
+*STRev*
+------------
+
+.. autoclass:: STRev
+   :members:
+
+*SmoothDelay*
+---------------
+
+.. autoclass:: SmoothDelay
+   :members:
+
diff --git a/doc-sphinx/source/api/classes/filters.rst b/doc-sphinx/source/api/classes/filters.rst
index 865fb9a..358744b 100644
--- a/doc-sphinx/source/api/classes/filters.rst
+++ b/doc-sphinx/source/api/classes/filters.rst
@@ -180,4 +180,9 @@ sinusoidal component according to its frequency.
 .. autoclass:: ButBR
    :members:
 
+*ComplexRes*
+------------
+
+.. autoclass:: ComplexRes
+   :members:
 
diff --git a/doc-sphinx/source/api/classes/fourier.rst b/doc-sphinx/source/api/classes/fourier.rst
index 148ea3d..1955415 100644
--- a/doc-sphinx/source/api/classes/fourier.rst
+++ b/doc-sphinx/source/api/classes/fourier.rst
@@ -51,12 +51,6 @@ spectral domain.
 .. autoclass:: CvlVerb
    :members:
 
-*Spectrum*
------------------------------------
-
-.. autoclass:: Spectrum
-   :members:
-
 *Vectral*
 -----------------------------------
 
diff --git a/doc-sphinx/source/api/classes/tableprocess.rst b/doc-sphinx/source/api/classes/tableprocess.rst
index 3ad98e6..c883866 100644
--- a/doc-sphinx/source/api/classes/tableprocess.rst
+++ b/doc-sphinx/source/api/classes/tableprocess.rst
@@ -56,12 +56,24 @@ store audio samples or algorithmic sequences for future uses.
 .. autoclass:: OscTrig
    :members:
 
+*Particle*
+-----------------------------------
+
+.. autoclass:: Particle
+   :members:
+
 *Pointer*
 -----------------------------------
 
 .. autoclass:: Pointer
    :members:
 
+*Pointer2*
+-----------------------------------
+
+.. autoclass:: Pointer2
+   :members:
+
 *Pulsar*
 -----------------------------------
 
diff --git a/doc-sphinx/source/api/classes/tables.rst b/doc-sphinx/source/api/classes/tables.rst
index 569743b..1891218 100644
--- a/doc-sphinx/source/api/classes/tables.rst
+++ b/doc-sphinx/source/api/classes/tables.rst
@@ -78,6 +78,12 @@ in memory and access them quickly.
 .. autoclass:: ParaTable
    :members:
 
+*PartialTable*
+-----------------------------------
+
+.. autoclass:: PartialTable
+   :members:
+
 *SawTable*
 -----------------------------------
 
diff --git a/doc-sphinx/source/api/classes/triggers.rst b/doc-sphinx/source/api/classes/triggers.rst
index 778d1d9..917c802 100644
--- a/doc-sphinx/source/api/classes/triggers.rst
+++ b/doc-sphinx/source/api/classes/triggers.rst
@@ -40,6 +40,12 @@ processes with sample rate timing accuracy.
 .. autoclass:: Counter
    :members:
 
+*Euclide*
+-----------------------------------
+
+.. autoclass:: Euclide
+   :members:
+
 *Iter*
 -----------------------------------
 
@@ -94,6 +100,12 @@ processes with sample rate timing accuracy.
 .. autoclass:: Trig
    :members:
 
+*TrigBurst*
+-----------------------------------
+
+.. autoclass:: TrigBurst
+   :members:
+
 *TrigChoice*
 -----------------------------------
 
diff --git a/doc-sphinx/source/api/classes/utils.rst b/doc-sphinx/source/api/classes/utils.rst
index 58ebb12..c84bbab 100644
--- a/doc-sphinx/source/api/classes/utils.rst
+++ b/doc-sphinx/source/api/classes/utils.rst
@@ -125,3 +125,9 @@ Miscellaneous objects.
 .. autoclass:: TranspoToCents
    :members:
 
+*TrackHold*
+-----------------------------------
+
+.. autoclass:: TrackHold
+   :members:
+
diff --git a/doc-sphinx/source/api/functions/audio.rst b/doc-sphinx/source/api/functions/audio.rst
index d9b36ec..eeff482 100644
--- a/doc-sphinx/source/api/functions/audio.rst
+++ b/doc-sphinx/source/api/functions/audio.rst
@@ -3,6 +3,16 @@ Audio Setup
 
 .. module:: pyo
 
+*pa_get_version*
+---------------------------------
+
+.. autofunction:: pa_get_version
+
+*pa_get_version_text*
+---------------------------------
+
+.. autofunction:: pa_get_version_text
+
 *pa_count_host_apis*
 ---------------------------------
 
diff --git a/doc-sphinx/source/api/functions/conv.rst b/doc-sphinx/source/api/functions/conv.rst
index ec0273c..9261abd 100644
--- a/doc-sphinx/source/api/functions/conv.rst
+++ b/doc-sphinx/source/api/functions/conv.rst
@@ -33,6 +33,11 @@ Conversions
 
 .. autofunction:: rescale(data, xmin=0.0, xmax=1.0, ymin=0.0, ymax=1.0, xlog=False, ylog=False)
 
+*floatmap*
+---------------------------------
+
+.. autofunction:: floatmap(x, min=0.0, max=1.0, exp=1.0)
+
 *distanceToSegment*
 ---------------------------------
 
diff --git a/doc-sphinx/source/compiling.rst b/doc-sphinx/source/compiling.rst
index 78adfb0..b984826 100644
--- a/doc-sphinx/source/compiling.rst
+++ b/doc-sphinx/source/compiling.rst
@@ -9,26 +9,25 @@ Dependencies
 To compile pyo, you will need the following dependencies: 
 
 - `Python 2.6 or 2.7 <http://www.python.org/download/releases/>`_
+- `WxPython 3.0 <http://www.wxpython.org/download.php/>`_
 - `Portaudio <http://www.portaudio.com/>`_
 - `Portmidi <http://portmedia.sourceforge.net/portmidi/>`_
 - `libsndfile <http://www.mega-nerd.com/libsndfile/>`_
 - `liblo <http://liblo.sourceforge.net/>`_
 
+Under Mac OS X, you can use Homebrew to retrieve necessary dependency librairies and headers (except for wxpython 3.0) to compile pyo.
 
-Under Mac OS X, to retrieve necessary dependency librairies and headers to compile pyo, you can run the "get_dependencies.sh" script from the scripts folder in pyo sources, it will download them to /usr/local/lib and /usr/local/include directory. 
-
-For i386 architecture (32-bit python): 
+First, install Homebrew with this command: 
 
 .. code-block:: bash
 
-    sh scripts/get_dependencies.sh
+    ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
 
-For i386/x86_64 architectures (64-bit python): 
+Then, install packages: 
 
 .. code-block:: bash
 
-    sh scripts/get_dependencies_x86_64.sh
-
+    brew install python liblo libsndfile portaudio portmidi --universal
 
 Getting sources
 -------------------
@@ -135,7 +134,7 @@ Under OS X, it is very simple to build pyo from sources with the Homebrew packag
 
 .. code-block:: bash
 
-    brew install python liblo libsndfile portaudio portmidi
+    brew install python liblo libsndfile portaudio portmidi --universal
     svn checkout http://pyo.googlecode.com/svn/trunk/ pyo
     cd pyo
     python setup.py install --use-coreaudio --use-double 
diff --git a/doc-sphinx/source/conf.py b/doc-sphinx/source/conf.py
index 55ad51d..c2779e5 100644
--- a/doc-sphinx/source/conf.py
+++ b/doc-sphinx/source/conf.py
@@ -12,6 +12,7 @@
 # serve to show the default.
 
 import sys, os
+from pyo import PYO_VERSION
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
@@ -42,16 +43,16 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'Pyo'
-copyright = u'2013, Olivier Bélanger'
+copyright = u'2014, Olivier Bélanger'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-version = '0.6.8'
+version = PYO_VERSION
 # The full version, including alpha/beta/rc tags.
-release = '0.6.8'
+release = PYO_VERSION
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/doc-sphinx/source/download.rst b/doc-sphinx/source/download.rst
index fdf63a4..fb5024b 100644
--- a/doc-sphinx/source/download.rst
+++ b/doc-sphinx/source/download.rst
@@ -1,8 +1,8 @@
 Downloading
 =================
 
-Installers are available for Windows (XP, Vista, 7, 8) and for Max OS X (from 10.5 to 10.8).
+Installers are available for Windows (Win 7/8) and for Max OS X (from 10.6 to 10.9).
 
-To download the latest pre-compiled version of pyo, go to the pyo's googlecode `download <http://code.google.com/p/pyo/downloads/list>`_ page.
+To download the latest pre-compiled version of pyo, go to the pyo's `web page <http://ajaxsoundstudio.com/software/pyo/>`_.
 
 Under Debian distros, you can get pyo from the package manager. The library's name is **python-pyo**.
diff --git a/doc-sphinx/source/index.rst b/doc-sphinx/source/index.rst
index abf1888..d2de0de 100644
--- a/doc-sphinx/source/index.rst
+++ b/doc-sphinx/source/index.rst
@@ -3,7 +3,7 @@
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
-Welcome to the Pyo 0.6.8 documentation
+Welcome to the Pyo 0.7.4 documentation
 ===================================================
 
 .. toctree::
diff --git a/doc-sphinx/source/tutorials/pyoobject2.rst b/doc-sphinx/source/tutorials/pyoobject2.rst
index db3db1c..3b31ba5 100644
--- a/doc-sphinx/source/tutorials/pyoobject2.rst
+++ b/doc-sphinx/source/tutorials/pyoobject2.rst
@@ -30,7 +30,7 @@ First of all, we need to import the pyo module
 Step 1 - Declaring the class
 ------------------------------
 
-We will create a new class called RingMod with PyoObject as its parent class. 
+We will create a new class called Flanger with PyoObject as its parent class. 
 Another good habit is to put a __doc__ string at the beginning of our classes. 
 Doing so will allow other users to retrieve the object's documentation with the 
 standard python help() function.
diff --git a/embedded/m_pyo.h b/embedded/m_pyo.h
new file mode 100644
index 0000000..c0a5235
--- /dev/null
+++ b/embedded/m_pyo.h
@@ -0,0 +1,312 @@
+#include <stdlib.h>
+#include "Python.h"
+
+#ifndef __m_pyo_h_
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+** Creates a new python interpreter and starts a pyo server in it.
+** Each instance of pyo, in order to be fully independent of other
+** instances, must be started in its own interpreter. An instance
+** can be an object in a programming language or a plugin in a daw.
+**
+** arguments:
+**  chnls : int, number of in/out channels of the pyo server.
+**
+** returns the new python thread's interpreter state.
+*/
+inline PyThreadState * pyo_new_interpreter(int chnls) {
+    char msg[64];
+    PyThreadState *interp;
+    if(!Py_IsInitialized()) {
+        Py_Initialize();
+        PyEval_InitThreads();
+        PyEval_ReleaseLock();
+    }
+    PyEval_AcquireLock();              /* get the GIL */
+    interp = Py_NewInterpreter();      /* add a new sub-interpreter */
+    PyRun_SimpleString("from pyo import *");
+    sprintf(msg, "_s_ = Server(44100, %d, 256, 1, 'embedded')", chnls);
+    PyRun_SimpleString(msg);
+    PyRun_SimpleString("_s_.boot()\n_s_.start()\n_s_.setServer()");
+    PyRun_SimpleString("_in_address_ = _s_.getInputAddr()");
+    PyRun_SimpleString("_out_address_ = _s_.getOutputAddr()");
+    PyRun_SimpleString("_server_id_ = _s_.getServerID()");
+    PyRun_SimpleString("_emb_callback_ = _s_.getEmbedICallbackAddr()");
+    PyEval_ReleaseThread(interp);
+    return interp;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo input buffer.
+** Used this function if pyo's audio samples resolution is 32-bit.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a float pointer.
+*/
+inline unsigned long pyo_get_input_buffer_address(PyThreadState *interp) {
+    PyObject *module, *obj;
+    char *address;
+    unsigned long uadd;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_in_address_");
+    address = PyString_AsString(obj);
+    uadd = strtoul(address, NULL, 0);
+    PyEval_ReleaseThread(interp);
+    return uadd;
+}
+
+/*
+** Returns the address, as unsigned long long, of the pyo input buffer.
+** Used this function if pyo's audio samples resolution is 64-bit.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long long" that should be recast to a double pointer.
+*/
+inline unsigned long long pyo_get_input_buffer_address_64(PyThreadState *interp) {
+    PyObject *module, *obj;
+    char *address;
+    unsigned long long uadd;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_in_address_");
+    address = PyString_AsString(obj);
+    uadd = strtoull(address, NULL, 0);
+    PyEval_ReleaseThread(interp);
+    return uadd;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo output buffer.
+** Used this function if pyo's audio samples resolution is 32-bit.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a float pointer.
+*/
+inline unsigned long pyo_get_output_buffer_address(PyThreadState *interp) {
+    PyObject *module, *obj;
+    char *address;
+    unsigned long uadd;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_out_address_");
+    address = PyString_AsString(obj);
+    uadd = strtoul(address, NULL, 0);
+    PyEval_ReleaseThread(interp);
+    return uadd;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo embedded callback.
+** This callback must be called in the host's perform routine whenever
+** pyo has to compute a new buffer of samples.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a void pointer.
+**
+** The callback should be called with the server id (int) as argument.
+**
+** Prototype:
+** void (*callback)(int);
+*/
+inline unsigned long pyo_get_embedded_callback_address(PyThreadState *interp) {
+    PyObject *module, *obj;
+    char *address;
+    unsigned long uadd;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_emb_callback_");
+    address = PyString_AsString(obj);
+    uadd = strtoul(address, NULL, 0);
+    PyEval_ReleaseThread(interp);
+    return uadd;
+}
+
+/*
+** Returns the pyo server id of this thread, as an integer.
+** The id must be pass as argument to the callback function.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an integer.
+*/
+inline int pyo_get_server_id(PyThreadState *interp) {
+    PyObject *module, *obj;
+    int id;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_server_id_");
+    id = PyInt_AsLong(obj);
+    PyEval_ReleaseThread(interp);
+    return id;
+}
+
+/*
+** Closes the interpreter linked to the thread state given as argument.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+*/
+inline void pyo_end_interpreter(PyThreadState *interp) {
+    PyEval_AcquireThread(interp);
+    Py_EndInterpreter(interp);
+    PyEval_ReleaseLock();
+}
+
+/*
+** Shutdown and reboot the pyo server while keeping current in/out buffers.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+*/
+inline void pyo_server_reboot(PyThreadState *interp) {
+    PyEval_AcquireThread(interp);
+    PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+    PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+    PyEval_ReleaseThread(interp);
+}
+
+/*
+** Reboot the pyo server with new sampling rate and buffer size.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**  sr : float, host sampling rate.
+**  bufsize : int, host buffer size.
+*/
+inline void pyo_set_server_params(PyThreadState *interp, float sr, int bufsize) {
+    char msg[64];
+    PyEval_AcquireThread(interp);
+    PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+    sprintf(msg, "_s_.setSamplingRate(%f)", sr);
+    PyRun_SimpleString(msg);
+    sprintf(msg, "_s_.setBufferSize(%d)", bufsize);
+    PyRun_SimpleString(msg);
+    PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+    PyEval_ReleaseThread(interp);
+}
+
+/*
+** Returns 1 if the pyo server is started for the given thread,
+** Otherwise returns 0.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+*/
+inline int pyo_is_server_started(PyThreadState *interp) {
+    int started;
+    PyObject *module, *obj;
+    PyEval_AcquireThread(interp);
+    PyRun_SimpleString("started = _s_.getIsStarted()");
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "started");
+    started = PyInt_AsLong(obj);
+    PyEval_ReleaseThread(interp);
+    return started;
+}
+
+/*
+** Execute a python script "file" in the given thread's interpreter (interp).
+** A pre-allocated string "msg" must be given to create the python command
+** used for error handling. An integer "add" is needed to indicate if the
+** pyo server should be reboot or not.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**  file : char *, filename to execute as a python script. The file is first
+**                 searched in the current working directory. If not found,
+**                 the module will try to open it as an absolute path.
+**  msg : char *, pre-allocated string used to create the python command
+**                used for error handling.
+**  add, int, if positive, the commands in the file will be added to whatever
+**            is already running in the pyo server. If 0, the server will be
+**            shutdown and reboot before executing the file.
+*/
+inline int pyo_exec_file(PyThreadState *interp, const char *file, char *msg, int add) {
+    int ok, err = 0;
+    PyObject *module, *obj;
+    PyEval_AcquireThread(interp);
+    sprintf(msg, "import os\n_ok_ = os.path.isfile('./%s')", file);
+    PyRun_SimpleString(msg);
+    sprintf(msg, "if not _ok_:\n    _ok_ = os.path.isfile('%s')", file);
+    PyRun_SimpleString(msg);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_ok_");
+    ok = PyInt_AsLong(obj);
+    if (ok) {
+        sprintf(msg, "try:\n    execfile('./%s')\nexcept:\n    execfile('%s')",
+                file, file);
+        if (!add) {
+            PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+            PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+        }
+        PyRun_SimpleString(msg);
+    }
+    else
+        err = 1;
+    PyEval_ReleaseThread(interp);
+    return err;
+}
+
+/*
+** Execute a python statement "msg" in the thread's interpreter "interp".
+** If "debug" is true, the statement will be executed in a try - except
+** block. The error message, if any, will be write back in the *msg
+** pointer and the function will return 1. If no error occured, the
+** function returned 0. If debug is false, the statement is executed
+** without any error checking (unsafe but faster).
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**  msg : char *, pointer to a string containing the statement to execute.
+**                In debug mode, if an error occured, the output log will
+**                be write back in this string.
+**  debug, int, if positive, the commands will be executed in a try-except
+**              statement. If 0, there will be no error checking, which is
+**              much faster.
+*/
+inline int pyo_exec_statement(PyThreadState *interp, char *msg, int debug) {
+    int err = 0;
+    if (debug) {
+        PyObject *module, *obj;
+        char pp[26] = "_error_=None\ntry:\n    ";
+        memmove(msg + strlen(pp), msg, strlen(msg)+1);
+        memmove(msg, pp, strlen(pp));
+        strcat(msg, "\nexcept Exception, _e_:\n    _error_=str(_e_)");
+        PyEval_AcquireThread(interp);
+        PyRun_SimpleString(msg);
+        module = PyImport_AddModule("__main__");
+        obj = PyObject_GetAttrString(module, "_error_");
+        if (obj != Py_None) {
+            strcpy(msg, PyString_AsString(obj));
+            err = 1;
+        }
+        PyEval_ReleaseThread(interp);
+    }
+    else {
+        PyEval_AcquireThread(interp);
+        PyRun_SimpleString(msg);
+        PyEval_ReleaseThread(interp);
+    }
+    return err;
+}
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#define __m_pyo_h_
+#endif /* __m_pyo_h_  */
diff --git a/embedded/openframeworks/PyoClass.cpp b/embedded/openframeworks/PyoClass.cpp
new file mode 100644
index 0000000..972541c
--- /dev/null
+++ b/embedded/openframeworks/PyoClass.cpp
@@ -0,0 +1,204 @@
+#include "PyoClass.h"
+
+/*
+** Creates a python interpreter and initialize a pyo server inside it.
+** This function must be called, once per Pyo object, before any other
+** calls.
+**
+** arguments:
+**   nChannels : int, number of in/out channels.
+**   bufferSize : int, number of samples per buffer.
+**   sampleRate : int, sample rate frequency.
+**
+** All arguments should be equal to the host audio settings.
+*/
+void Pyo::setup(int _nChannels, int _bufferSize, int _sampleRate) {
+    nChannels = _nChannels;
+    bufferSize = _bufferSize;
+    sampleRate = _sampleRate;
+    interpreter = pyo_new_interpreter(nChannels);
+    pyoInBuffer = reinterpret_cast<float*>(pyo_get_input_buffer_address(interpreter));
+    pyoOutBuffer = reinterpret_cast<float*>(pyo_get_output_buffer_address(interpreter));
+    pyoCallback = reinterpret_cast<callPtr*>(pyo_get_embedded_callback_address(interpreter));
+    pyoId = pyo_get_server_id(interpreter);
+    pyo_set_server_params(interpreter, sampleRate, bufferSize);
+}
+
+/*
+** Terminates this object's interpreter.
+*/
+Pyo::~Pyo() {
+    pyo_end_interpreter(interpreter);
+}
+
+/*
+** This function fills pyo's input buffers with new samples. Should be called
+** once per process block, inside the host's audioIn function.
+**
+** arguments:
+**   *buffer : float *, float pointer pointing to the host's input buffers.
+*/
+void Pyo::fillin(float *buffer) {
+    for (int i=0; i<(bufferSize*nChannels); i++) pyoInBuffer[i] = buffer[i];
+}
+
+
+/*
+** This function tells pyo to process a buffer of samples and fills the host's
+** output buffer with new samples. Should be called once per process block,
+** inside the host's audioOut function.
+**
+** arguments:
+**   *buffer : float *, float pointer pointing to the host's output buffers.
+*/
+void Pyo::process(float *buffer) {
+    pyoCallback(pyoId);
+    for (int i=0; i<(bufferSize*nChannels); i++) buffer[i] = pyoOutBuffer[i];
+}
+
+/*
+** Execute a python script "file" in the objectès thread's interpreter.
+** An integer "add" is needed to indicate if the pyo server should be
+** reboot or not.
+**
+** arguments:
+**   file : char *, filename to execute as a python script. The file is first
+**                  searched in the current working directory. If not found,
+**                  the module will try to open it as an absolute path.
+**   add, int, if positive, the commands in the file will be added to whatever
+**             is already running in the pyo server. If 0, the server will be
+**             shutdown and reboot before executing the file.
+*/
+int Pyo::loadfile(const char *file, int add) {
+    return pyo_exec_file(interpreter, file, pyoMsg, add);
+}
+
+/*
+** Sends a numerical value to an existing Sig or SigTo object.
+**
+** arguments:
+**   name : const char *, variable name of the object.
+**   value : float, value to be assign.
+**
+** Example:
+**
+** inside the script file:
+**
+** freq = SigTo(value=440, time=0.1, init=440)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** pyo.value("freq", 880);
+*/
+int Pyo::value(const char *name, float value) {
+    sprintf(pyoMsg, "%s.value=%f", name, value);
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends an array of numerical values to an existing Sig or SigTo object.
+**
+** arguments:
+**   name : const char *, variable name of the object.
+**   value : float *, array of floats.
+**   len : int, number of elements in the array.
+**
+** Example:
+**
+** inside the script file:
+**
+** freq = SigTo(value=[100,200,300,400], time=0.1, init=[100,200,300,400])
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** float frequencies[4] = {150, 250, 350, 450};
+** pyo.value("freq", frequencies, 4);
+*/
+int Pyo::value(const char *name, float *value, int len) {
+    char fchar[32];
+    sprintf(pyoMsg, "%s.value=[", name);
+    for (int i=0; i<len; i++) {
+        sprintf(fchar, "%f,", value[i]);
+        strcat(pyoMsg, fchar);
+    }
+    strcat(pyoMsg, "]");
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends a numerical value to a Pyo object's attribute.
+**
+** arguments:
+**   name : const char *, object name and attribute separated by a point.
+**   value : float, value to be assign.
+**
+** Example:
+**
+** inside the script file:
+**
+** filter = Biquad(input=Noise(0.5), freq=1000, q=4, type=2)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** pyo.set("filter.freq", 2000);
+*/
+int Pyo::set(const char *name, float value) {
+    sprintf(pyoMsg, "%s=%f", name, value);
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends an array of numerical values to a Pyo object's attribute.
+**
+** arguments:
+**   name : const char *, object name and attribute separated by a point.
+**   value : float *, array of floats.
+**   len : int, number of elements in the array.
+**
+** Example:
+**
+** inside the script file:
+**
+** filters = Biquad(input=Noise(0.5), freq=[250, 500, 1000, 2000], q=5, type=2)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** float frequencies[4] = {350, 700, 1400, 2800};
+** pyo.set("filters.freq", frequencies, 4);
+*/
+int Pyo::set(const char *name, float *value, int len) {
+    char fchar[32];
+    sprintf(pyoMsg, "%s=[", name);
+    for (int i=0; i<len; i++) {
+        sprintf(fchar, "%f,", value[i]);
+        strcat(pyoMsg, fchar);
+    }
+    strcat(pyoMsg, "]");
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Executes any raw valid python statement. With this function, one can dynamically
+** creates and manipulates audio objects and algorithms.
+**
+** arguments:
+**   msg : const char *, pointer to a string containing the statement to execute.
+**
+** Example (for a Pyo object named `pyo`):
+**
+** pyo.exec("pits = [0.001, 0.002, 0.003, 0.004]")
+** pyo.exec("fr = Rossler(pitch=pits, chaos=0.9, mul=250, add=500)")
+** pyo.exec("b = SumOsc(freq=fr, ratio=0.499, index=0.4, mul=0.2).out()")
+*/
+int Pyo::exec(const char *_msg) {
+    strcpy(pyoMsg, _msg);
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Shutdown and reboot the pyo server while keeping current in/out buffers.
+** This will erase audio objects currently active within the server.
+**
+*/void Pyo::clear() {
+    pyo_server_reboot(interpreter);
+}
diff --git a/embedded/openframeworks/PyoClass.h b/embedded/openframeworks/PyoClass.h
new file mode 100644
index 0000000..2ca65b4
--- /dev/null
+++ b/embedded/openframeworks/PyoClass.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "m_pyo.h"
+
+typedef int callPtr(int);
+
+class Pyo {
+    public:
+        ~Pyo();
+        void setup(int nChannels, int bufferSize, int sampleRate);
+        void process(float *buffer);
+        void fillin(float *buffer);
+        void clear();
+        int loadfile(const char *file, int add);
+        int exec(const char *msg);
+        int value(const char *name, float value);
+        int value(const char *name, float *value, int len);
+        int set(const char *name, float value);
+        int set(const char *name, float *value, int len);
+
+    private:
+        int nChannels;
+        int bufferSize;
+        int sampleRate;
+        PyThreadState *interpreter;
+        float *pyoInBuffer;
+        float *pyoOutBuffer;
+        callPtr *pyoCallback;
+        int pyoId;
+        char pyoMsg[262144];
+};
diff --git a/embedded/openframeworks/PyoTemplate/Makefile b/embedded/openframeworks/PyoTemplate/Makefile
new file mode 100644
index 0000000..7a7fe8b
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/Makefile
@@ -0,0 +1,13 @@
+# Attempt to load a config.make file.
+# If none is found, project defaults in config.project.make will be used.
+ifneq ($(wildcard config.make),)
+	include config.make
+endif
+
+# make sure the the OF_ROOT location is defined
+ifndef OF_ROOT
+    OF_ROOT=../../..
+endif
+
+# call the project makefile!
+include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk
diff --git a/embedded/openframeworks/PyoTemplate/config.make b/embedded/openframeworks/PyoTemplate/config.make
new file mode 100644
index 0000000..2a5b520
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/config.make
@@ -0,0 +1,141 @@
+################################################################################
+# CONFIGURE PROJECT MAKEFILE (optional)
+#   This file is where we make project specific configurations.
+################################################################################
+
+################################################################################
+# OF ROOT
+#   The location of your root openFrameworks installation
+#       (default) OF_ROOT = ../../.. 
+################################################################################
+# OF_ROOT = ../../..
+
+################################################################################
+# PROJECT ROOT
+#   The location of the project - a starting place for searching for files
+#       (default) PROJECT_ROOT = . (this directory)
+#    
+################################################################################
+# PROJECT_ROOT = .
+
+################################################################################
+# PROJECT SPECIFIC CHECKS
+#   This is a project defined section to create internal makefile flags to 
+#   conditionally enable or disable the addition of various features within 
+#   this makefile.  For instance, if you want to make changes based on whether
+#   GTK is installed, one might test that here and create a variable to check. 
+################################################################################
+# None
+
+################################################################################
+# PROJECT EXTERNAL SOURCE PATHS
+#   These are fully qualified paths that are not within the PROJECT_ROOT folder.
+#   Like source folders in the PROJECT_ROOT, these paths are subject to 
+#   exlclusion via the PROJECT_EXLCUSIONS list.
+#
+#     (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) 
+#
+#   Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXTERNAL_SOURCE_PATHS = 
+
+################################################################################
+# PROJECT EXCLUSIONS
+#   These makefiles assume that all folders in your current project directory 
+#   and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
+#   to look for source code. The any folders or files that match any of the 
+#   items in the PROJECT_EXCLUSIONS list below will be ignored.
+#
+#   Each item in the PROJECT_EXCLUSIONS list will be treated as a complete 
+#   string unless teh user adds a wildcard (%) operator to match subdirectories.
+#   GNU make only allows one wildcard for matching.  The second wildcard (%) is
+#   treated literally.
+#
+#      (default) PROJECT_EXCLUSIONS = (blank)
+#
+#		Will automatically exclude the following:
+#
+#			$(PROJECT_ROOT)/bin%
+#			$(PROJECT_ROOT)/obj%
+#			$(PROJECT_ROOT)/%.xcodeproj
+#
+#   Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXCLUSIONS =
+
+################################################################################
+# PROJECT LINKER FLAGS
+#	These flags will be sent to the linker when compiling the executable.
+#
+#		(default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
+#
+#   Note: Leave a leading space when adding list items with the += operator
+#
+# Currently, shared libraries that are needed are copied to the 
+# $(PROJECT_ROOT)/bin/libs directory.  The following LDFLAGS tell the linker to
+# add a runtime path to search for those shared libraries, since they aren't 
+# incorporated directly into the final executable application binary.
+################################################################################
+PROJECT_LDFLAGS = `python-config --ldflags`
+
+################################################################################
+# PROJECT DEFINES
+#   Create a space-delimited list of DEFINES. The list will be converted into 
+#   CFLAGS with the "-D" flag later in the makefile.
+#
+#		(default) PROJECT_DEFINES = (blank)
+#
+#   Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_DEFINES = 
+
+################################################################################
+# PROJECT CFLAGS
+#   This is a list of fully qualified CFLAGS required when compiling for this 
+#   project.  These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS 
+#   defined in your platform specific core configuration files. These flags are
+#   presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. 
+#
+#		(default) PROJECT_CFLAGS = (blank)
+#
+#   Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in 
+#   your platform specific configuration file will be applied by default and 
+#   further flags here may not be needed.
+#
+#   Note: Leave a leading space when adding list items with the += operator
+################################################################################
+PROJECT_CFLAGS = `python-config --cflags`
+
+################################################################################
+# PROJECT OPTIMIZATION CFLAGS
+#   These are lists of CFLAGS that are target-specific.  While any flags could 
+#   be conditionally added, they are usually limited to optimization flags. 
+#   These flags are added BEFORE the PROJECT_CFLAGS.
+#
+#   PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
+#
+#		(default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
+#
+#   PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
+#
+#		(default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
+#
+#   Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the 
+#   PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration 
+#   file will be applied by default and further optimization flags here may not 
+#   be needed.
+#
+#   Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE = 
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG = 
+
+################################################################################
+# PROJECT COMPILERS
+#   Custom compilers can be set for CC and CXX
+#		(default) PROJECT_CXX = (blank)
+#		(default) PROJECT_CC = (blank)
+#   Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CXX = 
+# PROJECT_CC = 
diff --git a/embedded/openframeworks/PyoTemplate/scripts/stereoDelay.py b/embedded/openframeworks/PyoTemplate/scripts/stereoDelay.py
new file mode 100644
index 0000000..0d98f4e
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/scripts/stereoDelay.py
@@ -0,0 +1,5 @@
+# Get the input sound and apply a stereo delay + reverb on it.
+st_input = Input([0,1])
+st_delay = Delay(st_input, delay=[.4, .5], feedback=0.7)
+st_rev = WGVerb(st_delay, feedback=0.8, cutoff=4000, bal=0.25).out()
+
diff --git a/embedded/openframeworks/PyoTemplate/src/PyoClass.cpp b/embedded/openframeworks/PyoTemplate/src/PyoClass.cpp
new file mode 100644
index 0000000..972541c
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/PyoClass.cpp
@@ -0,0 +1,204 @@
+#include "PyoClass.h"
+
+/*
+** Creates a python interpreter and initialize a pyo server inside it.
+** This function must be called, once per Pyo object, before any other
+** calls.
+**
+** arguments:
+**   nChannels : int, number of in/out channels.
+**   bufferSize : int, number of samples per buffer.
+**   sampleRate : int, sample rate frequency.
+**
+** All arguments should be equal to the host audio settings.
+*/
+void Pyo::setup(int _nChannels, int _bufferSize, int _sampleRate) {
+    nChannels = _nChannels;
+    bufferSize = _bufferSize;
+    sampleRate = _sampleRate;
+    interpreter = pyo_new_interpreter(nChannels);
+    pyoInBuffer = reinterpret_cast<float*>(pyo_get_input_buffer_address(interpreter));
+    pyoOutBuffer = reinterpret_cast<float*>(pyo_get_output_buffer_address(interpreter));
+    pyoCallback = reinterpret_cast<callPtr*>(pyo_get_embedded_callback_address(interpreter));
+    pyoId = pyo_get_server_id(interpreter);
+    pyo_set_server_params(interpreter, sampleRate, bufferSize);
+}
+
+/*
+** Terminates this object's interpreter.
+*/
+Pyo::~Pyo() {
+    pyo_end_interpreter(interpreter);
+}
+
+/*
+** This function fills pyo's input buffers with new samples. Should be called
+** once per process block, inside the host's audioIn function.
+**
+** arguments:
+**   *buffer : float *, float pointer pointing to the host's input buffers.
+*/
+void Pyo::fillin(float *buffer) {
+    for (int i=0; i<(bufferSize*nChannels); i++) pyoInBuffer[i] = buffer[i];
+}
+
+
+/*
+** This function tells pyo to process a buffer of samples and fills the host's
+** output buffer with new samples. Should be called once per process block,
+** inside the host's audioOut function.
+**
+** arguments:
+**   *buffer : float *, float pointer pointing to the host's output buffers.
+*/
+void Pyo::process(float *buffer) {
+    pyoCallback(pyoId);
+    for (int i=0; i<(bufferSize*nChannels); i++) buffer[i] = pyoOutBuffer[i];
+}
+
+/*
+** Execute a python script "file" in the objectès thread's interpreter.
+** An integer "add" is needed to indicate if the pyo server should be
+** reboot or not.
+**
+** arguments:
+**   file : char *, filename to execute as a python script. The file is first
+**                  searched in the current working directory. If not found,
+**                  the module will try to open it as an absolute path.
+**   add, int, if positive, the commands in the file will be added to whatever
+**             is already running in the pyo server. If 0, the server will be
+**             shutdown and reboot before executing the file.
+*/
+int Pyo::loadfile(const char *file, int add) {
+    return pyo_exec_file(interpreter, file, pyoMsg, add);
+}
+
+/*
+** Sends a numerical value to an existing Sig or SigTo object.
+**
+** arguments:
+**   name : const char *, variable name of the object.
+**   value : float, value to be assign.
+**
+** Example:
+**
+** inside the script file:
+**
+** freq = SigTo(value=440, time=0.1, init=440)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** pyo.value("freq", 880);
+*/
+int Pyo::value(const char *name, float value) {
+    sprintf(pyoMsg, "%s.value=%f", name, value);
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends an array of numerical values to an existing Sig or SigTo object.
+**
+** arguments:
+**   name : const char *, variable name of the object.
+**   value : float *, array of floats.
+**   len : int, number of elements in the array.
+**
+** Example:
+**
+** inside the script file:
+**
+** freq = SigTo(value=[100,200,300,400], time=0.1, init=[100,200,300,400])
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** float frequencies[4] = {150, 250, 350, 450};
+** pyo.value("freq", frequencies, 4);
+*/
+int Pyo::value(const char *name, float *value, int len) {
+    char fchar[32];
+    sprintf(pyoMsg, "%s.value=[", name);
+    for (int i=0; i<len; i++) {
+        sprintf(fchar, "%f,", value[i]);
+        strcat(pyoMsg, fchar);
+    }
+    strcat(pyoMsg, "]");
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends a numerical value to a Pyo object's attribute.
+**
+** arguments:
+**   name : const char *, object name and attribute separated by a point.
+**   value : float, value to be assign.
+**
+** Example:
+**
+** inside the script file:
+**
+** filter = Biquad(input=Noise(0.5), freq=1000, q=4, type=2)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** pyo.set("filter.freq", 2000);
+*/
+int Pyo::set(const char *name, float value) {
+    sprintf(pyoMsg, "%s=%f", name, value);
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Sends an array of numerical values to a Pyo object's attribute.
+**
+** arguments:
+**   name : const char *, object name and attribute separated by a point.
+**   value : float *, array of floats.
+**   len : int, number of elements in the array.
+**
+** Example:
+**
+** inside the script file:
+**
+** filters = Biquad(input=Noise(0.5), freq=[250, 500, 1000, 2000], q=5, type=2)
+**
+** Inside OpenFrameworks (for a Pyo object named `pyo`):
+**
+** float frequencies[4] = {350, 700, 1400, 2800};
+** pyo.set("filters.freq", frequencies, 4);
+*/
+int Pyo::set(const char *name, float *value, int len) {
+    char fchar[32];
+    sprintf(pyoMsg, "%s=[", name);
+    for (int i=0; i<len; i++) {
+        sprintf(fchar, "%f,", value[i]);
+        strcat(pyoMsg, fchar);
+    }
+    strcat(pyoMsg, "]");
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Executes any raw valid python statement. With this function, one can dynamically
+** creates and manipulates audio objects and algorithms.
+**
+** arguments:
+**   msg : const char *, pointer to a string containing the statement to execute.
+**
+** Example (for a Pyo object named `pyo`):
+**
+** pyo.exec("pits = [0.001, 0.002, 0.003, 0.004]")
+** pyo.exec("fr = Rossler(pitch=pits, chaos=0.9, mul=250, add=500)")
+** pyo.exec("b = SumOsc(freq=fr, ratio=0.499, index=0.4, mul=0.2).out()")
+*/
+int Pyo::exec(const char *_msg) {
+    strcpy(pyoMsg, _msg);
+    return pyo_exec_statement(interpreter, pyoMsg, 0);
+}
+
+/*
+** Shutdown and reboot the pyo server while keeping current in/out buffers.
+** This will erase audio objects currently active within the server.
+**
+*/void Pyo::clear() {
+    pyo_server_reboot(interpreter);
+}
diff --git a/embedded/openframeworks/PyoTemplate/src/PyoClass.h b/embedded/openframeworks/PyoTemplate/src/PyoClass.h
new file mode 100644
index 0000000..2ca65b4
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/PyoClass.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "m_pyo.h"
+
+typedef int callPtr(int);
+
+class Pyo {
+    public:
+        ~Pyo();
+        void setup(int nChannels, int bufferSize, int sampleRate);
+        void process(float *buffer);
+        void fillin(float *buffer);
+        void clear();
+        int loadfile(const char *file, int add);
+        int exec(const char *msg);
+        int value(const char *name, float value);
+        int value(const char *name, float *value, int len);
+        int set(const char *name, float value);
+        int set(const char *name, float *value, int len);
+
+    private:
+        int nChannels;
+        int bufferSize;
+        int sampleRate;
+        PyThreadState *interpreter;
+        float *pyoInBuffer;
+        float *pyoOutBuffer;
+        callPtr *pyoCallback;
+        int pyoId;
+        char pyoMsg[262144];
+};
diff --git a/embedded/openframeworks/PyoTemplate/src/m_pyo.h b/embedded/openframeworks/PyoTemplate/src/m_pyo.h
new file mode 100644
index 0000000..c0a5235
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/m_pyo.h
@@ -0,0 +1,312 @@
+#include <stdlib.h>
+#include "Python.h"
+
+#ifndef __m_pyo_h_
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+** Creates a new python interpreter and starts a pyo server in it.
+** Each instance of pyo, in order to be fully independent of other
+** instances, must be started in its own interpreter. An instance
+** can be an object in a programming language or a plugin in a daw.
+**
+** arguments:
+**  chnls : int, number of in/out channels of the pyo server.
+**
+** returns the new python thread's interpreter state.
+*/
+inline PyThreadState * pyo_new_interpreter(int chnls) {
+    char msg[64];
+    PyThreadState *interp;
+    if(!Py_IsInitialized()) {
+        Py_Initialize();
+        PyEval_InitThreads();
+        PyEval_ReleaseLock();
+    }
+    PyEval_AcquireLock();              /* get the GIL */
+    interp = Py_NewInterpreter();      /* add a new sub-interpreter */
+    PyRun_SimpleString("from pyo import *");
+    sprintf(msg, "_s_ = Server(44100, %d, 256, 1, 'embedded')", chnls);
+    PyRun_SimpleString(msg);
+    PyRun_SimpleString("_s_.boot()\n_s_.start()\n_s_.setServer()");
+    PyRun_SimpleString("_in_address_ = _s_.getInputAddr()");
+    PyRun_SimpleString("_out_address_ = _s_.getOutputAddr()");
+    PyRun_SimpleString("_server_id_ = _s_.getServerID()");
+    PyRun_SimpleString("_emb_callback_ = _s_.getEmbedICallbackAddr()");
+    PyEval_ReleaseThread(interp);
+    return interp;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo input buffer.
+** Used this function if pyo's audio samples resolution is 32-bit.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a float pointer.
+*/
+inline unsigned long pyo_get_input_buffer_address(PyThreadState *interp) {
+    PyObject *module, *obj;
+    char *address;
+    unsigned long uadd;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_in_address_");
+    address = PyString_AsString(obj);
+    uadd = strtoul(address, NULL, 0);
+    PyEval_ReleaseThread(interp);
+    return uadd;
+}
+
+/*
+** Returns the address, as unsigned long long, of the pyo input buffer.
+** Used this function if pyo's audio samples resolution is 64-bit.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long long" that should be recast to a double pointer.
+*/
+inline unsigned long long pyo_get_input_buffer_address_64(PyThreadState *interp) {
+    PyObject *module, *obj;
+    char *address;
+    unsigned long long uadd;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_in_address_");
+    address = PyString_AsString(obj);
+    uadd = strtoull(address, NULL, 0);
+    PyEval_ReleaseThread(interp);
+    return uadd;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo output buffer.
+** Used this function if pyo's audio samples resolution is 32-bit.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a float pointer.
+*/
+inline unsigned long pyo_get_output_buffer_address(PyThreadState *interp) {
+    PyObject *module, *obj;
+    char *address;
+    unsigned long uadd;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_out_address_");
+    address = PyString_AsString(obj);
+    uadd = strtoul(address, NULL, 0);
+    PyEval_ReleaseThread(interp);
+    return uadd;
+}
+
+/*
+** Returns the address, as unsigned long, of the pyo embedded callback.
+** This callback must be called in the host's perform routine whenever
+** pyo has to compute a new buffer of samples.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an "unsigned long" that should be recast to a void pointer.
+**
+** The callback should be called with the server id (int) as argument.
+**
+** Prototype:
+** void (*callback)(int);
+*/
+inline unsigned long pyo_get_embedded_callback_address(PyThreadState *interp) {
+    PyObject *module, *obj;
+    char *address;
+    unsigned long uadd;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_emb_callback_");
+    address = PyString_AsString(obj);
+    uadd = strtoul(address, NULL, 0);
+    PyEval_ReleaseThread(interp);
+    return uadd;
+}
+
+/*
+** Returns the pyo server id of this thread, as an integer.
+** The id must be pass as argument to the callback function.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**
+** returns an integer.
+*/
+inline int pyo_get_server_id(PyThreadState *interp) {
+    PyObject *module, *obj;
+    int id;
+    PyEval_AcquireThread(interp);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_server_id_");
+    id = PyInt_AsLong(obj);
+    PyEval_ReleaseThread(interp);
+    return id;
+}
+
+/*
+** Closes the interpreter linked to the thread state given as argument.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+*/
+inline void pyo_end_interpreter(PyThreadState *interp) {
+    PyEval_AcquireThread(interp);
+    Py_EndInterpreter(interp);
+    PyEval_ReleaseLock();
+}
+
+/*
+** Shutdown and reboot the pyo server while keeping current in/out buffers.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+*/
+inline void pyo_server_reboot(PyThreadState *interp) {
+    PyEval_AcquireThread(interp);
+    PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+    PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+    PyEval_ReleaseThread(interp);
+}
+
+/*
+** Reboot the pyo server with new sampling rate and buffer size.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**  sr : float, host sampling rate.
+**  bufsize : int, host buffer size.
+*/
+inline void pyo_set_server_params(PyThreadState *interp, float sr, int bufsize) {
+    char msg[64];
+    PyEval_AcquireThread(interp);
+    PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+    sprintf(msg, "_s_.setSamplingRate(%f)", sr);
+    PyRun_SimpleString(msg);
+    sprintf(msg, "_s_.setBufferSize(%d)", bufsize);
+    PyRun_SimpleString(msg);
+    PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+    PyEval_ReleaseThread(interp);
+}
+
+/*
+** Returns 1 if the pyo server is started for the given thread,
+** Otherwise returns 0.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+*/
+inline int pyo_is_server_started(PyThreadState *interp) {
+    int started;
+    PyObject *module, *obj;
+    PyEval_AcquireThread(interp);
+    PyRun_SimpleString("started = _s_.getIsStarted()");
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "started");
+    started = PyInt_AsLong(obj);
+    PyEval_ReleaseThread(interp);
+    return started;
+}
+
+/*
+** Execute a python script "file" in the given thread's interpreter (interp).
+** A pre-allocated string "msg" must be given to create the python command
+** used for error handling. An integer "add" is needed to indicate if the
+** pyo server should be reboot or not.
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**  file : char *, filename to execute as a python script. The file is first
+**                 searched in the current working directory. If not found,
+**                 the module will try to open it as an absolute path.
+**  msg : char *, pre-allocated string used to create the python command
+**                used for error handling.
+**  add, int, if positive, the commands in the file will be added to whatever
+**            is already running in the pyo server. If 0, the server will be
+**            shutdown and reboot before executing the file.
+*/
+inline int pyo_exec_file(PyThreadState *interp, const char *file, char *msg, int add) {
+    int ok, err = 0;
+    PyObject *module, *obj;
+    PyEval_AcquireThread(interp);
+    sprintf(msg, "import os\n_ok_ = os.path.isfile('./%s')", file);
+    PyRun_SimpleString(msg);
+    sprintf(msg, "if not _ok_:\n    _ok_ = os.path.isfile('%s')", file);
+    PyRun_SimpleString(msg);
+    module = PyImport_AddModule("__main__");
+    obj = PyObject_GetAttrString(module, "_ok_");
+    ok = PyInt_AsLong(obj);
+    if (ok) {
+        sprintf(msg, "try:\n    execfile('./%s')\nexcept:\n    execfile('%s')",
+                file, file);
+        if (!add) {
+            PyRun_SimpleString("_s_.setServer()\n_s_.stop()\n_s_.shutdown()");
+            PyRun_SimpleString("_s_.boot(newBuffer=False).start()");
+        }
+        PyRun_SimpleString(msg);
+    }
+    else
+        err = 1;
+    PyEval_ReleaseThread(interp);
+    return err;
+}
+
+/*
+** Execute a python statement "msg" in the thread's interpreter "interp".
+** If "debug" is true, the statement will be executed in a try - except
+** block. The error message, if any, will be write back in the *msg
+** pointer and the function will return 1. If no error occured, the
+** function returned 0. If debug is false, the statement is executed
+** without any error checking (unsafe but faster).
+**
+** arguments:
+**  interp : pointer, pointer to the targeted Python thread state.
+**  msg : char *, pointer to a string containing the statement to execute.
+**                In debug mode, if an error occured, the output log will
+**                be write back in this string.
+**  debug, int, if positive, the commands will be executed in a try-except
+**              statement. If 0, there will be no error checking, which is
+**              much faster.
+*/
+inline int pyo_exec_statement(PyThreadState *interp, char *msg, int debug) {
+    int err = 0;
+    if (debug) {
+        PyObject *module, *obj;
+        char pp[26] = "_error_=None\ntry:\n    ";
+        memmove(msg + strlen(pp), msg, strlen(msg)+1);
+        memmove(msg, pp, strlen(pp));
+        strcat(msg, "\nexcept Exception, _e_:\n    _error_=str(_e_)");
+        PyEval_AcquireThread(interp);
+        PyRun_SimpleString(msg);
+        module = PyImport_AddModule("__main__");
+        obj = PyObject_GetAttrString(module, "_error_");
+        if (obj != Py_None) {
+            strcpy(msg, PyString_AsString(obj));
+            err = 1;
+        }
+        PyEval_ReleaseThread(interp);
+    }
+    else {
+        PyEval_AcquireThread(interp);
+        PyRun_SimpleString(msg);
+        PyEval_ReleaseThread(interp);
+    }
+    return err;
+}
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#define __m_pyo_h_
+#endif /* __m_pyo_h_  */
diff --git a/embedded/openframeworks/PyoTemplate/src/main.cpp b/embedded/openframeworks/PyoTemplate/src/main.cpp
new file mode 100644
index 0000000..a7d241d
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/main.cpp
@@ -0,0 +1,13 @@
+#include "ofMain.h"
+#include "testApp.h"
+
+//========================================================================
+int main( ){
+	ofSetupOpenGL(1024,768,OF_WINDOW);			// <-------- setup the GL context
+
+	// this kicks off the running of my app
+	// can be OF_WINDOW or OF_FULLSCREEN
+	// pass in width and height too:
+	ofRunApp(new testApp());
+
+}
diff --git a/embedded/openframeworks/PyoTemplate/src/testApp.cpp b/embedded/openframeworks/PyoTemplate/src/testApp.cpp
new file mode 100644
index 0000000..882cec7
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/testApp.cpp
@@ -0,0 +1,80 @@
+#include "testApp.h"
+
+//--------------------------------------------------------------
+void testApp::setup(){
+    // define audio properties
+    int sampleRate = 44100;
+    int bufferSize = 256;
+    int nChannels = 2;
+    // initialize a pyo server
+    pyo.setup(nChannels, bufferSize, sampleRate);
+    // load a python file
+    pyo.loadfile("../scripts/stereoDelay.py", 0);
+    // initialize OpenFrameworks audio streaming channels
+	soundStream.setup(this, nChannels, nChannels, sampleRate, bufferSize, 4);
+}
+
+void testApp::audioIn(float * input, int bufferSize, int nChannels){
+    // send audio samples to pyo
+    pyo.fillin(input);
+}
+
+void testApp::audioOut(float * output, int bufferSize, int nChannels){
+    // process and get new audio samples from pyo
+    pyo.process(output);
+}
+
+//--------------------------------------------------------------
+void testApp::update(){
+
+}
+
+//--------------------------------------------------------------
+void testApp::draw(){
+
+}
+
+//--------------------------------------------------------------
+void testApp::keyPressed(int key){
+
+}
+
+//--------------------------------------------------------------
+void testApp::keyReleased(int key){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseMoved(int x, int y ){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseDragged(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mousePressed(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::mouseReleased(int x, int y, int button){
+
+}
+
+//--------------------------------------------------------------
+void testApp::windowResized(int w, int h){
+
+}
+
+//--------------------------------------------------------------
+void testApp::gotMessage(ofMessage msg){
+
+}
+
+//--------------------------------------------------------------
+void testApp::dragEvent(ofDragInfo dragInfo){
+
+}
diff --git a/embedded/openframeworks/PyoTemplate/src/testApp.h b/embedded/openframeworks/PyoTemplate/src/testApp.h
new file mode 100644
index 0000000..4a98213
--- /dev/null
+++ b/embedded/openframeworks/PyoTemplate/src/testApp.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "ofMain.h"
+#include "PyoClass.h"
+
+class testApp : public ofBaseApp{
+	public:
+		void setup();
+		void update();
+		void draw();
+
+		void keyPressed(int key);
+		void keyReleased(int key);
+		void mouseMoved(int x, int y );
+		void mouseDragged(int x, int y, int button);
+		void mousePressed(int x, int y, int button);
+		void mouseReleased(int x, int y, int button);
+		void windowResized(int w, int h);
+		void dragEvent(ofDragInfo dragInfo);
+		void gotMessage(ofMessage msg);
+
+		void audioIn(float * input, int bufferSize, int nChannels);
+		void audioOut(float * input, int bufferSize, int nChannels);
+		ofSoundStream soundStream;
+        Pyo pyo;
+};
diff --git a/embedded/openframeworks/README b/embedded/openframeworks/README
new file mode 100644
index 0000000..7879578
--- /dev/null
+++ b/embedded/openframeworks/README
@@ -0,0 +1,101 @@
+Introduction on how to use pyo inside an OpenFrameworks project.
+================================================================ 
+
+To use pyo inside an OpenFrameworks project, first you need a 
+working install of pyo on your system. After installing pyo,
+you can go and create an OpenFrameworks project.
+
+------------------------------------------------------------------------
+Step 1 - Create a default project with project generator.
+
+------------------------------------------------------------------------
+Step 2 - Add pyo files to your project. You only need to copy 
+these files in your project's src folder:
+
+- from this folder:
+PyoClass.cpp
+PyoClass.h
+
+- from the folder "embedded":
+m_pyo.h
+
+------------------------------------------------------------------------
+Step 3 - Make sure that your project includes flags for compiling 
+and linking against Python. On Unix systems, you can set the Python 
+flags in the file config.make. Uncomment and complete these lines:
+
+PROJECT_LDFLAGS = `python-config --ldflags` # linker flags for Python
+PROJECT_CFLAGS = `python-config --cflags` # compiler flags for Python
+
+------------------------------------------------------------------------
+Step 4 - Make a scripts folder at the root level of your project and 
+create a python file, named "stereoDelay.py", with these lines in it:
+
+# Get the input sound and apply a stereo delay + reverb on it.
+st_input = Input([0,1])
+st_delay = Delay(st_input, delay=[.4, .5], feedback=0.7)
+st_rev = WGVerb(st_delay, feedback=0.8, cutoff=4000, bal=0.25).out()
+
+------------------------------------------------------------------------
+Step 5 - Edit src/testApp.h.
+
+- Include PyoClass definition:
+
+#include "PyoClass.h"
+
+- Add audio in/out callbacks to the public attributes of the testApp class:
+
+void audioIn(float * input, int bufferSize, int nChannels);
+void audioOut(float * input, int bufferSize, int nChannels);
+
+- Add an ofSoundStream object to the public attributes of the testApp class:
+
+ofSoundStream soundStream;
+
+- Add a Pyo object to the public attributes of the testApp class:
+
+Pyo pyo;
+
+------------------------------------------------------------------------
+Step 6 - Edit src/testApp.cpp.
+
+- Creates the setup() function:
+
+void testApp::setup(){
+    // define audio properties
+    int sampleRate = 44100;
+    int bufferSize = 256;
+    int nChannels = 2;
+    // initialize a pyo server
+    pyo.setup(nChannels, bufferSize, sampleRate);
+    // load a python file
+    pyo.loadfile("../scripts/stereoDelay.py", 0);
+    // initialize OpenFrameworks audio streaming channels 
+	soundStream.setup(this, nChannels, nChannels, sampleRate, bufferSize, 4);
+}
+
+- Creates audio in/out functions:
+
+void testApp::audioIn(float * input, int bufferSize, int nChannels){
+    // send audio samples to pyo
+    pyo.fillin(input);
+}
+
+void testApp::audioOut(float * output, int bufferSize, int nChannels){
+    // process and get new audio samples from pyo
+    pyo.process(output);
+}
+
+------------------------------------------------------------------------
+Here you go! Compile, Run and Enjoy!
+
+Documentation
+=============
+
+For a complete description of functions that can be used to communicate 
+with the pyo embedded processes, see documentation comments in the file 
+PyoClass.cpp.
+
+belangeo
+
+
diff --git a/embedded/puredata/Makefile b/embedded/puredata/Makefile
new file mode 100644
index 0000000..6637883
--- /dev/null
+++ b/embedded/puredata/Makefile
@@ -0,0 +1,467 @@
+## Pd library template version 1.0.13
+# For instructions on how to use this template, see:
+#  http://puredata.info/docs/developer/MakefileTemplate
+LIBRARY_NAME = pyo~
+
+# add your .c source files, one object per file, to the SOURCES
+# variable, help files will be included automatically, and for GUI
+# objects, the matching .tcl file too
+SOURCES = pyo~.c
+
+# list all pd objects (i.e. myobject.pd) files here, and their helpfiles will
+# be included automatically
+PDOBJECTS = pyo~.pd
+
+# example patches and related files, in the 'examples' subfolder
+EXAMPLES = 
+
+# manuals and related files, in the 'manual' subfolder
+MANUAL = manual.txt
+
+# if you want to include any other files in the source and binary tarballs,
+# list them here.  This can be anything from header files, test patches,
+# documentation, etc.  README.txt and LICENSE.txt are required and therefore
+# automatically included
+EXTRA_DIST = m_pyo.h
+
+# unit tests and related files here, in the 'unittests' subfolder
+UNITTESTS = 
+
+# added to support the multiple shared source files
+SHARED_SOURCE = 
+SHARED_LIB = lib$(LIBRARY_NAME).$(SHARED_EXTENSION)
+
+
+#------------------------------------------------------------------------------#
+#
+# things you might need to edit if you are using other C libraries
+#
+#------------------------------------------------------------------------------#
+UNAME := $(shell uname -s)
+ifeq (MINGW,$(findstring MINGW,$(UNAME)))
+    ALL_CFLAGS = -I"$(PD_INCLUDE)" -I.. -Wno-unused-parameter -I/c/Python27/include
+    ALL_LDFLAGS =  -lpython27
+    SHARED_LDFLAGS =
+    ALL_LIBS = -L/c/Python27/libs
+endif
+ifeq ($(UNAME),Darwin)
+    MAC_SDK =                # put the path to your base SDK if you have problem to compile with the one given by python (ex: /Developer/SDKs/MacOSX10.6.sdk)
+    ARCH_TYPE = i386         # can put multiple architectures if they are available with your environment (ex: ppc i386)
+    ifeq ($(MAC_SDK),)
+        PYTHONFLAGS = $(shell python-config --cflags)
+    else
+        PYTHONFLAGS = $(patsubst /%, $(MAC_SDK), $(shell python-config --cflags))
+    endif
+    ALL_CFLAGS = -I"$(PD_INCLUDE)" -I.. -Wno-unused-parameter $(PYTHONFLAGS)
+    ALL_LDFLAGS = $(shell python-config --ldflags)
+    SHARED_LDFLAGS =
+    # ALL_LIBS = $(shell python-config --libs)
+    ALL_LIBS = -ldl -framework CoreFoundation -framework Python
+endif
+ifeq ($(UNAME),Linux)
+    ALL_CFLAGS = -I"$(PD_INCLUDE)" -I.. -Wno-unused-parameter $(shell python-config --cflags)
+    ALL_LDFLAGS =  $(shell python-config --ldflags)
+    SHARED_LDFLAGS =
+    ALL_LIBS = $(shell python-config --libs)
+endif
+
+#------------------------------------------------------------------------------#
+#
+# you shouldn't need to edit anything below here, if we did it right :)
+#
+#------------------------------------------------------------------------------#
+
+# these can be set from outside without (usually) breaking the build
+CFLAGS = -Wall -W -g
+LDFLAGS =
+LIBS =
+
+# get library version from meta file
+LIBRARY_VERSION = $(shell sed -n 's|^\#X text [0-9][0-9]* [0-9][0-9]* VERSION \(.*\);|\1|p' $(LIBRARY_NAME)-meta.pd)
+
+ALL_CFLAGS += -DPD -DVERSION='"$(LIBRARY_VERSION)"'
+
+PD_INCLUDE = $(PD_PATH)/include/pd
+# where to install the library, overridden below depending on platform
+prefix = /usr/local
+libdir = $(prefix)/lib
+pkglibdir = $(libdir)/pd-externals
+objectsdir = $(pkglibdir)
+
+INSTALL = install
+INSTALL_PROGRAM = $(INSTALL) -p -m 644
+INSTALL_DATA = $(INSTALL) -p -m 644
+INSTALL_DIR     = $(INSTALL) -p -m 755 -d
+
+ALLSOURCES := $(SOURCES) $(SOURCES_android) $(SOURCES_cygwin) $(SOURCES_macosx) \
+	         $(SOURCES_iphoneos) $(SOURCES_linux) $(SOURCES_windows)
+
+DISTDIR=$(LIBRARY_NAME)-$(LIBRARY_VERSION)
+ORIGDIR=pd-$(LIBRARY_NAME:~=)_$(LIBRARY_VERSION)
+
+UNAME := $(shell uname -s)
+ifeq ($(UNAME),Darwin)
+  CPU := $(shell uname -p)
+  ifeq ($(CPU),arm) # iPhone/iPod Touch
+    SOURCES += $(SOURCES_iphoneos)
+    EXTENSION = pd_darwin
+    SHARED_EXTENSION = dylib
+    OS = iphoneos
+    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+    IPHONE_BASE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
+    CC=$(IPHONE_BASE)/gcc
+    CPP=$(IPHONE_BASE)/cpp
+    CXX=$(IPHONE_BASE)/g++
+    ISYSROOT = -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk
+    IPHONE_CFLAGS = -miphoneos-version-min=3.0 $(ISYSROOT) -arch armv6
+    OPT_CFLAGS = -fast -funroll-loops -fomit-frame-pointer
+    ALL_CFLAGS := $(IPHONE_CFLAGS) $(ALL_CFLAGS)
+    ALL_LDFLAGS += -arch armv6 -bundle -undefined dynamic_lookup $(ISYSROOT)
+    SHARED_LDFLAGS += -arch armv6 -dynamiclib -undefined dynamic_lookup $(ISYSROOT)
+    ALL_LIBS += -lc $(LIBS_iphoneos)
+    STRIP = strip -x
+    DISTBINDIR=$(DISTDIR)-$(OS)
+  else # Mac OS X
+    SOURCES += $(SOURCES_macosx)
+    EXTENSION = pd_darwin
+    SHARED_EXTENSION = dylib
+    OS = macosx
+    PD_PATH = /Applications/Pd-extended.app/Contents/Resources
+    OPT_CFLAGS = -ftree-vectorize -ftree-vectorizer-verbose=2 -fast
+# build universal 32-bit on 10.4 and 32/64 on newer
+    ifeq ($(shell uname -r | sed 's|\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*|\1|'), 8)
+      # FAT_FLAGS = -arch ppc -arch i386 -mmacosx-version-min=10.5
+      ARCHWITHOUT64 := $(filter-out x86_64,$(ARCH_TYPE))
+      FAT_FLAGS = $(patsubst %,-arch %, $(ARCHWITHOUT64)) -mmacosx-version-min=10.5
+    else
+      # FAT_FLAGS = -arch ppc -arch i386 -arch x86_64 -mmacosx-version-min=10.5
+      FAT_FLAGS = $(patsubst %,-arch %, $(ARCH_TYPE)) -mmacosx-version-min=10.5
+      SOURCES += $(SOURCES_iphoneos)
+    endif
+    ALL_CFLAGS += $(FAT_FLAGS) -fPIC -I/sw/include
+    # if the 'pd' binary exists, check the linking against it to aid with stripping
+    BUNDLE_LOADER = $(shell test ! -e $(PD_PATH)/bin/pd || echo -bundle_loader $(PD_PATH)/bin/pd)
+    ALL_LDFLAGS += $(FAT_FLAGS) -headerpad_max_install_names -bundle $(BUNDLE_LOADER) \
+	-undefined dynamic_lookup -L/sw/lib
+    SHARED_LDFLAGS += $(FAT_FLAGS) -dynamiclib -undefined dynamic_lookup \
+	-install_name @loader_path/$(SHARED_LIB) -compatibility_version 1 -current_version 1.0
+    ALL_LIBS += -lc $(LIBS_macosx)
+    STRIP = strip -x
+    DISTBINDIR=$(DISTDIR)-$(OS)
+# install into ~/Library/Pd on Mac OS X since /usr/local isn't used much
+    pkglibdir=$(HOME)/Library/Pd
+  endif
+endif
+# Tho Android uses Linux, we use this fake uname to provide an easy way to
+# setup all this things needed to cross-compile for Android using the NDK
+ifeq ($(UNAME),ANDROID)
+  CPU := arm
+  SOURCES += $(SOURCES_android)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = android
+  PD_PATH = /usr
+  NDK_BASE := /usr/local/android-ndk
+  NDK_PLATFORM_VERSION := 5
+  NDK_SYSROOT=$(NDK_BASE)/platforms/android-$(NDK_PLATFORM_VERSION)/arch-arm
+  NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]')
+  NDK_TOOLCHAIN_BASE=$(NDK_BASE)/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$(NDK_UNAME)-x86
+  CC := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-gcc --sysroot=$(NDK_SYSROOT)
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  CFLAGS += 
+  LDFLAGS += -rdynamic -shared
+  SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared
+  LIBS += -lc $(LIBS_android)
+  STRIP := $(NDK_TOOLCHAIN_BASE)/bin/arm-linux-androideabi-strip \
+	--strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),Linux)
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -Wl,-soname,$(SHARED_LIB) -shared
+  ALL_LIBS += -lc $(LIBS_linux)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU)
+  # GNU/Hurd, should work like GNU/Linux for basically all externals
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+  ALL_LIBS += -lc $(LIBS_linux)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq ($(UNAME),GNU/kFreeBSD)
+  # Debian GNU/kFreeBSD, should work like GNU/Linux for basically all externals
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_linux)
+  EXTENSION = pd_linux
+  SHARED_EXTENSION = so
+  OS = linux
+  PD_PATH = /usr
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -fPIC
+  ALL_LDFLAGS += -rdynamic -shared -fPIC -Wl,-rpath,"\$$ORIGIN",--enable-new-dtags
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+  ALL_LIBS += -lc $(LIBS_linux)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)-$(shell uname -m)
+endif
+ifeq (CYGWIN,$(findstring CYGWIN,$(UNAME)))
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_cygwin)
+  EXTENSION = dll
+  SHARED_EXTENSION = dll
+  OS = cygwin
+  PD_PATH = $(shell cygpath $$PROGRAMFILES)/pd
+  OPT_CFLAGS = -O6 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += 
+  ALL_LDFLAGS += -rdynamic -shared -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin"
+  SHARED_LDFLAGS += -shared -Wl,-soname,$(SHARED_LIB)
+  ALL_LIBS += -lc -lpd $(LIBS_cygwin)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)
+endif
+ifeq (MINGW,$(findstring MINGW,$(UNAME)))
+  CPU := $(shell uname -m)
+  SOURCES += $(SOURCES_windows)
+  EXTENSION = dll
+  SHARED_EXTENSION = dll
+  OS = windows
+  PD_PATH = $(shell cd "$$PROGRAMFILES/pd" && pwd)
+  # MinGW doesn't seem to include cc so force gcc
+  CC=gcc
+  OPT_CFLAGS = -O3 -funroll-loops -fomit-frame-pointer
+  ALL_CFLAGS += -mms-bitfields
+  ALL_LDFLAGS += -s -shared -Wl,--enable-auto-import
+  SHARED_LDFLAGS += -shared
+  ALL_LIBS += -L"$(PD_PATH)/src" -L"$(PD_PATH)/bin" -L"$(PD_PATH)/obj" \
+	-lpd -lwsock32 -lkernel32 -luser32 -lgdi32 -liberty $(LIBS_windows)
+  STRIP = strip --strip-unneeded -R .note -R .comment
+  DISTBINDIR=$(DISTDIR)-$(OS)
+endif
+
+# in case somebody manually set the HELPPATCHES above
+HELPPATCHES ?= $(SOURCES:.c=-help.pd) $(PDOBJECTS:.pd=-help.pd)
+
+ALL_CFLAGS := $(ALL_CFLAGS) $(CFLAGS) $(OPT_CFLAGS)
+ALL_LDFLAGS := $(LDFLAGS) $(ALL_LDFLAGS)
+ALL_LIBS := $(LIBS) $(ALL_LIBS)
+
+SHARED_SOURCE ?= $(wildcard lib$(LIBRARY_NAME).c)
+SHARED_HEADER ?= $(shell test ! -e $(LIBRARY_NAME).h || echo $(LIBRARY_NAME).h)
+SHARED_LIB ?= $(SHARED_SOURCE:.c=.$(SHARED_EXTENSION))
+SHARED_TCL_LIB = $(wildcard lib$(LIBRARY_NAME).tcl)
+
+.PHONY = install libdir_install single_install install-doc install-examples install-manual install-unittests clean distclean dist etags $(LIBRARY_NAME)
+
+all: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB)
+
+%.o: %.c
+	$(CC) $(ALL_CFLAGS) -o "$*.o" -c "$*.c"
+
+%.$(EXTENSION): %.o $(SHARED_LIB)
+	$(CC) $(ALL_LDFLAGS) -o "$*.$(EXTENSION)" "$*.o"  $(ALL_LIBS) $(SHARED_LIB)
+	chmod a-x "$*.$(EXTENSION)"
+
+# this links everything into a single binary file
+$(LIBRARY_NAME): $(SOURCES:.c=.o) $(LIBRARY_NAME).o lib$(LIBRARY_NAME).o
+	$(CC) $(ALL_LDFLAGS) -o $(LIBRARY_NAME).$(EXTENSION) $(SOURCES:.c=.o) \
+		$(LIBRARY_NAME).o lib$(LIBRARY_NAME).o $(ALL_LIBS)
+	chmod a-x $(LIBRARY_NAME).$(EXTENSION)
+
+$(SHARED_LIB): $(SHARED_SOURCE:.c=.o)
+	$(CC) $(SHARED_LDFLAGS) -o $(SHARED_LIB) $(SHARED_SOURCE:.c=.o) $(ALL_LIBS)
+
+install: single_install
+
+# The meta and help files are explicitly installed to make sure they are
+# actually there.  Those files are not optional, then need to be there.
+libdir_install: $(SOURCES:.c=.$(EXTENSION)) $(SHARED_LIB) install-doc install-examples install-manual install-unittests
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd \
+		$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(SOURCES))" || (\
+		$(INSTALL_PROGRAM) $(SOURCES:.c=.$(EXTENSION)) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME) && \
+		$(STRIP) $(addprefix $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/,$(SOURCES:.c=.$(EXTENSION))))
+	test -z "$(strip $(SHARED_LIB))" || \
+		$(INSTALL_DATA) $(SHARED_LIB) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(wildcard $(SOURCES:.c=.tcl)))" || \
+		$(INSTALL_DATA) $(wildcard $(SOURCES:.c=.tcl)) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(PDOBJECTS) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(SHARED_TCL_LIB))" || \
+		$(INSTALL_DATA) $(SHARED_TCL_LIB) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+
+# install library linked as single binary
+single_install: $(LIBRARY_NAME) install-doc install-examples install-manual install-unittests
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_PROGRAM) $(LIBRARY_NAME).$(EXTENSION) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(STRIP) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/$(LIBRARY_NAME).$(EXTENSION)
+
+install-doc:
+	$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	test -z "$(strip $(SOURCES) $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(HELPPATCHES) \
+			$(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)
+	$(INSTALL_DATA) README.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/README.txt
+	$(INSTALL_DATA) LICENSE.txt $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/LICENSE.txt
+
+install-examples:
+	test -z "$(strip $(EXAMPLES))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples && \
+		for file in $(EXAMPLES); do \
+			$(INSTALL_DATA) examples/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/examples; \
+		done
+
+install-manual:
+	test -z "$(strip $(MANUAL))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual && \
+		for file in $(MANUAL); do \
+			$(INSTALL_DATA) manual/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/manual; \
+		done
+
+install-unittests:
+	test -z "$(strip $(UNITTESTS))" || \
+		$(INSTALL_DIR) $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests && \
+		for file in $(UNITTESTS); do \
+			$(INSTALL_DATA) unittests/$$file $(DESTDIR)$(objectsdir)/$(LIBRARY_NAME)/unittests; \
+		done
+
+clean:
+	-rm -f -- $(SOURCES:.c=.o) $(SOURCES_LIB:.c=.o) $(SHARED_SOURCE:.c=.o)
+	-rm -f -- $(SOURCES:.c=.$(EXTENSION))
+	-rm -f -- $(LIBRARY_NAME).o
+	-rm -f -- $(LIBRARY_NAME).$(EXTENSION)
+	-rm -f -- $(SHARED_LIB)
+
+distclean: clean
+	-rm -f -- $(DISTBINDIR).tar.gz
+	-rm -rf -- $(DISTBINDIR)
+	-rm -f -- $(DISTDIR).tar.gz
+	-rm -rf -- $(DISTDIR)
+	-rm -f -- $(ORIGDIR).tar.gz
+	-rm -rf -- $(ORIGDIR)
+
+
+$(DISTBINDIR):
+	$(INSTALL_DIR) $(DISTBINDIR)
+
+libdir: all $(DISTBINDIR)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTBINDIR)
+	$(INSTALL_DATA) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER) $(DISTBINDIR)
+	$(INSTALL_DATA) $(HELPPATCHES) $(DISTBINDIR)
+	test -z "$(strip $(EXTRA_DIST))" || \
+		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTBINDIR)
+#	tar --exclude-vcs -czpf $(DISTBINDIR).tar.gz $(DISTBINDIR)
+
+$(DISTDIR):
+	$(INSTALL_DIR) $(DISTDIR)
+
+$(ORIGDIR):
+	$(INSTALL_DIR) $(ORIGDIR)
+
+dist: $(DISTDIR)
+	$(INSTALL_DATA) Makefile  $(DISTDIR)
+	$(INSTALL_DATA) README.txt $(DISTDIR)
+	$(INSTALL_DATA) LICENSE.txt $(DISTDIR)
+	$(INSTALL_DATA) $(LIBRARY_NAME)-meta.pd  $(DISTDIR)
+	test -z "$(strip $(ALLSOURCES))" || \
+		$(INSTALL_DATA) $(ALLSOURCES)  $(DISTDIR)
+	test -z "$(strip $(wildcard $(ALLSOURCES:.c=.tcl)))" || \
+		$(INSTALL_DATA) $(wildcard $(ALLSOURCES:.c=.tcl))  $(DISTDIR)
+	test -z "$(strip $(wildcard $(LIBRARY_NAME).c))" || \
+		$(INSTALL_DATA) $(LIBRARY_NAME).c  $(DISTDIR)
+	test -z "$(strip $(SHARED_HEADER))" || \
+		$(INSTALL_DATA) $(SHARED_HEADER)  $(DISTDIR)
+	test -z "$(strip $(SHARED_SOURCE))" || \
+		$(INSTALL_DATA) $(SHARED_SOURCE)  $(DISTDIR)
+	test -z "$(strip $(SHARED_TCL_LIB))" || \
+		$(INSTALL_DATA) $(SHARED_TCL_LIB)  $(DISTDIR)
+	test -z "$(strip $(PDOBJECTS))" || \
+		$(INSTALL_DATA) $(PDOBJECTS)  $(DISTDIR)
+	test -z "$(strip $(HELPPATCHES))" || \
+		$(INSTALL_DATA) $(HELPPATCHES) $(DISTDIR)
+	test -z "$(strip $(EXTRA_DIST))" || \
+		$(INSTALL_DATA) $(EXTRA_DIST)    $(DISTDIR)
+	test -z "$(strip $(EXAMPLES))" || \
+		$(INSTALL_DIR) $(DISTDIR)/examples && \
+		for file in $(EXAMPLES); do \
+			$(INSTALL_DATA) examples/$$file $(DISTDIR)/examples; \
+		done
+	test -z "$(strip $(MANUAL))" || \
+		$(INSTALL_DIR) $(DISTDIR)/manual && \
+		for file in $(MANUAL); do \
+			$(INSTALL_DATA) manual/$$file $(DISTDIR)/manual; \
+		done
+	test -z "$(strip $(UNITTESTS))" || \
+		$(INSTALL_DIR) $(DISTDIR)/unittests && \
+		for file in $(UNITTESTS); do \
+			$(INSTALL_DATA) unittests/$$file $(DISTDIR)/unittests; \
+		done
+	tar --exclude-vcs -czpf $(DISTDIR).tar.gz $(DISTDIR)
+
+# make a Debian source package
+dpkg-source:
+	debclean
+	make distclean dist
+	mv $(DISTDIR) $(ORIGDIR)
+	tar --exclude-vcs -czpf ../$(ORIGDIR).orig.tar.gz $(ORIGDIR)
+	rm -f -- $(DISTDIR).tar.gz
+	rm -rf -- $(DISTDIR) $(ORIGDIR)
+	cd .. && dpkg-source -b $(LIBRARY_NAME)
+
+etags: TAGS
+
+TAGS: $(wildcard $(PD_INCLUDE)/*.h) $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER)
+	etags $(wildcard $(PD_INCLUDE)/*.h)
+	etags -a *.h $(SOURCES) $(SHARED_SOURCE) $(SHARED_HEADER)
+	etags -a --language=none --regex="/proc[ \t]+\([^ \t]+\)/\1/" *.tcl
+
+showsetup:
+	@echo "CC: $(CC)"
+	@echo "CFLAGS: $(CFLAGS)"
+	@echo "LDFLAGS: $(LDFLAGS)"
+	@echo "LIBS: $(LIBS)"
+	@echo "ALL_CFLAGS: $(ALL_CFLAGS)"
+	@echo "ALL_LDFLAGS: $(ALL_LDFLAGS)"
+	@echo "ALL_LIBS: $(ALL_LIBS)"
+	@echo "PD_INCLUDE: $(PD_INCLUDE)"
+	@echo "PD_PATH: $(PD_PATH)"
+	@echo "objectsdir: $(objectsdir)"
+	@echo "LIBRARY_NAME: $(LIBRARY_NAME)"
+	@echo "LIBRARY_VERSION: $(LIBRARY_VERSION)"
+	@echo "SOURCES: $(SOURCES)"
+	@echo "SHARED_HEADER: $(SHARED_HEADER)"
+	@echo "SHARED_SOURCE: $(SHARED_SOURCE)"
+	@echo "SHARED_LIB: $(SHARED_LIB)"
+	@echo "SHARED_TCL_LIB: $(SHARED_TCL_LIB)"
+	@echo "PDOBJECTS: $(PDOBJECTS)"
+	@echo "ALLSOURCES: $(ALLSOURCES)"
+	@echo "ALLSOURCES TCL: $(wildcard $(ALLSOURCES:.c=.tcl))"
+	@echo "UNAME: $(UNAME)"
+	@echo "CPU: $(CPU)"
+	@echo "pkglibdir: $(pkglibdir)"
+	@echo "DISTDIR: $(DISTDIR)"
+	@echo "ORIGDIR: $(ORIGDIR)"
+
diff --git a/embedded/puredata/examples/cvlverb.py b/embedded/puredata/examples/cvlverb.py
new file mode 100644
index 0000000..739e176
--- /dev/null
+++ b/embedded/puredata/examples/cvlverb.py
@@ -0,0 +1,3 @@
+bal = SigTo(0.25, 0.005, 0.25)
+ins = Input([0,1])
+dist = CvlVerb(ins, size=512, bal=bal, mul=0.3).out()
\ No newline at end of file
diff --git a/embedded/puredata/examples/random_waves.py b/embedded/puredata/examples/random_waves.py
new file mode 100644
index 0000000..6b9cc90
--- /dev/null
+++ b/embedded/puredata/examples/random_waves.py
@@ -0,0 +1,13 @@
+import random
+
+feed = SigTo(0.05, 0.05, 0.05)
+amp = Fader(fadein=0.005, fadeout=0.12, dur=0.125)
+syn = SineLoop(freq=[500,510], feedback=feed, mul=amp*amp)
+rev = WGVerb(syn, feedback=0.85, cutoff=4500, bal=0.1).out()
+
+def choose(a, b):
+    x = random.randint(a, b)
+    deg = [0,2,3,5,7,8,11][x%7]
+    hz = midiToHz(deg + (x / 7 * 12 + 36))
+    syn.freq = [hz,hz*1.005]
+    amp.play()
diff --git a/embedded/puredata/examples/resonators.py b/embedded/puredata/examples/resonators.py
new file mode 100644
index 0000000..233ae54
--- /dev/null
+++ b/embedded/puredata/examples/resonators.py
@@ -0,0 +1,8 @@
+reson = SigTo(2, 0.005, 2)
+freqs = SigTo([50,100,150,200,250,300,350,400], time=0.2)
+
+ins = Input([0,1])
+wgs = Waveguide(ins, freq=freqs, dur=reson, mul=0.1)
+wgss = wgs.mix(2)
+wgss.out()
+
diff --git a/embedded/puredata/examples/resonators_add_delays.py b/embedded/puredata/examples/resonators_add_delays.py
new file mode 100644
index 0000000..554ecce
--- /dev/null
+++ b/embedded/puredata/examples/resonators_add_delays.py
@@ -0,0 +1,3 @@
+deltime = SigTo(.25, 0.005, 0.25)
+delfeed = SigTo(.25, 0.005, 0.25)
+dd = Delay(wgs, delay=deltime, feedback=delfeed).out(0)
diff --git a/embedded/puredata/m_pd.h b/embedded/puredata/m_pd.h
new file mode 100755
index 0000000..71bd28e
--- /dev/null
+++ b/embedded/puredata/m_pd.h
@@ -0,0 +1,665 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.  */
+
+#ifndef __m_pd_h_
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
+#define PD_MAJOR_VERSION 0
+#define PD_MINOR_VERSION 41
+#define PD_BUGFIX_VERSION 4
+#define PD_TEST_VERSION "extended"
+
+/* old name for "MSW" flag -- we have to take it for the sake of many old
+"nmakefiles" for externs, which will define NT and not MSW */
+#if defined(NT) && !defined(MSW)
+#define MSW
+#endif
+
+/* These pragmas are only used for MSVC, not MinGW or Cygwin <hans at at.or.at> */
+#ifdef _MSC_VER
+/* #pragma warning( disable : 4091 ) */
+#pragma warning( disable : 4305 )  /* uncast const double to float */
+#pragma warning( disable : 4244 )  /* uncast float/int conversion etc. */
+#pragma warning( disable : 4101 )  /* unused automatic variables */
+#endif /* _MSC_VER */
+
+    /* the external storage class is "extern" in UNIX; in MSW it's ugly. */
+#ifdef MSW
+#ifdef PD_INTERNAL
+#define EXTERN __declspec(dllexport) extern
+#else
+#define EXTERN __declspec(dllimport) extern
+#endif /* PD_INTERNAL */
+#else
+#define EXTERN extern
+#endif /* MSW */
+
+    /* and depending on the compiler, hidden data structures are
+    declared differently: */
+#if defined( __GNUC__) || defined( __BORLANDC__ ) || defined( __MWERKS__ )
+#define EXTERN_STRUCT struct
+#else
+#define EXTERN_STRUCT extern struct
+#endif
+
+
+#if !defined(_SIZE_T) && !defined(_SIZE_T_)
+#include <stddef.h>     /* just for size_t -- how lame! */
+#endif
+
+#define MAXPDSTRING 1000        /* must be >= FILENAME_MAX */
+#define MAXPDARG 5              /* max number of args we can typecheck today */
+
+/* signed and unsigned integer types the size of a pointer:  */
+/* GG: long is the size of a pointer */
+typedef long t_int;
+
+typedef float t_float;  /* a floating-point number at most the same size */
+typedef float t_floatarg;  /* floating-point type for function calls */
+
+typedef struct _symbol
+{
+    char *s_name;
+    struct _class **s_thing;
+    struct _symbol *s_next;
+} t_symbol;
+
+EXTERN_STRUCT _array;
+#define t_array struct _array       /* g_canvas.h */
+
+/* pointers to glist and array elements go through a "stub" which sticks
+around after the glist or array is freed.  The stub itself is deleted when
+both the glist/array is gone and the refcount is zero, ensuring that no
+gpointers are pointing here. */
+
+#define GP_NONE 0       /* the stub points nowhere (has been cut off) */
+#define GP_GLIST 1      /* the stub points to a glist element */
+#define GP_ARRAY 2      /* ... or array */
+
+typedef struct _gstub
+{
+    union
+    {
+        struct _glist *gs_glist;    /* glist we're in */
+        struct _array *gs_array;    /* array we're in */
+    } gs_un;
+    int gs_which;                   /* GP_GLIST/GP_ARRAY */
+    int gs_refcount;                /* number of gpointers pointing here */
+} t_gstub;
+
+typedef struct _gpointer           /* pointer to a gobj in a glist */
+{
+    union
+    {   
+        struct _scalar *gp_scalar;  /* scalar we're in (if glist) */
+        union word *gp_w;           /* raw data (if array) */
+    } gp_un;
+    int gp_valid;                   /* number which must match gpointee */
+    t_gstub *gp_stub;               /* stub which points to glist/array */
+} t_gpointer;
+
+#define PD_BLOBS 1 /* MP20070211 Use this to test for blob capability */
+/* MP20061223 blob type: */
+typedef struct _blob /* pointer to a blob */
+{
+   unsigned long s_length; /* length of blob in bytes */
+   unsigned char *s_data; /* pointer to 1st byte of blob */
+} t_blob;
+/* ...MP20061223 blob type */
+
+
+typedef union word
+{
+    t_float w_float;
+    t_symbol *w_symbol;
+    t_gpointer *w_gpointer;
+    t_array *w_array;
+    struct _glist *w_list;
+    int w_index;
+    t_blob *w_blob; /* MP20061223 blob type */
+} t_word;
+
+typedef enum
+{
+    A_NULL,
+    A_FLOAT,
+    A_SYMBOL,
+    A_POINTER,
+    A_SEMI,
+    A_COMMA,
+    A_DEFFLOAT,
+    A_DEFSYM,
+    A_DOLLAR, 
+    A_DOLLSYM,
+    A_GIMME,
+    A_CANT,
+    A_BLOB /* MP20061223 blob type */
+}  t_atomtype;
+
+#define A_DEFSYMBOL A_DEFSYM    /* better name for this */
+
+typedef struct _atom
+{
+    t_atomtype a_type;
+    union word a_w;
+} t_atom;
+
+EXTERN_STRUCT _class;
+#define t_class struct _class
+
+EXTERN_STRUCT _outlet;
+#define t_outlet struct _outlet
+
+EXTERN_STRUCT _inlet;
+#define t_inlet struct _inlet
+
+EXTERN_STRUCT _binbuf;
+#define t_binbuf struct _binbuf
+
+EXTERN_STRUCT _clock;
+#define t_clock struct _clock
+
+EXTERN_STRUCT _outconnect;
+#define t_outconnect struct _outconnect
+
+EXTERN_STRUCT _glist;
+#define t_glist struct _glist
+#define t_canvas struct _glist  /* LATER lose this */
+
+typedef t_class *t_pd;      /* pure datum: nothing but a class pointer */
+
+typedef struct _gobj        /* a graphical object */
+{
+    t_pd g_pd;              /* pure datum header (class) */
+    struct _gobj *g_next;   /* next in list */
+} t_gobj;
+
+typedef struct _scalar      /* a graphical object holding data */
+{
+    t_gobj sc_gobj;         /* header for graphical object */
+    t_symbol *sc_template;  /* template name (LATER replace with pointer) */
+    t_word sc_vec[1];       /* indeterminate-length array of words */
+} t_scalar;
+
+typedef struct _text        /* patchable object - graphical, with text */
+{
+    t_gobj te_g;                /* header for graphical object */
+    t_binbuf *te_binbuf;        /* holder for the text */
+    t_outlet *te_outlet;        /* linked list of outlets */
+    t_inlet *te_inlet;          /* linked list of inlets */
+    short te_xpix;              /* x&y location (within the toplevel) */
+    short te_ypix;
+    short te_width;             /* requested width in chars, 0 if auto */
+    unsigned int te_type:2;     /* from defs below */
+} t_text;
+
+#define T_TEXT 0        /* just a textual comment */
+#define T_OBJECT 1      /* a MAX style patchable object */
+#define T_MESSAGE 2     /* a MAX stype message */
+#define T_ATOM 3        /* a cell to display a number or symbol */
+
+#define te_pd te_g.g_pd
+
+   /* t_object is synonym for t_text (LATER unify them) */
+
+typedef struct _text t_object;
+
+#define ob_outlet te_outlet
+#define ob_inlet te_inlet
+#define ob_binbuf te_binbuf
+#define ob_pd te_g.g_pd
+#define ob_g te_g
+
+typedef void (*t_method)(void);
+typedef void *(*t_newmethod)( void);
+typedef void (*t_gotfn)(void *x, ...);
+
+/* ---------------- pre-defined objects and symbols --------------*/
+EXTERN t_pd pd_objectmaker;     /* factory for creating "object" boxes */
+EXTERN t_pd pd_canvasmaker;     /* factory for creating canvases */
+EXTERN t_symbol s_pointer;
+EXTERN t_symbol s_float;
+EXTERN t_symbol s_symbol;
+EXTERN t_symbol s_blob;
+EXTERN t_symbol s_bang;
+EXTERN t_symbol s_list;
+EXTERN t_symbol s_anything;
+EXTERN t_symbol s_signal;
+EXTERN t_symbol s__N;
+EXTERN t_symbol s__X;
+EXTERN t_symbol s_x;
+EXTERN t_symbol s_y;
+EXTERN t_symbol s_;
+
+/* --------- prototypes from the central message system ----------- */
+EXTERN void pd_typedmess(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void pd_forwardmess(t_pd *x, int argc, t_atom *argv);
+EXTERN t_symbol *gensym(const char *s);
+EXTERN t_gotfn getfn(t_pd *x, t_symbol *s);
+EXTERN t_gotfn zgetfn(t_pd *x, t_symbol *s);
+EXTERN void nullfn(void);
+EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
+#define mess0(x, s) ((*getfn((x), (s)))((x)))
+#define mess1(x, s, a) ((*getfn((x), (s)))((x), (a)))
+#define mess2(x, s, a,b) ((*getfn((x), (s)))((x), (a),(b)))
+#define mess3(x, s, a,b,c) ((*getfn((x), (s)))((x), (a),(b),(c)))
+#define mess4(x, s, a,b,c,d) ((*getfn((x), (s)))((x), (a),(b),(c),(d)))
+#define mess5(x, s, a,b,c,d,e) ((*getfn((x), (s)))((x), (a),(b),(c),(d),(e)))
+EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_pd *pd_newest(void);
+
+/* --------------- memory management -------------------- */
+EXTERN void *getbytes(size_t nbytes);
+EXTERN void *getzbytes(size_t nbytes);
+EXTERN void *copybytes(void *src, size_t nbytes);
+EXTERN void freebytes(void *x, size_t nbytes);
+EXTERN void *resizebytes(void *x, size_t oldsize, size_t newsize);
+
+/* -------------------- atoms ----------------------------- */
+
+#define SETSEMI(atom) ((atom)->a_type = A_SEMI, (atom)->a_w.w_index = 0)
+#define SETCOMMA(atom) ((atom)->a_type = A_COMMA, (atom)->a_w.w_index = 0)
+#define SETPOINTER(atom, gp) ((atom)->a_type = A_POINTER, \
+    (atom)->a_w.w_gpointer = (gp))
+#define SETFLOAT(atom, f) ((atom)->a_type = A_FLOAT, (atom)->a_w.w_float = (f))
+#define SETSYMBOL(atom, s) ((atom)->a_type = A_SYMBOL, \
+    (atom)->a_w.w_symbol = (s))
+#define SETBLOB(atom, st) ((atom)->a_type = A_BLOB, (atom)->a_w.w_blob = (st)) /* MP 20061226 blob type */
+#define SETDOLLAR(atom, n) ((atom)->a_type = A_DOLLAR, \
+    (atom)->a_w.w_index = (n))
+#define SETDOLLSYM(atom, s) ((atom)->a_type = A_DOLLSYM, \
+    (atom)->a_w.w_symbol= (s))
+
+EXTERN t_float atom_getfloat(t_atom *a);
+EXTERN t_int atom_getint(t_atom *a);
+EXTERN t_symbol *atom_getsymbol(t_atom *a);
+EXTERN t_blob *atom_getblob(t_atom *a);/* MP 20070108 blob type */
+EXTERN t_symbol *atom_gensym(t_atom *a);
+EXTERN t_float atom_getfloatarg(int which, int argc, t_atom *argv);
+EXTERN t_int atom_getintarg(int which, int argc, t_atom *argv);
+EXTERN t_symbol *atom_getsymbolarg(int which, int argc, t_atom *argv);
+
+EXTERN void atom_string(t_atom *a, char *buf, unsigned int bufsize);
+
+/* ------------------  binbufs --------------- */
+
+EXTERN t_binbuf *binbuf_new(void);
+EXTERN void binbuf_free(t_binbuf *x);
+EXTERN t_binbuf *binbuf_duplicate(t_binbuf *y);
+
+EXTERN void binbuf_text(t_binbuf *x, char *text, size_t size);
+EXTERN void binbuf_gettext(t_binbuf *x, char **bufp, int *lengthp);
+EXTERN void binbuf_clear(t_binbuf *x);
+EXTERN void binbuf_add(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_addv(t_binbuf *x, char *fmt, ...);
+EXTERN void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y);
+EXTERN void binbuf_addsemi(t_binbuf *x);
+EXTERN void binbuf_restore(t_binbuf *x, int argc, t_atom *argv);
+EXTERN void binbuf_print(t_binbuf *x);
+EXTERN int binbuf_getnatom(t_binbuf *x);
+EXTERN t_atom *binbuf_getvec(t_binbuf *x);
+EXTERN void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv);
+EXTERN int binbuf_read(t_binbuf *b, char *filename, char *dirname,
+    int crflag);
+EXTERN int binbuf_read_via_canvas(t_binbuf *b, char *filename, t_canvas *canvas,
+    int crflag);
+EXTERN int binbuf_read_via_path(t_binbuf *b, char *filename, char *dirname,
+    int crflag);
+EXTERN int binbuf_write(t_binbuf *x, char *filename, char *dir,
+    int crflag);
+EXTERN void binbuf_evalfile(t_symbol *name, t_symbol *dir);
+EXTERN t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av,
+    int tonew);
+
+/* ------------------  clocks --------------- */
+
+EXTERN t_clock *clock_new(void *owner, t_method fn);
+EXTERN void clock_set(t_clock *x, double systime);
+EXTERN void clock_delay(t_clock *x, double delaytime);
+EXTERN void clock_unset(t_clock *x);
+EXTERN double clock_getlogicaltime(void);
+EXTERN double clock_getsystime(void); /* OBSOLETE; use clock_getlogicaltime() */
+EXTERN double clock_gettimesince(double prevsystime);
+EXTERN double clock_getsystimeafter(double delaytime);
+EXTERN void clock_free(t_clock *x);
+
+/* ----------------- pure data ---------------- */
+EXTERN t_pd *pd_new(t_class *cls);
+EXTERN void pd_free(t_pd *x);
+EXTERN void pd_bind(t_pd *x, t_symbol *s);
+EXTERN void pd_unbind(t_pd *x, t_symbol *s);
+EXTERN t_pd *pd_findbyclass(t_symbol *s, t_class *c);
+EXTERN void pd_pushsym(t_pd *x);
+EXTERN void pd_popsym(t_pd *x);
+EXTERN t_symbol *pd_getfilename(void);
+EXTERN t_symbol *pd_getdirname(void);
+EXTERN void pd_bang(t_pd *x);
+EXTERN void pd_pointer(t_pd *x, t_gpointer *gp);
+EXTERN void pd_float(t_pd *x, t_float f);
+EXTERN void pd_symbol(t_pd *x, t_symbol *s);
+EXTERN void pd_blob(t_pd *x, t_blob *st); /* MP 20061226 blob type */
+EXTERN void pd_list(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void pd_anything(t_pd *x, t_symbol *s, int argc, t_atom *argv);
+#define pd_class(x) (*(x))
+
+/* ----------------- pointers ---------------- */
+EXTERN void gpointer_init(t_gpointer *gp);
+EXTERN void gpointer_copy(const t_gpointer *gpfrom, t_gpointer *gpto);
+EXTERN void gpointer_unset(t_gpointer *gp);
+EXTERN int gpointer_check(const t_gpointer *gp, int headok);
+
+/* ----------------- patchable "objects" -------------- */
+EXTERN t_inlet *inlet_new(t_object *owner, t_pd *dest, t_symbol *s1,
+    t_symbol *s2);
+EXTERN t_inlet *pointerinlet_new(t_object *owner, t_gpointer *gp);
+EXTERN t_inlet *floatinlet_new(t_object *owner, t_float *fp);
+EXTERN t_inlet *symbolinlet_new(t_object *owner, t_symbol **sp);
+EXTERN t_inlet *signalinlet_new(t_object *owner, t_float f);
+EXTERN void inlet_free(t_inlet *x);
+
+EXTERN t_outlet *outlet_new(t_object *owner, t_symbol *s);
+EXTERN void outlet_bang(t_outlet *x);
+EXTERN void outlet_pointer(t_outlet *x, t_gpointer *gp);
+EXTERN void outlet_float(t_outlet *x, t_float f);
+EXTERN void outlet_symbol(t_outlet *x, t_symbol *s);
+EXTERN void outlet_blob(t_outlet *x, t_blob *st); /* MP 20061226 blob type */
+EXTERN void outlet_list(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void outlet_anything(t_outlet *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_symbol *outlet_getsymbol(t_outlet *x);
+EXTERN void outlet_free(t_outlet *x);
+EXTERN t_object *pd_checkobject(t_pd *x);
+
+
+/* -------------------- canvases -------------- */
+
+EXTERN void glob_setfilename(void *dummy, t_symbol *name, t_symbol *dir);
+
+EXTERN void canvas_setargs(int argc, t_atom *argv);
+EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
+EXTERN t_symbol *canvas_getcurrentdir(void);
+EXTERN t_glist *canvas_getcurrent(void);
+EXTERN void canvas_makefilename(t_glist *c, char *file,
+    char *result,int resultsize);
+EXTERN t_symbol *canvas_getdir(t_glist *x);
+EXTERN char sys_font[]; /* default typeface set in s_main.c */
+EXTERN char sys_fontweight[]; /* default font weight set in s_main.c */
+EXTERN int sys_fontwidth(int fontsize);
+EXTERN int sys_fontheight(int fontsize);
+EXTERN void canvas_dataproperties(t_glist *x, t_scalar *sc, t_binbuf *b);
+EXTERN int canvas_open(t_canvas *x, const char *name, const char *ext,
+    char *dirresult, char **nameresult, unsigned int size, int bin);
+
+/* ---------------- widget behaviors ---------------------- */
+
+EXTERN_STRUCT _widgetbehavior;
+#define t_widgetbehavior struct _widgetbehavior
+
+EXTERN_STRUCT _parentwidgetbehavior;
+#define t_parentwidgetbehavior struct _parentwidgetbehavior
+EXTERN t_parentwidgetbehavior *pd_getparentwidget(t_pd *x);
+
+/* -------------------- classes -------------- */
+
+#define CLASS_DEFAULT 0         /* flags for new classes below */
+#define CLASS_PD 1
+#define CLASS_GOBJ 2
+#define CLASS_PATCHABLE 3
+#define CLASS_NOINLET 8
+
+#define CLASS_TYPEMASK 3
+
+
+EXTERN t_class *class_new(t_symbol *name, t_newmethod newmethod,
+    t_method freemethod, size_t size, int flags, t_atomtype arg1, ...);
+EXTERN void class_addcreator(t_newmethod newmethod, t_symbol *s, 
+    t_atomtype type1, ...);
+EXTERN void class_addmethod(t_class *c, t_method fn, t_symbol *sel,
+    t_atomtype arg1, ...);
+EXTERN void class_addbang(t_class *c, t_method fn);
+EXTERN void class_addpointer(t_class *c, t_method fn);
+EXTERN void class_doaddfloat(t_class *c, t_method fn);
+EXTERN void class_addsymbol(t_class *c, t_method fn);
+EXTERN void class_addblob(t_class *c, t_method fn);/* MP 20061226 blob type */
+EXTERN void class_addlist(t_class *c, t_method fn);
+EXTERN void class_addanything(t_class *c, t_method fn);
+EXTERN void class_sethelpsymbol(t_class *c, t_symbol *s);
+EXTERN void class_setwidget(t_class *c, t_widgetbehavior *w);
+EXTERN void class_setparentwidget(t_class *c, t_parentwidgetbehavior *w);
+EXTERN t_parentwidgetbehavior *class_parentwidget(t_class *c);
+EXTERN char *class_getname(t_class *c);
+EXTERN char *class_gethelpname(t_class *c);
+EXTERN void class_setdrawcommand(t_class *c);
+EXTERN int class_isdrawcommand(t_class *c);
+EXTERN void class_domainsignalin(t_class *c, int onset);
+EXTERN void class_set_extern_dir(t_symbol *s);
+#define CLASS_MAINSIGNALIN(c, type, field) \
+    class_domainsignalin(c, (char *)(&((type *)0)->field) - (char *)0)
+
+         /* prototype for functions to save Pd's to a binbuf */
+typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
+EXTERN void class_setsavefn(t_class *c, t_savefn f);
+EXTERN t_savefn class_getsavefn(t_class *c);
+        /* prototype for functions to open properties dialogs */
+typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist);
+EXTERN void class_setpropertiesfn(t_class *c, t_propertiesfn f);
+EXTERN t_propertiesfn class_getpropertiesfn(t_class *c);
+
+#ifndef PD_CLASS_DEF
+#define class_addbang(x, y) class_addbang((x), (t_method)(y))
+#define class_addpointer(x, y) class_addpointer((x), (t_method)(y))
+#define class_addfloat(x, y) class_doaddfloat((x), (t_method)(y))
+#define class_addsymbol(x, y) class_addsymbol((x), (t_method)(y))
+#define class_addblob(x, y) class_addblob((x), (t_method)(y)) /* MP20061226 blob type */
+#define class_addlist(x, y) class_addlist((x), (t_method)(y))
+#define class_addanything(x, y) class_addanything((x), (t_method)(y))
+#endif
+
+/* ------------   printing --------------------------------- */
+EXTERN void post(const char *fmt, ...);
+EXTERN void startpost(const char *fmt, ...);
+EXTERN void poststring(const char *s);
+EXTERN void postfloat(float f);
+EXTERN void postatom(int argc, t_atom *argv);
+EXTERN void endpost(void);
+EXTERN void error(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+EXTERN void verbose(int level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+EXTERN void bug(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+EXTERN void pd_error(void *object, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+EXTERN void sys_logerror(const char *object, const char *s);
+EXTERN void sys_unixerror(const char *object);
+EXTERN void sys_ouch(void);
+
+
+/* ------------  system interface routines ------------------- */
+EXTERN int sys_isreadablefile(const char *name);
+EXTERN int sys_isabsolutepath(const char *dir);
+EXTERN void sys_bashfilename(const char *from, char *to);
+EXTERN void sys_unbashfilename(const char *from, char *to);
+EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
+    char *dirresult, char **nameresult, unsigned int size, int bin);
+EXTERN int sched_geteventno(void);
+EXTERN double sys_getrealtime(void);
+EXTERN int (*sys_idlehook)(void);   /* hook to add idle time computation */
+
+
+/* ------------  threading ------------------- */ 
+EXTERN void sys_lock(void);
+EXTERN void sys_unlock(void);
+EXTERN int sys_trylock(void);
+
+
+/* --------------- signals ----------------------------------- */
+
+typedef float t_sample;
+#define MAXLOGSIG 32
+#define MAXSIGSIZE (1 << MAXLOGSIG)
+
+typedef struct _signal
+{
+    int s_n;            /* number of points in the array */
+    t_sample *s_vec;    /* the array */
+    t_float s_sr;         /* sample rate */
+    int s_refcount;     /* number of times used */
+    int s_isborrowed;   /* whether we're going to borrow our array */
+    struct _signal *s_borrowedfrom;     /* signal to borrow it from */
+    struct _signal *s_nextfree;         /* next in freelist */
+    struct _signal *s_nextused;         /* next in used list */
+    int s_vecsize;      /* allocated size of array in points */
+} t_signal;
+
+typedef t_int *(*t_perfroutine)(t_int *args);
+
+EXTERN t_int *plus_perform(t_int *args);
+EXTERN t_int *zero_perform(t_int *args);
+EXTERN t_int *copy_perform(t_int *args);
+
+EXTERN void dsp_add_plus(t_sample *in1, t_sample *in2, t_sample *out, int n);
+EXTERN void dsp_add_copy(t_sample *in, t_sample *out, int n);
+EXTERN void dsp_add_scalarcopy(t_float *in, t_sample *out, int n);
+EXTERN void dsp_add_zero(t_sample *out, int n);
+
+EXTERN int sys_getblksize(void);
+EXTERN t_float sys_getsr(void);
+EXTERN int sys_get_inchannels(void);
+EXTERN int sys_get_outchannels(void);
+
+EXTERN void dsp_add(t_perfroutine f, int n, ...);
+EXTERN void dsp_addv(t_perfroutine f, int n, t_int *vec);
+EXTERN void pd_fft(t_float *buf, int npoints, int inverse);
+EXTERN int ilog2(int n);
+
+EXTERN void mayer_fht(t_sample *fz, int n);
+EXTERN void mayer_fft(int n, t_sample *real, t_sample *imag);
+EXTERN void mayer_ifft(int n, t_sample *real, t_sample *imag);
+EXTERN void mayer_realfft(int n, t_sample *real);
+EXTERN void mayer_realifft(int n, t_sample *real);
+
+EXTERN float *cos_table;
+#define LOGCOSTABSIZE 9
+#define COSTABSIZE (1<<LOGCOSTABSIZE)
+
+EXTERN int canvas_suspend_dsp(void);
+EXTERN void canvas_resume_dsp(int oldstate);
+EXTERN void canvas_update_dsp(void);
+EXTERN int canvas_dspstate;
+
+/*   up/downsampling */
+typedef struct _resample
+{
+  int method;       /* up/downsampling method ID */
+
+  t_int downsample; /* downsampling factor */
+  t_int upsample;   /* upsampling factor */
+
+  t_sample *s_vec;   /* here we hold the resampled data */
+  int      s_n;
+
+  t_sample *coeffs;  /* coefficients for filtering... */
+  int      coefsize;
+
+  t_sample *buffer;  /* buffer for filtering */
+  int      bufsize;
+} t_resample;
+
+EXTERN void resample_init(t_resample *x);
+EXTERN void resample_free(t_resample *x);
+
+EXTERN void resample_dsp(t_resample *x, t_sample *in, int insize, t_sample *out, int outsize, int method);
+EXTERN void resamplefrom_dsp(t_resample *x, t_sample *in, int insize, int outsize, int method);
+EXTERN void resampleto_dsp(t_resample *x, t_sample *out, int insize, int outsize, int method);
+
+/* ----------------------- utility functions for signals -------------- */
+EXTERN t_float mtof(t_float);
+EXTERN t_float ftom(t_float);
+EXTERN t_float rmstodb(t_float);
+EXTERN t_float powtodb(t_float);
+EXTERN t_float dbtorms(t_float);
+EXTERN t_float dbtopow(t_float);
+
+EXTERN t_float q8_sqrt(t_float);
+EXTERN t_float q8_rsqrt(t_float);
+#ifndef N32     
+EXTERN t_float qsqrt(t_float);  /* old names kept for extern compatibility */
+EXTERN t_float qrsqrt(t_float);
+#endif
+/* --------------------- data --------------------------------- */
+
+    /* graphical arrays */
+EXTERN_STRUCT _garray;
+#define t_garray struct _garray
+
+EXTERN t_class *garray_class;
+EXTERN int garray_getfloatarray(t_garray *x, int *size, t_float **vec);
+EXTERN int garray_getfloatwords(t_garray *x, int *size, t_word **vec);
+EXTERN t_float garray_get(t_garray *x, t_symbol *s, t_int indx);
+EXTERN void garray_redraw(t_garray *x);
+EXTERN int garray_npoints(t_garray *x);
+EXTERN char *garray_vec(t_garray *x);
+EXTERN void garray_resize(t_garray *x, t_floatarg f);
+EXTERN void garray_usedindsp(t_garray *x);
+EXTERN void garray_setsaveit(t_garray *x, int saveit);
+EXTERN t_class *scalar_class;
+
+EXTERN t_float *value_get(t_symbol *s);
+EXTERN void value_release(t_symbol *s);
+EXTERN int value_getfloat(t_symbol *s, t_float *f);
+EXTERN int value_setfloat(t_symbol *s, t_float f);
+
+/* ------- GUI interface - functions to send strings to TK --------- */
+typedef void (*t_guicallbackfn)(t_gobj *client, t_glist *glist);
+
+EXTERN void sys_vgui(char *fmt, ...);
+EXTERN void sys_gui(char *s);
+EXTERN void sys_pretendguibytes(int n);
+EXTERN void sys_queuegui(void *client, t_glist *glist, t_guicallbackfn f);
+EXTERN void sys_unqueuegui(void *client);
+    /* dialog window creation and destruction */
+EXTERN void gfxstub_new(t_pd *owner, void *key, const char *cmd);
+EXTERN void gfxstub_deleteforkey(void *key);
+
+extern t_class *glob_pdobject;  /* object to send "pd" messages */
+
+/*-------------  Max 0.26 compatibility --------------------*/
+
+/* the following reflects the new way classes are laid out, with the class
+   pointing to the messlist and not vice versa. Externs shouldn't feel it. */
+typedef t_class *t_externclass;
+
+EXTERN void c_extern(t_externclass *cls, t_newmethod newroutine,
+    t_method freeroutine, t_symbol *name, size_t size, int tiny, \
+    t_atomtype arg1, ...);
+EXTERN void c_addmess(t_method fn, t_symbol *sel, t_atomtype arg1, ...);
+
+#define t_getbytes getbytes
+#define t_freebytes freebytes
+#define t_resizebytes resizebytes
+#define typedmess pd_typedmess
+#define vmess pd_vmess
+
+/* A definition to help gui objects straddle 0.34-0.35 changes.  If this is
+defined, there is a "te_xpix" field in objects, not a "te_xpos" as before: */
+
+#define PD_USE_TE_XPIX
+
+#if defined(__i386__) || defined(__x86_64__)
+/* a test for NANs and denormals.  Should only be necessary on i386. */
+#define PD_BADFLOAT(f) ((((*(unsigned int*)&(f))&0x7f800000)==0) || \
+    (((*(unsigned int*)&(f))&0x7f800000)==0x7f800000))
+/* more stringent test: anything not between 1e-19 and 1e19 in absolute val */
+#define PD_BIGORSMALL(f) ((((*(unsigned int*)&(f))&0x60000000)==0) || \
+    (((*(unsigned int*)&(f))&0x60000000)==0x60000000))
+#else
+#define PD_BADFLOAT(f) 0
+#define PD_BIGORSMALL(f) 0
+#endif
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
+
+#define __m_pd_h_
+#endif /* __m_pd_h_ */
diff --git a/embedded/puredata/pyo~-help.pd b/embedded/puredata/pyo~-help.pd
new file mode 100644
index 0000000..e8c9c8a
--- /dev/null
+++ b/embedded/puredata/pyo~-help.pd
@@ -0,0 +1,311 @@
+#N canvas 296 140 952 365 10;
+#X obj 28 108 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X obj 144 108 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
+1;
+#X obj 13 234 *~;
+#X obj 51 234 *~;
+#X obj 13 256 dac~;
+#X obj 72 213 hsl 128 15 0 1 0 1 empty empty master_gain -2 -8 0 10
+-262144 -1 -1 6200 1;
+#X obj 274 223 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1
+1;
+#X msg 274 243 \; pd dsp \$1;
+#X obj 13 59 r msg_to_pyo;
+#X text 161 107 play;
+#X obj 13 166 pyo~ 2;
+#X text 66 168 argument sets the number of audio ins/outs (defaults
+to 2).;
+#N canvas 1 75 824 583 resonators_example 0;
+#X obj 35 103 hsl 128 15 0.01 30 1 0 empty empty resonance -2 -8 0
+10 -262144 -1 -1 11200 0;
+#X floatatom 32 120 5 0 0 0 - - -;
+#X obj 21 530 s msg_to_pyo;
+#X obj 98 387 hsl 128 15 0 1 0 0 empty empty delay_time -2 -8 0 10
+-262144 -1 -1 1300 0;
+#X floatatom 95 403 5 0 0 0 - - -;
+#X msg 95 418 value deltime \$1;
+#X obj 111 454 hsl 128 15 0 1 0 0 empty empty delay_feedback -2 -8
+0 10 -262144 -1 -1 10800 0;
+#X floatatom 108 470 5 0 0 0 - - -;
+#X msg 108 485 value delfeed \$1;
+#X msg 32 136 value reson \$1;
+#X obj 52 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 4700 0;
+#X obj 71 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 3200 0;
+#X obj 91 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 5800 0;
+#X obj 110 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 7100 0;
+#X obj 130 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 5500 0;
+#X obj 149 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 7100 0;
+#X obj 169 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 4400 0;
+#X obj 189 177 vsl 15 80 50 500 0 0 empty empty empty 0 -9 0 10 -262144
+-1 -1 1800 0;
+#X msg 52 306 value freqs \$1 \$2 \$3 \$4 \$5 \$6 \$7 \$8;
+#X obj 52 264 bondo 8 ____________;
+#X obj 52 285 pack f f f f f f f f;
+#X msg 21 66 read examples/resonators.py;
+#X msg 73 351 read -a examples/resonators_add_delays.py;
+#X text 52 159 resonator frequencies;
+#X text 20 30 load pyo processing file (audio signal must be given
+in pyo~ inputs).;
+#X text 168 103 adjust resonance in seconds;
+#X text 214 209 play with resonator frequencies;
+#X text 380 352 add a stereo delay taking resonator outputs as its
+input;
+#X text 234 387 adjust delay time;
+#X text 246 453 adjust delay feedback;
+#X connect 0 0 1 0;
+#X connect 1 0 9 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 2 0;
+#X connect 9 0 2 0;
+#X connect 10 0 19 0;
+#X connect 11 0 19 1;
+#X connect 12 0 19 2;
+#X connect 13 0 19 3;
+#X connect 14 0 19 4;
+#X connect 15 0 19 5;
+#X connect 16 0 19 6;
+#X connect 17 0 19 7;
+#X connect 18 0 2 0;
+#X connect 19 0 20 0;
+#X connect 19 1 20 1;
+#X connect 19 2 20 2;
+#X connect 19 3 20 3;
+#X connect 19 4 20 4;
+#X connect 19 5 20 5;
+#X connect 19 6 20 6;
+#X connect 19 7 20 7;
+#X connect 20 0 18 0;
+#X connect 21 0 2 0;
+#X connect 22 0 2 0;
+#X restore 531 60 pd resonators_example;
+#X msg 553 171 clear;
+#X obj 531 199 s msg_to_pyo;
+#X text 598 172 shutdown and reboot the server;
+#N canvas 1 75 450 300 synthesis_example 0;
+#N canvas 1 75 375 358 choose_sines 0;
+#X obj 57 77 metro 125;
+#X obj 78 109 hsl 128 15 0 36 0 0 empty empty empty -2 -8 0 10 -262144
+-1 -1 4233 1;
+#X obj 127 144 hsl 128 15 0 36 0 0 empty empty empty -2 -8 0 10 -262144
+-1 -1 4233 1;
+#X floatatom 75 125 5 0 0 0 - - -;
+#X floatatom 124 160 5 0 0 0 - - -;
+#X obj 124 209 +;
+#X obj 124 179 t b f;
+#X obj 75 144 t f f;
+#X obj 57 240 int;
+#X obj 124 232 int;
+#X msg 57 288 call choose \$1 \$2;
+#X obj 57 311 outlet;
+#X obj 57 54 inlet;
+#X obj 57 265 pack 24 24;
+#X text 7 3 Choose a random midi pitch between x and x+y;
+#X text 213 109 x;
+#X text 263 142 y;
+#X obj 224 42 loadbang;
+#X msg 224 64 12;
+#X obj 117 54 inlet speed;
+#X connect 0 0 8 0;
+#X connect 1 0 3 0;
+#X connect 2 0 4 0;
+#X connect 3 0 7 0;
+#X connect 4 0 6 0;
+#X connect 5 0 9 0;
+#X connect 6 0 5 0;
+#X connect 6 1 5 1;
+#X connect 7 0 8 1;
+#X connect 7 1 5 0;
+#X connect 8 0 13 0;
+#X connect 9 0 13 1;
+#X connect 10 0 11 0;
+#X connect 12 0 0 0;
+#X connect 13 0 10 0;
+#X connect 17 0 18 0;
+#X connect 18 0 1 0;
+#X connect 18 0 2 0;
+#X connect 19 0 0 1;
+#X restore 53 130 pd choose_sines;
+#X obj 41 246 s msg_to_pyo;
+#X obj 53 96 tgl 25 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 1
+;
+#X obj 67 172 hsl 128 15 0 0.25 0 0 empty empty brightness -2 -8 0
+10 -262144 -1 -1 0 0;
+#X floatatom 64 188 5 0 0 0 - - -;
+#X msg 64 203 value feed \$1;
+#X obj 158 75 hsl 128 15 50 500 0 0 empty empty metro_speed -2 -8 0
+10 -262144 -1 -1 0 1;
+#X floatatom 155 93 5 0 0 0 - - -;
+#X floatatom 222 186 5 0 0 0 - - -;
+#X msg 222 216 set amp.fadeout \$1;
+#X msg 281 184 set amp.dur \$1;
+#X floatatom 281 165 5 0 0 0 - - -;
+#X obj 222 132 * 0.001;
+#X obj 221 111 - 20;
+#X obj 222 165 - 0.005;
+#X msg 41 33 read -a examples/random_waves.py;
+#X text 54 80 GO!;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 1 0;
+#X connect 6 0 7 0;
+#X connect 7 0 0 1;
+#X connect 7 0 13 0;
+#X connect 8 0 9 0;
+#X connect 9 0 1 0;
+#X connect 10 0 1 0;
+#X connect 11 0 10 0;
+#X connect 12 0 11 0;
+#X connect 12 0 14 0;
+#X connect 13 0 12 0;
+#X connect 14 0 8 0;
+#X connect 15 0 1 0;
+#X restore 531 84 pd synthesis_example;
+#N canvas 1 75 629 295 loop_soundfile 0;
+#X obj 43 42 openpanel;
+#X obj 43 64 t a b;
+#X obj 43 170 soundfiler;
+#X obj 236 80 bng 15 250 50 0 empty empty empty 17 7 0 10 -262144 -1
+-1;
+#X obj 43 20 inlet open file;
+#X obj 392 16 inlet start;
+#X obj 236 52 sel 1;
+#X obj 236 205 outlet~;
+#X obj 347 163 spigot 1;
+#X obj 43 126 pack s s s;
+#X obj 71 86 symbol \$0-table_l;
+#X obj 100 105 symbol \$0-table_r;
+#X msg 43 148 read -resize \$1 \$2 \$3;
+#X obj 44 200 table \$0-table_l;
+#X obj 44 223 table \$0-table_r;
+#X obj 423 206 outlet~;
+#X obj 236 140 tabplay~ \$0-table_l;
+#X obj 424 140 tabplay~ \$0-table_r;
+#X connect 0 0 1 0;
+#X connect 1 0 9 0;
+#X connect 1 1 10 0;
+#X connect 1 1 11 0;
+#X connect 3 0 16 0;
+#X connect 3 0 17 0;
+#X connect 4 0 0 0;
+#X connect 5 0 6 0;
+#X connect 5 0 8 1;
+#X connect 6 0 3 0;
+#X connect 8 0 16 0;
+#X connect 8 0 17 0;
+#X connect 9 0 12 0;
+#X connect 10 0 9 1;
+#X connect 11 0 9 2;
+#X connect 12 0 2 0;
+#X connect 16 0 7 0;
+#X connect 16 1 8 0;
+#X connect 17 0 15 0;
+#X restore 28 126 pd loop_soundfile;
+#X text 44 108 load file;
+#N canvas 1 75 532 224 conv_reverb_example 0;
+#X obj 24 110 hsl 128 15 0 1 0 0 empty empty balance -2 -8 0 10 -262144
+-1 -1 0 0;
+#X floatatom 21 127 5 0 0 0 - - -;
+#X msg 21 143 value bal \$1;
+#X obj -3 170 s msg_to_pyo;
+#X msg -3 74 read examples/cvlverb.py;
+#X text -5 38 load pyo processing file (audio signal must be given
+in pyo~ inputs).;
+#X text 162 110 balance between dry and wet signal;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 4 0 3 0;
+#X restore 531 36 pd conv_reverb_example;
+#X text 26 86 play a soundfile to send audio signals to pyo;
+#N canvas 114 140 450 300 README 0;
+#X restore 406 227 pd README;
+#N canvas 198 75 1001 402 MESSAGES 0;
+#X text 20 53 read [-a] path/to/python/script;
+#X text 37 74 The message "read" executes the commands contained in
+the specified python script into the object's internal interpreter.
+If the "-a" flag is given \, new commands will be added to previously
+executed ones. Without the flag \, the server is shut down (this will
+erase actual processing) before the execution of the script.;
+#X text 18 164 value varname \$1 [\$2 \$3 ...];
+#X text 19 250 set varname.attribute \$1 [\$2 \$3 ...];
+#X text 499 43 call function [arg1 arg2 ...];
+#X text 499 229 clear;
+#X text 516 250 Shutdown and reboot pyo's server. This message will
+erase the current processing loaded into the object.;
+#X text 36 185 The messsage "value" sends value(s) to a pyo's Sig or
+SigTo object (with variable name "varname"). Values can be pyo's variables
+(already created in the loaded file) \, float or list (composed of
+floats and/or pyo objects).;
+#X text 516 63 The message "call" executes the function (or object's
+method) with optional arguments. If the callable is a method \, the
+syntax will looks like:;
+#X text 515 103 call varname.method [arg1 arg2 ...];
+#X text 36 351 set frequencies 100 200 300 400 500 600;
+#X text 499 130 create varname object [\$1 \$2 ...];
+#X text -16 3 Here are the messages that can be used to control the
+internal processing of the pyo~ object.;
+#X text 513 149 The message "create" creates a new python object of
+the class "object" \, stored in variable "varname" \, with optional
+initialization arguments. Arguments can be of the form freq=500 or
+mul=0.3 \, without spaces. Named arguments can't be followed by unamed
+arguments.;
+#X text 36 272 The messsage "set" sends value(s) to an attribute of
+any pyo object (with variable name "varname"). Values can be pyo's
+variables (already created in the loaded file) \, float or list (composed
+of floats and/or pyo objects). This message can be used to create a
+standard python variable like (to create a list of floats in variable
+"frequencies"):;
+#X text 499 291 debug \$1;
+#X text 516 312 If \$1 is positive \, messages to pyo will be sent
+through an Exception handler. This is safer and can help to debug messages
+to pyo but it is slower. For a faster execution \, turn off debug mode.
+;
+#X restore 406 248 pd MESSAGES;
+#X msg 553 297 call b.out;
+#X text 11 7 pyo~ object allows to execute processing with pyo (python
+dsp module) inside a puredata patch \, with any number of audio in/out
+channels.;
+#X obj 531 121 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0
+1;
+#X msg 531 144 debug \$1;
+#X text 549 113 Verbose mode. If on \, error messages from pyo will
+be printed to the Pd window.;
+#X obj 518 323 s msg_to_pyo;
+#X msg 553 234 set pits 0.001 0.002 0.003 0.004;
+#X msg 553 255 create fr Rossler pitch=pits chaos=0.9 mul=250 add=500
+;
+#X msg 553 276 create b SumOsc freq=fr ratio=0.499 index=0.4 mul=0.2
+;
+#X connect 0 0 17 0;
+#X connect 1 0 17 1;
+#X connect 2 0 4 0;
+#X connect 3 0 4 1;
+#X connect 5 0 3 1;
+#X connect 5 0 2 1;
+#X connect 6 0 7 0;
+#X connect 8 0 10 0;
+#X connect 10 0 2 0;
+#X connect 10 1 3 0;
+#X connect 13 0 14 0;
+#X connect 17 0 10 0;
+#X connect 17 1 10 1;
+#X connect 23 0 28 0;
+#X connect 25 0 26 0;
+#X connect 26 0 14 0;
+#X connect 29 0 28 0;
+#X connect 30 0 28 0;
+#X connect 31 0 28 0;
diff --git a/embedded/puredata/pyo~-meta.pd b/embedded/puredata/pyo~-meta.pd
new file mode 100644
index 0000000..18a355f
--- /dev/null
+++ b/embedded/puredata/pyo~-meta.pd
@@ -0,0 +1,6 @@
+#N canvas 15 49 200 200 10;
+#N canvas 25 49 420 300 META 1;
+#X text 13 41 NAME pyo~;
+#X text 10 25 AUTHOR belangeo at gmail.com;
+#X text 10 10 VERSION 0.1;
+#X restore 10 10 pd META;
diff --git a/embedded/puredata/pyo~.c b/embedded/puredata/pyo~.c
new file mode 100644
index 0000000..1e675b1
--- /dev/null
+++ b/embedded/puredata/pyo~.c
@@ -0,0 +1,250 @@
+#include <stdlib.h>
+#include "m_pd.h"
+#include "Python.h"
+#include "m_pyo.h"
+
+static t_class *pyo_tilde_class;
+
+typedef struct _pyo_tilde {
+    t_object  obj;
+    t_sample  f;
+    int debug;
+    int bs;
+    int add;
+    int chnls;
+    float sr;
+    char *file;
+    t_sample **in;
+    t_sample **out;
+    int id;                 /* pyo server id */
+    float *inbuf;           /* pyo input buffer */
+    float *outbuf;          /* pyo output buffer */
+    char *msg;              /* preallocated string to construct message for pyo */
+    void (*callback)(int);  /* pointer to pyo embedded server callback */
+    PyThreadState *interp;  /* Python thread state linked to this sub interpreter */
+} t_pyo_tilde;
+
+t_int *pyo_tilde_perform(t_int *w) {
+    int i, j, n;
+    t_pyo_tilde *x = (t_pyo_tilde *)(w[1]); /* pointer to instance struct */
+    n = (int)(w[2]);                        /* vector size */
+    t_sample **in = x->in;
+    t_sample **out = x->out;
+    for (i=0; i<n; i++) {
+        for (j=0; j<x->chnls; j++) {
+            x->inbuf[i*x->chnls+j] = in[j][i];
+        }
+    }
+    (*x->callback)(x->id);
+    for (i=0; i<n; i++) {
+        for (j=0; j<x->chnls; j++) {
+            out[j][i] = x->outbuf[i*x->chnls+j];
+        }
+    }
+    return (w+3);
+}
+
+void pyo_tilde_dsp(t_pyo_tilde *x, t_signal **sp) {
+    int i, err;
+    t_sample **dummy = x->in;
+    for (i=0; i<x->chnls; i++)
+        *dummy++ = sp[i]->s_vec;
+    dummy = x->out;
+    for (i=x->chnls; i<x->chnls*2; i++)
+        *dummy++ = sp[i]->s_vec;
+    /* reset pyo only if sampling rate or buffer size have changed */
+    if ((float)sp[0]->s_sr != x->sr || (int)sp[0]->s_n != x->bs) {
+        x->sr = (float)sp[0]->s_sr;
+        x->bs = (int)sp[0]->s_n;
+        pyo_set_server_params(x->interp, x->sr, x->bs);
+        if (x->file != NULL) {
+            err = pyo_exec_file(x->interp, x->file, x->msg, x->add);
+            if (err) {
+                post("Unable to open file < %s >", x->file);
+                x->file = NULL;
+            }
+        }
+    }
+    dsp_add(pyo_tilde_perform, 2, x, sp[0]->s_n);
+}
+
+void *pyo_tilde_new(t_floatarg f) {
+    int i;
+    t_pyo_tilde *x = (t_pyo_tilde *)pd_new(pyo_tilde_class);
+
+    x->chnls = (f) ? f : 2;
+    x->bs = -1;
+    x->sr = -1.0;
+    x->file = NULL;
+    x->add = 0;
+    x->debug = 0;
+
+    /* create signal inlets (first is done in pyo_tilde_setup) */
+    for (i=1; i<x->chnls; i++)
+        inlet_new(&x->obj, &x->obj.ob_pd, &s_signal, &s_signal);
+    /* create signal outlets */
+    for (i=0; i<x->chnls; i++)
+        outlet_new(&x->obj, &s_signal);
+
+    x->in = (t_sample **)getbytes(x->chnls * sizeof(t_sample **));
+    x->out = (t_sample **)getbytes(x->chnls * sizeof(t_sample **));
+    x->msg = (char *)getbytes(262144 * sizeof(char *));
+
+    for (i=0; i<x->chnls; i++)
+        x->in[i] = x->out[i] = 0;
+
+    x->interp = pyo_new_interpreter(x->chnls);
+    
+    x->inbuf = (float *)pyo_get_input_buffer_address(x->interp);
+    x->outbuf = (float *)pyo_get_output_buffer_address(x->interp);
+    x->callback = (void *)pyo_get_embedded_callback_address(x->interp);
+    x->id = pyo_get_server_id(x->interp);
+
+    return (void *)x;
+}
+
+void pyo_tilde_free(t_pyo_tilde *x) {
+    freebytes(x->in, sizeof(x->in));
+    freebytes(x->out, sizeof(x->out));
+    freebytes(x->msg, sizeof(x->msg));
+    pyo_end_interpreter(x->interp);
+}
+
+void pyo_tilde_set_value(t_pyo_tilde *x, char *att, int argc, t_atom *argv) {
+    int err, bracket = 0;
+    char fchar[32];
+    t_symbol *c = atom_getsymbol(argv);
+    argc--; argv++;
+    sprintf(x->msg, "%s%s=", c->s_name, att);
+    if (argc > 1) {
+        strcat(x->msg, "[");
+        bracket = 1;    
+    }
+    while (argc-- > 0) {
+        if (argv->a_type == A_SYMBOL) {
+            strcat(x->msg, atom_getsymbol(argv)->s_name);
+        }
+        else if (argv->a_type == A_FLOAT) {
+            sprintf(fchar, "%.6f", atom_getfloat(argv));
+            strcat(x->msg, fchar);
+        }
+        if (argc > 0)
+            strcat(x->msg, ",");
+        argv++;
+    }
+    if (bracket)
+        strcat(x->msg, "]");
+    err = pyo_exec_statement(x->interp, x->msg, x->debug);
+    if (err)
+        post("pyo~: %s", x->msg);
+}
+
+void pyo_tilde_value(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+    char *att = ".value";
+    pyo_tilde_set_value(x, att, argc, argv);
+}
+void pyo_tilde_set(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+    char *att = "";
+    pyo_tilde_set_value(x, att, argc, argv);
+}
+
+void pyo_tilde_create(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+    int err;
+    char *varname, *object;
+    char fchar[32];
+    t_symbol *c = atom_getsymbol(argv);
+    varname = c->s_name;
+    argc--; argv++;
+    c = atom_getsymbol(argv);
+    object = c->s_name;
+    argc--; argv++;
+    sprintf(x->msg, "%s=%s(", varname, object);
+    while (argc-- > 0) {
+        if (argv->a_type == A_SYMBOL) {
+            strcat(x->msg, atom_getsymbol(argv)->s_name);
+        }
+        else if (argv->a_type == A_FLOAT) {
+            sprintf(fchar, "%f", atom_getfloat(argv));
+            strcat(x->msg, fchar);
+        }
+        if (argc > 0)
+            strcat(x->msg, ",");
+        argv++;
+    }
+    strcat(x->msg, ")");
+    err = pyo_exec_statement(x->interp, x->msg, x->debug);
+    if (err)
+        post("pyo~: %s", x->msg);
+}
+
+void pyo_tilde_clear(t_pyo_tilde *x) {
+    pyo_server_reboot(x->interp);
+}
+
+void pyo_tilde_debug(t_pyo_tilde *x, t_float debug) {
+    x->debug = debug <= 0 ? 0 : 1;
+}
+
+void pyo_tilde_read(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+    int err;
+    switch (argc) {
+        case 1:
+            x->add = 0;
+            x->file = atom_getsymbol(argv)->s_name;
+            break;
+        case 2:
+            x->add = strcmp(atom_getsymbol(argv++)->s_name, "-a") == 0 ? 1 : 0;
+            x->file = atom_getsymbol(argv)->s_name;
+            break;
+    }
+    if (pyo_is_server_started(x->interp)) { 
+        err = pyo_exec_file(x->interp, x->file, x->msg, x->add);
+        if (err) {
+            post("Unable to open file < %s >", x->file);
+            x->file = NULL;
+        }
+    }
+}
+
+void pyo_tilde_call(t_pyo_tilde *x, t_symbol *s, int argc, t_atom *argv) {
+    int err;
+    char fchar[32];
+    sprintf(x->msg, "%s(", atom_getsymbol(argv)->s_name);
+    argc--; argv++;
+    while (argc-- > 0) {
+        if (argv->a_type == A_SYMBOL) {
+            strcat(x->msg, atom_getsymbol(argv)->s_name);
+        }
+        else if (argv->a_type == A_FLOAT) {
+            sprintf(fchar, "%f", atom_getfloat(argv));
+            strcat(x->msg, fchar);
+        }
+        if (argc > 0)
+            strcat(x->msg, ", ");
+        argv++;
+    }
+    strcat(x->msg, ")");
+    err = pyo_exec_statement(x->interp, x->msg, x->debug);
+    if (err)
+        post("pyo~: %s", x->msg);
+}
+
+void pyo_tilde_setup(void) {
+    pyo_tilde_class = class_new(gensym("pyo~"), (t_newmethod)pyo_tilde_new,
+        (t_method)pyo_tilde_free, sizeof(t_pyo_tilde), CLASS_DEFAULT, A_DEFFLOAT, 0);
+    class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_dsp, gensym("dsp"), 0);
+    class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_clear, gensym("clear"), 0);
+    class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_value, gensym("value"), 
+                    A_GIMME, 0); /* send value(s) to a Sig or SigTo object */
+    class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_set, gensym("set"), 
+                    A_GIMME, 0); /* send value(s) to any object's attribute */
+    class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_read, gensym("read"), 
+                    A_GIMME, 0); /* read a script file */
+    class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_call, gensym("call"), 
+                    A_GIMME, 0); /* call a function or a method */
+    class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_create, gensym("create"), 
+                    A_GIMME, 0); /* create a python object */
+    class_addmethod(pyo_tilde_class, (t_method)pyo_tilde_debug, gensym("debug"), 
+                    A_DEFFLOAT, 0); /* set the debug (verbose) mode */
+    CLASS_MAINSIGNALIN(pyo_tilde_class, t_pyo_tilde, f);
+}
diff --git a/examples/utilities/02_osc_scan.py b/examples/utilities/02_osc_scan.py
new file mode 100644
index 0000000..442247e
--- /dev/null
+++ b/examples/utilities/02_osc_scan.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Scan Open Sound Control inputs. Launch this script from a terminal.
+
+"""
+from pyo import *
+import time
+
+port = input("Enter the incoming port number : ")
+
+s = Server().boot().start()
+
+print "Play with your OSC interface..."
+
+go = True
+def pp(address, *args): 
+    if go:
+        print "Address =", address
+        print "Values =", args
+        print "---------------"
+
+scan = OscDataReceive(port, "*", pp)
+
+again = "y"
+while again == "y":
+    time.sleep(10)
+    go = False
+    again = raw_input("Do you want to continue ? (y/n) : ")
+    if again == "y":
+        print "Continue..."
+        go = True
+    
+s.stop()
+time.sleep(1)
+exit()
+    
\ No newline at end of file
diff --git a/examples/utilities/04_batch_processing.py b/examples/utilities/04_batch_processing.py
index fa7b094..fa1f6b6 100644
--- a/examples/utilities/04_batch_processing.py
+++ b/examples/utilities/04_batch_processing.py
@@ -4,37 +4,46 @@
 This script demonstrates how to use pyo to do offline batch processing.
 
 """
-import os
 from pyo import *
-s = Server(duplex=0, audio="offline").boot()
-
-# input sound
-sndpath = SNDS_PATH + "/accord.aif"
-# output folder
-recpath = os.path.join(os.path.expanduser("~"), "Desktop", "pyo_batch")
-if not os.path.isdir(recpath):
-    os.mkdir(recpath)
-
-# output file duration
-dur = sndinfo(sndpath)[1]
-
-NUM = 10
-for i in range(NUM):
-    note = 12 + i
-    noteFreq = midiToHz(note)
-    s.recordOptions(dur=dur+.1, filename=os.path.join(recpath, "file_%02d.wav" % note), fileformat=0, sampletype=0)
-
-    ### processing goes here ###
-    osc = Sine(freq=noteFreq, mul=i*0.01+.02, add=1)
-    a = SfPlayer(sndpath, speed=osc, loop=False, mul=0.7).mix(2).out()
-
-    ############################
-
-    s.start() # s.stop() is automatically called when rendering is done
-    # do not reboot the server after the last pass
-    if i < (NUM-1):
-        s.shutdown()
-        s.boot()
-
-print "Batch processing done"
+import os
 
+s = Server(audio="offline")
+
+# path to your sound folder
+folder_path = SNDS_PATH
+# path to the processed sounds folder (user's home directory/batch)
+output_folder = os.path.join(os.path.expanduser("~"), "pyo_batch_fx")
+# create it if it does not exist
+if not os.path.isdir(output_folder):
+    os.mkdir(output_folder)
+
+# get the list of files to process
+sounds = [file for file in os.listdir(folder_path) if sndinfo(os.path.join(folder_path, file)) != None]
+
+# enter the batch processing loop
+for sound in sounds:
+    # retrieve info about the sound
+    path = os.path.join(folder_path, sound)
+    info = sndinfo(path)
+    dur, sr, chnls = info[1], info[2], info[3]
+    fformat = ['WAVE', 'AIFF', 'AU', 'RAW', 'SD2', 'FLAC', 'CAF', 'OGG'].index(info[4])
+    samptype = ['16 bit int', '24 bit int', '32 bit int', '32 bit float', 
+                '64 bits float', 'U-Law encoded', 'A-Law encoded'].index(info[5])
+
+    # set server parameters
+    s.setSamplingRate(sr)
+    s.setNchnls(chnls)
+    s.boot()
+    s.recordOptions(dur=dur, filename=os.path.join(output_folder, sound), 
+                    fileformat=fformat, sampletype=samptype)
+    
+    # processing
+    sf = SfPlayer(path)
+    bp = ButBP(sf, 1000, 2)
+    dt = Disto(bp, drive=0.9, slope=0.8)
+    mx = Interp(sf, dt, interp=0.5, mul=0.5).out()
+    
+    # start the render
+    s.start()
+    # cleanup
+    s.shutdown()
diff --git a/examples/utilities/04_batch_synthesis.py b/examples/utilities/04_batch_synthesis.py
new file mode 100644
index 0000000..8b32246
--- /dev/null
+++ b/examples/utilities/04_batch_synthesis.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+This script demonstrates how to use pyo to do synthesis batch generation.
+
+"""
+import os
+from pyo import *
+s = Server(duplex=0, audio="offline")
+
+# output folder
+output_folder = os.path.join(os.path.expanduser("~"), "pyo_batch_synth")
+if not os.path.isdir(output_folder):
+    os.mkdir(output_folder)
+
+# output file duration
+dur = 2
+
+NUM = 12
+for i in range(NUM):
+    s.boot()
+    note = 60 + i
+    noteFreq = midiToHz(note)
+    s.recordOptions(dur=dur+.1, filename=os.path.join(output_folder, "file_%02d.wav" % note), 
+                    fileformat=0, sampletype=0)
+
+    ### processing goes here ###
+    env = Adsr(attack=0.005, decay=0.15, sustain=0.7, release=1.7, dur=dur).play()
+    qenv = Pow(env, 4, mul=0.8)
+    osc1 = SineLoop(freq=noteFreq, feedback=0.075, mul=qenv).out()
+    osc2 = SineLoop(freq=noteFreq*1.01, feedback=0.075, mul=qenv).out(1)
+
+    # start th render
+    s.start()
+    # cleanup
+    s.shutdown()
+
+print "Batch processing done"
+
diff --git a/examples/utilities/07_scope.py b/examples/utilities/07_scope.py
new file mode 100644
index 0000000..4af4ec3
--- /dev/null
+++ b/examples/utilities/07_scope.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Simple scope example.
+
+"""
+from pyo import *
+
+class Scope:
+    def __init__(self, input, length=0.05):
+        self.input = input
+        self.table = NewTable(length=length, chnls=len(input))
+        self.table.view(title="Signal Scope")
+        self.trig = Metro(time=length).play()
+        self.rec = TrigTableRec(self.input, self.trig, self.table)
+        self.trf = TrigFunc(self.trig, function=self.update)
+
+    def start(self, x):
+        if x: self.trig.play()
+        else: self.trig.stop()
+
+    def update(self):
+        self.table.refreshView()
+
+s = Server(duplex=1).boot()
+
+CHNLS = 2
+LENGTH = 0.05
+
+inp = Input(chnl=range(CHNLS))
+scope = Scope(inp, LENGTH)
+
+s.gui(locals())
diff --git a/externals/external-template.py b/externals/external-template.py
index 1ee8e92..3cdca10 100644
--- a/externals/external-template.py
+++ b/externals/external-template.py
@@ -41,12 +41,10 @@ class Gain(PyoObject):
     """
     # Do not forget "mul" and "add" attributes.
     def __init__(self, input, db=-3, mul=1, add=0):
-        PyoObject.__init__(self)
+        PyoObject.__init__(self, mul, add)
         # Keep trace of arguments (same name preceded by an underscore)
         self._input = input
         self._db = db
-        self._mul = mul
-        self._add = add
         # Always use InputFader for the input sound. That allows crossfade on input changes.  
         self._in_fader = InputFader(input)
         # Converts every arguments to lists (for multi-channel expansion).
diff --git a/include/pyomodule.h b/include/pyomodule.h
index ce4ba6c..a8b9c71 100644
--- a/include/pyomodule.h
+++ b/include/pyomodule.h
@@ -21,7 +21,7 @@
 #include "Python.h"
 #include <math.h>
 
-#define PYO_VERSION "0.6.8"
+#define PYO_VERSION "0.7.4"
 
 #ifndef __MYFLT_DEF
 #define __MYFLT_DEF
@@ -38,6 +38,8 @@
 #define TYPE__FII "|fii"
 #define TYPE_F_II "f|ii"
 #define TYPE__FFF "|fff"
+#define TYPE_F_FFF "f|fff"
+#define TYPE_O_FIFFI "O|fiffi"
 #define TYPE_O_F "O|f"
 #define TYPE_O_FO "O|fO"
 #define TYPE__OF "|Of"
@@ -73,6 +75,7 @@
 #define TYPE__OFII "|Ofii"
 #define TYPE__FIIOO "|fiiOO"
 #define TYPE_O_OFOO "O|OfOO"
+#define TYPE_O_OOOOFF "O|OOOOff"
 #define TYPE_O_IFFO "O|iffO"
 #define TYPE_O_OOIF "O|OOif"
 #define TYPE_O_FFFFIOO "O|ffffiOO"
@@ -105,6 +108,7 @@
 #define MYATAN2 atan2f
 #define MYEXP expf
 #define MYROUND roundf
+#define MYTANH tanhf
 
 #else
 #define LIB_BASE_NAME "_pyo64"
@@ -118,6 +122,8 @@
 #define TYPE__FII "|dii"
 #define TYPE_F_II "d|ii"
 #define TYPE__FFF "|ddd"
+#define TYPE_F_FFF "d|ddd"
+#define TYPE_O_FIFFI "O|diddi"
 #define TYPE_O_F "O|d"
 #define TYPE_O_FO "O|dO"
 #define TYPE__OF "|Od"
@@ -153,6 +159,7 @@
 #define TYPE__OFII "|Odii"
 #define TYPE__FIIOO "|diiOO"
 #define TYPE_O_OFOO "O|OdOO"
+#define TYPE_O_OOOOFF "O|OOOOdd"
 #define TYPE_O_IFFO "O|iddO"
 #define TYPE_O_OOIF "O|OOid"
 #define TYPE_O_FFFFIOO "O|ddddiOO"
@@ -185,7 +192,7 @@
 #define MYATAN2 atan2
 #define MYEXP exp
 #define MYROUND round
-
+#define MYTANH tanh
 
 #endif
 #endif
@@ -302,6 +309,7 @@ extern PyTypeObject CtlScanType;
 extern PyTypeObject CtlScan2Type;
 extern PyTypeObject MidiNoteType;
 extern PyTypeObject NoteinType;
+extern PyTypeObject NoteinTrigType;
 extern PyTypeObject BendinType;
 extern PyTypeObject TouchinType;
 extern PyTypeObject PrograminType;
@@ -395,6 +403,7 @@ extern PyTypeObject ScaleType;
 extern PyTypeObject CentsToTranspoType;
 extern PyTypeObject TranspoToCentsType;
 extern PyTypeObject MToFType;
+extern PyTypeObject FToMType;
 extern PyTypeObject MToTType;
 extern PyTypeObject M_SinType;
 extern PyTypeObject M_CosType;
@@ -409,6 +418,7 @@ extern PyTypeObject M_Atan2Type;
 extern PyTypeObject M_FloorType;
 extern PyTypeObject M_CeilType;
 extern PyTypeObject M_RoundType;
+extern PyTypeObject M_TanhType;
 extern PyTypeObject FFTMainType;
 extern PyTypeObject FFTType;
 extern PyTypeObject IFFTType;
@@ -455,6 +465,24 @@ extern PyTypeObject PVBufTabLoopsType;
 extern PyTypeObject PVMixType;
 extern PyTypeObject GranuleType;
 extern PyTypeObject TableScaleType;
+extern PyTypeObject TrackHoldType;
+extern PyTypeObject ComplexResType;
+extern PyTypeObject STReverbType;
+extern PyTypeObject STRevType;
+extern PyTypeObject Pointer2Type;
+extern PyTypeObject CentroidType;
+extern PyTypeObject AttackDetectorType;
+extern PyTypeObject SmoothDelayType;
+extern PyTypeObject TrigBursterType;
+extern PyTypeObject TrigBurstType;
+extern PyTypeObject TrigBurstTapStreamType;
+extern PyTypeObject TrigBurstAmpStreamType;
+extern PyTypeObject TrigBurstDurStreamType;
+extern PyTypeObject TrigBurstEndStreamType;
+extern PyTypeObject ScopeType;
+extern PyTypeObject PeakAmpType;
+extern PyTypeObject MainParticleType;
+extern PyTypeObject ParticleType;
 
 /* Constants */
 #define E M_E
@@ -492,6 +520,9 @@ extern PyTypeObject TableScaleType;
 #define FREEVERB_ID 24
 #define XNOISEDUR_ID 25
 #define URN_ID 26
+#define GRANULE_ID 27
+#define MAINPARTICLE_ID 28
+/* Do not forget to modify Server_generateSeed function */
 
 /* object headers */
 #define pyo_audio_HEAD \
@@ -578,11 +609,8 @@ extern PyTypeObject TableScaleType;
 /* INIT INPUT STREAM */
 #define INIT_INPUT_STREAM \
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "server") == 0 ) { \
-        PySys_WriteStderr("TypeError: \"input\" argument must be a PyoObject.\n"); \
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) { \
-            PyObject_CallMethod(self->server, "shutdown", NULL); \
-        } \
-        Py_Exit(1); \
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument must be a PyoObject.\n"); \
+        Py_RETURN_NONE; \
     } \
     Py_INCREF(inputtmp); \
     Py_XDECREF(self->input); \
@@ -637,13 +665,14 @@ extern PyTypeObject TableScaleType;
         PyErr_SetString(PyExc_TypeError, "The data must be a list of floats."); \
         return PyInt_FromLong(-1); \
     } \
-    self->size = PyList_Size(arg)-1; \
+    self->size = PyList_Size(arg); \
     self->data = (MYFLT *)realloc(self->data, (self->size+1) * sizeof(MYFLT)); \
     TableStream_setSize(self->tablestream, self->size+1); \
  \
-    for (i=0; i<(self->size+1); i++) { \
+    for (i=0; i<(self->size); i++) { \
         self->data[i] = PyFloat_AS_DOUBLE(PyNumber_Float(PyList_GET_ITEM(arg, i))); \
     } \
+    self->data[self->size] = self->data[0]; \
     TableStream_setData(self->tablestream, self->data); \
  \
     Py_INCREF(Py_None); \
@@ -720,21 +749,44 @@ extern PyTypeObject TableScaleType;
     return samples;
 
 #define GET_VIEW_TABLE \
-    int i, y; \
-    int w = 500; \
-    int h = 200; \
-    int h2 = h/2; \
-    int amp = h2 - 2; \
-    float step = (float)self->size / (float)(w); \
-    PyObject *samples; \
+    int i, y, w, h, h2, amp; \
+    float step; \
+    PyObject *samples, *tuple, *sizetmp = NULL; \
+ \
+    static char *kwlist[] = {"size", NULL}; \
  \
-    samples = PyList_New(w*4); \
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &sizetmp)) \
+        return PyInt_FromLong(-1); \
+ \
+    if (sizetmp) { \
+        if (PyTuple_Check(sizetmp)) { \
+            w = PyInt_AsLong(PyTuple_GET_ITEM(sizetmp, 0)); \
+            h = PyInt_AsLong(PyTuple_GET_ITEM(sizetmp, 1)); \
+        } \
+        else if (PyList_Check(sizetmp)) { \
+            w = PyInt_AsLong(PyList_GET_ITEM(sizetmp, 0)); \
+            h = PyInt_AsLong(PyList_GET_ITEM(sizetmp, 1)); \
+        } \
+        else { \
+            w = 500; \
+            h = 200; \
+        } \
+    } \
+    else { \
+        w = 500; \
+        h = 200; \
+    } \
+    h2 = h/2; \
+    amp = h2 - 2; \
+    step = (float)self->size / (float)(w); \
+ \
+    samples = PyList_New(w); \
     for(i=0; i<w; i++) { \
-        y = self->data[(int)(i*step)] * amp + amp; \
-        PyList_SetItem(samples, i*4, PyInt_FromLong(i)); \
-        PyList_SetItem(samples, i*4+1, PyInt_FromLong(h-y)); \
-        PyList_SetItem(samples, i*4+2, PyInt_FromLong(i)); \
-        PyList_SetItem(samples, i*4+3, PyInt_FromLong(h-y)); \
+        y = self->data[(int)(i*step)] * amp + amp + 2; \
+        tuple = PyTuple_New(2); \
+        PyTuple_SetItem(tuple, 0, PyInt_FromLong(i)); \
+        PyTuple_SetItem(tuple, 1, PyInt_FromLong(h-y)); \
+        PyList_SetItem(samples, i, tuple); \
     } \
  \
     return samples;
@@ -776,6 +828,128 @@ extern PyTypeObject TableScaleType;
     Py_INCREF(Py_None); \
     return Py_None; \
 
+/* Table amplitude reverse */
+#define INVERT \
+    int i; \
+    for (i=0; i<self->size+1; i++) { \
+        self->data[i] = -self->data[i]; \
+    } \
+    Py_INCREF(Py_None); \
+    return Py_None; \
+
+/* Table positive rectify */
+#define RECTIFY \
+    int i; \
+    MYFLT x; \
+    for (i=0; i<self->size+1; i++) { \
+        x = self->data[i]; \
+        if (x < 0) \
+            self->data[i] = -x; \
+    } \
+    Py_INCREF(Py_None); \
+    return Py_None; \
+
+/* Table bipolar gain */
+#define TABLE_BIPOLAR_GAIN \
+    MYFLT gpos = 1.0, gneg = 1.0; \
+    int i; \
+    static char *kwlist[] = {"gpos", "gneg", NULL}; \
+ \
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE__FF, kwlist, &gpos, &gneg)) \
+        return PyInt_FromLong(-1); \
+ \
+    for (i=0; i<self->size+1; i++) { \
+        if (self->data[i] < 0) \
+            self->data[i] *= gneg; \
+        else \
+            self->data[i] *= gpos; \
+    } \
+ \
+    Py_RETURN_NONE;
+
+/* Table power function */
+#define TABLE_POWER \
+    MYFLT x, exp; \
+    int i, sign; \
+    static char *kwlist[] = {"exp", NULL}; \
+ \
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F, kwlist, &exp)) \
+        return PyInt_FromLong(-1); \
+ \
+    for (i=0; i<self->size+1; i++) { \
+        x = self->data[i]; \
+        sign = 1; \
+        if (x < 0) \
+            sign = -1; \
+        x = MYPOW(x, exp); \
+        if (sign == -1 && x > 0) \
+            x = -x; \
+        self->data[i] = x; \
+    } \
+ \
+    Py_RETURN_NONE;
+
+/* Table one-pole lowpass filter */
+#define TABLE_LOWPASS \
+    MYFLT freq, b, c, x, y; \
+    int i; \
+    double sr = PyFloat_AsDouble(PyObject_CallMethod(PyServer_get_server(), "getSamplingRate", NULL)); \
+    static char *kwlist[] = {"freq", NULL}; \
+ \
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F, kwlist, &freq)) \
+        return PyInt_FromLong(-1); \
+ \
+    b = 2.0 - MYCOS(TWOPI * freq / sr); \
+    c = b - MYSQRT(b * b - 1.0); \
+    y = 0; \
+    for (i=0; i<self->size+1; i++) { \
+        x = self->data[i]; \
+        self->data[i] = y = x + (y - x) * c; \
+    } \
+ \
+    Py_RETURN_NONE;
+
+/* FADE IN, FADE OUT */
+#define TABLE_FADEIN \
+    MYFLT dur, inc; \
+    int i, samp; \
+    double sr = PyFloat_AsDouble(PyObject_CallMethod(PyServer_get_server(), "getSamplingRate", NULL)); \
+    static char *kwlist[] = {"dur", NULL}; \
+ \
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F, kwlist, &dur)) \
+        return PyInt_FromLong(-1); \
+ \
+    samp = (int)(dur * sr); \
+    if (samp < 0 || samp >= self->size) \
+        Py_RETURN_NONE; \
+ \
+    inc = 1.0 / samp; \
+    for (i=0; i<samp; i++) { \
+        self->data[i] = self->data[i] * MYSQRT(inc * i); \
+    } \
+ \
+    Py_RETURN_NONE;
+
+#define TABLE_FADEOUT \
+    MYFLT dur, inc; \
+    int i, samp; \
+    double sr = PyFloat_AsDouble(PyObject_CallMethod(PyServer_get_server(), "getSamplingRate", NULL)); \
+    static char *kwlist[] = {"dur", NULL}; \
+ \
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F, kwlist, &dur)) \
+        return PyInt_FromLong(-1); \
+ \
+    samp = (int)(dur * sr); \
+    if (samp < 0 || samp >= self->size) \
+        Py_RETURN_NONE; \
+ \
+    inc = 1.0 / samp; \
+    for (i=self->size; i>(self->size-samp); i--) { \
+        self->data[i] = self->data[i] * MYSQRT(inc * (self->size - i)); \
+    } \
+ \
+    Py_RETURN_NONE;
+
 /* Normalize */
 #define NORMALIZE \
 	int i; \
diff --git a/include/servermodule.h b/include/servermodule.h
index 396ed16..0fedc69 100644
--- a/include/servermodule.h
+++ b/include/servermodule.h
@@ -70,8 +70,12 @@ typedef struct {
     char *serverName; /* Only used for jack client name */
     int jackautoin; /* jack port auto-connection (on by default) */
     int jackautoout; /* jack port auto-connection (on by default) */
-    PmStream *in;
-    PmStream *out;
+    PyObject *jackAutoConnectInputPorts; /* list of regex to match for jack auto-connection */
+    PyObject *jackAutoConnectOutputPorts; /* list of regex to match for jack auto-connection */
+    PmStream *midiin[64];
+    PmStream *midiout[64];
+    int midiin_count;
+    int midiout_count;
     PmEvent midiEvents[200];
     int midi_count;
     double samplingRate;
diff --git a/installers/osx/PkgResources_i386/License.rtf b/installers/osx/PkgResources_i386/License.rtf
deleted file mode 100755
index 66b2d2a..0000000
--- a/installers/osx/PkgResources_i386/License.rtf
+++ /dev/null
@@ -1,681 +0,0 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
-{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
-{\colortbl;\red255\green255\blue255;}
-\margl1440\margr1440\vieww10100\viewh11340\viewkind0
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
-
-\f0\fs26 \cf0                     GNU GENERAL PUBLIC LICENSE\
-                       Version 3, 29 June 2007\
-\
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\
- Everyone is permitted to copy and distribute verbatim copies\
- of this license document, but changing it is not allowed.\
-\
-                            Preamble\
-\
-  The GNU General Public License is a free, copyleft license for\
-software and other kinds of works.\
-\
-  The licenses for most software and other practical works are designed\
-to take away your freedom to share and change the works.  By contrast,\
-the GNU General Public License is intended to guarantee your freedom to\
-share and change all versions of a program--to make sure it remains free\
-software for all its users.  We, the Free Software Foundation, use the\
-GNU General Public License for most of our software; it applies also to\
-any other work released this way by its authors.  You can apply it to\
-your programs, too.\
-\
-  When we speak of free software, we are referring to freedom, not\
-price.  Our General Public Licenses are designed to make sure that you\
-have the freedom to distribute copies of free software (and charge for\
-them if you wish), that you receive source code or can get it if you\
-want it, that you can change the software or use pieces of it in new\
-free programs, and that you know you can do these things.\
-\
-  To protect your rights, we need to prevent others from denying you\
-these rights or asking you to surrender the rights.  Therefore, you have\
-certain responsibilities if you distribute copies of the software, or if\
-you modify it: responsibilities to respect the freedom of others.\
-\
-  For example, if you distribute copies of such a program, whether\
-gratis or for a fee, you must pass on to the recipients the same\
-freedoms that you received.  You must make sure that they, too, receive\
-or can get the source code.  And you must show them these terms so they\
-know their rights.\
-\
-  Developers that use the GNU GPL protect your rights with two steps:\
-(1) assert copyright on the software, and (2) offer you this License\
-giving you legal permission to copy, distribute and/or modify it.\
-\
-  For the developers' and authors' protection, the GPL clearly explains\
-that there is no warranty for this free software.  For both users' and\
-authors' sake, the GPL requires that modified versions be marked as\
-changed, so that their problems will not be attributed erroneously to\
-authors of previous versions.\
-\
-  Some devices are designed to deny users access to install or run\
-modified versions of the software inside them, although the manufacturer\
-can do so.  This is fundamentally incompatible with the aim of\
-protecting users' freedom to change the software.  The systematic\
-pattern of such abuse occurs in the area of products for individuals to\
-use, which is precisely where it is most unacceptable.  Therefore, we\
-have designed this version of the GPL to prohibit the practice for those\
-products.  If such problems arise substantially in other domains, we\
-stand ready to extend this provision to those domains in future versions\
-of the GPL, as needed to protect the freedom of users.\
-\
-  Finally, every program is threatened constantly by software patents.\
-States should not allow patents to restrict development and use of\
-software on general-purpose computers, but in those that do, we wish to\
-avoid the special danger that patents applied to a free program could\
-make it effectively proprietary.  To prevent this, the GPL assures that\
-patents cannot be used to render the program non-free.\
-\
-  The precise terms and conditions for copying, distribution and\
-modification follow.\
-\
-                       TERMS AND CONDITIONS\
-\
-  0. Definitions.\
-\
-  "This License" refers to version 3 of the GNU General Public License.\
-\
-  "Copyright" also means copyright-like laws that apply to other kinds of\
-works, such as semiconductor masks.\
-\
-  "The Program" refers to any copyrightable work licensed under this\
-License.  Each licensee is addressed as "you".  "Licensees" and\
-"recipients" may be individuals or organizations.\
-\
-  To "modify" a work means to copy from or adapt all or part of the work\
-in a fashion requiring copyright permission, other than the making of an\
-exact copy.  The resulting work is called a "modified version" of the\
-earlier work or a work "based on" the earlier work.\
-\
-  A "covered work" means either the unmodified Program or a work based\
-on the Program.\
-\
-  To "propagate" a work means to do anything with it that, without\
-permission, would make you directly or secondarily liable for\
-infringement under applicable copyright law, except executing it on a\
-computer or modifying a private copy.  Propagation includes copying,\
-distribution (with or without modification), making available to the\
-public, and in some countries other activities as well.\
-\
-  To "convey" a work means any kind of propagation that enables other\
-parties to make or receive copies.  Mere interaction with a user through\
-a computer network, with no transfer of a copy, is not conveying.\
-\
-  An interactive user interface displays "Appropriate Legal Notices"\
-to the extent that it includes a convenient and prominently visible\
-feature that (1) displays an appropriate copyright notice, and (2)\
-tells the user that there is no warranty for the work (except to the\
-extent that warranties are provided), that licensees may convey the\
-work under this License, and how to view a copy of this License.  If\
-the interface presents a list of user commands or options, such as a\
-menu, a prominent item in the list meets this criterion.\
-\
-  1. Source Code.\
-\
-  The "source code" for a work means the preferred form of the work\
-for making modifications to it.  "Object code" means any non-source\
-form of a work.\
-\
-  A "Standard Interface" means an interface that either is an official\
-standard defined by a recognized standards body, or, in the case of\
-interfaces specified for a particular programming language, one that\
-is widely used among developers working in that language.\
-\
-  The "System Libraries" of an executable work include anything, other\
-than the work as a whole, that (a) is included in the normal form of\
-packaging a Major Component, but which is not part of that Major\
-Component, and (b) serves only to enable use of the work with that\
-Major Component, or to implement a Standard Interface for which an\
-implementation is available to the public in source code form.  A\
-"Major Component", in this context, means a major essential component\
-(kernel, window system, and so on) of the specific operating system\
-(if any) on which the executable work runs, or a compiler used to\
-produce the work, or an object code interpreter used to run it.\
-\
-  The "Corresponding Source" for a work in object code form means all\
-the source code needed to generate, install, and (for an executable\
-work) run the object code and to modify the work, including scripts to\
-control those activities.  However, it does not include the work's\
-System Libraries, or general-purpose tools or generally available free\
-programs which are used unmodified in performing those activities but\
-which are not part of the work.  For example, Corresponding Source\
-includes interface definition files associated with source files for\
-the work, and the source code for shared libraries and dynamically\
-linked subprograms that the work is specifically designed to require,\
-such as by intimate data communication or control flow between those\
-subprograms and other parts of the work.\
-\
-  The Corresponding Source need not include anything that users\
-can regenerate automatically from other parts of the Corresponding\
-Source.\
-\
-  The Corresponding Source for a work in source code form is that\
-same work.\
-\
-  2. Basic Permissions.\
-\
-  All rights granted under this License are granted for the term of\
-copyright on the Program, and are irrevocable provided the stated\
-conditions are met.  This License explicitly affirms your unlimited\
-permission to run the unmodified Program.  The output from running a\
-covered work is covered by this License only if the output, given its\
-content, constitutes a covered work.  This License acknowledges your\
-rights of fair use or other equivalent, as provided by copyright law.\
-\
-  You may make, run and propagate covered works that you do not\
-convey, without conditions so long as your license otherwise remains\
-in force.  You may convey covered works to others for the sole purpose\
-of having them make modifications exclusively for you, or provide you\
-with facilities for running those works, provided that you comply with\
-the terms of this License in conveying all material for which you do\
-not control copyright.  Those thus making or running the covered works\
-for you must do so exclusively on your behalf, under your direction\
-and control, on terms that prohibit them from making any copies of\
-your copyrighted material outside their relationship with you.\
-\
-  Conveying under any other circumstances is permitted solely under\
-the conditions stated below.  Sublicensing is not allowed; section 10\
-makes it unnecessary.\
-\
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\
-\
-  No covered work shall be deemed part of an effective technological\
-measure under any applicable law fulfilling obligations under article\
-11 of the WIPO copyright treaty adopted on 20 December 1996, or\
-similar laws prohibiting or restricting circumvention of such\
-measures.\
-\
-  When you convey a covered work, you waive any legal power to forbid\
-circumvention of technological measures to the extent such circumvention\
-is effected by exercising rights under this License with respect to\
-the covered work, and you disclaim any intention to limit operation or\
-modification of the work as a means of enforcing, against the work's\
-users, your or third parties' legal rights to forbid circumvention of\
-technological measures.\
-\
-  4. Conveying Verbatim Copies.\
-\
-  You may convey verbatim copies of the Program's source code as you\
-receive it, in any medium, provided that you conspicuously and\
-appropriately publish on each copy an appropriate copyright notice;\
-keep intact all notices stating that this License and any\
-non-permissive terms added in accord with section 7 apply to the code;\
-keep intact all notices of the absence of any warranty; and give all\
-recipients a copy of this License along with the Program.\
-\
-  You may charge any price or no price for each copy that you convey,\
-and you may offer support or warranty protection for a fee.\
-\
-  5. Conveying Modified Source Versions.\
-\
-  You may convey a work based on the Program, or the modifications to\
-produce it from the Program, in the form of source code under the\
-terms of section 4, provided that you also meet all of these conditions:\
-\
-    a) The work must carry prominent notices stating that you modified\
-    it, and giving a relevant date.\
-\
-    b) The work must carry prominent notices stating that it is\
-    released under this License and any conditions added under section\
-    7.  This requirement modifies the requirement in section 4 to\
-    "keep intact all notices".\
-\
-    c) You must license the entire work, as a whole, under this\
-    License to anyone who comes into possession of a copy.  This\
-    License will therefore apply, along with any applicable section 7\
-    additional terms, to the whole of the work, and all its parts,\
-    regardless of how they are packaged.  This License gives no\
-    permission to license the work in any other way, but it does not\
-    invalidate such permission if you have separately received it.\
-\
-    d) If the work has interactive user interfaces, each must display\
-    Appropriate Legal Notices; however, if the Program has interactive\
-    interfaces that do not display Appropriate Legal Notices, your\
-    work need not make them do so.\
-\
-  A compilation of a covered work with other separate and independent\
-works, which are not by their nature extensions of the covered work,\
-and which are not combined with it such as to form a larger program,\
-in or on a volume of a storage or distribution medium, is called an\
-"aggregate" if the compilation and its resulting copyright are not\
-used to limit the access or legal rights of the compilation's users\
-beyond what the individual works permit.  Inclusion of a covered work\
-in an aggregate does not cause this License to apply to the other\
-parts of the aggregate.\
-\
-  6. Conveying Non-Source Forms.\
-\
-  You may convey a covered work in object code form under the terms\
-of sections 4 and 5, provided that you also convey the\
-machine-readable Corresponding Source under the terms of this License,\
-in one of these ways:\
-\
-    a) Convey the object code in, or embodied in, a physical product\
-    (including a physical distribution medium), accompanied by the\
-    Corresponding Source fixed on a durable physical medium\
-    customarily used for software interchange.\
-\
-    b) Convey the object code in, or embodied in, a physical product\
-    (including a physical distribution medium), accompanied by a\
-    written offer, valid for at least three years and valid for as\
-    long as you offer spare parts or customer support for that product\
-    model, to give anyone who possesses the object code either (1) a\
-    copy of the Corresponding Source for all the software in the\
-    product that is covered by this License, on a durable physical\
-    medium customarily used for software interchange, for a price no\
-    more than your reasonable cost of physically performing this\
-    conveying of source, or (2) access to copy the\
-    Corresponding Source from a network server at no charge.\
-\
-    c) Convey individual copies of the object code with a copy of the\
-    written offer to provide the Corresponding Source.  This\
-    alternative is allowed only occasionally and noncommercially, and\
-    only if you received the object code with such an offer, in accord\
-    with subsection 6b.\
-\
-    d) Convey the object code by offering access from a designated\
-    place (gratis or for a charge), and offer equivalent access to the\
-    Corresponding Source in the same way through the same place at no\
-    further charge.  You need not require recipients to copy the\
-    Corresponding Source along with the object code.  If the place to\
-    copy the object code is a network server, the Corresponding Source\
-    may be on a different server (operated by you or a third party)\
-    that supports equivalent copying facilities, provided you maintain\
-    clear directions next to the object code saying where to find the\
-    Corresponding Source.  Regardless of what server hosts the\
-    Corresponding Source, you remain obligated to ensure that it is\
-    available for as long as needed to satisfy these requirements.\
-\
-    e) Convey the object code using peer-to-peer transmission, provided\
-    you inform other peers where the object code and Corresponding\
-    Source of the work are being offered to the general public at no\
-    charge under subsection 6d.\
-\
-  A separable portion of the object code, whose source code is excluded\
-from the Corresponding Source as a System Library, need not be\
-included in conveying the object code work.\
-\
-  A "User Product" is either (1) a "consumer product", which means any\
-tangible personal property which is normally used for personal, family,\
-or household purposes, or (2) anything designed or sold for incorporation\
-into a dwelling.  In determining whether a product is a consumer product,\
-doubtful cases shall be resolved in favor of coverage.  For a particular\
-product received by a particular user, "normally used" refers to a\
-typical or common use of that class of product, regardless of the status\
-of the particular user or of the way in which the particular user\
-actually uses, or expects or is expected to use, the product.  A product\
-is a consumer product regardless of whether the product has substantial\
-commercial, industrial or non-consumer uses, unless such uses represent\
-the only significant mode of use of the product.\
-\
-  "Installation Information" for a User Product means any methods,\
-procedures, authorization keys, or other information required to install\
-and execute modified versions of a covered work in that User Product from\
-a modified version of its Corresponding Source.  The information must\
-suffice to ensure that the continued functioning of the modified object\
-code is in no case prevented or interfered with solely because\
-modification has been made.\
-\
-  If you convey an object code work under this section in, or with, or\
-specifically for use in, a User Product, and the conveying occurs as\
-part of a transaction in which the right of possession and use of the\
-User Product is transferred to the recipient in perpetuity or for a\
-fixed term (regardless of how the transaction is characterized), the\
-Corresponding Source conveyed under this section must be accompanied\
-by the Installation Information.  But this requirement does not apply\
-if neither you nor any third party retains the ability to install\
-modified object code on the User Product (for example, the work has\
-been installed in ROM).\
-\
-  The requirement to provide Installation Information does not include a\
-requirement to continue to provide support service, warranty, or updates\
-for a work that has been modified or installed by the recipient, or for\
-the User Product in which it has been modified or installed.  Access to a\
-network may be denied when the modification itself materially and\
-adversely affects the operation of the network or violates the rules and\
-protocols for communication across the network.\
-\
-  Corresponding Source conveyed, and Installation Information provided,\
-in accord with this section must be in a format that is publicly\
-documented (and with an implementation available to the public in\
-source code form), and must require no special password or key for\
-unpacking, reading or copying.\
-\
-  7. Additional Terms.\
-\
-  "Additional permissions" are terms that supplement the terms of this\
-License by making exceptions from one or more of its conditions.\
-Additional permissions that are applicable to the entire Program shall\
-be treated as though they were included in this License, to the extent\
-that they are valid under applicable law.  If additional permissions\
-apply only to part of the Program, that part may be used separately\
-under those permissions, but the entire Program remains governed by\
-this License without regard to the additional permissions.\
-\
-  When you convey a copy of a covered work, you may at your option\
-remove any additional permissions from that copy, or from any part of\
-it.  (Additional permissions may be written to require their own\
-removal in certain cases when you modify the work.)  You may place\
-additional permissions on material, added by you to a covered work,\
-for which you have or can give appropriate copyright permission.\
-\
-  Notwithstanding any other provision of this License, for material you\
-add to a covered work, you may (if authorized by the copyright holders of\
-that material) supplement the terms of this License with terms:\
-\
-    a) Disclaiming warranty or limiting liability differently from the\
-    terms of sections 15 and 16 of this License; or\
-\
-    b) Requiring preservation of specified reasonable legal notices or\
-    author attributions in that material or in the Appropriate Legal\
-    Notices displayed by works containing it; or\
-\
-    c) Prohibiting misrepresentation of the origin of that material, or\
-    requiring that modified versions of such material be marked in\
-    reasonable ways as different from the original version; or\
-\
-    d) Limiting the use for publicity purposes of names of licensors or\
-    authors of the material; or\
-\
-    e) Declining to grant rights under trademark law for use of some\
-    trade names, trademarks, or service marks; or\
-\
-    f) Requiring indemnification of licensors and authors of that\
-    material by anyone who conveys the material (or modified versions of\
-    it) with contractual assumptions of liability to the recipient, for\
-    any liability that these contractual assumptions directly impose on\
-    those licensors and authors.\
-\
-  All other non-permissive additional terms are considered "further\
-restrictions" within the meaning of section 10.  If the Program as you\
-received it, or any part of it, contains a notice stating that it is\
-governed by this License along with a term that is a further\
-restriction, you may remove that term.  If a license document contains\
-a further restriction but permits relicensing or conveying under this\
-License, you may add to a covered work material governed by the terms\
-of that license document, provided that the further restriction does\
-not survive such relicensing or conveying.\
-\
-  If you add terms to a covered work in accord with this section, you\
-must place, in the relevant source files, a statement of the\
-additional terms that apply to those files, or a notice indicating\
-where to find the applicable terms.\
-\
-  Additional terms, permissive or non-permissive, may be stated in the\
-form of a separately written license, or stated as exceptions;\
-the above requirements apply either way.\
-\
-  8. Termination.\
-\
-  You may not propagate or modify a covered work except as expressly\
-provided under this License.  Any attempt otherwise to propagate or\
-modify it is void, and will automatically terminate your rights under\
-this License (including any patent licenses granted under the third\
-paragraph of section 11).\
-\
-  However, if you cease all violation of this License, then your\
-license from a particular copyright holder is reinstated (a)\
-provisionally, unless and until the copyright holder explicitly and\
-finally terminates your license, and (b) permanently, if the copyright\
-holder fails to notify you of the violation by some reasonable means\
-prior to 60 days after the cessation.\
-\
-  Moreover, your license from a particular copyright holder is\
-reinstated permanently if the copyright holder notifies you of the\
-violation by some reasonable means, this is the first time you have\
-received notice of violation of this License (for any work) from that\
-copyright holder, and you cure the violation prior to 30 days after\
-your receipt of the notice.\
-\
-  Termination of your rights under this section does not terminate the\
-licenses of parties who have received copies or rights from you under\
-this License.  If your rights have been terminated and not permanently\
-reinstated, you do not qualify to receive new licenses for the same\
-material under section 10.\
-\
-  9. Acceptance Not Required for Having Copies.\
-\
-  You are not required to accept this License in order to receive or\
-run a copy of the Program.  Ancillary propagation of a covered work\
-occurring solely as a consequence of using peer-to-peer transmission\
-to receive a copy likewise does not require acceptance.  However,\
-nothing other than this License grants you permission to propagate or\
-modify any covered work.  These actions infringe copyright if you do\
-not accept this License.  Therefore, by modifying or propagating a\
-covered work, you indicate your acceptance of this License to do so.\
-\
-  10. Automatic Licensing of Downstream Recipients.\
-\
-  Each time you convey a covered work, the recipient automatically\
-receives a license from the original licensors, to run, modify and\
-propagate that work, subject to this License.  You are not responsible\
-for enforcing compliance by third parties with this License.\
-\
-  An "entity transaction" is a transaction transferring control of an\
-organization, or substantially all assets of one, or subdividing an\
-organization, or merging organizations.  If propagation of a covered\
-work results from an entity transaction, each party to that\
-transaction who receives a copy of the work also receives whatever\
-licenses to the work the party's predecessor in interest had or could\
-give under the previous paragraph, plus a right to possession of the\
-Corresponding Source of the work from the predecessor in interest, if\
-the predecessor has it or can get it with reasonable efforts.\
-\
-  You may not impose any further restrictions on the exercise of the\
-rights granted or affirmed under this License.  For example, you may\
-not impose a license fee, royalty, or other charge for exercise of\
-rights granted under this License, and you may not initiate litigation\
-(including a cross-claim or counterclaim in a lawsuit) alleging that\
-any patent claim is infringed by making, using, selling, offering for\
-sale, or importing the Program or any portion of it.\
-\
-  11. Patents.\
-\
-  A "contributor" is a copyright holder who authorizes use under this\
-License of the Program or a work on which the Program is based.  The\
-work thus licensed is called the contributor's "contributor version".\
-\
-  A contributor's "essential patent claims" are all patent claims\
-owned or controlled by the contributor, whether already acquired or\
-hereafter acquired, that would be infringed by some manner, permitted\
-by this License, of making, using, or selling its contributor version,\
-but do not include claims that would be infringed only as a\
-consequence of further modification of the contributor version.  For\
-purposes of this definition, "control" includes the right to grant\
-patent sublicenses in a manner consistent with the requirements of\
-this License.\
-\
-  Each contributor grants you a non-exclusive, worldwide, royalty-free\
-patent license under the contributor's essential patent claims, to\
-make, use, sell, offer for sale, import and otherwise run, modify and\
-propagate the contents of its contributor version.\
-\
-  In the following three paragraphs, a "patent license" is any express\
-agreement or commitment, however denominated, not to enforce a patent\
-(such as an express permission to practice a patent or covenant not to\
-sue for patent infringement).  To "grant" such a patent license to a\
-party means to make such an agreement or commitment not to enforce a\
-patent against the party.\
-\
-  If you convey a covered work, knowingly relying on a patent license,\
-and the Corresponding Source of the work is not available for anyone\
-to copy, free of charge and under the terms of this License, through a\
-publicly available network server or other readily accessible means,\
-then you must either (1) cause the Corresponding Source to be so\
-available, or (2) arrange to deprive yourself of the benefit of the\
-patent license for this particular work, or (3) arrange, in a manner\
-consistent with the requirements of this License, to extend the patent\
-license to downstream recipients.  "Knowingly relying" means you have\
-actual knowledge that, but for the patent license, your conveying the\
-covered work in a country, or your recipient's use of the covered work\
-in a country, would infringe one or more identifiable patents in that\
-country that you have reason to believe are valid.\
-\
-  If, pursuant to or in connection with a single transaction or\
-arrangement, you convey, or propagate by procuring conveyance of, a\
-covered work, and grant a patent license to some of the parties\
-receiving the covered work authorizing them to use, propagate, modify\
-or convey a specific copy of the covered work, then the patent license\
-you grant is automatically extended to all recipients of the covered\
-work and works based on it.\
-\
-  A patent license is "discriminatory" if it does not include within\
-the scope of its coverage, prohibits the exercise of, or is\
-conditioned on the non-exercise of one or more of the rights that are\
-specifically granted under this License.  You may not convey a covered\
-work if you are a party to an arrangement with a third party that is\
-in the business of distributing software, under which you make payment\
-to the third party based on the extent of your activity of conveying\
-the work, and under which the third party grants, to any of the\
-parties who would receive the covered work from you, a discriminatory\
-patent license (a) in connection with copies of the covered work\
-conveyed by you (or copies made from those copies), or (b) primarily\
-for and in connection with specific products or compilations that\
-contain the covered work, unless you entered into that arrangement,\
-or that patent license was granted, prior to 28 March 2007.\
-\
-  Nothing in this License shall be construed as excluding or limiting\
-any implied license or other defenses to infringement that may\
-otherwise be available to you under applicable patent law.\
-\
-  12. No Surrender of Others' Freedom.\
-\
-  If conditions are imposed on you (whether by court order, agreement or\
-otherwise) that contradict the conditions of this License, they do not\
-excuse you from the conditions of this License.  If you cannot convey a\
-covered work so as to satisfy simultaneously your obligations under this\
-License and any other pertinent obligations, then as a consequence you may\
-not convey it at all.  For example, if you agree to terms that obligate you\
-to collect a royalty for further conveying from those to whom you convey\
-the Program, the only way you could satisfy both those terms and this\
-License would be to refrain entirely from conveying the Program.\
-\
-  13. Use with the GNU Affero General Public License.\
-\
-  Notwithstanding any other provision of this License, you have\
-permission to link or combine any covered work with a work licensed\
-under version 3 of the GNU Affero General Public License into a single\
-combined work, and to convey the resulting work.  The terms of this\
-License will continue to apply to the part which is the covered work,\
-but the special requirements of the GNU Affero General Public License,\
-section 13, concerning interaction through a network will apply to the\
-combination as such.\
-\
-  14. Revised Versions of this License.\
-\
-  The Free Software Foundation may publish revised and/or new versions of\
-the GNU General Public License from time to time.  Such new versions will\
-be similar in spirit to the present version, but may differ in detail to\
-address new problems or concerns.\
-\
-  Each version is given a distinguishing version number.  If the\
-Program specifies that a certain numbered version of the GNU General\
-Public License "or any later version" applies to it, you have the\
-option of following the terms and conditions either of that numbered\
-version or of any later version published by the Free Software\
-Foundation.  If the Program does not specify a version number of the\
-GNU General Public License, you may choose any version ever published\
-by the Free Software Foundation.\
-\
-  If the Program specifies that a proxy can decide which future\
-versions of the GNU General Public License can be used, that proxy's\
-public statement of acceptance of a version permanently authorizes you\
-to choose that version for the Program.\
-\
-  Later license versions may give you additional or different\
-permissions.  However, no additional obligations are imposed on any\
-author or copyright holder as a result of your choosing to follow a\
-later version.\
-\
-  15. Disclaimer of Warranty.\
-\
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY\
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\
-\
-  16. Limitation of Liability.\
-\
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\
-SUCH DAMAGES.\
-\
-  17. Interpretation of Sections 15 and 16.\
-\
-  If the disclaimer of warranty and limitation of liability provided\
-above cannot be given local legal effect according to their terms,\
-reviewing courts shall apply local law that most closely approximates\
-an absolute waiver of all civil liability in connection with the\
-Program, unless a warranty or assumption of liability accompanies a\
-copy of the Program in return for a fee.\
-\
-                     END OF TERMS AND CONDITIONS\
-\
-            How to Apply These Terms to Your New Programs\
-\
-  If you develop a new program, and you want it to be of the greatest\
-possible use to the public, the best way to achieve this is to make it\
-free software which everyone can redistribute and change under these terms.\
-\
-  To do so, attach the following notices to the program.  It is safest\
-to attach them to the start of each source file to most effectively\
-state the exclusion of warranty; and each file should have at least\
-the "copyright" line and a pointer to where the full notice is found.\
-\
-    <one line to give the program's name and a brief idea of what it does.>\
-    Copyright (C) <year>  <name of author>\
-\
-    This program is free software: you can redistribute it and/or modify\
-    it under the terms of the GNU General Public License as published by\
-    the Free Software Foundation, either version 3 of the License, or\
-    (at your option) any later version.\
-\
-    This program is distributed in the hope that it will be useful,\
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\
-    GNU General Public License for more details.\
-\
-    You should have received a copy of the GNU General Public License\
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.\
-\
-Also add information on how to contact you by electronic and paper mail.\
-\
-  If the program does terminal interaction, make it output a short\
-notice like this when it starts in an interactive mode:\
-\
-    <program>  Copyright (C) <year>  <name of author>\
-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\
-    This is free software, and you are welcome to redistribute it\
-    under certain conditions; type `show c' for details.\
-\
-The hypothetical commands `show w' and `show c' should show the appropriate\
-parts of the General Public License.  Of course, your program's commands\
-might be different; for a GUI interface, you would use an "about box".\
-\
-  You should also get your employer (if you work as a programmer) or school,\
-if any, to sign a "copyright disclaimer" for the program, if necessary.\
-For more information on this, and how to apply and follow the GNU GPL, see\
-<http://www.gnu.org/licenses/>.\
-\
-  The GNU General Public License does not permit incorporating your program\
-into proprietary programs.  If your program is a subroutine library, you\
-may consider it more useful to permit linking proprietary applications with\
-the library.  If this is what you want to do, use the GNU Lesser General\
-Public License instead of this License.  But first, please read\
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.\
-}
\ No newline at end of file
diff --git a/installers/osx/PkgResources_i386/ReadMe.rtf b/installers/osx/PkgResources_i386/ReadMe.rtf
deleted file mode 100755
index da986d8..0000000
--- a/installers/osx/PkgResources_i386/ReadMe.rtf
+++ /dev/null
@@ -1,71 +0,0 @@
-{\rtf1\ansi\deff3\adeflang1025
-{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset1 LucidaGrande;}{\f6\froman\fprq0\fcharset1 LucidaGrande;}{\f7\fnil\fprq2\fcharset0 DejaVu Sans;}{\f8\fnil\fprq2\fcharset0 Lohit Hindi;}{\f9\fnil\fprq0\fcharset1 Lohit Hindi;}}
-{\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
-{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105 Normal;}
-{\s15\sbasedon0\snext16\sb240\sa120\keepn\dbch\af7\dbch\af8\afs28\loch\f4\fs28 Heading;}
-{\s16\sbasedon0\snext16\sb0\sa120 Text body;}
-{\s17\sbasedon16\snext17\sb0\sa120\dbch\af9 List;}
-{\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af9\afs24\ai\fs24 Caption;}
-{\s19\sbasedon0\snext19\noline\dbch\af9 Index;}
-}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern3600}}\deftab720
-\viewscale110
-{\*\pgdsctbl
-{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default;}}
-\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
-\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-pyo (version 0.6.}{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-6}{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-)}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-This package installs all the required components to run pyo inside your current Python installation. Python 2.5, 2.6 (preferred) or 2.7 (32-bit Mac OS X Installer) must be already installed on your system.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-This package is divided into two separate installers. If you do not require one of them, please unselect the package in custom installation mode.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
-1. pyo extension:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-The following components will be installed in the site-packages folder of the current Python Framework:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-_pyo.so}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-_pyo64.so}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-pyo.py}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-pyo64.py}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-pyolib (folder)}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
-2. Support libraries (i386):}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-This component will install a number of dynamic libraries on which pyo depends. If you already have these, then you can skip this installation.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
-Warning:}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
- this installation will overwrite any previously installed libraries. These are the libraries that will be installed in your /usr/local/lib directory:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-liblo.0.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-libportaudio.2.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-libportmidi.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-libsndfile.1.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-Olivier B\u233\'e9langer, 201}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-3}
-\par }
\ No newline at end of file
diff --git a/installers/osx/PkgResources_i386/Welcome.rtf b/installers/osx/PkgResources_i386/Welcome.rtf
deleted file mode 100755
index b8b9917..0000000
--- a/installers/osx/PkgResources_i386/Welcome.rtf
+++ /dev/null
@@ -1,7 +0,0 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
-{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
-{\colortbl;\red255\green255\blue255;}
-\margl1440\margr1440\vieww10100\viewh11340\viewkind0
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
-
-\f0\fs26 \cf0 You are about to install pyo in your computer. This includes the pyo Python module and support libs.}
\ No newline at end of file
diff --git a/installers/osx/PkgResources_i386/postinstall b/installers/osx/PkgResources_i386/postinstall
deleted file mode 100755
index 21e721a..0000000
--- a/installers/osx/PkgResources_i386/postinstall
+++ /dev/null
@@ -1,106 +0,0 @@
-#! /bin/sh
-
-VERSION=`sw_vers -productVersion | sed -e 's/\.//g'`
-
-if [ $VERSION -ge '1070' ]; then
-    echo "Install pyo on OSX 10.7";
-elif [ $VERSION -ge '1060' ]; then
-    echo "Install pyo on OSX 10.6";
-else
-    echo "Install pyo on OSX 10.5";
-fi
-
-# Removed older versions in the python site-packages builtin directories
-# Removed older versions in the python site-packages from python.org install directories
-PATHS=/Library/Python/2.5/site-packages/:/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
-for path in ${PATHS//:/ }; do
-    if cd $path; then
-        if [ -f pyo.py ]; then
-            sudo rm pyo.py;
-        fi    
-        if [ -f pyo64.py ]; then
-            sudo rm pyo64.py;
-        fi    
-        if [ -f pyo.pyc ]; then
-            sudo rm pyo.pyc;
-        fi    
-        if [ -f pyo64.pyc ]; then
-            sudo rm pyo64.pyc;
-        fi    
-        if [ -f _pyo.so ]; then
-            sudo rm _pyo.so;
-        fi    
-        if [ -f _pyo64.so ]; then
-            sudo rm _pyo64.so;
-        fi    
-        if [ -d pyolib ]; then
-            sudo rm -rf pyolib/;
-        fi    
-        ls -1 pyo*-info > /dev/null 2>&1
-        if [ "$?" = "0" ]; then
-            sudo rm pyo*-info;
-        fi    
-    fi
-done
-
-# Install pyo in the python site-packages builtin directories
-if [ $VERSION -ge '1070' ]; then
-    if cd /Library/Python/2.7/site-packages/; then
-        sudo cp -r /tmp/python27/* .
-    else
-        sudo mkdir -p /Library/Python/2.7/site-packages/
-        cd /Library/Python/2.7/site-packages/
-        sudo cp -r /tmp/python27/* .
-    fi
-else
-    if cd /Library/Python/2.6/site-packages/; then
-        sudo cp -r /tmp/python26/* .
-    else
-        sudo mkdir -p /Library/Python/2.6/site-packages/
-        cd /Library/Python/2.6/site-packages/
-        sudo cp -r /tmp/python26/* .
-    fi
-fi
-
-# Install pyo in the python site-packages from python.org install directories
-if cd /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/; then
-    sudo cp -r /tmp/python26/* .
-else
-    sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/
-    cd /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/
-    sudo cp -r /tmp/python26/* .
-fi
-
-if cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/; then  
-    sudo cp -r /tmp/python27/* .
-else
-    sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
-    cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
-    sudo cp -r /tmp/python27/* .
-fi
-
-sudo rm -rf /tmp/python2*
-
-# Add /usr/local/lib in .bash_profile if not already done
-searchString="/usr/local/lib"
-
-if [ -f ~/.bash_profile ]; then
-    if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
-        echo "path already in PATH variable";
-    else
-        echo "adding path to .bash_profile..."
-        echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" >> ~/.bash_profile;
-    fi
-else
-    echo "creating .bash_profile and adding path to it..."
-	echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" > ~/.bash_profile;
-fi	
-
-# Add VERSIONER_PYTHON_PREFER_32_BIT in .bash_profile if not already done
-searchString="VERSIONER_PYTHON_PREFER_32_BIT"
-
-if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
-    echo "Variable VERSIONER_PYTHON_PREFER_32_BIT already set.";
-else
-    echo "export VERSIONER_PYTHON_PREFER_32_BIT=yes" >> ~/.bash_profile;
-fi
diff --git a/installers/osx/PkgResources_i386/postupgrade b/installers/osx/PkgResources_i386/postupgrade
deleted file mode 100755
index 21e721a..0000000
--- a/installers/osx/PkgResources_i386/postupgrade
+++ /dev/null
@@ -1,106 +0,0 @@
-#! /bin/sh
-
-VERSION=`sw_vers -productVersion | sed -e 's/\.//g'`
-
-if [ $VERSION -ge '1070' ]; then
-    echo "Install pyo on OSX 10.7";
-elif [ $VERSION -ge '1060' ]; then
-    echo "Install pyo on OSX 10.6";
-else
-    echo "Install pyo on OSX 10.5";
-fi
-
-# Removed older versions in the python site-packages builtin directories
-# Removed older versions in the python site-packages from python.org install directories
-PATHS=/Library/Python/2.5/site-packages/:/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
-for path in ${PATHS//:/ }; do
-    if cd $path; then
-        if [ -f pyo.py ]; then
-            sudo rm pyo.py;
-        fi    
-        if [ -f pyo64.py ]; then
-            sudo rm pyo64.py;
-        fi    
-        if [ -f pyo.pyc ]; then
-            sudo rm pyo.pyc;
-        fi    
-        if [ -f pyo64.pyc ]; then
-            sudo rm pyo64.pyc;
-        fi    
-        if [ -f _pyo.so ]; then
-            sudo rm _pyo.so;
-        fi    
-        if [ -f _pyo64.so ]; then
-            sudo rm _pyo64.so;
-        fi    
-        if [ -d pyolib ]; then
-            sudo rm -rf pyolib/;
-        fi    
-        ls -1 pyo*-info > /dev/null 2>&1
-        if [ "$?" = "0" ]; then
-            sudo rm pyo*-info;
-        fi    
-    fi
-done
-
-# Install pyo in the python site-packages builtin directories
-if [ $VERSION -ge '1070' ]; then
-    if cd /Library/Python/2.7/site-packages/; then
-        sudo cp -r /tmp/python27/* .
-    else
-        sudo mkdir -p /Library/Python/2.7/site-packages/
-        cd /Library/Python/2.7/site-packages/
-        sudo cp -r /tmp/python27/* .
-    fi
-else
-    if cd /Library/Python/2.6/site-packages/; then
-        sudo cp -r /tmp/python26/* .
-    else
-        sudo mkdir -p /Library/Python/2.6/site-packages/
-        cd /Library/Python/2.6/site-packages/
-        sudo cp -r /tmp/python26/* .
-    fi
-fi
-
-# Install pyo in the python site-packages from python.org install directories
-if cd /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/; then
-    sudo cp -r /tmp/python26/* .
-else
-    sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/
-    cd /Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/
-    sudo cp -r /tmp/python26/* .
-fi
-
-if cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/; then  
-    sudo cp -r /tmp/python27/* .
-else
-    sudo mkdir -p /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
-    cd /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
-    sudo cp -r /tmp/python27/* .
-fi
-
-sudo rm -rf /tmp/python2*
-
-# Add /usr/local/lib in .bash_profile if not already done
-searchString="/usr/local/lib"
-
-if [ -f ~/.bash_profile ]; then
-    if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
-        echo "path already in PATH variable";
-    else
-        echo "adding path to .bash_profile..."
-        echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" >> ~/.bash_profile;
-    fi
-else
-    echo "creating .bash_profile and adding path to it..."
-	echo "export PATH=/usr/local/lib:/usr/local/bin:\$PATH" > ~/.bash_profile;
-fi	
-
-# Add VERSIONER_PYTHON_PREFER_32_BIT in .bash_profile if not already done
-searchString="VERSIONER_PYTHON_PREFER_32_BIT"
-
-if `cat ~/.bash_profile | grep "${searchString}" 1>/dev/null 2>&1`; then
-    echo "Variable VERSIONER_PYTHON_PREFER_32_BIT already set.";
-else
-    echo "export VERSIONER_PYTHON_PREFER_32_BIT=yes" >> ~/.bash_profile;
-fi
diff --git a/installers/osx/PkgResources_x86_64/ReadMe.rtf b/installers/osx/PkgResources_x86_64/ReadMe.rtf
index d6db53b..7339a3b 100755
--- a/installers/osx/PkgResources_x86_64/ReadMe.rtf
+++ b/installers/osx/PkgResources_x86_64/ReadMe.rtf
@@ -1,75 +1,82 @@
 {\rtf1\ansi\deff3\adeflang1025
-{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset1 LucidaGrande;}{\f6\froman\fprq0\fcharset1 LucidaGrande;}{\f7\fnil\fprq2\fcharset0 DejaVu Sans;}{\f8\fnil\fprq2\fcharset0 Lohit Hindi;}{\f9\fnil\fprq0\fcharset1 Lohit Hindi;}}
+{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\fswiss\fprq2\fcharset0 Liberation Sans{\*\falt Arial};}{\f5\froman\fprq2\fcharset0 LucidaGrande;}{\f6\fnil\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f7\fnil\fprq2\fcharset0 FreeSans;}{\f8\fswiss\fprq0\fcharset128 FreeSans;}}
 {\colortbl;\red0\green0\blue0;\red128\green128\blue128;}
-{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105 Normal;}
-{\s15\sbasedon0\snext16\sb240\sa120\keepn\dbch\af7\dbch\af8\afs28\loch\f4\fs28 Heading;}
-{\s16\sbasedon0\snext16\sb0\sa120 Text body;}
-{\s17\sbasedon16\snext17\sb0\sa120\dbch\af9 List;}
-{\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af9\afs24\ai\fs24 Caption;}
-{\s19\sbasedon0\snext19\noline\dbch\af9 Index;}
-}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\revtim\yr0\mo0\dy0\hr0\min0}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern3600}}\deftab720
-\viewscale110
+{\stylesheet{\s0\snext0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084 Normal;}
+{\s15\sbasedon0\snext16\ql\nowidctlpar\sb240\sa120\keepn\ltrpar\cf1\kerning1\dbch\af7\langfe1081\dbch\af7\afs28\loch\f4\fs28\lang3084 Heading;}
+{\s16\sbasedon0\snext16\sl288\slmult1\ql\nowidctlpar\sb0\sa140\ltrpar\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\loch\f3\fs24\lang3084 Text Body;}
+{\s17\sbasedon16\snext17\sl288\slmult1\ql\nowidctlpar\sb0\sa140\ltrpar\cf1\kerning1\dbch\af7\langfe1081\dbch\af8\afs24\loch\f3\fs24\lang3084 List;}
+{\s18\sbasedon0\snext18\ql\nowidctlpar\sb120\sa120\noline\ltrpar\cf1\i\kerning1\dbch\af7\langfe1081\dbch\af8\afs24\ai\loch\f3\fs24\lang3084 Caption;}
+{\s19\sbasedon0\snext19\ql\nowidctlpar\noline\ltrpar\cf1\kerning1\dbch\af7\langfe1081\dbch\af8\afs24\loch\f3\fs24\lang3084 Index;}
+}{\info{\creatim\yr0\mo0\dy0\hr0\min0}{\author olivier }{\revtim\yr2015\mo1\dy29\hr19\min33}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern67306242}}\deftab720
+\viewscale100
 {\*\pgdsctbl
-{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default;}}
+{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\pgdscnxt0 Default Style;}}
 \formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1440\margr1440\margt1440\margb1440\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
-\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-pyo (version 0.6.}{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-6}{\cf1\rtlch \ltrch\loch\fs26\loch\f6
+{\*\ftnsep}\pgndec\pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+Python-pyo (version 0.7.}{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+4}{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 )}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-System requirements : OS X 10.6 or 10.7}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+System requirements : OS X 10.6 to 10.9}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
-This package installs all the required components to run pyo inside your current Python installation. Python 2.6 or 2.7 (64-bit) must be already installed on your system.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+This package installs all the required components to run pyo inside your current Python installation. Python 2.6 or 2.7 (32/64 bit) must be already installed on your system.}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 This package is divided into two separate installers. If you do not require one of them, please unselect the package in custom installation mode.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 1. pyo extension:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 The following components will be installed in the site-packages folder of the current Python Framework:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 _pyo.so}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 _pyo64.so}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 pyo.py}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 pyo64.py}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 pyolib (folder)}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 2. Support libraries (i386 and x86_64):}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 This component will install a number of dynamic libraries on which pyo depends. If you already have these, then you can skip this installation.}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\rtlch \ltrch\loch\fs26\loch\f6
-Warning:}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+Warning:}{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
  this installation will overwrite any previously installed libraries. These are the libraries that will be installed in your /usr/local/lib directory:}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 liblo.7.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 libportaudio.2.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 libportmidi.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 libsndfile.1.dylib}
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105\ql\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+libFLAC.8.dylib}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+libvorbisenc.2.dylib}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+libvorbis.0.dylib}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+libogg.0.dylib}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
 
-\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\dbch\af7\langfe2052\dbch\af8\afs24\alang1081\loch\f3\fs24\lang4105{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-Olivier B\u233\'e9langer, 201}{\cf1\b0\rtlch \ltrch\loch\fs26\loch\f6
-3}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf1\kerning1\dbch\af6\langfe1081\dbch\af6\afs24\alang1081\loch\f3\fs24\lang3084\ql\nowidctlpar{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+Olivier B\u233\'e9langer, 2014}
 \par }
\ No newline at end of file
diff --git a/installers/osx/PkgResources_x86_64/postinstall b/installers/osx/PkgResources_x86_64/postinstall
index ade04c8..ddcb4ab 100755
--- a/installers/osx/PkgResources_x86_64/postinstall
+++ b/installers/osx/PkgResources_x86_64/postinstall
@@ -1,15 +1,6 @@
 #! /bin/sh
 
-VERSION=`sw_vers -productVersion | sed -e 's/\.//g'`
-
-if [ $VERSION -ge '1070' ]; then
-    echo "Install pyo on OSX 10.7";
-else
-    echo "Install pyo on OSX 10.6";
-fi
-
-# Removed older versions in the python site-packages builtin directories
-# Removed older versions in the python site-packages from python.org install directories
+# Removed older versions in the python site-packages builtin and in the python site-packages from python.org directories
 PATHS=/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
 for path in ${PATHS//:/ }; do
     if cd $path; then
@@ -42,22 +33,20 @@ for path in ${PATHS//:/ }; do
 done
 
 # Install pyo in the python site-packages builtin directories
-if [ $VERSION -ge '1070' ]; then
-    if cd /Library/Python/2.7/site-packages/; then
-        sudo cp -r /tmp/python27/* .
-    else
-        sudo mkdir -p /Library/Python/2.7/site-packages/
-        cd /Library/Python/2.7/site-packages/
-        sudo cp -r /tmp/python27/* .
-    fi
+if cd /Library/Python/2.7/site-packages/; then
+    sudo cp -r /tmp/python27/* .
 else
-    if cd /Library/Python/2.6/site-packages/; then
-        sudo cp -r /tmp/python26/* .
-    else
-        sudo mkdir -p /Library/Python/2.6/site-packages/
-        cd /Library/Python/2.6/site-packages/
-        sudo cp -r /tmp/python26/* .
-    fi
+    sudo mkdir -p /Library/Python/2.7/site-packages/
+    cd /Library/Python/2.7/site-packages/
+    sudo cp -r /tmp/python27/* .
+fi
+
+if cd /Library/Python/2.6/site-packages/; then
+    sudo cp -r /tmp/python26/* .
+else
+    sudo mkdir -p /Library/Python/2.6/site-packages/
+    cd /Library/Python/2.6/site-packages/
+    sudo cp -r /tmp/python26/* .
 fi
 
 # Install pyo in the python.org site-packages directories
@@ -77,6 +66,15 @@ else
     sudo cp -r /tmp/python27/* .
 fi
 
+# Check if anaconda is already installed and copy files to site-packages directory
+if cd ~/anaconda/lib/python2.6/site-packages/; then  
+    sudo cp -r /tmp/python26/* .
+fi
+
+if cd ~/anaconda/lib/python2.7/site-packages/; then  
+    sudo cp -r /tmp/python27/* .
+fi
+
 sudo rm -rf /tmp/python2*
 
 # Add /usr/local/lib in .bash_profile if not already done
diff --git a/installers/osx/PkgResources_x86_64/postupgrade b/installers/osx/PkgResources_x86_64/postupgrade
index ade04c8..ddcb4ab 100755
--- a/installers/osx/PkgResources_x86_64/postupgrade
+++ b/installers/osx/PkgResources_x86_64/postupgrade
@@ -1,15 +1,6 @@
 #! /bin/sh
 
-VERSION=`sw_vers -productVersion | sed -e 's/\.//g'`
-
-if [ $VERSION -ge '1070' ]; then
-    echo "Install pyo on OSX 10.7";
-else
-    echo "Install pyo on OSX 10.6";
-fi
-
-# Removed older versions in the python site-packages builtin directories
-# Removed older versions in the python site-packages from python.org install directories
+# Removed older versions in the python site-packages builtin and in the python site-packages from python.org directories
 PATHS=/Library/Python/2.6/site-packages/:/Library/Python/2.7/site-packages/:/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/:/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/
 for path in ${PATHS//:/ }; do
     if cd $path; then
@@ -42,22 +33,20 @@ for path in ${PATHS//:/ }; do
 done
 
 # Install pyo in the python site-packages builtin directories
-if [ $VERSION -ge '1070' ]; then
-    if cd /Library/Python/2.7/site-packages/; then
-        sudo cp -r /tmp/python27/* .
-    else
-        sudo mkdir -p /Library/Python/2.7/site-packages/
-        cd /Library/Python/2.7/site-packages/
-        sudo cp -r /tmp/python27/* .
-    fi
+if cd /Library/Python/2.7/site-packages/; then
+    sudo cp -r /tmp/python27/* .
 else
-    if cd /Library/Python/2.6/site-packages/; then
-        sudo cp -r /tmp/python26/* .
-    else
-        sudo mkdir -p /Library/Python/2.6/site-packages/
-        cd /Library/Python/2.6/site-packages/
-        sudo cp -r /tmp/python26/* .
-    fi
+    sudo mkdir -p /Library/Python/2.7/site-packages/
+    cd /Library/Python/2.7/site-packages/
+    sudo cp -r /tmp/python27/* .
+fi
+
+if cd /Library/Python/2.6/site-packages/; then
+    sudo cp -r /tmp/python26/* .
+else
+    sudo mkdir -p /Library/Python/2.6/site-packages/
+    cd /Library/Python/2.6/site-packages/
+    sudo cp -r /tmp/python26/* .
 fi
 
 # Install pyo in the python.org site-packages directories
@@ -77,6 +66,15 @@ else
     sudo cp -r /tmp/python27/* .
 fi
 
+# Check if anaconda is already installed and copy files to site-packages directory
+if cd ~/anaconda/lib/python2.6/site-packages/; then  
+    sudo cp -r /tmp/python26/* .
+fi
+
+if cd ~/anaconda/lib/python2.7/site-packages/; then  
+    sudo cp -r /tmp/python27/* .
+fi
+
 sudo rm -rf /tmp/python2*
 
 # Add /usr/local/lib in .bash_profile if not already done
diff --git a/installers/osx/release_i386.sh b/installers/osx/release_i386.sh
deleted file mode 100644
index 7fc5e31..0000000
--- a/installers/osx/release_i386.sh
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/sh
-
-# Need Xcode 3.2.6 or later (pkgbuild and productbuild)
-# 1. install python (and wxpython) 2.6 and 2.7 (32-bit)
-# 2. update pyo sources
-# 3. compile and install pyo float and double
-# 4. cd utils and build E-Pyo
-# 5. cd installer/osx and build the realease
-
-export PACKAGE_NAME=pyo_0.6.8_i386.pkg
-export DMG_DIR="pyo 0.6.8 Intel"
-export DMG_NAME="pyo_0.6.8_OSX-Intel.dmg"
-export INSTALLER_DIR=`pwd`/installer
-export PYO_MODULE_DIR=$INSTALLER_DIR/PyoModule/Package_Contents/tmp
-export SUPPORT_LIBS_DIR=$INSTALLER_DIR/SupportLibs/Package_Contents/usr/local/lib
-export BUILD_RESOURCES=$INSTALLER_DIR/PkgResources/English.lproj
-export PKG_RESOURCES=$INSTALLER_DIR/../PkgResources_i386
-
-mkdir -p $PYO_MODULE_DIR
-mkdir -p $SUPPORT_LIBS_DIR
-mkdir -p $BUILD_RESOURCES
-
-cp $PKG_RESOURCES/License.rtf $BUILD_RESOURCES/License.rtf
-cp $PKG_RESOURCES/Welcome.rtf $BUILD_RESOURCES/Welcome.rtf
-cp $PKG_RESOURCES/ReadMe.rtf $BUILD_RESOURCES/ReadMe.rtf
-
-svn export ../.. installer/pyo-build
-cd installer/pyo-build
-
-echo "building pyo for python 2.6 (32-bit)..."
-sudo /usr/local/bin/python2.6 setup.py install --use-coreaudio --use-double
-
-sudo cp -R build/lib.macosx-10.3-fat-2.6 $PYO_MODULE_DIR/python26
-
-echo "building pyo for python 2.7 (32-bit)..."
-sudo /usr/local/bin/python2.7 setup.py install --use-coreaudio --use-double
-
-sudo cp -R build/lib.macosx-10.3-fat-2.7 $PYO_MODULE_DIR/python27
-
-cd ..
-
-echo "copying support libs..."
-sudo cp /usr/local/lib/liblo.7.dylib $SUPPORT_LIBS_DIR/liblo.7.dylib
-sudo cp /usr/local/lib/libportaudio.2.dylib $SUPPORT_LIBS_DIR/libportaudio.2.dylib
-sudo cp /usr/local/lib/libportmidi.dylib $SUPPORT_LIBS_DIR/libportmidi.dylib
-sudo cp /usr/local/lib/libsndfile.1.dylib $SUPPORT_LIBS_DIR/libsndfile.1.dylib
-sudo cp /usr/local/lib/libFLAC.8.dylib $SUPPORT_LIBS_DIR/libFLAC.8.dylib
-sudo cp /usr/local/lib/libogg.0.dylib $SUPPORT_LIBS_DIR/libogg.0.dylib
-sudo cp /usr/local/lib/libvorbis.0.dylib $SUPPORT_LIBS_DIR/libvorbis.0.dylib
-sudo cp /usr/local/lib/libvorbisenc.2.dylib $SUPPORT_LIBS_DIR/libvorbisenc.2.dylib
-
-echo "setting permissions..."
-
-sudo chgrp -R admin PyoModule/Package_Contents/tmp
-sudo chown -R root PyoModule/Package_Contents/tmp
-sudo chmod -R 755 PyoModule/Package_Contents/tmp
-
-sudo chgrp -R wheel SupportLibs/Package_Contents/usr
-sudo chown -R root SupportLibs/Package_Contents/usr
-sudo chmod -R 755 SupportLibs/Package_Contents/usr
-
-echo "building packages..."
-
-pkgbuild    --identifier com.iact.umontreal.ca.pyo.tmp.pkg \
-            --root PyoModule/Package_Contents/ \
-            --version 1.0 \
-            --scripts $PKG_RESOURCES \
-            PyoModule.pkg
-
-pkgbuild    --identifier com.iact.umontreal.ca.pyo.usr.pkg \
-            --root SupportLibs/Package_Contents/ \
-            --version 1.0 \
-            SupportLibs.pkg
-
-echo "building product..."
-productbuild --distribution ../Distribution.dist --resources $BUILD_RESOURCES $PACKAGE_NAME
-
-echo "assembling DMG..."
-mkdir "$DMG_DIR"
-cd "$DMG_DIR"
-cp ../$PACKAGE_NAME .
-cp -R ../../../../utils/E-Pyo.app .
-ln -s /Applications .
-cd ..
-
-hdiutil create "$DMG_NAME" -srcfolder "$DMG_DIR"
-
-cd ..
-mv installer/$DMG_NAME .
-
-echo "clean up resources..."
-sudo rm -rf installer
-
-
diff --git a/installers/osx/release_x86_64.sh b/installers/osx/release_x86_64.sh
index 4c21d67..c8bcfad 100644
--- a/installers/osx/release_x86_64.sh
+++ b/installers/osx/release_x86_64.sh
@@ -1,8 +1,16 @@
 #!/bin/sh
 
-export PACKAGE_NAME=pyo_0.6.8_x86_64.pkg
-export DMG_DIR="pyo 0.6.8 Universal"
-export DMG_NAME="pyo_0.6.8_OSX-universal.dmg"
+# Need Xcode 3.2.6 or later (pkgbuild and productbuild)
+# 1. install python (and wxpython) 2.6 and 2.7 (32-bit)
+# 2. update pyo sources
+# 3. compile and install pyo float and double
+# 4. cd utils and build E-Pyo
+# 5. install python (and wxpython) 2.7 (64-bit)
+# 6. cd installer/osx and build the realease, only x86_64 version
+
+export PACKAGE_NAME=pyo_0.7.4_x86_64.pkg
+export DMG_DIR="pyo 0.7.4 Universal"
+export DMG_NAME="pyo_0.7.4_OSX-universal.dmg"
 export INSTALLER_DIR=`pwd`/installer
 export PYO_MODULE_DIR=$INSTALLER_DIR/PyoModule/Package_Contents/tmp
 export SUPPORT_LIBS_DIR=$INSTALLER_DIR/SupportLibs/Package_Contents/usr/local/lib
@@ -33,6 +41,11 @@ sudo /usr/local/bin/python2.7 setup.py install --use-coreaudio --use-double
 
 sudo cp -R build/lib.macosx-10.6-intel-2.7 $PYO_MODULE_DIR/python27
 
+sudo install_name_tool -change libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python26/_pyo.so
+sudo install_name_tool -change libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python26/_pyo64.so
+sudo install_name_tool -change libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python27/_pyo.so
+sudo install_name_tool -change libportmidi.dylib /usr/local/lib/libportmidi.dylib $PYO_MODULE_DIR/python27/_pyo64.so
+
 cd ..
 
 echo "copying support libs..."
@@ -41,12 +54,11 @@ sudo cp /usr/local/lib/libportaudio.2.dylib $SUPPORT_LIBS_DIR/libportaudio.2.dyl
 sudo cp /usr/local/lib/libportmidi.dylib $SUPPORT_LIBS_DIR/libportmidi.dylib
 sudo cp /usr/local/lib/libsndfile.1.dylib $SUPPORT_LIBS_DIR/libsndfile.1.dylib
 sudo cp /usr/local/lib/libFLAC.8.dylib $SUPPORT_LIBS_DIR/libFLAC.8.dylib
-sudo cp /usr/local/lib/libogg.0.dylib $SUPPORT_LIBS_DIR/libogg.0.dylib
-sudo cp /usr/local/lib/libvorbis.0.dylib $SUPPORT_LIBS_DIR/libvorbis.0.dylib
 sudo cp /usr/local/lib/libvorbisenc.2.dylib $SUPPORT_LIBS_DIR/libvorbisenc.2.dylib
+sudo cp /usr/local/lib/libvorbis.0.dylib $SUPPORT_LIBS_DIR/libvorbis.0.dylib
+sudo cp /usr/local/lib/libogg.0.dylib $SUPPORT_LIBS_DIR/libogg.0.dylib
 
 echo "setting permissions..."
-
 sudo chgrp -R admin PyoModule/Package_Contents/tmp
 sudo chown -R root PyoModule/Package_Contents/tmp
 sudo chmod -R 755 PyoModule/Package_Contents/tmp
diff --git a/installers/win/README-win32-py26.txt b/installers/win/README-win32-py26.txt
index bbe9866..e482de4 100644
--- a/installers/win/README-win32-py26.txt
+++ b/installers/win/README-win32-py26.txt
@@ -4,7 +4,7 @@ Pyo is a Python module written in C to help digital signal processing script cre
 
 http://www.python.org/download/releases/2.6.6/
 
-To use the WxPython toolkit for widgets, you need to install wxPython2.8-win32-unicode-py26:
+To use the WxPython toolkit for widgets, you need to install wxPython 3.0 for python 2.6:
 
 http://www.wxpython.org/download.php#stable
 
@@ -13,8 +13,8 @@ it's a good starting point to explore the library!
 
 In a Command Prompt:
 
-cd Desktop\pyo_examples
-python xnoise_example.py
+cd Desktop\pyo_examples\algorithmic
+python 01_music_box.py
 
 Please, send comments and bugs to:
 
diff --git a/installers/win/README-win32-py27.txt b/installers/win/README-win32-py27.txt
index 872130e..eddb84d 100644
--- a/installers/win/README-win32-py27.txt
+++ b/installers/win/README-win32-py27.txt
@@ -4,7 +4,7 @@ Pyo is a Python module written in C to help digital signal processing script cre
 
 http://www.python.org/download/
 
-To use the WxPython toolkit for widgets, you need to install wxPython2.8-win32-unicode-py27:
+To use the WxPython toolkit for widgets, you need to install wxPython 3.0 for python 2.7:
 
 http://www.wxpython.org/download.php#stable
 
@@ -13,8 +13,8 @@ it's a good starting point to explore the library!
 
 In a Command Prompt:
 
-cd Desktop\pyo_examples
-python xnoise_example.py
+cd Desktop\pyo_examples\algorithmic
+python 01_music_box.py
 
 Please, send comments and bugs to:
 
diff --git a/installers/win/win_installer_py26.iss b/installers/win/win_installer_py26.iss
index 1d24ca6..f973793 100644
--- a/installers/win/win_installer_py26.iss
+++ b/installers/win/win_installer_py26.iss
@@ -1,55 +1,63 @@
 ; Script generated by the Inno Setup Script Wizard.
 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+
+#define appName "pyo"
+#define pyVer "2.6"
+#define appVer "0.7.4"
 
 [Setup]
 ; NOTE: The value of AppId uniquely identifies this application.
 ; Do not use the same AppId value in installers for other applications.
 ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
-AppId={{4F72B6EF-CFA0-434F-A2B4-B130F94F54EB}
-AppName=Pyo
-AppVersion=0.6.8
-AppPublisher=iACT.umontreal.ca
-AppPublisherURL=http://code.google.com/p/pyo
-AppSupportURL=http://code.google.com/p/pyo
-AppUpdatesURL=http://code.google.com/p/pyo
-DefaultDirName={sd}\Python26
-DisableDirPage=yes
-DefaultGroupName=pyo
-AllowNoIcons=yes
-InfoBeforeFile=C:\Documents and Settings\user\svn\pyo\installers\win\\README-win32-py26.txt
-OutputBaseFilename=pyo_0.6.8_py2.6_setup
+AppId={{AC79C5C4-BE36-419E-B94A-98C6D0DCF4B9}
+AppName={#appName}
+AppVersion={#appVer}
+AppPublisher=iACT.umontreal.ca
+AppPublisherURL=http://code.google.com/p/pyo
+AppSupportURL=http://code.google.com/p/pyo
+AppUpdatesURL=http://code.google.com/p/pyo
+DefaultDirName={code:GetDirName}
+DisableDirPage=no
+AlwaysShowDirOnReadyPage=yes
+DefaultGroupName={#appName}
+AllowNoIcons=yes
+InfoBeforeFile=C:\Users\olipet\svn\pyo\installers\win\\README-win32-py26.txt
+LicenseFile=C:\Users\olipet\svn\pyo\COPYING.txt
+OutputBaseFilename={#appName}_{#appVer}_py{#pyVer}_setup
 Compression=lzma
 SolidCompression=yes
 ChangesAssociations=yes
 ChangesEnvironment=yes
+DirExistsWarning=no
+SetupIconFile=C:\Users\olipet\svn\pyo\utils\E-PyoIcon.ico
 
 [Languages]
 Name: "english"; MessagesFile: "compiler:Default.isl"
 
 ; should use PYTHONPATH variable
 [Files]
-Source: "C:\Python26\Lib\site-packages\pyo.py"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\pyo64.py"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\pyolib\*"; DestDir: "{sd}\Python26\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Python26\Lib\site-packages\_pyo.pyd"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\_pyo64.pyd"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\libsndfile-1.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\lo.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\portaudio.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\portmidi.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\porttime.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\pthreadVC2.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\msvcr90.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python26\Lib\site-packages\pyo-0.6.8-py2.6.egg-info"; DestDir: "{sd}\Python26\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Documents and Settings\user\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Documents and Settings\user\svn\pyo\installers\win\README-win32-py26.txt"; DestDir: "{userdesktop}"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pyo.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pyo64.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pyolib\*"; DestDir: "{app}\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Python26\Lib\site-packages\_pyo.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\_pyo64.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\libsndfile-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\lo.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\portaudio.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\portmidi.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\porttime.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pthreadVC2.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\msvcr90.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python26\Lib\site-packages\pyo-{#appVer}-py{#pyVer}.egg-info"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olipet\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olipet\svn\pyo\installers\win\README-win32-py26.txt"; DestDir: "{userdesktop}"; Flags: ignoreversion
 ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
 
 ; E-Pyo stuff
-Source: "C:\Documents and Settings\user\svn\pyo\utils\E-Pyo_py26\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
-Source: "C:\Documents and Settings\user\svn\pyo\utils\E-Pyo_py26\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olipet\svn\pyo\utils\E-Pyo_py26\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
+Source: "C:\Users\olipet\svn\pyo\utils\E-Pyo_py26\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
 
 [Tasks]
 Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
@@ -67,9 +75,12 @@ Type: filesandordirs; Name: "{userdocs}\.epyo";
 ;;;;;;;;;;;;;
 
 [Registry]
-Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "C:\Python26;{olddata}"; Check: NeedsAddPath('C:\Python26')
+Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "C:\Python26;{olddata}"; Check: NeedsAddPath('{app}')
 
 [Code]
+procedure ExitProcess(exitCode:integer);
+  external 'ExitProcess at kernel32.dll stdcall';
+
 function NeedsAddPath(Param: string): boolean;
 var
   OrigPath: string;
@@ -86,6 +97,37 @@ begin
   Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
 end;
 
-
+function GetDirName(Value: string): string;
+var          
+  InstallPath: string;
+  reg1 : string;
+  reg2 : string;
+  reg3 : string;
+  reg4 : string;
+begin
+  reg1 := 'SOFTWARE\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+  reg2 := 'SOFTWARE\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+  reg3 := 'Software\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+  reg4 := 'Software\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+  if RegQueryStringValue(HKLM, reg1, '', InstallPath) then
+    BEGIN
+    Result := InstallPath;
+  END else
+  if RegQueryStringValue(HKCU, reg3, '', InstallPath) then
+    BEGIN
+    Result := InstallPath;
+  END else
+  if RegQueryStringValue(HKLM, reg2, '', InstallPath) then
+    BEGIN
+    Result := InstallPath;
+  END else
+  if RegQueryStringValue(HKCU, reg4, '', InstallPath) then
+    BEGIN
+    Result := InstallPath;
+  END else
+    BEGIN
+    Result := 'C:\Python26';
+   END
+end;
 
 
diff --git a/installers/win/win_installer_py27.iss b/installers/win/win_installer_py27.iss
index 6b0cf86..5935569 100644
--- a/installers/win/win_installer_py27.iss
+++ b/installers/win/win_installer_py27.iss
@@ -1,54 +1,61 @@
 ; Script generated by the Inno Setup Script Wizard.
 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
+
+#define appName "pyo"
+#define pyVer "2.7"
+#define appVer "0.7.4"
 
 [Setup]
 ; NOTE: The value of AppId uniquely identifies this application.
 ; Do not use the same AppId value in installers for other applications.
 ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
-AppId={{244D309A-C251-481A-AD24-0602D392A634}
-AppName=Pyo
-AppVersion=0.6.8
+AppId={{59447873-F994-4BC7-8B1D-0DDCA5B6AFFD}
+AppName={#appName}
+AppVersion={#appVer}
 AppPublisher=iACT.umontreal.ca
 AppPublisherURL=http://code.google.com/p/pyo
 AppSupportURL=http://code.google.com/p/pyo
 AppUpdatesURL=http://code.google.com/p/pyo
-DefaultDirName={sd}\Python27
-DisableDirPage=yes
-DefaultGroupName=pyo
+DefaultDirName={code:GetDirName}
+DisableDirPage=no
+AlwaysShowDirOnReadyPage=yes
+DefaultGroupName={#appName}
 AllowNoIcons=yes
-InfoBeforeFile=C:\Documents and Settings\user\svn\pyo\installers\win\\README-win32-py27.txt
-OutputBaseFilename=pyo_0.6.8_py2.7_setup
+InfoBeforeFile=C:\Users\olipet\svn\pyo\installers\win\\README-win32-py27.txt
+LicenseFile=C:\Users\olipet\svn\pyo\COPYING.txt
+OutputBaseFilename={#appName}_{#appVer}_py{#pyVer}_setup
 Compression=lzma
 SolidCompression=yes
 ChangesAssociations=yes
-ChangesEnvironment=yes
+ChangesEnvironment=yes
+DirExistsWarning=no
+SetupIconFile=C:\Users\olipet\svn\pyo\utils\E-PyoIcon.ico
 
 [Languages]
 Name: "english"; MessagesFile: "compiler:Default.isl"
 
 [Files]
-Source: "C:\Python27\Lib\site-packages\pyo.py"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyo64.py"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyolib\*"; DestDir: "{sd}\Python27\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Python27\Lib\site-packages\_pyo.pyd"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\_pyo64.pyd"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\libsndfile-1.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\lo.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\portaudio.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\portmidi.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\porttime.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pthreadVC2.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\msvcr90.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Python27\Lib\site-packages\pyo-0.6.8-py2.7.egg-info"; DestDir: "{sd}\Python27\Lib\site-packages"; Flags: ignoreversion
-Source: "C:\Documents and Settings\user\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
-Source: "C:\Documents and Settings\user\svn\pyo\installers\win\README-win32-py27.txt"; DestDir: "{userdesktop}"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pyo.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion 
+Source: "C:\Python27\Lib\site-packages\pyo64.py"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pyolib\*"; DestDir: "{app}\Lib\site-packages\pyolib"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Python27\Lib\site-packages\_pyo.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\_pyo64.pyd"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\libsndfile-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\lo.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\portaudio.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\portmidi.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\porttime.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pthreadVC2.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\msvcr90.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libgcc_s_dw2-1.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\MinGW\bin\libstdc++-6.dll"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Python27\Lib\site-packages\pyo-{#appVer}-py{#pyVer}.egg-info"; DestDir: "{app}\Lib\site-packages"; Flags: ignoreversion
+Source: "C:\Users\olipet\svn\pyo\examples\*"; DestDir: "{userdesktop}\pyo_examples\"; Flags: ignoreversion recursesubdirs createallsubdirs
 ; NOTE: Don't use "Flags: ignoreversion" on any shared system files
 
 ; E-Pyo stuff
-Source: "C:\Documents and Settings\user\svn\pyo\utils\E-Pyo_py27\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
-Source: "C:\Documents and Settings\user\svn\pyo\utils\E-Pyo_py27\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
+Source: "C:\Users\olipet\svn\pyo\utils\E-Pyo_py27\E-Pyo.exe"; DestDir: "{pf}\E-Pyo"; Flags: ignoreversion
+Source: "C:\Users\olipet\svn\pyo\utils\E-Pyo_py27\Resources\*"; DestDir: "{pf}\E-Pyo\Resources"; Flags: ignoreversion recursesubdirs createallsubdirs
 
 [Tasks]
 Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
@@ -66,9 +73,12 @@ Type: filesandordirs; Name: "{userdocs}\.epyo";
 ;;;;;;;;;;;;;
 
 [Registry]
-Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "C:\Python27;{olddata}"; Check: NeedsAddPath('C:\Python27')
+Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{app};{olddata}"; Check: NeedsAddPath('{app}')
 
 [Code]
+procedure ExitProcess(exitCode:integer);
+  external 'ExitProcess at kernel32.dll stdcall';
+
 function NeedsAddPath(Param: string): boolean;
 var
   OrigPath: string;
@@ -84,3 +94,36 @@ begin
   // Pos() returns 0 if not found
   Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
 end;
+
+function GetDirName(Value: string): string;
+var          
+  InstallPath: string;
+  reg1 : string;
+  reg2 : string;
+  reg3 : string;
+  reg4 : string;
+begin
+  reg1 := 'SOFTWARE\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+  reg2 := 'SOFTWARE\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+  reg3 := 'Software\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+  reg4 := 'Software\Wow6432Node\Python\PythonCore\' + '{#PyVer}' + '\InstallPath';
+  if RegQueryStringValue(HKLM, reg1, '', InstallPath) then
+    BEGIN
+    Result := InstallPath;
+  END else
+  if RegQueryStringValue(HKCU, reg3, '', InstallPath) then
+    BEGIN
+    Result := InstallPath;
+  END else
+  if RegQueryStringValue(HKLM, reg2, '', InstallPath) then
+    BEGIN
+    Result := InstallPath;
+  END else
+  if RegQueryStringValue(HKCU, reg4, '', InstallPath) then
+    BEGIN
+    Result := InstallPath;
+  END else
+    BEGIN
+    Result := 'C:\Python27';
+   END
+end;
\ No newline at end of file
diff --git a/pyo.py b/pyo.py
index f7a865f..02421c5 100644
--- a/pyo.py
+++ b/pyo.py
@@ -99,7 +99,6 @@ if WITH_EXTERNALS:
     import pyolib.external as external
     from pyolib.external import *
 
-# Temporary objects, need to be coded in C
 class FreqShift(PyoObject):
     """
     Frequency shifting using single sideband amplitude modulation.
@@ -110,26 +109,14 @@ class FreqShift(PyoObject):
     100, 200, 300, 400 and 500 Hz, shifted up by 50 Hz, will have harmonics 
     at 150, 250, 350, 450, and 550 Hz.
 
-    Parent class : PyoObject
+    :Parent: :py:class:`PyoObject`
 
-    Parameters:
+    :Args:
 
-    input : PyoObject
-        Input signal to process.
-    shift : float or PyoObject, optional
-        Amount of shifting in Hertz. Defaults to 100.
-
-    Methods:
-
-    setInput(x, fadetime) : Replace the `input` attribute.
-    setShift(x) : Replace the `shift` attribute.
-
-    Attributes:
-
-    input : PyoObject. Input signal to process.
-    shift : float or PyoObject. Amount of shifting in Hertz.
-
-    Examples:
+        input : PyoObject
+            Input signal to process.
+        shift : float or PyoObject, optional
+            Amount of shifting in Hertz. Defaults to 100.
 
     >>> s = Server().boot()
     >>> s.start()
@@ -141,11 +128,9 @@ class FreqShift(PyoObject):
 
     """
     def __init__(self, input, shift=100, mul=1, add=0):
-        PyoObject.__init__(self)
+        PyoObject.__init__(self, mul, add)
         self._input = input
         self._shift = shift
-        self._mul = mul
-        self._add = add
         self._in_fader = InputFader(input)
         in_fader, shift, mul, add, lmax = convertArgsToLists(self._in_fader, shift, mul, add)
 
@@ -162,25 +147,20 @@ class FreqShift(PyoObject):
                                       mul=wrap(mul,i), add=wrap(add,i)))
             self._base_objs.extend(self._mod_objs[-1].getBaseObjects())
 
-    def __dir__(self):
-        return ["input", "shift", "mul", "add"]
-
     def play(self, dur=0, delay=0):
         dur, delay, lmax = convertArgsToLists(dur, delay)
         [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._hilb_objs)]
         [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._sin_objs)]
         [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._cos_objs)]
         [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._mod_objs)]
-        self._base_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
-        return self
+        return PyoObject.play(self, dur, delay)
 
     def stop(self):
         [obj.stop() for obj in self._hilb_objs]
         [obj.stop() for obj in self._sin_objs]
         [obj.stop() for obj in self._cos_objs]
         [obj.stop() for obj in self._mod_objs]
-        [obj.stop() for obj in self._base_objs]
-        return self
+        return PyoObject.stop(self)
 
     def out(self, chnl=0, inc=1, dur=0, delay=0):
         dur, delay, lmax = convertArgsToLists(dur, delay)
@@ -188,14 +168,7 @@ class FreqShift(PyoObject):
         [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._sin_objs)]
         [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._cos_objs)]
         [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._mod_objs)]
-        if type(chnl) == ListType:
-            self._base_objs = [obj.out(wrap(chnl,i), wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
-        else:
-            if chnl < 0:    
-                self._base_objs = [obj.out(i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(random.sample(self._base_objs, len(self._base_objs)))]
-            else:
-                self._base_objs = [obj.out(chnl+i*inc, wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._base_objs)]
-        return self
+        return PyoObject.out(self, chnl, inc, dur, delay)
 
     def setInput(self, x, fadetime=0.05):
         """
@@ -245,30 +218,123 @@ class FreqShift(PyoObject):
     @shift.setter
     def shift(self, x): self.setShift(x)
 
+class PartialTable(PyoTableObject):
+    """
+    Inharmonic waveform generator.
+
+    Generates waveforms made of inharmonic components. Partials are
+    given as a list of 2-values tuple, where the first one is the
+    partial number (can be float) and the second one is the strength
+    of the partial.
+    
+    The object uses the first two decimal values of each partial to 
+    compute a higher harmonic at a multiple of 100 (so each component
+    is in reality truly harmonic). If the oscillator has a frequency
+    divided by 100, the real desired partials will be restituted.
+    
+    The list:
+        
+    [(1, 1), (1.1, 0.7), (1.15, 0.5)] will draw a table with:
+        
+    harmonic 100 : amplitude = 1
+    harmonic 110 : amplitude = 0.7
+    harmonic 115 : amplitude = 0.5
+    
+    To listen to a signal composed of 200, 220 and 230 Hz, one should
+    declared an oscillator like this (frequency of 200Hz divided by 100):
+        
+    a = Osc(t, freq=2, mul=0.5).out()
+
+    :Parent: :py:class:`PyoTableObject`
+
+    :Args:
+
+        list : list of tuple, optional
+            List of 2-values tuples. First value is the partial number (float up 
+            to two decimal values) and second value is its amplitude (relative to
+            the other harmonics). Defaults to [(1,1), (1.33,0.5),(1.67,0.3)].
+        size : int, optional
+            Table size in samples. Because computed harmonics are very high in
+            frequency, the table size must be bigger than a classic HarmTable.
+            Defaults to 65536.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> t = PartialTable([(1,1), (2.37, 0.5), (4.55, 0.3)]).normalize()
+    >>> # Play with fundamentals 199 and 200 Hz
+    >>> a = Osc(table=t, freq=[1.99,2], mul=.2).out()
+
+    """
+    def __init__(self, list=[(1,1), (1.33,0.5),(1.67,0.3)], size=65536):
+        PyoTableObject.__init__(self, size)
+        self._list = list
+        self._par_table = HarmTable(self._create_list(), size)
+        self._base_objs = self._par_table.getBaseObjects()
+        self.normalize()
+
+    def _create_list(self):
+        # internal method used to compute the harmonics's weight
+        hrms = [(int(x*100.), y) for x, y in self._list]
+        l = []
+        ind = 0
+        for i in range(10000):
+            if i == hrms[ind][0]:
+                l.append(hrms[ind][1])
+                ind += 1
+                if ind == len(hrms):
+                    break
+            else:
+                l.append(0)
+        return l
+    
+    def replace(self, list):
+        """
+        Redraw the waveform according to a new set of harmonics 
+        relative strengths.
+        
+        :Args:
+        
+            list : list of tuples
+                Each tuple contains the partial number, as a float,
+                and its strength.
+
+        """      
+        self._list = list
+        [obj.replace(self._create_list()) for obj in self._base_objs]
+        self.normalize()
+        self.refreshView()
+
+    @property
+    def list(self): 
+        """list. List of partial numbers and strength."""
+        return self._list
+    @list.setter
+    def list(self, x): self.replace(x)
 
 OBJECTS_TREE = {'functions': sorted(['pa_count_devices', 'pa_get_default_input', 'pa_get_default_output', 'pm_get_input_devices',
                                     'pa_list_devices', 'pa_count_host_apis', 'pa_list_host_apis', 'pa_get_default_host_api', 
                                     'pm_count_devices', 'pm_list_devices', 'sndinfo', 'savefile', 'pa_get_output_devices', 
-                                    'pa_get_input_devices', 'midiToHz', 'sampsToSec', 'secToSamps', 'example', 'class_args', 
+                                    'pa_get_input_devices', 'midiToHz', 'hzToMidi', 'sampsToSec', 'secToSamps', 'example', 'class_args', 
                                     'pm_get_default_input', 'pm_get_output_devices', 'pm_get_default_output', 'midiToTranspo',
                                      'getVersion', 'reducePoints', 'serverCreated', 'serverBooted', 'distanceToSegment', 'rescale',
                                      'upsamp', 'downsamp', 'linToCosCurve', 'convertStringToSysEncoding', 'savefileFromTable',
-                                    'pa_get_input_max_channels', 'pa_get_output_max_channels', 'pa_get_devices_infos']),
+                                    'pa_get_input_max_channels', 'pa_get_output_max_channels', 'pa_get_devices_infos', 'pa_get_version',
+                                    'pa_get_version_text', 'floatmap']),
                 'PyoObjectBase': {
                     'PyoMatrixObject': sorted(['NewMatrix']),                        
                     'PyoTableObject': sorted(['LinTable', 'NewTable', 'SndTable', 'HannTable', 'HarmTable', 'SawTable', 'ParaTable', 'LogTable', 'CosLogTable',
-                                            'SquareTable', 'ChebyTable', 'CosTable', 'CurveTable', 'ExpTable', 'DataTable', 'WinTable', 'SincTable']),
+                                            'SquareTable', 'ChebyTable', 'CosTable', 'CurveTable', 'ExpTable', 'DataTable', 'WinTable', 'SincTable', 'PartialTable']),
                     'PyoPVObject' : sorted(['PVAnal', 'PVSynth', 'PVTranspose', 'PVVerb', 'PVGate', 'PVAddSynth', 'PVCross', 'PVMult', 'PVMorph', 'PVFilter', 'PVDelay', 'PVBuffer', 'PVShift', 'PVAmpMod', 'PVFreqMod', 'PVBufLoops', 'PVBufTabLoops', 'PVMix']),
-                    'PyoObject': {'analysis': sorted(['Follower', 'Follower2', 'ZCross', 'Yin']),
+                    'PyoObject': {'analysis': sorted(['Follower', 'Follower2', 'ZCross', 'Yin', 'Centroid', 'AttackDetector', 'Scope', 'Spectrum', 'PeakAmp']),
                                   'arithmetic': sorted(['Sin', 'Cos', 'Tan', 'Abs', 'Sqrt', 'Log', 'Log2', 'Log10', 'Pow', 'Atan2', 'Floor', 'Round',
-                                                        'Ceil']),
+                                                        'Ceil', 'Tanh']),
                                   'controls': sorted(['Fader', 'Sig', 'SigTo', 'Adsr', 'Linseg', 'Expseg']),
                                   'dynamics': sorted(['Clip', 'Compress', 'Degrade', 'Mirror', 'Wrap', 'Gate', 'Balance', 'Min', 'Max']),
-                                  'effects': sorted(['Delay', 'SDelay', 'Disto', 'Freeverb', 'Waveguide', 'Convolve', 'WGVerb', 
-                                                     'Harmonizer', 'Chorus', 'AllpassWG', 'FreqShift', 'Vocoder', 'Delay1']),
+                                  'effects': sorted(['Delay', 'SDelay', 'Disto', 'Freeverb', 'Waveguide', 'Convolve', 'WGVerb', 'SmoothDelay',
+                                                     'Harmonizer', 'Chorus', 'AllpassWG', 'FreqShift', 'Vocoder', 'Delay1', 'STRev']),
                                   'filters': sorted(['Biquad', 'BandSplit', 'Port', 'Hilbert', 'Tone', 'DCBlock', 'EQ', 'Allpass',
                                                      'Allpass2', 'Phaser', 'Biquadx', 'IRWinSinc', 'IRAverage', 'IRPulse', 'IRFM', 'FourBand',
-                                                     'Biquada', 'Atone', 'SVF', 'Average', 'Reson', 'Resonx', 'ButLP', 'ButHP', 'ButBP', 'ButBR']),
+                                                     'Biquada', 'Atone', 'SVF', 'Average', 'Reson', 'Resonx', 'ButLP', 'ButHP', 'ButBP', 'ButBR', 'ComplexRes']),
                                   'generators': sorted(['Noise', 'Phasor', 'Sine', 'Input', 'FM', 'SineLoop', 'Blit', 'PinkNoise', 'CrossFM',
                                                         'BrownNoise', 'Rossler', 'Lorenz', 'LFO', 'SumOsc', 'SuperSaw', 'RCOsc']),
                                   'internals': sorted(['Dummy', 'InputFader', 'Mix', 'VarPort']),
@@ -278,22 +344,21 @@ OBJECTS_TREE = {'functions': sorted(['pa_count_devices', 'pa_get_default_input',
                                   'pattern': sorted(['Pattern', 'Score', 'CallAfter']),
                                   'randoms': sorted(['Randi', 'Randh', 'Choice', 'RandInt', 'Xnoise', 'XnoiseMidi', 'RandDur', 'XnoiseDur', 'Urn']),
                                   'players': sorted(['SfMarkerShuffler', 'SfPlayer', 'SfMarkerLooper']),
-                                  'tableprocess': sorted(['TableRec', 'Osc', 'Pointer', 'Lookup', 'Granulator', 'Pulsar', 'OscLoop', 'Granule',
-                                                        'TableRead', 'TableMorph', 'Looper', 'TableIndex', 'OscBank', 'OscTrig', 'TablePut', 'TableScale']),
+                                  'tableprocess': sorted(['TableRec', 'Osc', 'Pointer', 'Pointer2', 'Lookup', 'Granulator', 'Pulsar', 'OscLoop', 'Granule',
+                                                        'TableRead', 'TableMorph', 'Looper', 'TableIndex', 'OscBank', 'OscTrig', 'TablePut', 'TableScale', 'Particle']),
                                   'matrixprocess': sorted(['MatrixRec', 'MatrixPointer', 'MatrixMorph', 'MatrixRecLoop']), 
                                   'triggers': sorted(['Metro', 'Beat', 'TrigEnv', 'TrigRand', 'TrigRandInt', 'Select', 'Counter', 'TrigChoice', 
                                                     'TrigFunc', 'Thresh', 'Cloud', 'Trig', 'TrigXnoise', 'TrigXnoiseMidi', 'Timer', 'Count',
                                                     'Change', 'TrigLinseg', 'TrigExpseg', 'Percent', 'Seq', 'TrigTableRec', 'Iter', 'NextTrig',
-                                                    'TrigVal']),
+                                                    'TrigVal', 'Euclide', 'TrigBurst']),
                                   'utils': sorted(['Clean_objects', 'Print', 'Snap', 'Interp', 'SampHold', 'Compare', 'Record', 'Between', 'Denorm',
                                                     'ControlRec', 'ControlRead', 'NoteinRec', 'NoteinRead', 'DBToA', 'AToDB', 'Scale', 'CentsToTranspo',
-                                                    'TranspoToCents', 'MToF', 'MToT']),
-                                  'fourier': sorted(['FFT', 'IFFT', 'CarToPol', 'PolToCar', 'FrameDelta', 'FrameAccum', 'Vectral', 'CvlVerb', 'Spectrum'])}},
+                                                    'TranspoToCents', 'MToF', 'FToM', 'MToT', 'TrackHold']),
+                                  'fourier': sorted(['FFT', 'IFFT', 'CarToPol', 'PolToCar', 'FrameDelta', 'FrameAccum', 'Vectral', 'CvlVerb'])}},
         'Map': {'SLMap': sorted(['SLMapFreq', 'SLMapMul', 'SLMapPhase', 'SLMapQ', 'SLMapDur', 'SLMapPan'])},
         'Server': [], 
         'Stream': [], 
         'TableStream': []}
 
 DOC_KEYWORDS = ['Attributes', 'Examples', 'Parameters', 'Methods', 'Notes', 'Methods details', 'See also', 'Parentclass']
-
 DEMOS_PATH = SNDS_PATH
diff --git a/pyolib/_core.py b/pyolib/_core.py
index 0a643c6..07a9e98 100644
--- a/pyolib/_core.py
+++ b/pyolib/_core.py
@@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License
 along with pyo.  If not, see <http://www.gnu.org/licenses/>.
 
 """
-from types import ListType, SliceType, FloatType, StringType, UnicodeType
+from types import ListType, SliceType, FloatType, StringType, UnicodeType, NoneType
 import random, os, sys, inspect, tempfile
 from subprocess import call
 
@@ -46,6 +46,7 @@ FILE_FORMATS = {'wav': 0, 'wave': 0, 'aif': 1, 'aiff': 1, 'au': 2, '': 3, 'sd2':
 FUNCTIONS_INIT_LINES = {"pa_count_host_apis": "pa_count_host_apis()", "pa_list_host_apis": "pa_list_host_apis()",
                         "pa_get_default_host_api": "pa_get_default_host_api()", "pa_count_devices": "pa_count_devices()",
                         "pa_list_devices": "pa_list_devices()", "pa_get_devices_infos": "pa_get_devices_infos()",
+                        "pa_get_version": "pa_get_version()", "pa_get_version_text": "pa_get_version_text()",
                         "pa_get_input_devices": "pa_get_input_devices()", "pa_get_output_devices": "pa_get_output_devices()",
                         "pa_get_default_input": "pa_get_default_input()", "pa_get_default_output": "pa_get_default_output()",
                         "pa_get_input_max_channels": "pa_get_input_max_channels(x)", "pa_get_output_max_channels": "pa_get_output_max_channels(x)",
@@ -55,14 +56,14 @@ FUNCTIONS_INIT_LINES = {"pa_count_host_apis": "pa_count_host_apis()", "pa_list_h
                         "sndinfo": "sndinfo(path, print=False)", "savefile": "savefile(samples, path, sr=44100, channels=1, fileformat=0, sampletype=0)",
                         "savefileFromTable": "savefileFromTable(table, path, fileformat=0, sampletype=0)",
                         "upsamp": "upsamp(path, outfile, up=4, order=128)", "downsamp": "downsamp(path, outfile, down=4, order=128)",
-                        "midiToHz": "midiToHz(x)", "midiToTranspo": "midiToTranspo(x)", "sampsToSec": "sampsToSec(x)",
+                        "midiToHz": "midiToHz(x)", "hzToMidi": "hzToMidi(x)", "midiToTranspo": "midiToTranspo(x)", "sampsToSec": "sampsToSec(x)",
                         "secToSamps": "secToSamps(x)", "linToCosCurve": "linToCosCurve(data, yrange=[0, 1], totaldur=1, points=1024, log=False)",
                         "rescale": "rescale(data, xmin=0.0, xmax=1.0, ymin=0.0, ymax=1.0, xlog=False, ylog=False)",
                         "distanceToSegment": "distanceToSegment(p, p1, p2, xmin=0.0, xmax=1.0, ymin=0.0, ymax=1.0, xlog=False, ylog=False)",
                         "reducePoints": "reducePoints(pointlist, tolerance=0.02)", "serverCreated": "serverCreated()", "serverBooted": "serverBooted()",
                         "example": "example(cls, dur=5, toprint=True, double=False)", "class_args": "class_args(cls)", "getVersion": "getVersion()",
                         "convertStringToSysEncoding": "convertStringToSysEncoding(str)", "convertArgsToLists": "convertArgsToLists(*args)",
-                        "wrap": "wrap(arg, i)"
+                        "wrap": "wrap(arg, i)", "floatmap": "floatmap(x, min=0, max=1, exp=1)"
                         }
 
 def convertStringToSysEncoding(str):
@@ -223,6 +224,9 @@ def getVersion():
     major, minor, rev = PYO_VERSION.split('.')
     return (int(major), int(minor), int(rev))
 
+def dumpref():
+    pass
+
 class PyoError(Exception):
     """Base class for all pyo exceptions."""
 
@@ -286,6 +290,20 @@ class PyoObjectBase(object):
         """
         return self._base_objs
 
+    def cleanFuncRefs(self):
+        """
+        Method used to remove internal references to callback functions.
+        
+        An internal reference to a callback function (ex. the function
+        called by the TrigFunc object) may prevent the object to be
+        properly deleted when its reference count drop to zero. Calling
+        this function just before deleting the last reference will replace
+        the callback reference by a dump ref.
+
+        """
+        if hasattr(self, "_function"):
+            self.setFunction(dumpref)
+
     def __getitem__(self, i):
         if i == 'trig':
             return self._trig_objs
@@ -768,12 +786,12 @@ class PyoObject(PyoObjectBase):
 
     def setSub(self, x):
         """
-        Replace and inverse the `mul` attribute.
+        Replace and inverse the `add` attribute.
         
         :Args:
 
             x : float or PyoObject
-                New inversed `mul` attribute.
+                New inversed `add` attribute.
         
         """
         self._add = x
@@ -782,12 +800,12 @@ class PyoObject(PyoObjectBase):
 
     def setDiv(self, x):
         """
-        Replace and inverse the `add` attribute.
+        Replace and inverse the `mul` attribute.
                 
         :Args:
 
             x : float or PyoObject
-                New inversed `add` attribute.
+                New inversed `mul` attribute.
 
         """
         self._mul = x
@@ -899,7 +917,8 @@ class PyoTableObject(PyoObjectBase):
         PyoObjectBase.__init__(self)
         self._size = size
         self.viewFrame = None
-
+        self.graphFrame = None
+        
     def save(self, path, format=0, sampletype=0):
         """
         Writes the content of the table in an audio file.
@@ -1123,13 +1142,103 @@ class PyoTableObject(PyoObjectBase):
 
     def reverse(self):
         """
-        Reverse the table's data.
+        Reverse the table's data in time.
 
         """
         [obj.reverse() for obj in self._base_objs]
         self.refreshView()
         return self
 
+    def invert(self):
+        """
+        Reverse the table's data in amplitude.
+
+        """
+        [obj.invert() for obj in self._base_objs]
+        self.refreshView()
+        return self
+
+    def rectify(self):
+        """
+        Positive rectification of the table's data.
+
+        """
+        [obj.rectify() for obj in self._base_objs]
+        self.refreshView()
+        return self
+
+    def pow(self, exp=10):
+        """
+        Apply a power function on each sample in the table.
+
+        :Args:
+
+            exp : float, optional
+                Exponent factor. Defaults to 10.
+
+        """
+        [obj.pow(exp) for obj in self._base_objs]
+        self.refreshView()
+        return self
+
+    def bipolarGain(self, gpos=1, gneg=1):
+        """
+        Apply different gain factor for positive and negative samples.
+
+        :Args:
+
+            gpos : float, optional
+                Gain factor for positive samples. Defaults to 1.
+            gneg : float, optional
+                Gain factor for negative samples. Defaults to 1.
+
+        """
+        [obj.bipolarGain(gpos, gneg) for obj in self._base_objs]
+        self.refreshView()
+        return self
+
+    def lowpass(self, freq=1000):
+        """
+        Apply a one-pole lowpass filter on table's samples.
+
+        :Args:
+
+            freq : float, optional
+                Filter's cutoff, in Hertz. Defaults to 1000.
+
+        """
+        [obj.lowpass(freq) for obj in self._base_objs]
+        self.refreshView()
+        return self
+
+    def fadein(self, dur=0.1):
+        """
+        Apply a gradual increase in the level of the table's samples.
+
+        :Args:
+
+            dur : float, optional
+                Fade in duration, in seconds. Defaults to 0.1.
+
+        """
+        [obj.fadein(dur) for obj in self._base_objs]
+        self.refreshView()
+        return self
+
+    def fadeout(self, dur=0.1):
+        """
+        Apply a gradual decrease in the level of the table's samples.
+
+        :Args:
+
+            dur : float, optional
+                Fade out duration, in seconds. Defaults to 0.1.
+
+        """
+        [obj.fadeout(dur) for obj in self._base_objs]
+        self.refreshView()
+        return self
+
     def copy(self):
         """
         Returns a deep copy of the object.
@@ -1167,11 +1276,14 @@ class PyoTableObject(PyoObjectBase):
         the server GUI before showing the controller window. 
         
         """
-        samples = self._base_objs[0].getViewTable()
+        samples = self._base_objs[0].getViewTable((500,200))
         createViewTableWindow(samples, title, wxnoserver, self.__class__.__name__, self)
 
     def _setViewFrame(self, frame):
         self.viewFrame = frame
+
+    def _setGraphFrame(self, frame):
+        self.graphFrame = frame
         
     def refreshView(self):
         """
@@ -1179,9 +1291,12 @@ class PyoTableObject(PyoObjectBase):
 
         """
         if self.viewFrame != None:
-            samples = self._base_objs[0].getViewTable()
+            size = self.viewFrame.wavePanel.GetSize()
+            samples = self._base_objs[0].getViewTable((size[0], size[1]))
             self.viewFrame.update(samples)
-
+        if self.graphFrame != None:
+            self.graphFrame.update(self.getTable())
+            
     @property
     def size(self):
         """int. Table size in samples.""" 
@@ -1779,6 +1894,7 @@ class VarPort(PyoObject):
         PyoObject.__init__(self, mul, add)
         self._value = value
         self._time = time
+        self._function = function
         value, time, init, function, arg, mul ,add, lmax = convertArgsToLists(value, time, init, function, arg, mul, add)
         self._base_objs = [VarPort_base(wrap(value,i), wrap(time,i), wrap(init,i), wrap(function,i), wrap(arg,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
 
@@ -1810,6 +1926,20 @@ class VarPort(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setTime(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
+    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)]
+
     @property
     def value(self):
         """float. Numerical value to convert.""" 
@@ -1824,6 +1954,13 @@ class VarPort(PyoObject):
     @time.setter
     def time(self, x): self.setTime(x)
 
+    @property
+    def function(self): 
+        """Python callable. Function to be called."""
+        return self._function
+    @function.setter
+    def function(self, x): self.setFunction(x)
+
 class Pow(PyoObject):
     """
     Performs a power function on audio signal.
@@ -2040,7 +2177,11 @@ class Compare(PyoObject):
     def __init__(self, input, comp, mode="<", mul=1, add=0):
         PyoObject.__init__(self, mul, add)
         self._input = input
-        self._comp = comp
+        if type(comp) in [StringType, UnicodeType, NoneType]:
+            print 'TypeError: "comp" argument of %s must be a float or a PyoObject. Set to 0.\n' % self.__class__.__name__
+            comp = self._comp = 0
+        else:
+            self._comp = comp
         self._mode = mode
         self._in_fader = InputFader(input)
         self.comp_dict = {"<": 0, "<=": 1, ">": 2, ">=": 3, "==": 4, "!=": 5}
@@ -2071,10 +2212,13 @@ class Compare(PyoObject):
         
         :Args:
 
-            x : PyoObject
+            x : float or PyoObject
                 New comparison signal.
 
         """
+        if type(x) in [StringType, UnicodeType, NoneType]:
+            print >> sys.stderr, 'TypeError: "comp" argument of %s must be a float or a PyoObject.\n' % self.__class__.__name__
+            return
         self._comp = x
         x, lmax = convertArgsToLists(x)
         [obj.setComp(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
diff --git a/pyolib/_maps.py b/pyolib/_maps.py
index 9845c77..7005918 100644
--- a/pyolib/_maps.py
+++ b/pyolib/_maps.py
@@ -158,17 +158,22 @@ class SLMap(Map):
         ramp : float, optional
             Ramp time, in seconds, used to smooth the signal sent from slider 
             to object's attribute. Defaults to 0.025.
+        dataOnly : boolean, optional
+            Set this argument to True if the parameter does not accept audio 
+            signal as control but discreet values. If True, label will be 
+            marked with a star symbol (*). Defaults to False. 
 
     >>> s = Server().boot()
+    >>> s.start()
     >>> ifs = [350,360,375,388]
     >>> maps = [SLMap(20., 2000., 'log', 'freq', ifs), SLMap(0, 0.25, 'lin', 'feedback', 0), SLMapMul(.1)]
     >>> a = SineLoop(freq=ifs, mul=.1).out()
     >>> a.ctrl(maps)
 
     """
-    def __init__(self, min, max, scale, name, init, res='float', ramp=0.025):
+    def __init__(self, min, max, scale, name, init, res='float', ramp=0.025, dataOnly=False):
         Map.__init__(self, min, max, scale)
-        self._name, self._init, self._res, self._ramp = name, init, res, ramp
+        self._name, self._init, self._res, self._ramp, self._dataOnly = name, init, res, ramp, dataOnly
 
     @property
     def name(self): 
@@ -186,6 +191,10 @@ class SLMap(Map):
     def ramp(self): 
         """float. Ramp time in seconds."""
         return self._ramp
+    @property
+    def dataOnly(self): 
+        """boolean. True if argument does not accept audio stream."""
+        return self._dataOnly
 
 class SLMapFreq(SLMap):
     """
diff --git a/pyolib/_widgets.py b/pyolib/_widgets.py
index 518299c..40bded2 100644
--- a/pyolib/_widgets.py
+++ b/pyolib/_widgets.py
@@ -15,7 +15,7 @@ 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 Licensehack for OSX display
+You should have received a copy of the GNU General Public License
 along with pyo.  If not, see <http://www.gnu.org/licenses/>.
 """
 from types import ListType, FloatType, IntType
@@ -28,28 +28,39 @@ except:
     WITH_PIL = False
 
 try:
-    import wxversion
-    if (wxversion.checkInstalled("2.8")):
-        wxversion.ensureMinimal("2.8")
+    try:
+        import wxversion
+        if (wxversion.checkInstalled("2.8")):
+            wxversion.ensureMinimal("2.8")
+    except:
+        pass
     import wx
     from _wxwidgets import *
     PYO_USE_WX = True
 except:
     PYO_USE_WX = False
 
+PYO_USE_TK = False
 if not PYO_USE_WX:
     try:
         from Tkinter import *
         from _tkwidgets import *
+        PYO_USE_TK = True
+        print """
+WxPython is not found for the current python version. 
+Pyo will use a minimal GUI toolkit written with Tkinter. 
+This toolkit has limited functionnalities and is no more 
+maintained or updated. If you want to use all of pyo's
+GUI features, you should install WxPython, available here: 
+http://www.wxpython.org/
+"""
     except:
-        if sys.platform == "linux2":
-            response = raw_input("""python-tk package is missing! It is needed to use pyo graphical interfaces.
-Do you want to install it? (yes/no): """)
-            if response == 'yes':
-                os.system('sudo apt-get install python-tk')
-        else:
-            print "Tkinter is missing! It is needed to use pyo graphical interfaces. Please install it!"
-        sys.exit()
+        PYO_USE_TK = False
+        print """
+Neither WxPython nor Tkinter are found for the current python version.
+Pyo's GUI features are disabled. For a complete GUI toolkit, you should 
+consider installing WxPython, available here: http://www.wxpython.org/
+"""
 
 X, Y, CURRENT_X, MAX_X, NEXT_Y = 800, 700, 30, 30, 30
 WINDOWS = []
@@ -60,8 +71,11 @@ TABLEWINDOWS = []
 SNDTABLEWINDOWS = []
 MATRIXWINDOWS = []
 SPECTRUMWINDOWS = []
+SCOPEWINDOWS = []
+WX_APP = False
 
 def createRootWindow():
+    global WX_APP
     if not PYO_USE_WX:
         if len(WINDOWS) == 0:
             root = Tk()
@@ -70,8 +84,9 @@ def createRootWindow():
         else:
             return None
     else:        
-        if wx.GetApp() == None: 
-            win = wx.App(False) 
+        if not WX_APP: 
+            win = wx.App(False)
+            WX_APP = True 
             return win
         else:
             return None
@@ -134,6 +149,7 @@ def wxCreateDelayedGraphWindows():
 def wxCreateDelayedDataGraphWindows():
     for win in DATAGRAPHWINDOWS:
         f = DataTableGrapher(None, win[0], win[1])
+        win[0]._setGraphFrame(f)
         if win[2] == None: title = win[0].__class__.__name__
         else: title = win[2]
         wxDisplayWindow(f, title)
@@ -142,8 +158,7 @@ def wxCreateDelayedTableWindows():
     global CURRENT_X, MAX_X, NEXT_Y
     for win in TABLEWINDOWS:
         object = win[3]
-        if WITH_PIL: f = ViewTable_withPIL(None, win[0], win[1], object)
-        else: f = ViewTable_withoutPIL(None, win[0], win[1], object)
+        f = ViewTable(None, win[0], win[1], object)
         if object != None:
             object._setViewFrame(f)
         wxDisplayWindow(f, win[2])
@@ -151,8 +166,7 @@ def wxCreateDelayedTableWindows():
 def wxCreateDelayedSndTableWindows():
     global CURRENT_X, MAX_X, NEXT_Y
     for win in SNDTABLEWINDOWS:
-        if WITH_PIL: f = SndViewTable_withPIL(None, win[0], win[1], win[3])
-        else: f = SndViewTable_withoutPIL(None, win[0], win[1], win[3])
+        f = SndViewTable(None, win[0], win[1], win[3])
         win[0]._setViewFrame(f)
         wxDisplayWindow(f, win[2])
 
@@ -174,6 +188,15 @@ def wxCreateDelayedSpectrumWindows():
         if win[0] != None:
             win[0]._setViewFrame(f)
         wxDisplayWindow(f, title)
+
+def wxCreateDelayedScopeWindows():
+    for win in SCOPEWINDOWS:
+        f = ScopeDisplay(None, win[0])
+        if win[1] == None: title = win[0].__class__.__name__
+        else: title = win[1]
+        if win[0] != None:
+            win[0]._setViewFrame(f)
+        wxDisplayWindow(f, title)
     
 def createCtrlWindow(obj, map_list, title, wxnoserver=False):
     if not PYO_USE_WX:
@@ -184,7 +207,7 @@ def createCtrlWindow(obj, map_list, title, wxnoserver=False):
         if title == None: title = obj.__class__.__name__
         win.title(title)
     else:
-        if wxnoserver or wx.GetApp() != None:
+        if wxnoserver or WX_APP:
             root = createRootWindow()
             f = PyoObjectControl(None, obj, map_list)
             if title == None: title = obj.__class__.__name__
@@ -196,7 +219,7 @@ def createGraphWindow(obj, mode, xlen, yrange, title, wxnoserver=False):
     if not PYO_USE_WX:
         print "WxPython must be installed to use the 'graph()' method."
     else:
-        if wxnoserver or wx.GetApp() != None:
+        if wxnoserver or WX_APP:
             root = createRootWindow()
             f = TableGrapher(None, obj, mode, xlen, yrange)
             if title == None: title = obj.__class__.__name__
@@ -208,11 +231,12 @@ def createDataGraphWindow(obj, yrange, title, wxnoserver=False):
     if not PYO_USE_WX:
         print "WxPython must be installed to use the 'graph()' method."
     else:
-        if wxnoserver or wx.GetApp() != None:
+        if wxnoserver or WX_APP:
             root = createRootWindow()
             f = DataTableGrapher(None, obj, yrange)
             if title == None: title = obj.__class__.__name__
             wxShowWindow(f, title, root)
+            obj._setGraphFrame(f)
         else:
             DATAGRAPHWINDOWS.append([obj, yrange, title])   
         
@@ -225,10 +249,9 @@ def createViewTableWindow(samples, title="Table waveform", wxnoserver=False, tab
         win.resizable(False, False)
         win.title(title)
     else:
-        if wxnoserver or wx.GetApp() != None:
+        if wxnoserver or WX_APP:
             root = createRootWindow()
-            if WITH_PIL: f = ViewTable_withPIL(None, samples, tableclass)
-            else: f = ViewTable_withoutPIL(None, samples, tableclass)
+            f = ViewTable(None, samples, tableclass, object)
             wxShowWindow(f, title, root)
             if object != None:
                 object._setViewFrame(f)
@@ -244,10 +267,9 @@ def createSndViewTableWindow(obj, title="Table waveform", wxnoserver=False, tabl
         win.resizable(False, False)
         win.title(title)
     else:
-        if wxnoserver or wx.GetApp() != None:
+        if wxnoserver or WX_APP:
             root = createRootWindow()
-            if WITH_PIL: f = SndViewTable_withPIL(None, obj, tableclass, mouse_callback)
-            else: f = SndViewTable_withoutPIL(None, obj, tableclass, mouse_callback)
+            f = SndViewTable(None, obj, tableclass, mouse_callback)
             if title == None: title = obj.__class__.__name__
             wxShowWindow(f, title, root)
             obj._setViewFrame(f)
@@ -265,10 +287,10 @@ It helps a lot to speed up matrix drawing!"""
         win.resizable(False, False)
         win.title(title)
     else:
-        if wxnoserver or wx.GetApp() != None:
+        if wxnoserver or WX_APP:
             root = createRootWindow()
-            if WITH_PIL: f = ViewMatrix_withPIL(None, samples, size)
-            else: f = ViewMatrix_withoutPIL(None, samples, size)
+            if WITH_PIL: f = ViewMatrix_withPIL(None, samples, size, object)
+            else: f = ViewMatrix_withoutPIL(None, samples, size, object)
             wxShowWindow(f, title, root)
             if object != None:
                 object._setViewFrame(f)
@@ -279,7 +301,7 @@ def createSpectrumWindow(object, title, wxnoserver=False):
     if not PYO_USE_WX:
         print "WxPython must be installed to use the Spectrum display."
     else:
-        if wxnoserver or wx.GetApp() != None:
+        if wxnoserver or WX_APP:
             root = createRootWindow()
             f = SpectrumDisplay(None, object)
             if title == None: title = object.__class__.__name__
@@ -288,8 +310,22 @@ def createSpectrumWindow(object, title, wxnoserver=False):
                 object._setViewFrame(f)
         else:
             SPECTRUMWINDOWS.append([object, title])   
+
+def createScopeWindow(object, title, wxnoserver=False):
+    if not PYO_USE_WX:
+        print "WxPython must be installed to use the Scope display."
+    else:
+        if wxnoserver or WX_APP:
+            root = createRootWindow()
+            f = ScopeDisplay(None, object)
+            if title == None: title = object.__class__.__name__
+            wxShowWindow(f, title, root)
+            if object != None:
+                object._setViewFrame(f)
+        else:
+            SCOPEWINDOWS.append([object, title])   
         
-def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, locals, shutdown, meter, timer, amp):
+def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, locals, shutdown, meter, timer, amp, exit):
     global X, Y, MAX_X, NEXT_Y
     if not PYO_USE_WX:
         createRootWindow()
@@ -299,7 +335,7 @@ def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, loc
         f.focus_set()
     else:
         win = createRootWindow()
-        f = ServerGUI(None, nchnls, start, stop, recstart, recstop, setAmp, started, locals, shutdown, meter, timer, amp) 
+        f = ServerGUI(None, nchnls, start, stop, recstart, recstop, setAmp, started, locals, shutdown, meter, timer, amp, exit) 
         f.SetTitle("pyo server")
         f.SetPosition((30, 30))
         f.Show()
@@ -315,6 +351,7 @@ def createServerGUI(nchnls, start, stop, recstart, recstop, setAmp, started, loc
         wx.CallAfter(wxCreateDelayedMatrixWindows)
         wx.CallAfter(wxCreateDelayedCtrlWindows)
         wx.CallAfter(wxCreateDelayedSpectrumWindows)
+        wx.CallAfter(wxCreateDelayedScopeWindows)
         wx.CallAfter(f.Raise)
     return f, win
-        
\ No newline at end of file
+        
diff --git a/pyolib/_wxwidgets.py b/pyolib/_wxwidgets.py
index 4e85080..9fed692 100644
--- a/pyolib/_wxwidgets.py
+++ b/pyolib/_wxwidgets.py
@@ -19,7 +19,6 @@ along with pyo.  If not, see <http://www.gnu.org/licenses/>.
 
 import wx, os, sys, math, time, random
 from types import ListType, FloatType, IntType
-from wx.lib.embeddedimage import PyEmbeddedImage
 
 try:
     from PIL import Image, ImageDraw, ImageTk
@@ -28,93 +27,6 @@ except:
     
 BACKGROUND_COLOUR = "#EBEBEB"
 
-vu_metre = PyEmbeddedImage(
-    "iVBORw0KGgoAAAANSUhEUgAAAMgAAAAFCAIAAACPTDSjAAAAAXNSR0IArs4c6QAAACF0RVh0"
-    "U29mdHdhcmUAR3JhcGhpY0NvbnZlcnRlciAoSW50ZWwpd4f6GQAAAMJJREFUeJxiYBgFo4BG"
-    "wHWbO1bEKc6JS4pXiddxtTNWKTFLMYspVlilpFyk9WsNsUopR6toF+lglVJP0wDKYpUCmiYX"
-    "II9VyqTTFOgSrFI28+0E9YSwSgE9hcfXLNwsZEgBDcQVVkBnAB2DKxi7qg13LHHERIEeMvWF"
-    "ulilYoIUM2JUsUoVp2vGKyjsdbDHRH0G+u4SElilZpkYW4uIYJXaaGNtwMDwHxsaTVijCWs0"
-    "YY0mrNGENZqwRhMWAAAA//8DAHGDnlocOW36AAAAAElFTkSuQmCC")
-
-vu_metre_dark = PyEmbeddedImage(
-    "iVBORw0KGgoAAAANSUhEUgAAAMgAAAAFCAYAAAAALqP0AAAAAXNSR0IArs4c6QAAAAlwSFlz"
-    "AAALEgAACxIB0t1+/AAADst0RVh0Q29tbWVudABwclZXIGNodW5rbGVuIDMwMiBpZ25vcmVk"
-    "Og1BU0NJSTogeJzt0U1WwjAuwPHpLohUKS5tibG3yM4ude11ei4u4OtdvIE4ky76cOVz+/9l"
-    "LuYjaS68f759yKu8nMys6zTPc8rm9Exq1C6nLicuS7UwcS5ljHGMMopEyyQu0S5FJGUuLi4u"
-    "Li5Xdb2pd/cuu1pj899y+6ixrTV+lufcktvvLl7p1ut+8C7r9efnUut2Kb/PhOshu5vK9I5l"
-    "LtrQtiG0wdmmq3IuT7ffLp1vOt9rLnvfaVjprfSNdo69jvy+P5fPjZbDfunZuSYNSEVYOiA3"
-    "ODlDRUREMTRENTZDMjMwMTBDMEYxRTkwNzg4NTQyOTBENkQ4OUIxQjdDOENFMDM3NUVENzU3"
-    "QTE5MEZFMEVCNURCQzgxMzg5MzAyRkE3MEU1NzNGQkZGNjUxQUU2MjM2OTE3QkM3RkJFN0RD"
-    "OEFCQkM5Q0NDQUNFQjM0Q0Y3M0NBRTZGNDRDNkFENDE4QTcxODI3MTE0QkI1MzA3MTFDNjU4"
-    "QzcxOEMzMjhBNDRDQjI0MUFEMTE1NDUyNDY1MDAwMDAwMDAwMA1ta0JGIGNodW5rbGVuIDcy"
-    "IGlnbm9yZWQ6DUFTQ0lJOiD63sr+Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
-    "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4NSEVYOiBGQURFQ0FGRTAwMDAw"
-    "MDA0MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDANbWtUUyBjaHVua2xlbiA4ODg2IGlnbm9yZWQ6DUFT"
-    "Q0lJOiB4nO1dWXPbSJLG9ozbLd/unph92C5FbGzsU2twLnwuRVHSWC6HpHy9OHjB1rSPLllW"
-    "t5fB/76ZWVUgUCiAOChSni6rW0WiUC6+zPwqqyouOnnWup51ensuM2ve+8cpJKHfLobj+cvj"
-    "vXBmzl+x5MVRO5zZtjk/PC6EM2/e2++Hs4Y97/XPLyC7dS4uhPRv3j0+vp61uvBrb3fweWZs"
-    "LiNjbLwxusbU+C6fLoz386PTLsi5LjkuIccyfobcLuN3uOP9vNc+LmGVuw1IRVg6IDc4OUNF"
-    "RDVENTk3M0RCNDg5MkM2RjY4Q0RCMkRERkVFOUU5ODdERDgxNzQ1NkM2Q0VDNTM2QjcwMTM3"
-    "QzE0NDU1MUQyNTgwNzg3QTQ3Q0JEMzg3OEMxRDZCNDhGMUU1OTU2Qjc5N0MxRkZCRTk5NTk1"
-    "NTIwNTAyODgwMzgyODUyOUUyRUFCNUI0NUEyNTAwN0JFQ0NGQzJBQUIyQTBCM0E3OUQ2QkE5"
-    "RTc1N0E3QjE3MzM2QkRFRkJDNzI5MjRBMURGMDg4NkUzDW1rQlMgY2h1bmtsZW4gMTkwIGln"
-    "bm9yZWQ6DUFTQ0lJOiB4nF1Oyy6CMC7szd/wLi6DwFHKq2GrLmoub2hswlWTJmaz/27Lw4Nz"
-    "mcnMzmZknS4sLj6iTy5wjS71M11FpjEu91QupdGPLmryVqPj9jLag7S0Lb2AoC6DcOgupnV5"
-    "t/GlLkdwlG9kLi5sYC72ZC+2ZT7Jdi452C7PXZPXzshBLi6y/C7dqZg2zfS38NzZ2Z5HlS7D"
-    "g1R7LjH2SC77UYlsxEgnOopp0YOOnqvexY9w1WEuJ0SZOi6kLl+6Ll+mDUhFWDogNzg5QzVE"
-    "NEVDQjBFODIzMDEwRUNDRERGRjAxMzAwODNDMDUxQ0FBQjYxQUIwNjZBMDQ2RjY4NkNDMjU1"
-    "OTMyNjY2QjNGRjZFQ0JDMzgzNzM5OUM5Q0NDRTY2NjQ5RDFBMkMxQTNFQTI0RjFENzA4RDFF"
-    "RjUzMzVENDVBNjMxMDhGNzU0MDlBNUQxOEYwMjZBRjI1NkEzRTNGNjMyREE4M0I0QjQyREJE"
-    "ODBBMDA3ODM3MEU4MERBNjc1NzlCN0YxQTUwMTQ3NzANbWtCVCBjaHVua2xlbiAxMTQ1IGln"
-    "bm9yZWQ6DUFTQ0lJOiD6zsr+Ln84xS4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
-    "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4ueJztmolt6zAuLl1ILkkhKSSN"
-    "pJAukkZSiD82+GM8bEjZsWT4mi4udJDisctDIrXfK6WUUkoppZRSSv3X9/f3/uvra0qF34Oy"
-    "LpdM+y7pX1NVn91uN+Xz83P/+vr6c37LdacuVdYtVb5/eXk52GPr9K+t9P/7+/svSnWseg1I"
-    "RVg6IEZBQ0VDQUZFMDA3RjM4QzUwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwNzg5Q0VE"
-    "OUE4OTZERUIzMDEwMDU1RDQ4MUE0OTIxMjkyNDhEQTQ5MDE0OTI0NjUyDW1rQlQgY2h1bmts"
-    "ZW4gMzM5IGlnbm9yZWQ6DUFTQ0lJOiD6zsr+Ln9ViS4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
-    "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4ueJzt1uFpg2Au"
-    "hlEucS4ucS4ucS4ucS4usbyBLremIf+KLueBQ5tP++tNbM5TkiRJkiRJkiRJkiRJkiRJkiRJ"
-    "LtFxLue+70/nOcu1d/e/uk/3b13Xcy7Hc5qmx8/sLv0s99S9dS7LsjxexzAuf76HdO+yY5V9"
-    "s2F2rc37PQ1IRVg6IEZBQ0VDQUZFMDA3RjU1ODkwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwNzg5Q0VERDZFMTY5ODM2MDE0ODY1MTA3NzExMTA3NzExMDE3NzExMDA3NzExMTA3DW1r"
-    "QlQgY2h1bmtsZW4gMzc5OSBpZ25vcmVkOg1BU0NJSTog+s7K/i5/n3guLi4uLi4uLi4uLi4u"
-    "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
-    "Lnic7Z2NkS4pLoUuiC5xIC7EiTguLuJELshe6eo+17tnSUDPz/5Yr2pqZ7tpLi4u0IOel5fB"
-    "YDAuLi6DwWAwLi4ug8HgP/z69evl58+ff3ziOveq5+JzpawuZfj3wf9R6fmK/jN8//795dOn"
-    "T3984jr3Mnz58uXfzy6+ffsNSEVYOiBGQUNFQ0FGRTAwN0Y5Rjc4MDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDc4OUNFRDlEOEQ5MTFDMjkwQzg1MUQ4ODEzNzEyMDBFQzQ4OTM4MTAw"
-    "N0UyNDQxQw1ta0JUIGNodW5rbGVuIDI3NDEgaWdub3JlZDoNQVNDSUk6IPrOyv4uf69+Li4u"
-    "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
-    "Li4uLi4uLi4uLi54nO2djZHbOC5GU0guSSEpJI2kkC6SRlJIbpCbd/PuLkjJWa8u23gzntXq"
-    "h6QuLqIukPr5cy6GYS6GYS6GYS6GYXhJvn///tvvx48u/y67J1WOe5fh2fnw4cNvv69fv/6q"
-    "99q+Z/1XOaouw/uBvM/i9vCW/rm7to7Vbyd/DUhFWDogRkFDRUNBRkUwMDdGQUY3RTAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA3ODlDRUQ5RDhEOTFEQjM4MEM0NjUzNDgxQTQ5MjEy"
-    "OTI0OERBNDkwMTQ5MjQ2NTINbWtCVCBjaHVua2xlbiAxMDc3NSBpZ25vcmVkOg1BU0NJSTog"
-    "+s7K/i5/1PAuLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4u"
-    "Li4uLi4uLi4uLi4uLi4uLi4uLi4uLnic7X0ruOwo1vaSSCwuicQikUgkLi6JxCIjkVgkLi6J"
-    "jYyMjI0smX9R+5zunp7p+dT/1Ihac+k+VXvXLrAu77suVObnfTaeLtqzkS3G10Zgh6PDLnBd"
-    "xS5rLt+FfsPzYi7ggS4uLrYuLtCeJMF33ZPZsYTB8c18c/zxQ28NSEVYOiBGQUNFQ0FGRTAw"
-    "N0ZENEYwMDAwMDAwMDEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw"
-    "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDc4OUNFRDdEMkJCOEVDMjhENkY2"
-    "OTI0ODJDMTI4OUM0MjI5MTQ4MjQxNjE5ODlDNIWzHPoAAAAhdEVYdFNvZnR3YXJlAEdyYXBo"
-    "aWNDb252ZXJ0ZXIgKEludGVsKXeH+hkAAADWSURBVHic7JO7CsJAEEVH95UHpFBEhBUTJIpB"
-    "I0GFFDYRBNHSxr/Zn/B/R9c+Ewvt5sLtDswwwwHgcDh06muAVE3Y62TipA+HM80MxgLKoyGZ"
-    "kRWw3GmSsbmEealIJi2Ue3Mk4+dMUukopqj1Z2+KqRqDybBPMv4239xRqt8wflbXP/zOfveu"
-    "n9VVgLcmam1mJew3hmQWmXJFrklmu9K41to94hjbegoCzKQEirmEIVohSOYeRWiVhud0hm1l"
-    "QVgQFoQFYUFYEBaEBWFB/iLICwAA//8DAHqeTXUOgGpTAAAAAElFTkSuQmCC")
-
 def interpFloat(t, v1, v2):
     "interpolator for a single value; interprets t in [0-1] between v1 and v2"
     return (v2-v1)*t + v1
@@ -160,8 +72,12 @@ def GetRoundShape( w, h, r ):
     return wx.RegionFromBitmap( GetRoundBitmap(w,h,r) )
 
 class ControlSlider(wx.Panel):
-    def __init__(self, parent, minvalue, maxvalue, init=None, pos=(0,0), size=(200,16), log=False, outFunction=None, integer=False, powoftwo=False, backColour=None):
-        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size, style=wx.NO_BORDER | wx.WANTS_CHARS | wx.EXPAND)
+    def __init__(self, parent, minvalue, maxvalue, init=None, pos=(0,0), size=(200,16), log=False, 
+                 outFunction=None, integer=False, powoftwo=False, backColour=None, orient=wx.HORIZONTAL):
+        if size == (200,16) and orient == wx.VERTICAL:
+            size = (40, 200)
+        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size, 
+                            style=wx.NO_BORDER | wx.WANTS_CHARS | wx.EXPAND)
         self.parent = parent
         if backColour: 
             self.backgroundColour = backColour
@@ -169,10 +85,16 @@ class ControlSlider(wx.Panel):
             self.backgroundColour = BACKGROUND_COLOUR
         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)  
         self.SetBackgroundColour(self.backgroundColour)
-        self.SetMinSize(self.GetSize())
-        self.knobSize = 40
-        self.knobHalfSize = 20
-        self.sliderHeight = size[1] - 5
+        self.orient = orient
+        # self.SetMinSize(self.GetSize())
+        if self.orient == wx.VERTICAL:
+            self.knobSize = 17
+            self.knobHalfSize = 8
+            self.sliderWidth = size[0] - 29
+        else:
+            self.knobSize = 40
+            self.knobHalfSize = 20
+            self.sliderHeight = size[1] - 5
         self.outFunction = outFunction
         self.integer = integer
         self.log = log
@@ -202,8 +124,11 @@ class ControlSlider(wx.Panel):
         self.Bind(wx.EVT_SIZE, self.OnResize)
         self.Bind(wx.EVT_KEY_DOWN, self.keyDown)
         self.Bind(wx.EVT_KILL_FOCUS, self.LooseFocus)
-        self.createSliderBitmap()
-        self.createKnobBitmap()
+
+        if sys.platform == "win32":
+            self.dcref = wx.BufferedPaintDC
+        else:
+            self.dcref = wx.PaintDC
 
     def setMidiCtl(self, x, propagate=True):
         self.propagate = propagate
@@ -229,41 +154,10 @@ class ControlSlider(wx.Panel):
         
     def setSliderHeight(self, height):
         self.sliderHeight = height
-        self.createSliderBitmap()
-        self.createKnobBitmap()
         self.Refresh()
 
-    def createSliderBitmap(self):
-        w, h = self.GetSize()
-        b = wx.EmptyBitmap(w,h)
-        dc = wx.MemoryDC(b)
-        dc.SetPen(wx.Pen(self.backgroundColour, width=1))
-        dc.SetBrush(wx.Brush(self.backgroundColour))
-        dc.DrawRectangle(0,0,w,h)
-        dc.SetBrush(wx.Brush("#999999"))
-        dc.SetPen(wx.Pen(self.backgroundColour, width=1))
-        h2 = self.sliderHeight / 4
-        dc.DrawRoundedRectangle(0,h2,w,self.sliderHeight,2)
-        dc.SelectObject(wx.NullBitmap)
-        b.SetMaskColour("#999999")
-        self.sliderMask = b
-
-    def createKnobBitmap(self):
-        w, h = self.knobSize, self.GetSize()[1]
-        b = wx.EmptyBitmap(w,h)
-        dc = wx.MemoryDC(b)
-        rec = wx.Rect(0, 0, w, h)
-        dc.SetPen(wx.Pen(self.backgroundColour, width=1))
-        dc.SetBrush(wx.Brush(self.backgroundColour))
-        dc.DrawRectangleRect(rec)
-        h2 = self.sliderHeight / 4
-        rec = wx.Rect(0, h2, w, self.sliderHeight)
-        dc.GradientFillLinear(rec, "#414753", "#99A7CC", wx.BOTTOM)
-        dc.SetBrush(wx.Brush("#999999"))
-        dc.DrawRoundedRectangle(0,0,w,h,2)
-        dc.SelectObject(wx.NullBitmap)
-        b.SetMaskColour("#999999")
-        self.knobMask = b
+    def setSliderWidth(self, width):
+        self.sliderWidth = width
 
     def getInit(self):
         return self.init
@@ -276,7 +170,11 @@ class ControlSlider(wx.Panel):
         return [self.minvalue, self.maxvalue]
 
     def scale(self):
-        inter = tFromValue(self.pos, self.knobHalfSize, self.GetSize()[0]-self.knobHalfSize)
+        if self.orient == wx.VERTICAL:
+            h = self.GetSize()[1]
+            inter = tFromValue(h-self.pos, self.knobHalfSize, self.GetSize()[1]-self.knobHalfSize)
+        else:
+            inter = tFromValue(self.pos, self.knobHalfSize, self.GetSize()[0]-self.knobHalfSize)
         if not self.integer:
             return interpFloat(inter, self.minvalue, self.maxvalue)
         elif self.powoftwo:
@@ -348,7 +246,10 @@ class ControlSlider(wx.Panel):
             return
         if self._enable:
             size = self.GetSize()
-            self.pos = clamp(evt.GetPosition()[0], self.knobHalfSize, size[0]-self.knobHalfSize)
+            if self.orient == wx.VERTICAL:
+                self.pos = clamp(evt.GetPosition()[1], self.knobHalfSize, size[1]-self.knobHalfSize)
+            else:
+                self.pos = clamp(evt.GetPosition()[0], self.knobHalfSize, size[0]-self.knobHalfSize)
             self.value = self.scale()
             self.CaptureMouse()
             self.selected = False
@@ -363,8 +264,12 @@ class ControlSlider(wx.Panel):
         if self._enable:
             w, h = self.GetSize()
             pos = event.GetPosition()
-            if wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize, h).Contains(pos):
-                self.selected = True
+            if self.orient == wx.VERTICAL:
+                if wx.Rect(0, self.pos-self.knobHalfSize, w, self.knobSize).Contains(pos):
+                    self.selected = True
+            else:
+                if wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize, h).Contains(pos):
+                    self.selected = True
             self.Refresh()
         event.Skip()
             
@@ -372,13 +277,15 @@ class ControlSlider(wx.Panel):
         if self._enable:
             size = self.GetSize()
             if self.HasCapture():
-                self.pos = clamp(evt.GetPosition()[0], self.knobHalfSize, size[0]-self.knobHalfSize)
+                if self.orient == wx.VERTICAL:
+                    self.pos = clamp(evt.GetPosition()[1], self.knobHalfSize, size[1]-self.knobHalfSize)
+                else:
+                    self.pos = clamp(evt.GetPosition()[0], self.knobHalfSize, size[0]-self.knobHalfSize)
                 self.value = self.scale()
                 self.selected = False
                 self.Refresh()
 
     def OnResize(self, evt):
-        self.createSliderBitmap()
         self.clampPos()    
         self.Refresh()
 
@@ -387,20 +294,23 @@ class ControlSlider(wx.Panel):
         if self.powoftwo:
             val = powOfTwoToInt(self.value)
         else:
-            val = self.value    
-        self.pos = tFromValue(val, self.minvalue, self.maxvalue) * (size[0] - self.knobSize) + self.knobHalfSize
-        self.pos = clamp(self.pos, self.knobHalfSize, size[0]-self.knobHalfSize)
+            val = self.value 
+        if self.orient == wx.VERTICAL:
+            self.pos = tFromValue(val, self.minvalue, self.maxvalue) * (size[1] - self.knobSize) + self.knobHalfSize
+            self.pos = clamp(size[1]-self.pos, self.knobHalfSize, size[1]-self.knobHalfSize)
+        else:
+            self.pos = tFromValue(val, self.minvalue, self.maxvalue) * (size[0] - self.knobSize) + self.knobHalfSize
+            self.pos = clamp(self.pos, self.knobHalfSize, size[0]-self.knobHalfSize)
         
     def setBackgroundColour(self, colour):
         self.backgroundColour = colour
         self.SetBackgroundColour(self.backgroundColour)
-        self.createSliderBitmap()
-        self.createKnobBitmap()
         self.Refresh()
 
     def OnPaint(self, evt):
         w,h = self.GetSize()
-        dc = wx.AutoBufferedPaintDC(self)
+        dc = self.dcref(self)
+        gc = wx.GraphicsContext_Create(dc)
 
         dc.SetBrush(wx.Brush(self.backgroundColour, wx.SOLID))
         dc.Clear()
@@ -412,10 +322,16 @@ class ControlSlider(wx.Panel):
         # Draw inner part
         if self._enable: sliderColour =  "#99A7CC"
         else: sliderColour = "#BBBBBB"
-        h2 = self.sliderHeight / 4
-        rec = wx.Rect(0, h2, w, self.sliderHeight)
-        dc.GradientFillLinear(rec, "#646986", sliderColour, wx.BOTTOM)
-        dc.DrawBitmap(self.sliderMask, 0, 0, True)
+        if self.orient == wx.VERTICAL:
+            w2 = (w - self.sliderWidth) / 2
+            rec = wx.Rect(w2, 0, self.sliderWidth, h)
+            brush = gc.CreateLinearGradientBrush(w2, 0, w2+self.sliderWidth, 0, "#646986", sliderColour)
+        else:
+            h2 = self.sliderHeight / 4
+            rec = wx.Rect(0, h2, w, self.sliderHeight)
+            brush = gc.CreateLinearGradientBrush(0, h2, 0, h2+self.sliderHeight, "#646986", sliderColour)
+        gc.SetBrush(brush)
+        gc.DrawRoundedRectangle(rec[0], rec[1], rec[2], rec[3], 2)
 
         if self.midictl != None:
             if sys.platform in ['win32', 'linux2']:
@@ -423,21 +339,32 @@ class ControlSlider(wx.Panel):
             else:    
                 dc.SetFont(wx.Font(9, wx.ROMAN, wx.NORMAL, wx.NORMAL))
             dc.SetTextForeground('#FFFFFF')
-            dc.DrawLabel(str(self.midictl), wx.Rect(2,0,h,h), wx.ALIGN_CENTER)
-            dc.DrawLabel(str(self.midictl), wx.Rect(w-h,0,h,h), wx.ALIGN_CENTER)
+            if self.orient == wx.VERTICAL:
+                dc.DrawLabel(str(self.midictl), wx.Rect(w2,2,self.sliderWidth,12), wx.ALIGN_CENTER)
+                dc.DrawLabel(str(self.midictl), wx.Rect(w2,h-12,self.sliderWidth,12), wx.ALIGN_CENTER)
+            else:
+                dc.DrawLabel(str(self.midictl), wx.Rect(2,0,h,h), wx.ALIGN_CENTER)
+                dc.DrawLabel(str(self.midictl), wx.Rect(w-h,0,h,h), wx.ALIGN_CENTER)
 
         # Draw knob
         if self._enable: knobColour = '#888888'
         else: knobColour = "#DDDDDD"
-        rec = wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize, h)  
-        dc.GradientFillLinear(rec, "#424864", knobColour, wx.RIGHT)
-        dc.DrawBitmap(self.knobMask, rec[0], rec[1], True)
-        
-        if self.selected:
-            rec2 = wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize, h)  
-            dc.SetBrush(wx.Brush('#333333', wx.SOLID))
-            dc.SetPen(wx.Pen('#333333', width=self.borderWidth, style=wx.SOLID))  
-            dc.DrawRoundedRectangleRect(rec2, 3)
+        if self.orient == wx.VERTICAL:
+            rec = wx.Rect(0, self.pos-self.knobHalfSize, w, self.knobSize-1)
+            if self.selected:
+                brush = wx.Brush('#333333', wx.SOLID)
+            else:
+                brush = gc.CreateLinearGradientBrush(0, 0, w, 0, "#323854", knobColour)
+            gc.SetBrush(brush)
+            gc.DrawRoundedRectangle(rec[0], rec[1], rec[2], rec[3], 3)
+        else:
+            rec = wx.Rect(self.pos-self.knobHalfSize, 0, self.knobSize-1, h)  
+            if self.selected:
+                brush = wx.Brush('#333333', wx.SOLID)
+            else:
+                brush = gc.CreateLinearGradientBrush(self.pos-self.knobHalfSize, 0, self.pos+self.knobHalfSize, 0, "#323854", knobColour)
+            gc.SetBrush(brush)
+            gc.DrawRoundedRectangle(rec[0], rec[1], rec[2], rec[3], 3)
 
         if sys.platform in ['win32', 'linux2']:
             dc.SetFont(wx.Font(7, wx.ROMAN, wx.NORMAL, wx.NORMAL))
@@ -524,7 +451,10 @@ class MultiSlider(wx.Panel):
         slide = pos[1] / self._height
         if 0 <= slide < self._nchnls:
             self._values[slide] = pos[0] / float(w)
-            self._labels = [self._slmap.get(x) for x in self._values]
+            if self._slmap._res == 'int':
+                self._labels = [int(self._slmap.get(x)) for x in self._values]
+            else:
+                self._labels = [self._slmap.get(x) for x in self._values]
             self._command(self._key, self._labels)
             self.CaptureMouse()
         self.Refresh()
@@ -541,45 +471,103 @@ class MultiSlider(wx.Panel):
             slide = pos[1] / self._height
             if 0 <= slide < self._nchnls:
                 self._values[slide] = pos[0] / float(w)
-                self._labels = [self._slmap.get(x) for x in self._values]
+                if self._slmap._res == 'int':
+                    self._labels = [int(self._slmap.get(x)) for x in self._values]
+                else:
+                    self._labels = [self._slmap.get(x) for x in self._values]
                 self._command(self._key, self._labels)
             self.Refresh()
         
 class VuMeter(wx.Panel):
-    def __init__(self, parent, size=(200,11), numSliders=2):
+    def __init__(self, parent, size=(200,11), numSliders=2, orient=wx.HORIZONTAL):
+        if orient == wx.HORIZONTAL:
+            size = (size[0], numSliders * 5 + 1)
+        else:
+            size = (numSliders * 5 + 1, size[1])        
         wx.Panel.__init__(self, parent, -1, size=size)
         self.parent = parent
+        self.orient = orient
         self.SetBackgroundColour("#000000")
         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
         self.old_nchnls = numSliders
         self.numSliders = numSliders
-        self.SetMinSize((200,5*self.numSliders+1))
-        self.SetSize((200, 5*self.numSliders+1))
-        self.bitmap = vu_metre.GetBitmap()
-        self.backBitmap = vu_metre_dark.GetBitmap()
         self.amplitude = [0] * self.numSliders
+        self.createBitmaps()
 
         self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
         self.Bind(wx.EVT_CLOSE, self.OnClose)   
 
+    def OnSize(self, evt):
+        self.createBitmaps()
+        wx.CallAfter(self.Refresh)
+
+    def createBitmaps(self):
+        w, h = self.GetSize()
+        b = wx.EmptyBitmap(w,h)
+        f = wx.EmptyBitmap(w,h)
+        dcb = wx.MemoryDC(b)
+        dcf = wx.MemoryDC(f)
+        dcb.SetPen(wx.Pen("#000000", width=1))
+        dcf.SetPen(wx.Pen("#000000", width=1))
+        if self.orient == wx.HORIZONTAL:
+            height = 6
+            steps = int(w / 10.0 + 0.5)
+        else:
+            width = 6
+            steps = int(h / 10.0 + 0.5)
+        bounds = int(steps / 6.0)
+        for i in range(steps):
+            if i == (steps - 1):
+                dcb.SetBrush(wx.Brush("#770000"))
+                dcf.SetBrush(wx.Brush("#FF0000"))
+            elif i >= (steps - bounds):
+                dcb.SetBrush(wx.Brush("#440000"))
+                dcf.SetBrush(wx.Brush("#CC0000"))
+            elif i >= (steps - (bounds*2)):
+                dcb.SetBrush(wx.Brush("#444400"))
+                dcf.SetBrush(wx.Brush("#CCCC00"))
+            else:
+                dcb.SetBrush(wx.Brush("#004400"))
+                dcf.SetBrush(wx.Brush("#00CC00"))
+            if self.orient == wx.HORIZONTAL:
+                dcb.DrawRectangle(i*10, 0, 11, height)
+                dcf.DrawRectangle(i*10, 0, 11, height)
+            else:
+                ii = steps - 1 - i
+                dcb.DrawRectangle(0, ii*10, width, 11)
+                dcf.DrawRectangle(0, ii*10, width, 11)
+        if self.orient == wx.HORIZONTAL:
+            dcb.DrawLine(w-1, 0, w-1, height)
+            dcf.DrawLine(w-1, 0, w-1, height)
+        else:
+            dcb.DrawLine(0, 0, width, 0)
+            dcf.DrawLine(0, 0, width, 0)
+        dcb.SelectObject(wx.NullBitmap)
+        dcf.SelectObject(wx.NullBitmap)
+        self.backBitmap = b
+        self.bitmap = f
+
     def setNumSliders(self, numSliders):
+        w, h = self.GetSize()
         oldChnls = self.old_nchnls
         self.numSliders = numSliders
         self.amplitude = [0] * self.numSliders
         gap = (self.numSliders - oldChnls) * 5
         parentSize = self.parent.GetSize()
-        if sys.platform == 'linux2':
-            self.SetSize((200, 5*self.numSliders+1))
-            self.SetMinSize((200, 5*self.numSliders+1))
+        if self.orient == wx.HORIZONTAL:
+            self.SetSize((w, self.numSliders * 5 + 1))
+            self.SetMinSize((w, 5*self.numSliders+1))
             self.parent.SetSize((parentSize[0], parentSize[1]+gap))
             self.parent.SetMinSize((parentSize[0], parentSize[1]+gap))
         else:
-            self.SetSize((200, 5*self.numSliders+1))
-            self.SetMinSize((200, 5*self.numSliders+1))
-            self.parent.SetSize((parentSize[0], parentSize[1]+gap))
-            self.parent.SetMinSize((parentSize[0], parentSize[1]+gap))
-        self.Refresh()
-        self.parent.Layout()
+            self.SetSize((self.numSliders * 5 + 1, h))
+            self.SetMinSize((5*self.numSliders+1, h))
+            self.parent.SetSize((parentSize[0]+gap, parentSize[1]))
+            self.parent.SetMinSize((parentSize[0]+gap, parentSize[1]))
+        wx.CallAfter(self.Refresh)
+        wx.CallAfter(self.parent.Layout)
+        wx.CallAfter(self.parent.Refresh)
 
     def setRms(self, *args):
         if args[0] < 0: 
@@ -596,13 +584,28 @@ class VuMeter(wx.Panel):
         dc.SetBrush(wx.Brush("#000000"))
         dc.Clear()
         dc.DrawRectangle(0,0,w,h)
-        for i in range(self.numSliders):
-            db = math.log10(self.amplitude[i]+0.00001) * 0.2 + 1.
-            width = int(db*w)
-            dc.DrawBitmap(self.backBitmap, 0, i*5)
-            dc.SetClippingRegion(0, i*5, width, 5)
-            dc.DrawBitmap(self.bitmap, 0, i*5)
-            dc.DestroyClippingRegion()
+        if self.orient == wx.HORIZONTAL:
+            height = 6
+            for i in range(self.numSliders):
+                y = i * (height - 1)
+                db = math.log10(self.amplitude[i]+0.00001) * 0.2 + 1.
+                width = int(db*w)
+                dc.DrawBitmap(self.backBitmap, 0, y)
+                if width > 0:
+                    dc.SetClippingRegion(0, y, width, height)
+                    dc.DrawBitmap(self.bitmap, 0, y)
+                    dc.DestroyClippingRegion()
+        else:
+            width = 6
+            for i in range(self.numSliders):
+                y = i * (width - 1)
+                db = math.log10(self.amplitude[i]+0.00001) * 0.2 + 1.
+                height = int(db*h)
+                dc.DrawBitmap(self.backBitmap, y, 0)
+                if height > 0:
+                    dc.SetClippingRegion(y, h-height, width, height)
+                    dc.DrawBitmap(self.bitmap, y, 0)
+                    dc.DestroyClippingRegion()
         event.Skip()
         
     def OnClose(self, evt):
@@ -887,14 +890,17 @@ class PyoObjectControl(wx.Frame):
         self.box = wx.FlexGridSizer(10,2,5,5)
         
         for i, m in enumerate(self._map_list):
-            key, init, mini, maxi, scl, res = m.name, m.init, m.min, m.max, m.scale, m.res
+            key, init, mini, maxi, scl, res, dataOnly = m.name, m.init, m.min, m.max, m.scale, m.res, m.dataOnly
             # filters PyoObjects
             if type(init) not in [ListType, FloatType, IntType]:
                 self._excluded.append(key)
             else:    
                 self._maps[key] = m
                 # label (param name)
-                label = wx.StaticText(panel, -1, key)
+                if dataOnly:
+                    label = wx.StaticText(panel, -1, key+" *")
+                else:
+                    label = wx.StaticText(panel, -1, key)
                 # create and pack slider
                 if type(init) != ListType:
                     if scl == 'log': scl = True
@@ -907,15 +913,16 @@ class PyoObjectControl(wx.Frame):
                 else:
                     self._sliders.append(MultiSlider(panel, init, key, self.setval, m))
                     self.box.AddMany([(label, 0, wx.LEFT, 5), (self._sliders[-1], 1, wx.EXPAND | wx.LEFT, 5)])   
-                # set obj attribute to PyoObject SigTo  
-                self._values[key] = init
-                self._sigs[key] = SigTo(init, .025, init)
-                refStream = self._obj.getBaseObjects()[0]._getStream()
-                server = self._obj.getBaseObjects()[0].getServer()
-                for k in range(len(self._sigs[key].getBaseObjects())):
-                    curStream = self._sigs[key].getBaseObjects()[k]._getStream()
-                    server.changeStreamPosition(refStream, curStream)
-                setattr(self._obj, key, self._sigs[key])
+                # set obj attribute to PyoObject SigTo
+                if not dataOnly:
+                    self._values[key] = init
+                    self._sigs[key] = SigTo(init, .025, init)
+                    refStream = self._obj.getBaseObjects()[0]._getStream()
+                    server = self._obj.getBaseObjects()[0].getServer()
+                    for k in range(len(self._sigs[key].getBaseObjects())):
+                        curStream = self._sigs[key].getBaseObjects()[k]._getStream()
+                        server.changeStreamPosition(refStream, curStream)
+                    setattr(self._obj, key, self._sigs[key])
         self.box.AddGrowableCol(1, 1) 
         mainBox.Add(self.box, 1, wx.EXPAND | wx.TOP | wx.BOTTOM | wx.RIGHT, 10)
 
@@ -927,22 +934,25 @@ class PyoObjectControl(wx.Frame):
     def _destroy(self, event):
         for m in self._map_list:
             key = m.name
-            if key not in self._excluded:
+            if key not in self._excluded and key in self._values:
                 setattr(self._obj, key, self._values[key])
                 del self._sigs[key]
         self.Destroy()        
 
     def setval(self, key, x):
-        self._values[key] = x
-        setattr(self._sigs[key], "value", x)
+        if key in self._values:
+            self._values[key] = x
+            setattr(self._sigs[key], "value", x)
+        else:
+            setattr(self._obj, key, x)
 
 ######################################################################
 ### View window for PyoTableObject
 ######################################################################
 class ViewTable(wx.Frame):
     def __init__(self, parent, samples=None, tableclass=None, object=None):
-        wx.Frame.__init__(self, parent)
-        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        wx.Frame.__init__(self, parent, size=(500,200))
+        self.SetMinSize((300, 150))
         menubar = wx.MenuBar()        
         fileMenu = wx.Menu()
         closeItem = fileMenu.Append(-1, 'Close\tCtrl+W', kind=wx.ITEM_NORMAL)
@@ -951,77 +961,61 @@ class ViewTable(wx.Frame):
         self.SetMenuBar(menubar)
         self.tableclass = tableclass
         self.object = object
-        self.Bind(wx.EVT_PAINT, self.OnPaint)
         self.Bind(wx.EVT_CLOSE, self._destroy)
-        self.width, self.height = 500, 200
-        self.half_height = self.height / 2
-        self.SetClientSize((self.width+10, self.height+10))
-        self.SetMinSize(self.GetSize())
-        self.SetMaxSize(self.GetSize())
-        self.draw(samples)
+        self.panel = wx.Panel(self)
+        self.panel.SetBackgroundColour(BACKGROUND_COLOUR)
+        self.box = wx.BoxSizer(wx.VERTICAL)
+        self.wavePanel = ViewTablePanel(self.panel, object)
+        self.box.Add(self.wavePanel, 1, wx.EXPAND|wx.ALL, 5)
+        self.panel.SetSizerAndFit(self.box)
+        self.update(samples)
 
     def update(self, samples):
-        wx.CallAfter(self.draw, samples)
+        wx.CallAfter(self.wavePanel.draw, samples)
 
     def _destroy(self, evt):
         self.object._setViewFrame(None)
         self.Destroy()
-        
-class ViewTable_withPIL(ViewTable):
-    _WITH_PIL = True
-    def __init__(self, parent, samples=None, tableclass=None, object=None):
-        ViewTable.__init__(self, parent, samples, tableclass, object)
 
-    def draw(self, samples):
-        im = Image.new("L", (self.width, self.height), 255)
-        draw = ImageDraw.Draw(im)
-        draw.line(samples, fill=0, width=1)
-        image = wx.EmptyImage(self.width, self.height)
-        image.SetData(im.convert("RGB").tostring())
-        self.img = wx.BitmapFromImage(image)
-        self.Refresh()
-
-    def OnPaint(self, evt):
-        dc = wx.PaintDC(self)
-        dc.DrawBitmap(self.img, 0, 0)
-        dc.SetPen(wx.Pen('#BBBBBB', width=1, style=wx.SOLID))  
-        dc.DrawLine(0, self.half_height+1, self.width, self.half_height+1)
+class ViewTablePanel(wx.Panel):
+    def __init__(self, parent, obj):
+        wx.Panel.__init__(self, parent)
+        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        self.obj = obj
+        self.samples = []
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        if sys.platform == "win32":
+            self.dcref = wx.BufferedPaintDC
+        else:
+            self.dcref = wx.PaintDC
 
-class ViewTable_withoutPIL(ViewTable):
-    _WITH_PIL = False
-    def __init__(self, parent, samples=None, tableclass=None, object=None):
-        ViewTable.__init__(self, parent, samples, tableclass, object)
         
     def draw(self, samples):
-        if sys.platform == 'win32':
-            if self.tableclass == 'SndTable':
-                self.samples = [(samples[i], samples[i+1], samples[i+2], samples[i+3]) for i in range(0, len(samples), 4)]
-            else:    
-                self.samples = [(samples[i], samples[i+1]) for i in range(0, len(samples), 2)]
-        else:        
-            self.samples = [(samples[i], samples[i+1], samples[i+2], samples[i+3]) for i in range(0, len(samples), 4)]
+        self.samples = samples
         self.Refresh()
 
     def OnPaint(self, evt):
         w,h = self.GetSize()
-        dc = wx.AutoBufferedPaintDC(self)
+        dc = self.dcref(self)
+        gc = wx.GraphicsContext_Create(dc)
         dc.SetBrush(wx.Brush("#FFFFFF"))
+        dc.SetPen(wx.Pen('#BBBBBB', width=1, style=wx.SOLID))  
         dc.Clear()
         dc.DrawRectangle(0,0,w,h)
-        if sys.platform == 'win32':
-            if self.tableclass == 'SndTable':
-                dc.DrawLineList(self.samples)
-            else:
-                dc.DrawPointList(self.samples)
-        else:
-            dc.DrawLineList(self.samples)
-        dc.SetPen(wx.Pen('#BBBBBB', width=1, style=wx.SOLID))  
-        dc.DrawLine(0, self.half_height+1, self.width, self.half_height+1)
+        gc.SetPen(wx.Pen('#000000', width=1, style=wx.SOLID))
+        gc.SetBrush(wx.Brush("#FFFFFF"))
+        if len(self.samples) > 1:
+            gc.DrawLines(self.samples)
+        dc.DrawLine(0, h/2+1, w, h/2+1)
 
+    def OnSize(self, evt):
+        wx.CallAfter(self.obj.refreshView)
+        
 class SndViewTable(wx.Frame):
     def __init__(self, parent, obj=None, tableclass=None, mouse_callback=None):
         wx.Frame.__init__(self, parent, size=(500,250))
-        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        self.SetMinSize((300, 150))
         self.menubar = wx.MenuBar()        
         self.fileMenu = wx.Menu()
         closeItem = self.fileMenu.Append(-1, 'Close\tCtrl+W', kind=wx.ITEM_NORMAL)
@@ -1029,24 +1023,59 @@ class SndViewTable(wx.Frame):
         self.menubar.Append(self.fileMenu, "&File")
         self.SetMenuBar(self.menubar)
         self.Bind(wx.EVT_CLOSE, self._destroy)
-        self.Bind(wx.EVT_PAINT, self.OnPaint)
-        self.Bind(wx.EVT_SIZE, self.OnSize)
-        self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
-        self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
-        self.Bind(wx.EVT_MOTION, self.OnMotion)
         self.obj = obj
         self.chnls = len(self.obj)
-        self.mouse_callback = mouse_callback
+        self.dur = self.obj.getDur(False)
+        self.panel = wx.Panel(self)
+        self.panel.SetBackgroundColour(BACKGROUND_COLOUR)
+        self.box = wx.BoxSizer(wx.VERTICAL)
+        self.wavePanel = SndViewTablePanel(self.panel, obj, mouse_callback)
+        self.box.Add(self.wavePanel, 1, wx.EXPAND|wx.ALL, 5)
+        self.zoomH = HRangeSlider(self.panel, minvalue=0, maxvalue=1, init=None, pos=(0,0), size=(200,15), 
+                 valtype='float', log=False, function=self.setZoomH)
+        self.box.Add(self.zoomH, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
+        self.panel.SetSizer(self.box)
+
+    def setZoomH(self, values):
+        self.wavePanel.setBegin(self.dur * values[0])
+        self.wavePanel.setEnd(self.dur * values[1])
+        self.update()
 
     def update(self):
-        wx.CallAfter(self.setImage)
+        wx.CallAfter(self.wavePanel.setImage)
 
     def _destroy(self, evt):
         self.obj._setViewFrame(None)
         self.Destroy()
 
-    def OnSize(self, evt):
+class SndViewTablePanel(wx.Panel):
+    def __init__(self, parent, obj, mouse_callback=None):
+        wx.Panel.__init__(self, parent)
+        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
+        self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
+        self.Bind(wx.EVT_MOTION, self.OnMotion)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.obj = obj
+        self.chnls = len(self.obj)
+        self.begin = 0
+        self.end = self.obj.getDur(False)
+        self.mouse_callback = mouse_callback
+        if sys.platform == "win32":
+            self.dcref = wx.BufferedPaintDC
+        else:
+            self.dcref = wx.PaintDC
         self.setImage()
+
+    def setBegin(self, x):
+        self.begin = x
+
+    def setEnd(self, x):
+        self.end = x
+
+    def setImage(self):
+        self.img = self.obj.getViewTable(self.GetSize(), self.begin, self.end)
         self.Refresh()
 
     def clipPos(self, pos):
@@ -1056,6 +1085,7 @@ class SndViewTable(wx.Frame):
         if pos[1] < 0.0: y = 0.0
         elif pos[1] > 1.0: y = 1.0
         else: y = pos[1]
+        x = x * ((self.end - self.begin) / self.obj.getDur(False)) + (self.begin / self.obj.getDur(False))
         return (x, y)
 
     def OnMouseDown(self, evt):
@@ -1086,77 +1116,50 @@ class SndViewTable(wx.Frame):
         if self.HasCapture():
             self.ReleaseMouse()
 
-class SndViewTable_withPIL(SndViewTable):
-    def __init__(self, parent, obj=None, tableclass=None, mouse_callback=None):
-        SndViewTable.__init__(self, parent, obj, tableclass, mouse_callback)
-        self.setImage()
-
-    def setImage(self):
-        w, h = self.GetSize()
-        self.img = []
-        imgHeight = h/self.chnls
-        for i in range(self.chnls):
-            im = Image.new("L", (w, imgHeight), 255)
-            draw = ImageDraw.Draw(im)
-            samples = self.obj._base_objs[i].getViewTable((w, imgHeight))
-            draw.line(samples, fill=0, width=1)
-            image = wx.EmptyImage(w, imgHeight)
-            image.SetData(im.convert("RGB").tostring())
-            self.img.append(wx.BitmapFromImage(image))
-        self.Refresh()
-
-    def OnPaint(self, evt):
-        w, h = self.GetSize()
-        dc = wx.AutoBufferedPaintDC(self)
-        dc.SetPen(wx.Pen('#444444', width=1, style=wx.SHORT_DASH))
-        off = h/self.chnls/2
-        for i, img in enumerate(self.img):
-            y = h/self.chnls*i
-            dc.DrawBitmap(img, 0, y)
-            dc.DrawLine(0, y+off, w, y+off)
-
-class SndViewTable_withoutPIL(SndViewTable):
-    def __init__(self, parent, obj=None, tableclass=None, mouse_callback=None):
-        SndViewTable.__init__(self, parent, obj, tableclass, mouse_callback)
-        self.tableclass = tableclass
-        self.setImage()
-
-    def setImage(self):
-        w, h = self.GetSize()
-        self.img = []
-        imgHeight = h/self.chnls
-        for j in range(self.chnls):
-            off = h/self.chnls*j
-            samples = self.obj._base_objs[j].getViewTable((w, imgHeight))
-            if sys.platform == 'win32':
-                if self.tableclass == 'SndTable':
-                    samples = [(samples[i], samples[i+1]+off, samples[i+2], samples[i+3]+off) for i in range(0, len(samples), 4)]
-                else:
-                    samples = [(samples[i], samples[i+1]+off) for i in range(0, len(samples), 2)]
-            else:
-                samples = [(samples[i], samples[i+1]+off, samples[i+2], samples[i+3]+off) for i in range(0, len(samples), 4)]
-            self.img.append(samples)
-        self.Refresh()
-
     def OnPaint(self, evt):
         w,h = self.GetSize()
-        dc = wx.AutoBufferedPaintDC(self)
+        dc = self.dcref(self)
+        gc = wx.GraphicsContext_Create(dc)
         dc.SetBrush(wx.Brush("#FFFFFF"))
         dc.Clear()
         dc.DrawRectangle(0,0,w,h)
         off = h/self.chnls/2
+        gc.SetPen(wx.Pen('#000000', width=1, style=wx.SOLID))
+        gc.SetBrush(wx.Brush("#FFFFFF", style=wx.TRANSPARENT))
+        dc.SetTextForeground("#444444")
+        if sys.platform in "darwin":
+            font, ptsize = dc.GetFont(), dc.GetFont().GetPointSize()
+            font.SetPointSize(ptsize - 3)
+            dc.SetFont(font)
+        elif sys.platform == "win32":
+            font = dc.GetFont()
+            font.SetPointSize(8)
+            dc.SetFont(font)
+        tickstep = w / 10
+        if tickstep < 40:
+            timelabel = "%.1f"
+        elif tickstep < 80:
+            timelabel = "%.2f"
+        elif tickstep < 120:
+            timelabel = "%.3f"
+        else:
+            timelabel = "%.4f"
+        timestep = (self.end - self.begin) * 0.1
         for i, samples in enumerate(self.img):
-            dc.SetPen(wx.Pen('#000000', width=1, style=wx.SOLID))  
             y = h/self.chnls*i
-            if sys.platform == 'win32':
-                if self.tableclass == 'SndTable':
-                    dc.DrawLineList(samples)
-                else:
-                    dc.DrawPointList(samples)
-            else:
-                dc.DrawLineList(samples)
-            dc.SetPen(wx.Pen('#444444', width=1, style=wx.SHORT_DASH))  
+            if len(samples):
+                gc.DrawLines(samples)
+            dc.SetPen(wx.Pen('#888888', width=1, style=wx.DOT))  
             dc.DrawLine(0, y+off, w, y+off)
+            for j in range(10):
+                dc.SetPen(wx.Pen('#888888', width=1, style=wx.DOT))  
+                dc.DrawLine(j*tickstep, 0, j*tickstep, h)
+                dc.DrawText(timelabel % (self.begin+j*timestep), j*tickstep+2, h-y-12)
+            dc.SetPen(wx.Pen('#000000', width=1))  
+            dc.DrawLine(0, h-y, w, h-y)            
+
+    def OnSize(self, evt):
+        wx.CallAfter(self.setImage)
 
 ######################################################################
 ## View window for PyoMatrixObject
@@ -1298,9 +1301,8 @@ class SpectrumDisplay(wx.Frame):
                  valtype='float', log=False, function=self.setZoomH)
         self.box.Add(self.zoomH, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
         self.dispBox.Add(self.box, 1, wx.EXPAND, 0)
-        self.gainSlider = wx.Slider(self.panel, -1, 0, -24, 24, style=wx.SL_VERTICAL|wx.SL_INVERSE)
-        self.gainSlider.Bind(wx.EVT_SLIDER, self.setGain)
-        self.dispBox.Add(self.gainSlider, 0, wx.EXPAND|wx.BOTTOM, 15)
+        self.gainSlider = ControlSlider(self.panel, -24, 24, 0, outFunction=self.setGain, orient=wx.VERTICAL)
+        self.dispBox.Add(self.gainSlider, 0, wx.EXPAND|wx.TOP, 5)
         self.dispBox.AddSpacer(5)  
         self.mainBox.Add(self.dispBox, 1, wx.EXPAND) 
         self.panel.SetSizer(self.mainBox)
@@ -1334,8 +1336,8 @@ class SpectrumDisplay(wx.Frame):
         size = 1 << (evt.GetInt() + 6)
         self.obj.size = size
 
-    def setGain(self, evt):
-        self.obj.setGain(pow(10.0, evt.GetInt() * 0.05))
+    def setGain(self, gain):
+        self.obj.setGain(pow(10.0, gain * 0.05))
 
     def setZoomH(self, values):
         self.spectrumPanel.setLowFreq(self.obj.setLowbound(values[0]))
@@ -1543,6 +1545,164 @@ class SpectrumPanel(wx.Panel):
                 gc.DrawLines(samples)
 
 ######################################################################
+## Spectrum Display
+######################################################################
+class ScopeDisplay(wx.Frame):
+    def __init__(self, parent, obj=None):
+        wx.Frame.__init__(self, parent, size=(600,350))
+        self.SetMinSize((400,240))
+        self.menubar = wx.MenuBar()        
+        self.fileMenu = wx.Menu()
+        closeItem = self.fileMenu.Append(-1, 'Close\tCtrl+W', kind=wx.ITEM_NORMAL)
+        self.Bind(wx.EVT_MENU, self._destroy, closeItem)
+        self.menubar.Append(self.fileMenu, "&File")
+        self.SetMenuBar(self.menubar)
+        self.Bind(wx.EVT_CLOSE, self._destroy)
+        self.obj = obj
+        gain = self.obj.gain
+        length = self.obj.length
+        self.panel = wx.Panel(self)
+        self.panel.SetBackgroundColour(BACKGROUND_COLOUR)
+        self.mainBox = wx.BoxSizer(wx.VERTICAL)
+        self.toolBox = wx.BoxSizer(wx.HORIZONTAL)
+        if sys.platform == "darwin":
+            X_OFF = 24
+        else:
+            X_OFF = 16
+        tw, th = self.GetTextExtent("Start")
+        self.activeTog = wx.ToggleButton(self.panel, -1, label="Start", size=(tw+X_OFF, th+10))
+        self.activeTog.SetValue(1)
+        self.activeTog.Bind(wx.EVT_TOGGLEBUTTON, self.activate)
+        self.toolBox.Add(self.activeTog, 0, wx.TOP|wx.LEFT|wx.RIGHT, 5)
+        self.toolBox.AddSpacer(10)
+        self.toolBox.Add(wx.StaticText(self.panel, -1, label="Window length (ms):"), 0, wx.TOP, 11)
+        self.lenSlider = ControlSlider(self.panel, 10, 60, length * 1000, outFunction=self.setLength)
+        self.toolBox.Add(self.lenSlider, 1, wx.TOP|wx.LEFT|wx.RIGHT, 11)
+        self.toolBox.AddSpacer(40)
+        self.mainBox.Add(self.toolBox, 0, wx.EXPAND)
+        self.dispBox = wx.BoxSizer(wx.HORIZONTAL)
+        self.box = wx.BoxSizer(wx.VERTICAL)
+        self.scopePanel = ScopePanel(self.panel, self.obj)
+        self.box.Add(self.scopePanel, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
+        self.dispBox.Add(self.box, 1, wx.EXPAND, 0)
+        self.gainSlider = ControlSlider(self.panel, -24, 24, 20.0 * math.log10(gain), outFunction=self.setGain, orient=wx.VERTICAL)
+        self.dispBox.Add(self.gainSlider, 0, wx.EXPAND)
+        self.dispBox.AddSpacer(5)  
+        self.mainBox.Add(self.dispBox, 1, wx.EXPAND) 
+        self.panel.SetSizer(self.mainBox)
+
+    def activate(self, evt):
+        self.obj.poll(evt.GetInt())
+
+    def setLength(self, length):
+        length *= 0.001
+        self.obj.setLength(length)
+        self.scopePanel.setLength(length)
+        
+    def setGain(self, gain):
+        gain = pow(10.0, gain * 0.05)
+        self.scopePanel.setGain(gain)
+        self.obj.setGain(gain)
+
+    def update(self, points):
+        wx.CallAfter(self.scopePanel.setImage, points)
+
+    def _destroy(self, evt):
+        self.obj._setViewFrame(None)
+        self.Destroy()
+
+class ScopePanel(wx.Panel):
+    def __init__(self, parent, obj):
+        wx.Panel.__init__(self, parent)
+        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+        self.Bind(wx.EVT_PAINT, self.OnPaint)
+        self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.img = [[]]
+        self.obj = obj
+        self.gain = self.obj.gain
+        self.length = self.obj.length
+        self.chnls = len(self.obj)
+        if self.chnls == 1:
+            self.pens = [wx.Pen(wx.Colour(100,0,0), width=2)]
+        else:
+            self.pens = [wx.Pen(wx.Colour(166,4,0), width=2), wx.Pen(wx.Colour(8,11,116), width=2), wx.Pen(wx.Colour(0,204,0), width=2),
+                        wx.Pen(wx.Colour(255,167,0), width=2), wx.Pen(wx.Colour(133,0,75), width=2), wx.Pen(wx.Colour(255,236,0), width=2),
+                        wx.Pen(wx.Colour(1,147,154), width=2), wx.Pen(wx.Colour(162,239,0), width=2)]
+
+        if sys.platform == "win32":
+            self.dcref = wx.BufferedPaintDC
+        else:
+            self.dcref = wx.PaintDC
+
+    def OnSize(self, evt):
+        size = self.GetSize()
+        self.obj.setWidth(size[0])
+        self.obj.setHeight(size[1])
+
+    def setGain(self, gain):
+        self.gain = gain
+        print self.gain
+
+    def setLength(self, length):
+        self.length = length
+
+    def setImage(self, points):
+        self.img = points
+        self.Refresh()
+
+    def OnPaint(self, evt):
+        w,h = self.GetSize()
+        dc = self.dcref(self)
+        gc = wx.GraphicsContext_Create(dc)
+        tw, th = dc.GetTextExtent("0")
+        dc.SetBrush(wx.Brush("#FFFFFF"))
+        dc.Clear()
+        dc.DrawRectangle(0,0,w,h)
+        gc.SetPen(wx.Pen('#000000', width=1, style=wx.SOLID))
+        gc.SetBrush(wx.Brush("#FFFFFF", style=wx.TRANSPARENT))
+        dc.SetTextForeground("#444444")
+        if sys.platform in "darwin":
+            font, ptsize = dc.GetFont(), dc.GetFont().GetPointSize()
+            font.SetPointSize(ptsize - 3)
+            dc.SetFont(font)
+        elif sys.platform == "win32":
+            font = dc.GetFont()
+            font.SetPointSize(8)
+            dc.SetFont(font)
+        
+        dc.SetPen(wx.Pen('#888888', width=1, style=wx.DOT))  
+        # horizontal grid
+        step = h / 6
+        ampstep = 1.0 / 3.0 / self.gain
+        for i in range(1, 6):
+            pos = int(h - i * step)
+            npos = i - 3
+            text = "%.2f" % (ampstep * npos)
+            tw, th = dc.GetTextExtent(text)
+            dc.DrawText(text, w-tw-2, pos-th/2)
+            dc.DrawLine(0, pos, w-tw-10, pos)
+
+        # vertical grid
+        tickstep = w / 4
+        timestep = self.length * 0.25
+        for j in range(4):
+            dc.SetPen(wx.Pen('#888888', width=1, style=wx.DOT))  
+            dc.DrawLine(j*tickstep, 0, j*tickstep, h)
+            dc.DrawText("%.3f" % (j*timestep), j*tickstep+2, h-12)
+        # draw waveforms
+        for i, samples in enumerate(self.img):
+            gc.SetPen(self.pens[i])
+            if len(samples):
+                gc.DrawLines(samples)
+
+        # legend
+        last_tw = tw
+        tw, th = dc.GetTextExtent("chan 8")
+        for i in range(self.chnls):
+            dc.SetTextForeground(self.pens[i].GetColour())
+            dc.DrawText("chan %d" % (i+1), w-tw-20-last_tw, i*th+10)
+
+######################################################################
 ## Grapher window for PyoTableObject control
 ######################################################################
 OFF = 15
@@ -1578,6 +1738,11 @@ class Grapher(wx.Panel):
         self.init = [tup for tup in init]
         self.points = init
         self.outFunction = outFunction
+
+        if sys.platform == "win32":
+            self.dcref = wx.BufferedPaintDC
+        else:
+            self.dcref = wx.PaintDC
         
         self.SetFocus()
 
@@ -1676,6 +1841,7 @@ class Grapher(wx.Panel):
             self.points = [(pt[0], pt[1]-0.002) for pt in self.points]
             self.sendValues()
             self.Refresh()
+        evt.Skip()
 
     def MouseDown(self, evt):
         self.CaptureMouse()
@@ -1714,7 +1880,7 @@ class Grapher(wx.Panel):
                 if self.mode == 4 and y <= 0:
                     y = 0.000001
                 self.points[self.selected] = (x, y)
-        self.Refresh()
+            self.Refresh()
 
     def getLogPoints(self, pt1, pt2):
         tmp = []
@@ -1850,7 +2016,10 @@ class Grapher(wx.Panel):
     def OnPaint(self, evt):
         w,h = self.GetSize()
         corners = [(OFF,OFF),(w-OFF,OFF),(w-OFF,h-OFF),(OFF,h-OFF)]
-        dc = wx.AutoBufferedPaintDC(self)
+        dc = self.dcref(self)
+        gc = wx.GraphicsContext_Create(dc)
+        gc.SetBrush(wx.Brush("#000000"))
+        gc.SetPen(wx.Pen("#000000"))
         if sys.platform == "darwin":
             font, ptsize = dc.GetFont(), dc.GetFont().GetPointSize()
         else:
@@ -1904,44 +2073,44 @@ class Grapher(wx.Panel):
         if len(tmp) > 1:
             if self.mode == 0:
                 for i in range(len(tmp)-1):
-                    dc.DrawLinePoint(tmp[i], tmp[i+1])
+                    gc.DrawLines([tmp[i], tmp[i+1]])
             elif self.mode == 1:
                 for i in range(len(tmp)-1):
                     tmp2 = self.getCosPoints(tmp[i], tmp[i+1])
                     if i == 0 and len(tmp2) < 2:
-                        dc.DrawLinePoint(tmp[i], tmp[i+1])
+                        gc.DrawLines([tmp[i], tmp[i+1]])
                     if last_p != None:
-                        dc.DrawLinePoint(last_p, tmp[i])
+                        gc.DrawLines([last_p, tmp[i]])
                     for j in range(len(tmp2)-1):
-                        dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+                        gc.DrawLines([tmp2[j], tmp2[j+1]])
                         last_p = tmp2[j+1]
                 if last_p != None:
-                    dc.DrawLinePoint(last_p, tmp[-1])
+                    gc.DrawLines([last_p, tmp[-1]])
             elif self.mode == 2:
                 for i in range(len(tmp)-1):
                     tmp2 = self.getExpPoints(tmp[i], tmp[i+1])
                     if i == 0 and len(tmp2) < 2:
-                        dc.DrawLinePoint(tmp[i], tmp[i+1])
+                        gc.DrawLines([tmp[i], tmp[i+1]])
                     if last_p != None:
-                        dc.DrawLinePoint(last_p, tmp[i])
+                        gc.DrawLines([last_p, tmp[i]])
                     for j in range(len(tmp2)-1):
-                        dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+                        gc.DrawLines([tmp2[j], tmp2[j+1]])
                         last_p = tmp2[j+1]
                 if last_p != None:
-                    dc.DrawLinePoint(last_p, tmp[-1])
+                    gc.DrawLines([last_p, tmp[-1]])
             elif self.mode == 3:
                 curvetmp = self.addImaginaryPoints(tmp)
                 for i in range(1, len(curvetmp)-2):
                     tmp2 = self.getCurvePoints(curvetmp[i-1], curvetmp[i], curvetmp[i+1], curvetmp[i+2])
                     if i == 1 and len(tmp2) < 2:
-                        dc.DrawLinePoint(curvetmp[i], curvetmp[i+1])
+                        gc.DrawLines([curvetmp[i], curvetmp[i+1]])
                     if last_p != None:
-                        dc.DrawLinePoint(last_p, curvetmp[i])
+                        gc.DrawLines([last_p, curvetmp[i]])
                     for j in range(len(tmp2)-1):
-                        dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+                        gc.DrawLines([tmp2[j], tmp2[j+1]])
                         last_p = tmp2[j+1]
                 if last_p != None:
-                    dc.DrawLinePoint(last_p, tmp[-1])
+                    gc.DrawLines([last_p, tmp[-1]])
             elif self.mode == 4:
                 back_tmp = [p for p in tmp]
                 for i in range(len(tmp)):
@@ -1951,14 +2120,14 @@ class Grapher(wx.Panel):
                     for j in range(len(tmp2)):
                         tmp2[j] = (tmp2[j][0], int(round((1.0-tmp2[j][1]) * h)) + OFF + RAD)
                     if i == 0 and len(tmp2) < 2:
-                        dc.DrawLinePoint(back_tmp[i], back_tmp[i+1])
+                        gc.DrawLines([back_tmp[i], back_tmp[i+1]])
                     if last_p != None:
-                        dc.DrawLinePoint(last_p, back_tmp[i])
+                        gc.DrawLines([last_p, back_tmp[i]])
                     for j in range(len(tmp2)-1):
-                        dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+                        gc.DrawLines([tmp2[j], tmp2[j+1]])
                         last_p = tmp2[j+1]
                 if last_p != None:
-                    dc.DrawLinePoint(last_p, back_tmp[-1])
+                    gc.DrawLines([last_p, back_tmp[-1]])
                 tmp = [p for p in back_tmp]
             elif self.mode == 5:
                 back_tmp = [p for p in tmp]
@@ -1969,23 +2138,25 @@ class Grapher(wx.Panel):
                     for j in range(len(tmp2)):
                         tmp2[j] = (tmp2[j][0], int(round((1.0-tmp2[j][1]) * h)) + OFF + RAD)
                     if i == 0 and len(tmp2) < 2:
-                        dc.DrawLinePoint(back_tmp[i], back_tmp[i+1])
+                        gc.DrawLines([back_tmp[i], back_tmp[i+1]])
                     if last_p != None:
-                        dc.DrawLinePoint(last_p, back_tmp[i])
+                        gc.DrawLines([last_p, back_tmp[i]])
                     for j in range(len(tmp2)-1):
-                        dc.DrawLinePoint(tmp2[j], tmp2[j+1])
+                        gc.DrawLines([tmp2[j], tmp2[j+1]])
                         last_p = tmp2[j+1]
                 if last_p != None:
-                    dc.DrawLinePoint(last_p, back_tmp[-1])
+                    gc.DrawLines([last_p, back_tmp[-1]])
                 tmp = [p for p in back_tmp]
 
         # Draw points
         for i,p in enumerate(tmp):
             if i == self.selected:
+                gc.SetBrush(wx.Brush("#FFFFFF"))
                 dc.SetBrush(wx.Brush("#FFFFFF"))
             else:
+                gc.SetBrush(wx.Brush("#000000"))
                 dc.SetBrush(wx.Brush("#000000"))
-            dc.DrawCircle(p[0],p[1],RAD)
+            gc.DrawEllipse(p[0]-RAD,p[1]-RAD,RAD2,RAD2)
         
         # Draw position values
         font.SetPointSize(ptsize-3)
@@ -2080,7 +2251,11 @@ class DataMultiSlider(wx.Panel):
     def OnResize(self, event):
         self.Layout()
         self.Refresh()
-        
+
+    def update(self, points):
+        self.values = points
+        self.Refresh()
+
     def OnPaint(self, event):
         w,h = self.GetSize()
         dc = self.dcref(self)
@@ -2181,10 +2356,13 @@ class DataTableGrapher(wx.Frame):
     def close(self, evt):
         self.Destroy()
 
+    def update(self, samples):
+        wx.CallAfter(self.multi.update, samples)
+
 class ServerGUI(wx.Frame):
     def __init__(self, parent=None, nchnls=2, startf=None, stopf=None, recstartf=None, 
-                recstopf=None, ampf=None, started=0, locals=None, shutdown=None, meter=True, timer=True, amp=1.):
-        wx.Frame.__init__(self, parent)
+                recstopf=None, ampf=None, started=0, locals=None, shutdown=None, meter=True, timer=True, amp=1., exit=True):
+        wx.Frame.__init__(self, parent, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
 
         self.SetTitle("pyo server")
         
@@ -2205,6 +2383,7 @@ class ServerGUI(wx.Frame):
         self.recstartf = recstartf
         self.recstopf = recstopf
         self.ampf = ampf
+        self.exit = exit
         self._started = False
         self._recstarted = False
         self._history = []
@@ -2237,7 +2416,7 @@ class ServerGUI(wx.Frame):
 
         box.Add(wx.StaticText(panel, -1, "Amplitude (dB)"), 0, wx.LEFT, leftMargin)
         ampBox = wx.BoxSizer(wx.HORIZONTAL)
-        self.ampScale = ControlSlider(panel, -60, 18, 20.0 * math.log10(amp), size=(203, 16), outFunction=self.setAmp)
+        self.ampScale = ControlSlider(panel, -60, 18, 20.0 * math.log10(amp), size=(202, 16), outFunction=self.setAmp)
         ampBox.Add(self.ampScale, 0, wx.LEFT, leftMargin-10)
         box.Add(ampBox, 0, wx.LEFT | wx.RIGHT, 8)
         
@@ -2259,16 +2438,15 @@ class ServerGUI(wx.Frame):
             box.AddSpacer(10)
             t = wx.StaticText(panel, -1, "Interpreter")
             box.Add(t, 0, wx.LEFT, leftMargin)
-            self.text = wx.TextCtrl(panel, -1, "", size=(200, -1), style=wx.TE_PROCESS_ENTER)
+            tw, th = self.GetTextExtent("|")
+            self.text = wx.TextCtrl(panel, -1, "", size=(202, th+8), style=wx.TE_PROCESS_ENTER)
             self.text.Bind(wx.EVT_TEXT_ENTER, self.getText)
             self.text.Bind(wx.EVT_CHAR, self.onChar)
-            box.Add(self.text, 0, wx.LEFT, leftMargin)
+            box.Add(self.text, 0, wx.LEFT, leftMargin-1)
 
         box.AddSpacer(10)
         panel.SetSizerAndFit(box)
         self.SetClientSize(panel.GetSize())
-        self.SetMinSize(self.GetSize())
-        self.SetMaxSize(self.GetSize())
 
         if started == 1:
             self.start(None, True)
@@ -2281,13 +2459,15 @@ class ServerGUI(wx.Frame):
             if not justSet:
                 self.startf()
             self._started = True
-            self.startButton.SetLabel('Stop')
-            self.quitButton.Disable()
+            wx.CallAfter(self.startButton.SetLabel, 'Stop')
+            if self.exit:
+                wx.CallAfter(self.quitButton.Disable)
         else:
-            self.stopf()
+            wx.CallLater(100, self.stopf)
             self._started = False
-            self.startButton.SetLabel('Start')
-            self.quitButton.Enable()
+            wx.CallAfter(self.startButton.SetLabel, 'Start')
+            if self.exit:
+                wx.CallAfter(self.quitButton.Enable)
 
     def record(self, evt):
         if self._recstarted == False:
@@ -2300,9 +2480,11 @@ class ServerGUI(wx.Frame):
             self.recButton.SetLabel('Rec Start')
 
     def on_quit(self, evt):
-        self.shutdown()
+        if self.exit:
+            self.shutdown()
         self.Destroy()
-        sys.exit()
+        if self.exit:
+            sys.exit()
 
     def getPrev(self):
         self.text.Clear()
@@ -2332,9 +2514,12 @@ class ServerGUI(wx.Frame):
         key = evt.GetKeyCode()
         if key == 315:
             self.getPrev()
+            evt.StopPropagation()
         elif key == 317:
-            self.getNext()  
-        evt.Skip()      
+            self.getNext()
+            evt.StopPropagation()
+        else:
+            evt.Skip()      
 
     def setAmp(self, value):
         self.ampf(math.pow(10.0, float(value) * 0.05))
@@ -2342,12 +2527,3 @@ class ServerGUI(wx.Frame):
     def setRms(self, *args):
         self.meter.setRms(*args)
 
-if __name__ == "__main__":
-    def pprint(values):
-        print values
-
-    app = wx.App(False)
-    values = [random.uniform(10, 25) for i in range(10)]
-    f = DataTableGrapher(init=values, yrange=(2, 50))
-    f.Show()
-    app.MainLoop()
diff --git a/pyolib/analysis.py b/pyolib/analysis.py
index ffcdc53..6b8316c 100644
--- a/pyolib/analysis.py
+++ b/pyolib/analysis.py
@@ -29,6 +29,8 @@ along with pyo.  If not, see <http://www.gnu.org/licenses/>.
 
 from _core import *
 from _maps import *
+from _widgets import createSpectrumWindow, createScopeWindow
+from pattern import Pattern
 
 class Follower(PyoObject):
     """
@@ -246,7 +248,7 @@ class ZCross(PyoObject):
         The out() method is bypassed. ZCross's signal can not be sent to 
         audio outs.
     
-    >>> s = Server(duplex=1).boot()
+    >>> s = Server().boot()
     >>> s.start()
     >>> a = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out()
     >>> b = ZCross(a, thresh=.02)
@@ -292,6 +294,10 @@ class ZCross(PyoObject):
 
     def out(self, chnl=0, inc=1, dur=0, delay=0):
         return self.play(dur, delay)
+
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0., 0.5, 'lin', 'thresh', self._thresh)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
      
     @property
     def input(self):
@@ -440,6 +446,13 @@ class Yin(PyoObject):
 
     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', 'tolerance', self._tolerance, dataOnly=True),
+                          SLMap(20, 400, 'log', 'minfreq', self._minfreq, dataOnly=True),
+                          SLMap(500, 5000, 'log', 'maxfreq', self._maxfreq, dataOnly=True),
+                          SLMap(200, 15000, 'log', 'cutoff', self._cutoff, dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
      
     @property
     def input(self):
@@ -475,3 +488,974 @@ class Yin(PyoObject):
         return self._cutoff
     @cutoff.setter
     def cutoff(self, x): self.setCutoff(x)
+
+class Centroid(PyoObject):
+    """
+    Computes the spectral centroid of an input signal.
+    
+    Output signal is the spectral centroid, in Hz, of the input signal.
+    It indicates where the "center of mass" of the spectrum is. Perceptually, 
+    it has a robust connection with the impression of "brightness" of a sound.
+    
+    Centroid does its computation with two overlaps, so a new output value 
+    comes every half of the FFT window size.
+ 
+    :Parent: :py:class:`PyoObject`
+   
+    :Args:
+    
+        input : PyoObject
+            Input signal to process.
+        size : int, optional
+            Size, as a power-of-two, of the FFT used to compute the centroid.
+
+            Available at initialization time only.  Defaults to 1024.
+            
+
+    .. note::
+
+        The out() method is bypassed. Centroid's signal can not be sent to 
+        audio outs.
+    
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> a = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out()
+    >>> b = Centroid(a, 1024)
+    >>> c = Port(b, 0.05, 0.05)
+    >>> d = ButBP(Noise(0.2), freq=c, q=5).out(1)
+
+    """
+    def __init__(self, input, size=1024, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._input = input
+        self._size = size
+        self._in_fader = InputFader(input)
+        in_fader, size, mul, add, lmax = convertArgsToLists(self._in_fader, size, mul, add)
+        self._base_objs = [Centroid_base(wrap(in_fader,i), wrap(size,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+    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 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 = []
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+     
+    @property
+    def input(self):
+        """PyoObject. Input signal to process.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+class AttackDetector(PyoObject):
+    """
+    Audio signal onset detection.
+    
+    AttackDetector anaylises an audio signal in input an output a trigger each
+    time an onset is detected. An onset is a sharp amplitude rising while the
+    signal had previously fall below a minimum threshold. Parameters must be
+    carefully tuned depending on the nature of the analysed signal and the level
+    of the background noise. 
+
+    :Parent: :py:class:`PyoObject`
+   
+    :Args:
+    
+        input : PyoObject
+            Input signal to process.
+        deltime : float, optional
+            Delay time, in seconds, between previous and current rms analysis to compare.
+            Defaults to 0.005.
+        cutoff : float, optional
+            Cutoff frequency, in Hz, of the amplitude follower's lowpass filter. 
+            Defaults to 10.
+            
+            Higher values are more responsive and also more likely to give false onsets. 
+        maxthresh : float, optional
+            Attack threshold in positive dB (current rms must be higher than previous 
+            rms + maxthresh to be reported as an attack). Defaults to 3.0.
+        minthresh : float, optional
+            Minimum threshold in dB (signal must fall below this threshold to allow 
+            a new attack to be detected). Defaults to -30.0.
+        reltime : float, optional
+            Time, in seconds, to wait before reporting a new attack. Defaults to 0.1.
+            
+
+    >>> s = Server(duplex=1).boot()
+    >>> s.start()
+    >>> a = Input()
+    >>> d = AttackDetector(a, deltime=0.005, cutoff=10, maxthresh=4, minthresh=-20, reltime=0.05)
+    >>> exc = TrigEnv(d, HannTable(), dur=0.005, mul=BrownNoise(0.3))
+    >>> wgs = Waveguide(exc, freq=[100,200.1,300.3,400.5], dur=30).out()
+
+    """
+    def __init__(self, input, deltime=0.005, cutoff=10, maxthresh=3, minthresh=-30, reltime=0.1, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._input = input
+        self._deltime = deltime
+        self._cutoff = cutoff
+        self._maxthresh = maxthresh
+        self._minthresh = minthresh
+        self._reltime = reltime
+        self._in_fader = InputFader(input)
+        in_fader, deltime, cutoff, maxthresh, minthresh, reltime, mul, add, lmax = convertArgsToLists(self._in_fader, deltime, cutoff, maxthresh, minthresh, reltime, mul, add)
+        self._base_objs = [AttackDetector_base(wrap(in_fader,i), wrap(deltime,i), wrap(cutoff,i), wrap(maxthresh,i), wrap(minthresh,i), wrap(reltime,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+    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 setDeltime(self, x):
+        """
+        Replace the `deltime` attribute.
+        
+        :Args:
+
+            x : float
+                New delay between rms analysis.
+
+        """
+        self._deltime = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setDeltime(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setCutoff(self, x):
+        """
+        Replace the `cutoff` attribute.
+        
+        :Args:
+
+            x : float
+                New cutoff for the follower lowpass filter.
+
+        """
+        self._cutoff = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setCutoff(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setMaxthresh(self, x):
+        """
+        Replace the `maxthresh` attribute.
+        
+        :Args:
+
+            x : float
+                New attack threshold in dB.
+
+        """
+        self._maxthresh = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setMaxthresh(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setMinthresh(self, x):
+        """
+        Replace the `minthresh` attribute.
+        
+        :Args:
+
+            x : float
+                New minimum threshold in dB.
+
+        """
+        self._minthresh = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setMinthresh(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setReltime(self, x):
+        """
+        Replace the `reltime` attribute.
+        
+        :Args: 
+
+            x : float
+                Time, in seconds, to wait before reporting a new attack.
+
+        """
+        self._reltime = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setReltime(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.001, 0.05, 'lin', 'deltime', self._deltime, dataOnly=True),
+                          SLMap(1.0, 1000.0, 'log', 'cutoff', self._cutoff, dataOnly=True),
+                          SLMap(0.0, 18.0, 'lin', 'maxthresh', self._maxthresh, dataOnly=True),
+                          SLMap(-90.0, 0.0, 'lin', 'minthresh', self._minthresh, dataOnly=True),
+                          SLMap(0.001, 1.0, 'log', 'reltime', self._reltime, dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+     
+    @property
+    def input(self):
+        """PyoObject. Input signal to process.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+    @property
+    def deltime(self):
+        """float. Delay between rms analysis.""" 
+        return self._deltime
+    @deltime.setter
+    def deltime(self, x): self.setDeltime(x)
+
+    @property
+    def cutoff(self):
+        """float. Cutoff for the follower lowpass filter.""" 
+        return self._cutoff
+    @cutoff.setter
+    def cutoff(self, x): self.setCutoff(x)
+
+    @property
+    def maxthresh(self):
+        """float. Attack threshold in dB.""" 
+        return self._maxthresh
+    @maxthresh.setter
+    def maxthresh(self, x): self.setMaxthresh(x)
+
+    @property
+    def minthresh(self):
+        """float. Minimum threshold in dB.""" 
+        return self._minthresh
+    @minthresh.setter
+    def minthresh(self, x): self.setMinthresh(x)
+
+    @property
+    def reltime(self):
+        """float. Time to wait before reporting a new attack.""" 
+        return self._reltime
+    @reltime.setter
+    def reltime(self, x): self.setReltime(x)
+
+class Spectrum(PyoObject):
+    """
+    Spectrum analyzer and display.
+
+    Spectrum measures the magnitude of an input signal versus frequency
+    within a user defined range. It can show both magnitude and frequency
+    on linear or logarithmic scale.
+    
+    :Parent: :py:class:`PyoObject`
+    
+    :Args:
+    
+        input : PyoObject
+            Input signal to process.
+        size : int {pow-of-two > 4}, optional
+            FFT size. Must be a power of two greater than 4.
+            The FFT size is the number of samples used in each
+            analysis frame. Defaults to 1024.
+        wintype : int, optional
+            Shape of the envelope used to filter each input frame.
+            Possible shapes are :
+                0. rectangular (no windowing)
+                1. Hamming
+                2. Hanning
+                3. Bartlett (triangular)
+                4. Blackman 3-term
+                5. Blackman-Harris 4-term
+                6. Blackman-Harris 7-term
+                7. Tuckey (alpha = 0.66)
+                8. Sine (half-sine window)
+        function : python callable, optional
+            If set, this function will be called with magnitudes (as
+            list of lists, one list per channel). Useful if someone
+            wants to save the analysis data into a text file.
+            Defaults to None.
+
+    .. note::
+    
+        Spectrum has no `out` method.
+        
+        Spectrum has no `mul` and `add` attributes.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> a = SuperSaw(freq=[500,750], detune=0.6, bal=0.7, mul=0.5).out()
+    >>> spec = Spectrum(a, size=1024)
+
+    """
+    def __init__(self, input, size=1024, wintype=2, function=None):
+        PyoObject.__init__(self)
+        self.points = None
+        self.viewFrame = None
+        self._input = input
+        self._size = size
+        self._wintype = wintype
+        self._function = function
+        self._fscaling = 0
+        self._mscaling = 1
+        self._lowbound = 0
+        self._highbound = 0.5
+        self._width = 500
+        self._height = 400
+        self._gain = 1
+        self._in_fader = InputFader(input)
+        in_fader, size, wintype, lmax = convertArgsToLists(self._in_fader, size, wintype)
+        self._base_objs = [Spectrum_base(wrap(in_fader,i), wrap(size,i), wrap(wintype,i)) for i in range(lmax)]
+        if function == None:
+            self.view()
+        self._timer = Pattern(self.refreshView, 0.05).play()
+ 
+    def setInput(self, x, fadetime=0.05):
+        """
+        Replace the `input` attribute.
+        
+        :Args:
+
+            x : PyoObject
+                New signal to process.
+            fadetime : float, optional
+                Crossfade time between old and new input. Default to 0.05.
+
+        """
+        self._input = x
+        self._in_fader.setInput(x, fadetime)
+
+    def setSize(self, x):
+        """
+        Replace the `size` attribute.
+        
+        :Args:
+
+            x : int
+                new `size` attribute.
+        
+        """
+        self._size = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setSize(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setWinType(self, x):
+        """
+        Replace the `wintype` attribute.
+        
+        :Args:
+
+            x : int
+                new `wintype` attribute.
+        
+        """
+        self._wintype = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setWinType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setFunction(self, function):
+        """
+        Sets the function to be called to retrieve the analysis data.
+        
+        :Args:
+            
+            function : python callable
+                The function called by the internal timer to retrieve the
+                analysis data. The function must be created with one argument
+                and will receive the data as a list of lists (one list per channel).
+
+        """
+        self._function = function
+
+    def poll(self, active):
+        """
+        Turns on and off the analysis polling.
+        
+        :Args:
+            
+            active : boolean
+                If True, starts the analysis polling, False to stop it.
+                defaults to True.
+
+        """
+        if active:
+            self._timer.play()
+        else:
+            self._timer.stop()
+
+    def polltime(self, time):
+        """
+        Sets the polling time in seconds.
+        
+        :Args:
+            
+            time : float
+                Adjusts the frequency of the internal timer used to
+                retrieve the current analysis frame. defaults to 0.05.
+        
+        """
+        self._timer.time = time
+
+    def setLowbound(self, x):
+        """
+        Sets the lower frequency, as multiplier of sr, returned by the analysis.
+        
+        Returns the real low frequency en Hz.
+        
+        :Args:
+
+            x : float {0 <= x <= 0.5}
+                new `lowbound` attribute.
+        
+        """
+        self._lowbound = x
+        x, lmax = convertArgsToLists(x)
+        tmp = [obj.setLowbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+        return tmp[0]
+
+    def setHighbound(self, x):
+        """
+        Sets the higher frequency, as multiplier of sr, returned by the analysis.
+        
+        Returns the real high frequency en Hz.
+        
+        :Args:
+
+            x : float {0 <= x <= 0.5}
+                new `highbound` attribute.
+        
+        """
+        self._highbound = x
+        x, lmax = convertArgsToLists(x)
+        tmp = [obj.setHighbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+        return tmp[0]
+
+    def getLowfreq(self):
+        """
+        Returns the current lower frequency, in Hz, used by the analysis.
+        
+        """
+
+        return self._base_objs[0].getLowfreq()
+
+    def getHighfreq(self):
+        """
+        Returns the current higher frequency, in Hz, used by the analysis.
+        
+        """
+        return self._base_objs[0].getHighfreq()
+
+    def setWidth(self, x):
+        """
+        Sets the width, in pixels, of the current display.
+        
+        Used internally to build the list of points to draw.
+        
+        :Args:
+
+            x : int
+                new `width` attribute.
+        
+        """
+        self._width = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setWidth(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setHeight(self, x):
+        """
+        Sets the height, in pixels, of the current display.
+        
+        Used internally to build the list of points to draw.
+        
+        :Args:
+
+            x : int
+                new `height` attribute.
+        
+        """
+        self._height = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setHeight(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setFscaling(self, x):
+        """
+        Sets the frequency display to linear or logarithmic.
+        
+        :Args:
+
+            x : boolean
+                If True, the frequency display is logarithmic. False turns
+                it back to linear. Defaults to False.
+        
+        """
+        self._fscaling = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setFscaling(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+        if self.viewFrame != None:
+            self.viewFrame.setFscaling(self._fscaling)
+
+    def setMscaling(self, x):
+        """
+        Sets the magnitude display to linear or logarithmic.
+        
+        :Args:
+
+            x : boolean
+                If True, the magnitude display is logarithmic (which means in dB). 
+                False turns it back to linear. Defaults to True.
+        
+        """
+        self._mscaling = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setMscaling(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+        if self.viewFrame != None:
+            self.viewFrame.setMscaling(self._mscaling)
+
+    def getFscaling(self):
+        """
+        Returns the scaling of the frequency display.
+        
+        Returns True for logarithmic or False for linear.
+
+        """
+        return self._fscaling
+
+    def getMscaling(self):
+        """
+        Returns the scaling of the magnitude display.
+        
+        Returns True for logarithmic or False for linear.
+
+        """
+        return self._mscaling
+
+    def setGain(self, x):
+        """
+        Set the gain of the analysis data. For drawing purpose.
+        
+        :Args:
+
+            x : float
+                new `gain` attribute, as linear values.
+        
+        """
+        self._gain = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setGain(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def view(self, title="Spectrum", wxnoserver=False):
+        """
+        Opens a window showing the result of the analysis.
+        
+        :Args:
+        
+            title : string, optional
+                Window title. Defaults to "Spectrum". 
+            wxnoserver : boolean, optional
+                With wxPython graphical toolkit, if True, tells the 
+                interpreter that there will be no server window.
+                
+        If `wxnoserver` is set to True, the interpreter will not wait for 
+        the server GUI before showing the controller window. 
+        
+        """
+        createSpectrumWindow(self, title, wxnoserver)
+
+    def _setViewFrame(self, frame):
+        self.viewFrame = frame
+        
+    def refreshView(self):
+        """
+        Updates the graphical display of the spectrum.
+        
+        Called automatically by the internal timer.
+
+        """
+        self.points = [obj.display() for obj in self._base_objs]
+        if self._function != None:
+            self._function(self.points)
+        if self.viewFrame != None:
+            self.viewFrame.update(self.points)
+
+
+    @property
+    def input(self):
+        """PyoObject. Input signal to process.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+    @property
+    def size(self):
+        """int. FFT size."""
+        return self._size
+    @size.setter
+    def size(self, x): self.setSize(x)
+
+    @property
+    def wintype(self):
+        """int. Windowing method."""
+        return self._wintype
+    @wintype.setter
+    def wintype(self, x): self.setWinType(x)
+
+    @property
+    def gain(self):
+        """float. Sets the gain of the analysis data."""
+        return self._gain
+    @gain.setter
+    def gain(self, x): self.setGain(x)
+
+    @property
+    def lowbound(self):
+        """float. Lowest frequency (multiplier of sr) to output."""
+        return self._lowbound
+    @lowbound.setter
+    def lowbound(self, x): self.setLowbound(x)
+
+    @property
+    def highbound(self):
+        """float. Highest frequency (multiplier of sr) to output."""
+        return self._highbound
+    @highbound.setter
+    def highbound(self, x): self.setHighbound(x)
+
+    @property
+    def width(self):
+        """int. Width, in pixels, of the current display."""
+        return self._width
+    @width.setter
+    def width(self, x): self.setWidth(x)
+
+    @property
+    def height(self):
+        """int. Height, in pixels, of the current display."""
+        return self._height
+    @height.setter
+    def height(self, x): self.setHeight(x)
+
+    @property
+    def fscaling(self):
+        """boolean. Scaling of the frequency display."""
+        return self._fscaling
+    @fscaling.setter
+    def fscaling(self, x): self.setFscaling(x)
+
+    @property
+    def mscaling(self):
+        """boolean. Scaling of the magnitude display."""
+        return self._mscaling
+    @mscaling.setter
+    def mscaling(self, x): self.setMscaling(x)
+
+class Scope(PyoObject):
+    """
+    Oscilloscope - audio waveform display.
+
+    Oscilloscopes are used to observe the change of an electrical 
+    signal over time.
+    
+    :Parent: :py:class:`PyoObject`
+    
+    :Args:
+    
+        input : PyoObject
+            Input signal to process.
+        length : float, optional
+            Length, in seconds, of the displayed window. Can't be a list.
+            Defaults to 0.05.
+        gain : float, optional
+            Linear gain applied to the signal to be displayed.
+            Can't be a list. Defaults to 0.67.
+
+    .. note::
+    
+        Scope has no `out` method.
+        
+        Scope has no `mul` and `add` attributes.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> a = Sine([100,100.2], mul=0.7)
+    >>> b = Noise(0.1)
+    >>> scope = Scope(a+b)
+
+    """
+    def __init__(self, input, length=0.05, gain=0.67):
+        PyoObject.__init__(self)
+        self.points = None
+        self.viewFrame = None
+        self._input = input
+        self._length = length
+        self._gain = gain
+        self._width = 500
+        self._height = 400
+        self._in_fader = InputFader(input)
+        in_fader, lmax = convertArgsToLists(self._in_fader)
+        self._base_objs = [Scope_base(wrap(in_fader,i), length) for i in range(lmax)]
+        self.view()
+        self._timer = Pattern(self.refreshView, length).play()
+ 
+    def setInput(self, x, fadetime=0.05):
+        """
+        Replace the `input` attribute.
+        
+        :Args:
+
+            x : PyoObject
+                New signal to process.
+            fadetime : float, optional
+                Crossfade time between old and new input. Default to 0.05.
+
+        """
+        self._input = x
+        self._in_fader.setInput(x, fadetime)
+
+    def setLength(self, x):
+        """
+        Replace the `length` attribute.
+        
+        :Args:
+
+            x : float
+                new `length` attribute.
+        
+        """
+        self._length = x
+        self._timer.time = x
+        [obj.setLength(x) for obj in self._base_objs]
+
+    def setGain(self, x):
+        """
+        Set the gain boost applied to the analysed data. For drawing purpose.
+        
+        :Args:
+
+            x : float
+                new `gain` attribute, as linear values.
+        
+        """
+        self._gain = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setGain(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def poll(self, active):
+        """
+        Turns on and off the analysis polling.
+        
+        :Args:
+            
+            active : boolean
+                If True, starts the analysis polling, False to stop it.
+                defaults to True.
+
+        """
+        if active:
+            self._timer.play()
+        else:
+            self._timer.stop()
+
+    def setWidth(self, x):
+        """
+        Gives the width of the display to the analyzer.
+        
+        The analyzer needs this value to construct the list
+        of points to draw on the display.
+        
+        :Args:
+            
+            x : int
+                Width of the display in pixel value. The default
+                width is 500.
+
+        """
+        self._width = x
+        [obj.setWidth(x) for obj in self._base_objs]
+
+    def setHeight(self, x):
+        """
+        Gives the height of the display to the analyzer.
+        
+        The analyzer needs this value to construct the list
+        of points to draw on the display.
+        
+        :Args:
+            
+            x : int
+                Height of the display in pixel value. The default
+                height is 400.
+
+        """
+        self._height = x
+        [obj.setHeight(x) for obj in self._base_objs]
+        
+    def view(self, title="Scope", wxnoserver=False):
+        """
+        Opens a window showing the result of the analysis.
+        
+        :Args:
+        
+            title : string, optional
+                Window title. Defaults to "Spectrum". 
+            wxnoserver : boolean, optional
+                With wxPython graphical toolkit, if True, tells the 
+                interpreter that there will be no server window.
+                
+        If `wxnoserver` is set to True, the interpreter will not wait for 
+        the server GUI before showing the controller window. 
+        
+        """
+        createScopeWindow(self, title, wxnoserver)
+
+    def _setViewFrame(self, frame):
+        self.viewFrame = frame
+        
+    def refreshView(self):
+        """
+        Updates the graphical display of the scope.
+        
+        Called automatically by the internal timer.
+
+        """
+        self.points = [obj.display() for obj in self._base_objs]
+        if self.viewFrame != None:
+            self.viewFrame.update(self.points)
+
+
+    @property
+    def input(self):
+        """PyoObject. Input signal to process.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+    @property
+    def length(self):
+        """float. Window length."""
+        return self._length
+    @length.setter
+    def length(self, x): self.setLength(x)
+
+    @property
+    def gain(self):
+        """float. Sets the gain of the analysis data."""
+        return self._gain
+    @gain.setter
+    def gain(self, x): self.setGain(x)
+
+class PeakAmp(PyoObject):
+    """
+    Peak amplitude follower.
+    
+    Output signal is the continuous peak amplitude of an input signal.
+    A new peaking value is computed every buffer size. If `function`
+    argument is not None, it should be a function that will be called
+    every buffer size with a variable-length argument list containing
+    the peaking values of all object's streams. Useful for meter drawing.
+    Function definition must look like this:
+        
+    >>> def getValues(*args)
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+    
+        input : PyoObject
+            Input signal to process.
+        function : callable, optional
+            Function that will be called with amplitude values in arguments. 
+            Default to None.
+
+    .. note::
+
+        The out() method is bypassed. PeakAmp's signal can not be sent to 
+        audio outs.
+    
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> sf = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.4).out()
+    >>> amp = PeakAmp(sf)
+    >>> n = Noise(mul=Port(amp)).out(1)
+
+    """
+    def __init__(self, input, function=None, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._input = input
+        if callable(function):
+            self._function = function
+        else:
+            self._function = None
+        self._in_fader = InputFader(input)
+        in_fader, mul, add, lmax = convertArgsToLists(self._in_fader, mul, add)
+        self._base_objs = [PeakAmp_base(wrap(in_fader,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+        sr = self._base_objs[0].getServer().getSamplingRate()
+        bs = self._base_objs[0].getServer().getBufferSize()
+        self._timer = Pattern(self._buildList, bs/sr).play()
+
+    def setInput(self, x, fadetime=0.05):
+        """
+        Replace the `input` attribute.
+        
+        :Args:
+
+            x : PyoObject
+                New signal to process.
+            fadetime : float, optional
+                Crossfade time between old and new input. Default to 0.05.
+
+        """
+        self._input = x
+        self._in_fader.setInput(x, fadetime)
+
+    def setFunction(self, x):
+        """
+        Replace the `function` attribute.
+        
+        :Args:
+
+            x : callable
+                New function to call with amplitude values in arguments.
+
+        """
+        if callable(x):
+            self._function = x
+
+    def out(self, chnl=0, inc=1, dur=0, delay=0):
+        return self.play(dur, delay)
+
+    def _buildList(self):
+        if self._function != None:
+            values = [obj.getValue() for obj in self._base_objs]
+            self._function(*values)
+
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = []
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+      
+    @property
+    def input(self):
+        """PyoObject. Input signal to process."""
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+    @property
+    def function(self):
+        """PyoObject. function signal to process."""
+        return self._function
+    @function.setter
+    def function(self, x): self.setFunction(x)
diff --git a/pyolib/arithmetic.py b/pyolib/arithmetic.py
index bf10013..9bc37bc 100644
--- a/pyolib/arithmetic.py
+++ b/pyolib/arithmetic.py
@@ -673,3 +673,53 @@ class Round(PyoObject):
         return self._input
     @input.setter
     def input(self, x): self.setInput(x)
+
+class Tanh(PyoObject):
+    """
+    Performs a hyperbolic tangent function on audio signal.
+
+    Returns the hyperbolic tangent of audio signal as input.
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+
+        input : PyoObject
+            Input signal, angle in radians.
+    
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> import math
+    >>> a = Phasor(250, mul=math.pi*2)
+    >>> b = Tanh(Sin(a, mul=10), mul=0.3).mix(2).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 = [M_Tanh_base(wrap(in_fader,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)
+
+    @property
+    def input(self):
+        """PyoObject. Input signal to process.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
diff --git a/pyolib/controls.py b/pyolib/controls.py
index d993bbc..a3682bd 100644
--- a/pyolib/controls.py
+++ b/pyolib/controls.py
@@ -129,6 +129,12 @@ class Fader(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setDur(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, 10., 'lin', 'fadein', self._fadein, dataOnly=True),
+                          SLMap(0, 10., 'lin', 'fadeout', self._fadeout, dataOnly=True),
+                          SLMap(0, 20., 'lin', 'dur', self._dur, dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def fadein(self):
         """float. Rising time of the envelope in seconds.""" 
@@ -186,8 +192,6 @@ class Adsr(PyoObject):
         The play() method starts the envelope.
         
         The stop() calls the envelope's release phase if `dur` = 0.
-    
-        Shape of a classical Adsr:
 
     >>> s = Server().boot()
     >>> s.start()
@@ -281,6 +285,14 @@ class Adsr(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setDur(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, 5, 'lin', 'attack', self._attack, dataOnly=True),
+                          SLMap(0, 5, 'lin', 'decay', self._decay, dataOnly=True),
+                          SLMap(0, 1, 'lin', 'sustain', self._sustain, dataOnly=True),
+                          SLMap(0, 10, 'lin', 'release', self._release, dataOnly=True),
+                          SLMap(0, 20., 'lin', 'dur', self._dur, dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def attack(self):
         """float. Duration of the attack phase in seconds.""" 
@@ -749,6 +761,10 @@ class SigTo(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setTime(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, 10, 'lin', 'time', self._time, dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def value(self):
         """float or PyoObject. Numerical value to convert.""" 
diff --git a/pyolib/dynamics.py b/pyolib/dynamics.py
index 9e6abd8..f4d6a88 100644
--- a/pyolib/dynamics.py
+++ b/pyolib/dynamics.py
@@ -511,6 +511,8 @@ class Compress(PyoObject):
                           SLMap(1., 10., 'lin', 'ratio',  self._ratio),
                           SLMap(0.001, .3, 'lin', 'risetime',  self._risetime),
                           SLMap(0.001, .3, 'lin', 'falltime',  self._falltime),
+                          SLMap(0, 25, 'lin', 'lookahead',  self._lookahead, dataOnly=True),
+                          SLMap(0, 1, 'lin', 'knee',  self._knee, dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -690,6 +692,7 @@ class Gate(PyoObject):
         self._map_list = [SLMap(-100., 0., 'lin', 'thresh',  self._thresh),
                           SLMap(0.0001, .3, 'lin', 'risetime',  self._risetime),
                           SLMap(0.0001, .3, 'lin', 'falltime',  self._falltime),
+                          SLMap(0, 25, 'lin', 'lookahead',  self._lookahead, dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
diff --git a/pyolib/effects.py b/pyolib/effects.py
index 09024ed..cfde21c 100644
--- a/pyolib/effects.py
+++ b/pyolib/effects.py
@@ -150,6 +150,17 @@ class Delay(PyoObject):
             Maximum delay length in seconds. Available only at initialization. 
             Defaults to 1.
 
+    .. note::
+
+        The minimum delay time allowed with Delay is one sample. It can be computed
+        with :
+            
+        onesamp = 1.0 / s.getSamplingRate()
+        
+    .. seealso::
+        
+        :py:class:`SDelay`, :py:class:`Waveguide`
+
     >>> s = Server().boot()
     >>> s.start()
     >>> a = SfPlayer(SNDS_PATH + "/transparent.aif", loop=True, mul=.3).mix(2).out()
@@ -259,6 +270,10 @@ class SDelay(PyoObject):
             Maximum delay length in seconds. Available only at initialization. 
             Defaults to 1.
 
+    .. seealso::
+        
+        :py:class:`Delay`, :py:class:`Delay1`
+
     >>> s = Server().boot()
     >>> s.start()
     >>> srPeriod = 1. / s.getSamplingRate()
@@ -313,7 +328,7 @@ class SDelay(PyoObject):
         [obj.reset() for obj in self._base_objs]
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMap(0.001, self._maxdelay, 'log', 'delay',  self._delay),
+        self._map_list = [SLMap(0.0001, self._maxdelay, 'log', 'delay',  self._delay),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -1166,6 +1181,7 @@ class Harmonizer(PyoObject):
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMap(-24.0, 24.0, 'lin', 'transpo',  self._transpo),
                           SLMap(0., 1., 'lin', 'feedback', self._feedback),
+                          SLMap(0.001, 1, 'log', 'winsize',  self._winsize, dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -1247,3 +1263,373 @@ class Delay1(PyoObject):
         return self._input
     @input.setter
     def input(self, x): self.setInput(x)
+
+class STRev(PyoObject):
+    """
+    Stereo reverb.
+
+    Stereo reverb based on WGVerb (8 delay line FDN reverb). A mono
+    input will produce two audio streams, left and right channels.
+    Therefore, a stereo input will produce four audio streams, left
+    and right channels for each input channel. Position of input 
+    streams can be set with the `inpos` argument. To achieve a stereo
+    reverb, delay line lengths are slightly differents on both channels,
+    but also, pre-delays length and filter cutoff of both channels will 
+    be affected to reflect the input position. 
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+
+        input : PyoObject
+            Input signal to process.
+        inpos : float or PyoObject, optional
+            Position of the source, between 0 and 1. 0 means fully left
+            and 1 means fully right. Defaults to 0.5.
+        revtime : float or PyoObject, optional
+            Duration, in seconds, of the reverberated sound, defined as 
+            the time needed to the sound to drop 40 dB below its peak. 
+            Defaults to 1.
+        cutoff : float or PyoObject, optional
+            cutoff frequency, in Hz, of a first order lowpass filters in the 
+            feedback loop of delay lines. Defaults to 5000.
+        bal : float or PyoObject, optional
+            Balance between wet and dry signal, between 0 and 1. 0 means no 
+            reverb. Defaults to 0.5.
+        roomSize : float, optional
+            Delay line length scaler, between 0.25 and 4. Values higher than
+            1 make the delay lines longer and simulate larger rooms. Defaults to 1.
+        firstRefGain : float, optional
+            Gain, in dB, of the first reflexions of the room. Defaults to -3.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> t = SndTable(SNDS_PATH + "/transparent.aif")
+    >>> sf = Looper(t, dur=t.getDur()*2, xfade=0, mul=0.5)
+    >>> rev = STRev(sf, inpos=0.25, revtime=2, cutoff=5000, bal=0.25, roomSize=1).out()
+
+    """
+    def __init__(self, input, inpos=0.5, revtime=1, cutoff=5000, bal=.5, roomSize=1, firstRefGain=-3, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._input = input
+        self._inpos = inpos
+        self._revtime = revtime
+        self._cutoff = cutoff
+        self._bal = bal
+        self._roomSize = roomSize
+        self._firstRefGain = firstRefGain
+        self._in_fader = InputFader(input)
+        in_fader, inpos, revtime, cutoff, bal, roomSize, firstRefGain, mul, add, lmax = convertArgsToLists(self._in_fader, inpos, revtime, cutoff, bal, roomSize, firstRefGain, mul, add)
+        self._base_players = [STReverb_base(wrap(in_fader,i), wrap(inpos,i), wrap(revtime,i), wrap(cutoff,i), wrap(bal,i), wrap(roomSize,i), wrap(firstRefGain,i)) for i in range(lmax)]
+        self._base_objs = [STRev_base(wrap(self._base_players,i), j, wrap(mul,i), wrap(add,i)) for i in range(lmax) for j in range(2)]
+
+    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 setInpos(self, x):
+        """
+        Replace the `inpos` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                New `inpos` attribute.
+
+        """
+        self._inpos = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setInpos(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+ 
+    def setRevtime(self, x):
+        """
+        Replace the `revtime` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                New `revtime` attribute.
+
+        """
+        self._revtime = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setRevtime(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setCutoff(self, x):
+        """
+        Replace the `cutoff` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                New `cutoff` attribute.
+
+        """
+        self._cutoff = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setCutoff(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setBal(self, x):
+        """
+        Replace the `bal` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                New `bal` attribute.
+
+        """
+        self._bal = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setMix(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setRoomSize(self, x):
+        """
+        Set the room size scaler, between 0.25 and 4.
+        
+        :Args:
+
+            x : float
+                Room size scaler, between 0.25 and 4.0.
+
+        """
+        self._roomSize = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setRoomSize(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setFirstRefGain(self, x):
+        """
+        Set the gain of the first reflexions.
+        
+        :Args:
+
+            x : float
+                Gain, in dB, of the first reflexions.
+
+        """
+        self._firstRefGain = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setFirstRefGain(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0., 1., 'lin', 'inpos',  self._inpos),
+                          SLMap(0.01, 120., 'log', 'revtime',  self._revtime),
+                          SLMap(500., 15000., 'log', 'cutoff',  self._cutoff),
+                          SLMap(0., 1., 'lin', 'bal',  self._bal),
+                          SLMap(0.25, 4., 'lin', 'roomSize',  self._roomSize, dataOnly=True),
+                          SLMap(-48, 12, 'lin', 'firstRefGain', self._firstRefGain, dataOnly=True),
+                          SLMapMul(self._mul)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+    @property
+    def input(self):
+        """PyoObject. Input signal to process.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+    @property
+    def inpos(self):
+        """float or PyoObject. Position of the source.""" 
+        return self._inpos
+    @inpos.setter
+    def inpos(self, x): self.setInpos(x)
+
+    @property
+    def revtime(self):
+        """float or PyoObject. Room size.""" 
+        return self._revtime
+    @revtime.setter
+    def revtime(self, x): self.setRevtime(x)
+
+    @property
+    def cutoff(self):
+        """float or PyoObject. High frequency damping.""" 
+        return self._cutoff
+    @cutoff.setter
+    def cutoff(self, x): self.setCutoff(x)
+
+    @property
+    def bal(self):
+        """float or PyoObject. Balance between wet and dry signal.""" 
+        return self._bal
+    @bal.setter
+    def bal(self, x): self.setBal(x)
+
+    @property
+    def roomSize(self):
+        """float. Room size scaler, between 0.25 and 4.0.""" 
+        return self._roomSize
+    @roomSize.setter
+    def roomSize(self, x): self.setRoomSize(x)
+
+    @property
+    def firstRefGain(self):
+        """float. Gain, in dB, of the first reflexions.""" 
+        return self._firstRefGain
+    @firstRefGain.setter
+    def firstRefGain(self, x): self.setFirstRefGain(x)
+
+class SmoothDelay(PyoObject):
+    """
+    Artifact free sweepable recursive delay.
+
+    SmoothDelay implements a delay line that does not produce 
+    clicks or pitch shifting when the delay time is changing.
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+
+        input : PyoObject
+            Input signal to delayed.
+        delay : float or PyoObject, optional
+            Delay time in seconds. Defaults to 0.25.
+        feedback : float or PyoObject, optional
+            Amount of output signal sent back into the delay line.
+            Defaults to 0.
+        crossfade : float, optional
+            Crossfade time, in seconds, between overlaped readers.
+            Defaults to 0.05.
+        maxdelay : float, optional
+            Maximum delay length in seconds. Available only at initialization. 
+            Defaults to 1.
+
+    .. note::
+
+        The minimum delay time allowed with SmoothDelay is one sample. 
+        It can be computed with :
+            
+        onesamp = 1.0 / s.getSamplingRate()
+        
+    .. seealso::
+        
+        :py:class:`Delay`, :py:class:`Waveguide`
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> sf = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=0.3).mix(2).out()
+    >>> lf = Sine(freq=0.1, mul=0.24, add=0.25)
+    >>> sd = SmoothDelay(sf, delay=lf, feedback=0.5, crossfade=0.05, mul=0.7).out()
+
+    """
+    def __init__(self, input, delay=0.25, feedback=0, crossfade=0.05, maxdelay=1, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._input = input
+        self._delay = delay
+        self._feedback = feedback
+        self._crossfade = crossfade
+        self._maxdelay = maxdelay
+        self._in_fader = InputFader(input)
+        in_fader, delay, feedback, crossfade, maxdelay, mul, add, lmax = convertArgsToLists(self._in_fader, delay, feedback, crossfade, maxdelay, mul, add)
+        self._base_objs = [SmoothDelay_base(wrap(in_fader,i), wrap(delay,i), wrap(feedback,i), wrap(crossfade,i), wrap(maxdelay,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 delayed.
+            fadetime : float, optional
+                Crossfade time between old and new input. Defaults to 0.05.
+
+        """
+        self._input = x
+        self._in_fader.setInput(x, fadetime)
+
+    def setDelay(self, x):
+        """
+        Replace the `delay` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                New `delay` attribute.
+
+        """
+        self._delay = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setDelay(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setFeedback(self, x):
+        """
+        Replace the `feedback` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                New `feedback` attribute.
+
+        """
+        self._feedback = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setFeedback(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setCrossfade(self, x):
+        """
+        Replace the `crossfade` attribute.
+        
+        :Args:
+
+            x : float
+                New `crossfade` attribute.
+
+        """
+        self._crossfade = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setCrossfade(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def reset(self):
+        """
+        Reset the memory buffer to zeros.
+        
+        """
+        [obj.reset() for obj in self._base_objs]
+
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0.001, self._maxdelay, 'log', 'delay',  self._delay),
+                          SLMap(0., 1., 'lin', 'feedback', self._feedback),
+                          SLMap(0., self._maxdelay, 'lin', 'crossfade', self._crossfade, dataOnly=True),
+                          SLMapMul(self._mul)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+    @property
+    def input(self):
+        """PyoObject. Input signal to delayed.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+ 
+    @property
+    def delay(self):
+        """float or PyoObject. Delay time in seconds.""" 
+        return self._delay
+    @delay.setter
+    def delay(self, x): self.setDelay(x)
+
+    @property
+    def feedback(self):
+        """float or PyoObject. Amount of output signal sent back into the delay line.""" 
+        return self._feedback
+    @feedback.setter
+    def feedback(self, x): self.setFeedback(x)
+
+    @property
+    def crossfade(self):
+        """float. Crossfade time, in seconds, between overlaps.""" 
+        return self._crossfade
+    @crossfade.setter
+    def crossfade(self, x): self.setCrossfade(x)
diff --git a/pyolib/filters.py b/pyolib/filters.py
index 1feb485..5442a14 100644
--- a/pyolib/filters.py
+++ b/pyolib/filters.py
@@ -141,7 +141,9 @@ class Biquad(PyoObject):
         [obj.setType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q), SLMapMul(self._mul)]
+        self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q), 
+                          SLMap(0, 4, 'lin', 'type', self._type, res="int", dataOnly=True),
+                          SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
@@ -297,7 +299,9 @@ class Biquadx(PyoObject):
         [obj.setStages(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q), SLMapMul(self._mul)]
+        self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q), 
+                          SLMap(0, 4, 'lin', 'type', self._type, res="int", dataOnly=True),
+                          SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
@@ -684,6 +688,7 @@ class EQ(PyoObject):
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMapFreq(self._freq), SLMapQ(self._q), 
                           SLMap(-40.0, 40.0, "lin", "boost", self._boost), 
+                          SLMap(0, 2, 'lin', 'type', self._type, res="int", dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -1300,8 +1305,8 @@ class Hilbert(PyoObject):
         Real and imaginary parts are two separated set of streams. 
         The user should call :
         
-        Hilbert['real'] to retrieve the real part.
-        Hilbert['imag'] to retrieve the imaginary part.
+        |  Hilbert['real'] to retrieve the real part.
+        |  Hilbert['imag'] to retrieve the imaginary part.
 
     >>> s = Server().boot()
     >>> s.start()
@@ -1946,6 +1951,7 @@ class Vocoder(PyoObject):
                           SLMap(0.25, 2, "lin", "spread", self._spread),
                           SLMap(0.5, 200, "log", "q", self._q), 
                           SLMap(0, 1, "lin", "slope", self._slope),
+                          SLMap(2, 64, 'lin', 'stages',  self._stages, res="int", dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -2125,7 +2131,8 @@ class IRWinSinc(PyoObject):
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMapFreq(self._freq),
-                          SLMap(20., 10000., "log", "bw", self._bw)]
+                          SLMap(20., 10000., "log", "bw", self._bw),
+                          SLMap(0, 3, 'lin', 'type', self._type, res="int", dataOnly=True)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
@@ -2352,7 +2359,8 @@ class IRPulse(PyoObject):
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMapFreq(self._freq),
-                          SLMap(20., 10000., "log", "bw", self._bw)]
+                          SLMap(20., 10000., "log", "bw", self._bw),
+                          SLMap(0, 3, 'lin', 'type', self._type, res="int", dataOnly=True)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
@@ -2738,7 +2746,8 @@ class Average(PyoObject):
         [obj.setSize(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMapMul(self._mul)]
+        self._map_list = [SLMap(2, 256, 'lin', 'size', self._size, res="int", dataOnly=True),
+                          SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
       
     @property
@@ -3361,3 +3370,109 @@ class ButBR(PyoObject):
         return self._q
     @q.setter
     def q(self, x): self.setQ(x)
+
+class ComplexRes(PyoObject):
+    """
+    Complex one-pole resonator filter. 
+    
+    ComplexRes implements a resonator derived from a complex 
+    multiplication, which is very similar to a digital filter.
+    
+    :Parent: :py:class:`PyoObject`
+    
+    :Args:
+    
+        input : PyoObject
+            Input signal to process.
+        freq : float or PyoObject, optional
+            Center frequency of the filter. Defaults to 1000.
+        decay : float or PyoObject, optional
+            Decay time, in seconds, for the filter's response.
+            Defaults to 0.25.
+    
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> env = HannTable()
+    >>> trigs = Metro(.2, poly=4).play()
+    >>> amp = TrigEnv(trigs, table=env, dur=0.005, mul=2)
+    >>> im = Noise(mul=amp)
+    >>> res = ComplexRes(im, freq=[950,530,780,1490], decay=1).out()
+
+    """
+    def __init__(self, input, freq=1000, decay=.25, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._input = input
+        self._freq = freq
+        self._decay = decay
+        self._in_fader = InputFader(input)
+        in_fader, freq, decay, mul, add, lmax = convertArgsToLists(self._in_fader, freq, decay, mul, add)
+        self._base_objs = [ComplexRes_base(wrap(in_fader,i), wrap(freq,i), wrap(decay,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 setFreq(self, x):
+        """
+        Replace the `freq` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                New `freq` attribute.
+
+        """
+        self._freq = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setFreq(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setDecay(self, x):
+        """
+        Replace the `decay` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                New `decay` attribute.
+
+        """
+        self._decay = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setDecay(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMapFreq(self._freq), SLMap(0.0001, 10, "log", "decay", self._decay), 
+                          SLMapMul(self._mul)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+    @property
+    def input(self):
+        """PyoObject. Input signal to filter.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+    @property
+    def freq(self):
+        """float or PyoObject. Center frequency of the filter.""" 
+        return self._freq
+    @freq.setter
+    def freq(self, x): self.setFreq(x)
+
+    @property
+    def decay(self):
+        """float or PyoObject. Decay time of the filter's response.""" 
+        return self._decay
+    @decay.setter
+    def decay(self, x): self.setDecay(x)
diff --git a/pyolib/fourier.py b/pyolib/fourier.py
index d48b223..9ab0667 100644
--- a/pyolib/fourier.py
+++ b/pyolib/fourier.py
@@ -30,8 +30,6 @@ along with pyo.  If not, see <http://www.gnu.org/licenses/>.
 """
 from _core import *
 from _maps import *
-from _widgets import createSpectrumWindow
-from pattern import Pattern
 
 class FFT(PyoObject):
     """
@@ -84,9 +82,9 @@ class FFT(PyoObject):
         Real, imaginary and bin_number parts are three separated set 
         of audio streams. The user should call :
         
-        FFT['real'] to retrieve the real part.
-        FFT['imag'] to retrieve the imaginary part.
-        FFT['bin'] to retrieve the bin number part.
+        |  FFT['real'] to retrieve the real part.
+        |  FFT['imag'] to retrieve the imaginary part.
+        |  FFT['bin'] to retrieve the bin number part.
 
     >>> s = Server().boot()
     >>> s.start()
@@ -451,8 +449,8 @@ class CarToPol(PyoObject):
     
         Polar coordinates can be retrieve by calling :
         
-        CarToPol['mag'] to retrieve the magnitude part.
-        CarToPol['ang'] to retrieve the angle part.
+        |  CarToPol['mag'] to retrieve the magnitude part.
+        |  CarToPol['ang'] to retrieve the angle part.
 
         CarToPol has no `out` method. Signal must be converted back to time domain, 
         with IFFT, before being sent to output.
@@ -594,8 +592,8 @@ class PolToCar(PyoObject):
 
         Cartesians coordinates can be retrieve by calling :
         
-        PolToCar['real'] to retrieve the real part.
-        CarToPol['imag'] to retrieve the imaginary part.
+        |  PolToCar['real'] to retrieve the real part.
+        |  CarToPol['imag'] to retrieve the imaginary part.
 
         PolToCar has no `out` method. Signal must be converted back to time domain, 
         with IFFT, before being sent to output.
@@ -1237,410 +1235,3 @@ class CvlVerb(PyoObject):
         return self._bal
     @bal.setter
     def bal(self, x): self.setBal(x)
-
-class Spectrum(PyoObject):
-    """
-    Spectrum analyzer and display.
-
-    Spectrum measures the magnitude of an input signal versus frequency
-    within a user defined range. It can show both magnitude and frequency
-    on linear or logarithmic scale.
-    
-    :Parent: :py:class:`PyoObject`
-    
-    :Args:
-    
-        input : PyoObject
-            Input signal to process.
-        size : int {pow-of-two > 4}, optional
-            FFT size. Must be a power of two greater than 4.
-            The FFT size is the number of samples used in each
-            analysis frame. Defaults to 1024.
-        wintype : int, optional
-            Shape of the envelope used to filter each input frame.
-            Possible shapes are :
-                0. rectangular (no windowing)
-                1. Hamming
-                2. Hanning
-                3. Bartlett (triangular)
-                4. Blackman 3-term
-                5. Blackman-Harris 4-term
-                6. Blackman-Harris 7-term
-                7. Tuckey (alpha = 0.66)
-                8. Sine (half-sine window)
-        function : python callable, optional
-            If set, this function will be called with magnitudes (as
-            list of lists, one list per channel). Useful if someone
-            wants to save the analysis data into a text file.
-            Defaults to None.
-
-    .. note::
-    
-        Spectrum has no `out` method.
-        Spectrum has no `mul` and `add` attributes.
-
-    >>> s = Server().boot()
-    >>> s.start()
-    >>> a = SuperSaw(freq=[500,750], detune=0.6, bal=0.7, mul=0.5).out()
-    >>> spec = Spectrum(a, size=1024)
-
-    """
-    def __init__(self, input, size=1024, wintype=2, function=None):
-        PyoObject.__init__(self)
-        self.points = None
-        self.viewFrame = None
-        self._input = input
-        self._size = size
-        self._wintype = wintype
-        self._function = function
-        self._fscaling = 0
-        self._mscaling = 1
-        self._lowbound = 0
-        self._highbound = 0.5
-        self._width = 500
-        self._height = 400
-        self._gain = 1
-        self._in_fader = InputFader(input)
-        in_fader, size, wintype, lmax = convertArgsToLists(self._in_fader, size, wintype)
-        self._base_objs = [Spectrum_base(wrap(in_fader,i), wrap(size,i), wrap(wintype,i)) for i in range(lmax)]
-        if function == None:
-            self.view()
-        self._timer = Pattern(self.refreshView, 0.05).play()
- 
-    def setInput(self, x, fadetime=0.05):
-        """
-        Replace the `input` attribute.
-        
-        :Args:
-
-            x : PyoObject
-                New signal to process.
-            fadetime : float, optional
-                Crossfade time between old and new input. Default to 0.05.
-
-        """
-        self._input = x
-        self._in_fader.setInput(x, fadetime)
-
-    def setSize(self, x):
-        """
-        Replace the `size` attribute.
-        
-        :Args:
-
-            x : int
-                new `size` attribute.
-        
-        """
-        self._size = x
-        x, lmax = convertArgsToLists(x)
-        [obj.setSize(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
-    def setWinType(self, x):
-        """
-        Replace the `wintype` attribute.
-        
-        :Args:
-
-            x : int
-                new `wintype` attribute.
-        
-        """
-        self._wintype = x
-        x, lmax = convertArgsToLists(x)
-        [obj.setWinType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
-    def setFunction(self, function):
-        """
-        Sets the function to be called to retrieve the analysis data.
-        
-        :Args:
-            
-            function : python callable
-                The function called by the internal timer to retrieve the
-                analysis data. The function must be created with one argument
-                and will receive the data as a list of lists (one list per channel).
-
-        """
-        self._function = function
-
-    def poll(self, active):
-        """
-        Turns on and off the analysis polling.
-        
-        :Args:
-            
-            active : boolean
-                If True, starts the analysis polling, False to stop it.
-                defaults to True.
-
-        """
-        if active:
-            self._timer.play()
-        else:
-            self._timer.stop()
-
-    def polltime(self, time):
-        """
-        Sets the polling time in seconds.
-        
-        :Args:
-            
-            time : float
-                Adjusts the frequency of the internal timer used to
-                retrieve the current analysis frame. defaults to 0.05.
-        
-        """
-        self._timer.time = time
-
-    def setLowbound(self, x):
-        """
-        Sets the lower frequency, as multiplier of sr, returned by the analysis.
-        
-        Returns the real low frequency en Hz.
-        
-        :Args:
-
-            x : float {0 <= x <= 0.5}
-                new `lowbound` attribute.
-        
-        """
-        self._lowbound = x
-        x, lmax = convertArgsToLists(x)
-        tmp = [obj.setLowbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-        return tmp[0]
-
-    def setHighbound(self, x):
-        """
-        Sets the higher frequency, as multiplier of sr, returned by the analysis.
-        
-        Returns the real high frequency en Hz.
-        
-        :Args:
-
-            x : float {0 <= x <= 0.5}
-                new `highbound` attribute.
-        
-        """
-        self._highbound = x
-        x, lmax = convertArgsToLists(x)
-        tmp = [obj.setHighbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-        return tmp[0]
-
-    def getLowfreq(self):
-        """
-        Returns the current lower frequency, in Hz, used by the analysis.
-        
-        """
-
-        return self._base_objs[0].getLowfreq()
-
-    def getHighfreq(self):
-        """
-        Returns the current higher frequency, in Hz, used by the analysis.
-        
-        """
-        return self._base_objs[0].getHighfreq()
-
-    def setWidth(self, x):
-        """
-        Sets the width, in pixels, of the current display.
-        
-        Used internally to build the list of points to draw.
-        
-        :Args:
-
-            x : int
-                new `width` attribute.
-        
-        """
-        self._width = x
-        x, lmax = convertArgsToLists(x)
-        [obj.setWidth(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
-    def setHeight(self, x):
-        """
-        Sets the height, in pixels, of the current display.
-        
-        Used internally to build the list of points to draw.
-        
-        :Args:
-
-            x : int
-                new `height` attribute.
-        
-        """
-        self._height = x
-        x, lmax = convertArgsToLists(x)
-        [obj.setHeight(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
-    def setFscaling(self, x):
-        """
-        Sets the frequency display to linear or logarithmic.
-        
-        :Args:
-
-            x : boolean
-                If True, the frequency display is logarithmic. False turns
-                it back to linear. Defaults to False.
-        
-        """
-        self._fscaling = x
-        x, lmax = convertArgsToLists(x)
-        [obj.setFscaling(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-        if self.viewFrame != None:
-            self.viewFrame.setFscaling(self._fscaling)
-
-    def setMscaling(self, x):
-        """
-        Sets the magnitude display to linear or logarithmic.
-        
-        :Args:
-
-            x : boolean
-                If True, the magnitude display is logarithmic (which means in dB). 
-                False turns it back to linear. Defaults to True.
-        
-        """
-        self._mscaling = x
-        x, lmax = convertArgsToLists(x)
-        [obj.setMscaling(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-        if self.viewFrame != None:
-            self.viewFrame.setMscaling(self._mscaling)
-
-    def getFscaling(self):
-        """
-        Returns the scaling of the frequency display.
-        
-        Returns True for logarithmic or False for linear.
-
-        """
-        return self._fscaling
-
-    def getMscaling(self):
-        """
-        Returns the scaling of the magnitude display.
-        
-        Returns True for logarithmic or False for linear.
-
-        """
-        return self._mscaling
-
-    def setGain(self, x):
-        """
-        Set the gain of the anaysis data. For drawing purpose.
-        
-        :Args:
-
-            x : float
-                new `gain` attribute, as linear values.
-        
-        """
-        self._gain = x
-        x, lmax = convertArgsToLists(x)
-        [obj.setGain(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
-
-    def view(self, title="Spectrum", wxnoserver=False):
-        """
-        Opens a window showing the result of the analysis.
-        
-        :Args:
-        
-            title : string, optional
-                Window title. Defaults to "Spectrum". 
-            wxnoserver : boolean, optional
-                With wxPython graphical toolkit, if True, tells the 
-                interpreter that there will be no server window.
-                
-        If `wxnoserver` is set to True, the interpreter will not wait for 
-        the server GUI before showing the controller window. 
-        
-        """
-        createSpectrumWindow(self, title, wxnoserver)
-
-    def _setViewFrame(self, frame):
-        self.viewFrame = frame
-        
-    def refreshView(self):
-        """
-        Updates the graphical display of the spectrum.
-        
-        Called automatically by the internal timer.
-
-        """
-        self.points = [obj.display() for obj in self._base_objs]
-        if self._function != None:
-            self._function(self.points)
-        if self.viewFrame != None:
-            self.viewFrame.update(self.points)
-
-
-    @property
-    def input(self):
-        """PyoObject. Input signal to process.""" 
-        return self._input
-    @input.setter
-    def input(self, x): self.setInput(x)
-
-    @property
-    def size(self):
-        """int. FFT size."""
-        return self._size
-    @size.setter
-    def size(self, x): self.setSize(x)
-
-    @property
-    def wintype(self):
-        """int. Windowing method."""
-        return self._wintype
-    @wintype.setter
-    def wintype(self, x): self.setWinType(x)
-
-    @property
-    def gain(self):
-        """float. Sets the gain of the analysis data."""
-        return self._gain
-    @gain.setter
-    def gain(self, x): self.setGain(x)
-
-    @property
-    def lowbound(self):
-        """float. Lowest frequency (multiplier of sr) to output."""
-        return self._lowbound
-    @lowbound.setter
-    def lowbound(self, x): self.setLowbound(x)
-
-    @property
-    def highbound(self):
-        """float. Highest frequency (multiplier of sr) to output."""
-        return self._highbound
-    @highbound.setter
-    def highbound(self, x): self.setHighbound(x)
-
-    @property
-    def width(self):
-        """int. Width, in pixels, of the current display."""
-        return self._width
-    @width.setter
-    def width(self, x): self.setWidth(x)
-
-    @property
-    def height(self):
-        """int. Height, in pixels, of the current display."""
-        return self._height
-    @height.setter
-    def height(self, x): self.setHeight(x)
-
-    @property
-    def fscaling(self):
-        """boolean. Scaling of the frequency display."""
-        return self._fscaling
-    @fscaling.setter
-    def fscaling(self, x): self.setFscaling(x)
-
-    @property
-    def mscaling(self):
-        """boolean. Scaling of the magnitude display."""
-        return self._mscaling
-    @mscaling.setter
-    def mscaling(self, x): self.setMscaling(x)
diff --git a/pyolib/generators.py b/pyolib/generators.py
index a24bb1e..72fcfc5 100644
--- a/pyolib/generators.py
+++ b/pyolib/generators.py
@@ -1019,10 +1019,9 @@ class LFO(PyoObject):
             
 
         """
-        if x >= 0 and x < 8:
-            self._type = x
-            x, lmax = convertArgsToLists(x)
-            [obj.setType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+        self._type = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setType(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
     def reset(self):
         """
@@ -1033,7 +1032,10 @@ class LFO(PyoObject):
 
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMapFreq(self._freq), SLMap(0., 1., "lin", "sharp", self._sharp), SLMapMul(self._mul)]
+        self._map_list = [SLMapFreq(self._freq), 
+                          SLMap(0., 1., "lin", "sharp", self._sharp), 
+                          SLMap(0, 7, "lin", "type", self._type, "int", dataOnly=True), 
+                          SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
diff --git a/pyolib/midi.py b/pyolib/midi.py
index e305ba4..5936021 100644
--- a/pyolib/midi.py
+++ b/pyolib/midi.py
@@ -257,6 +257,13 @@ class CtlScan(PyoObject):
     def setDiv(self, x):
         pass
 
+    def reset(self):
+        """
+        Resets the scanner.
+
+        """
+        [obj.reset() for obj in self._base_objs]
+
     def setFunction(self, x):
         """
         Replace the `function` attribute.
@@ -362,6 +369,13 @@ class CtlScan2(PyoObject):
     def setDiv(self, x):
         pass
 
+    def reset(self):
+        """
+        Resets the scanner.
+
+        """
+        [obj.reset() for obj in self._base_objs]
+        
     def setFunction(self, x):
         """
         Replace the `function` attribute.
@@ -442,10 +456,16 @@ class Notein(PyoObject):
         Pitch and velocity are two separated set of streams. 
         The user should call :
         
-        Notein['pitch'] to retrieve pitch streams.
-        Notein['velocity'] to retrieve velocity streams.    
+        |  Notein['pitch'] to retrieve pitch streams.
+        |  Notein['velocity'] to retrieve velocity streams.    
 
         Velocity is automatically scaled between 0 and 1.
+
+        Notein also outputs trigger streams on noteon and noteoff. 
+        These streams can be retrieved with :
+        
+        |  Notein['trigon'] to retrieve noteon trigger streams.
+        |  Notein['trigoff'] to retrieve noteoff trigger streams.    
         
         The out() method is bypassed. Notein's signal can not be sent 
         to audio outs.
@@ -463,6 +483,8 @@ class Notein(PyoObject):
         PyoObject.__init__(self, mul, add)
         self._pitch_dummy = []
         self._velocity_dummy = []
+        self._trigon_dummy = []
+        self._trigoff_dummy = []
         self._poly = poly
         self._scale = scale
         self._first = first
@@ -471,17 +493,26 @@ class Notein(PyoObject):
         mul, add, lmax = convertArgsToLists(mul, add)
         self._base_handler = MidiNote_base(self._poly, self._scale, self._first, self._last, self._channel)
         self._base_objs = []
+        self._trig_objs = []
         for i in range(lmax * poly):
             self._base_objs.append(Notein_base(self._base_handler, i, 0, 1, 0))
             self._base_objs.append(Notein_base(self._base_handler, i, 1, wrap(mul,i), wrap(add,i)))
-
+            self._trig_objs.append(NoteinTrig_base(self._base_handler, i, 0, 1, 0))
+            self._trig_objs.append(NoteinTrig_base(self._base_handler, i, 1, 1, 0))
+            
     def __getitem__(self, str):
         if str == 'pitch':
             self._pitch_dummy.append(Dummy([self._base_objs[i*2] for i in range(self._poly)]))
             return self._pitch_dummy[-1]
-        if str == 'velocity':
+        elif str == 'velocity':
             self._velocity_dummy.append(Dummy([self._base_objs[i*2+1] for i in range(self._poly)]))
             return self._velocity_dummy[-1]
+        elif str == 'trigon':
+            self._trigon_dummy.append(Dummy([self._trig_objs[i*2] for i in range(self._poly)]))
+            return self._trigon_dummy[-1]
+        elif str == 'trigoff':
+            self._trigoff_dummy.append(Dummy([self._trig_objs[i*2+1] for i in range(self._poly)]))
+            return self._trigoff_dummy[-1]
 
     def setChannel(self, x):
         """
diff --git a/pyolib/pan.py b/pyolib/pan.py
index 54b16d7..f66eb18 100644
--- a/pyolib/pan.py
+++ b/pyolib/pan.py
@@ -39,7 +39,8 @@ class Pan(PyoObject):
         input : PyoObject
             Input signal to process.
         outs : int, optional
-            Number of channels on the panning circle. Defaults to 2.
+            Number of channels on the panning circle. Available at 
+            initialization time only. Defaults to 2.
         pan : float or PyoObject
             Position of the sound on the panning circle, between 0 and 1. 
             Defaults to 0.5.
@@ -149,7 +150,8 @@ class SPan(PyoObject):
         input : PyoObject
             Input signal to process.
         outs : int, optional
-            Number of channels on the panning circle. Defaults to 2.
+            Number of channels on the panning circle. Available at 
+            initialization time only. Defaults to 2.
         pan : float or PyoObject
             Position of the sound on the panning circle, between 0 and 1. 
             Defaults to 0.5.
@@ -238,7 +240,8 @@ class Switch(PyoObject):
         input : PyoObject
             Input signal to process.
         outs : int, optional
-            Number of outputs. Defaults to 2.
+            Number of outputs. Available at initialization time only. 
+            Defaults to 2.
         voice : float or PyoObject
             Voice position pointer, between 0 and (outs-1) / len(input). 
             Defaults to 0.
@@ -684,7 +687,8 @@ class Mixer(PyoObject):
         return self._inputs.keys()
         
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMapMul(self._mul)]
+        self._map_list = [SLMap(0, 10, 'lin', 'time', self._time, dataOnly=True),
+                          SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
diff --git a/pyolib/pattern.py b/pyolib/pattern.py
index 851ad20..e7b2a7c 100644
--- a/pyolib/pattern.py
+++ b/pyolib/pattern.py
@@ -245,7 +245,7 @@ class CallAfter(PyoObject):
         
         CallAfter has no `mul` and `add` attributes.
         
-        The object is not deleted after the call. The User must delete it himself.
+        The object is not deleted after the call. The user must delete it himself.
 
     >>> s = Server().boot()
     >>> s.start()
diff --git a/pyolib/phasevoc.py b/pyolib/phasevoc.py
index bb4f5e5..379b934 100644
--- a/pyolib/phasevoc.py
+++ b/pyolib/phasevoc.py
@@ -295,8 +295,8 @@ class PVAddSynth(PyoObject):
     >>> s = Server().boot()
     >>> s.start()
     >>> a = SfPlayer(SNDS_PATH+"/transparent.aif", loop=True, mul=0.7)
-    >>> pva = PVAnal(a, size=1024, overlaps=4, pitch=2)
-    >>> pvs = PVAddSynth(pva, pitch=1.25, num=100, first=0, inc=2)
+    >>> pva = PVAnal(a, size=1024, overlaps=4, wintype=2)
+    >>> pvs = PVAddSynth(pva, pitch=1.25, num=100, first=0, inc=2).out()
 
     """
     def __init__(self, input, pitch=1, num=100, first=0, inc=1, mul=1, add=0):
diff --git a/pyolib/players.py b/pyolib/players.py
index 98992ad..3a1f7a4 100644
--- a/pyolib/players.py
+++ b/pyolib/players.py
@@ -208,7 +208,9 @@ class SfPlayer(PyoObject):
         [obj.setInterp(wrap(x,i)) for i, obj in enumerate(self._base_players)]
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMap(-2., 2., 'lin', 'speed', self._speed), SLMapMul(self._mul)]
+        self._map_list = [SLMap(-2., 2., 'lin', 'speed', self._speed), 
+                          SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
+                          SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
@@ -354,7 +356,9 @@ class SfMarkerShuffler(PyoObject):
         return self._markers
         
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMap(0.01, 2., 'lin', 'speed', self._speed), SLMapMul(self._mul)]
+        self._map_list = [SLMap(0.01, 2., 'lin', 'speed', self._speed), 
+                          SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
+                          SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
                     
     @property
@@ -492,6 +496,7 @@ class SfMarkerLooper(PyoObject):
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMap(0.01, 2., 'lin', 'speed', self._speed), 
                           SLMap(0, len(self._markers)-1, 'lin', 'mark', self._mark, 'int'),
+                          SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
diff --git a/pyolib/randoms.py b/pyolib/randoms.py
index 695ee21..737a0e6 100644
--- a/pyolib/randoms.py
+++ b/pyolib/randoms.py
@@ -627,7 +627,7 @@ class Xnoise(PyoObject):
                 new `x2` attribute.
 
         """
-        self._x2= x
+        self._x2 = x
         x, lmax = convertArgsToLists(x)
         [obj.setX2(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
@@ -645,6 +645,15 @@ class Xnoise(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setFreq(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0, 12, 'lin', 'dist', self._dist, res="int", dataOnly=True),
+                          SLMap(0.001, 200., 'log', 'freq', self._freq),
+                          SLMap(0, 1, 'lin', 'x1', self._x1),
+                          SLMap(0, 1, 'lin', 'x2', self._x2),
+                          SLMap(0, 2500, 'lin', 'mul', self._mul),
+                          SLMap(0, 2500, 'lin', 'add', self._add)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def dist(self): 
         """string or int. Distribution type."""
@@ -880,6 +889,14 @@ class XnoiseMidi(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setFreq(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0, 12, 'lin', 'dist', self._dist, res="int", dataOnly=True),
+                          SLMap(0.001, 200., 'log', 'freq', self._freq),
+                          SLMap(0, 1, 'lin', 'x1', self._x1),
+                          SLMap(0, 1, 'lin', 'x2', self._x2),
+                          SLMap(0, 2, 'lin', 'scale', self._scale, res="int", dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def dist(self): 
         """string or int. Distribution type."""
@@ -1097,6 +1114,14 @@ class XnoiseDur(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setX2(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0, 12, 'lin', 'dist', self._dist, res="int", dataOnly=True),
+                          SLMap(0, 20, 'lin', 'min', self._min),
+                          SLMap(0, 20, 'lin', 'max', self._max),
+                          SLMap(0, 1, 'lin', 'x1', self._x1),
+                          SLMap(0, 1, 'lin', 'x2', self._x2)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def dist(self): 
         """string or int. Distribution type."""
@@ -1208,7 +1233,7 @@ class Urn(PyoObject):
         [obj.setFreq(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(1., 2., 'lin', 'max', self._max),
+        self._map_list = [SLMap(1, 1000, 'lin', 'max', self._max, res="int", dataOnly=True),
                           SLMap(0.1, 20., 'lin', 'freq', self._freq),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
diff --git a/pyolib/server.py b/pyolib/server.py
index b7729a0..7c1f134 100644
--- a/pyolib/server.py
+++ b/pyolib/server.py
@@ -98,7 +98,7 @@ class Server(object):
         
     """
     def __init__(self, sr=44100, nchnls=2, buffersize=256, duplex=1, audio='portaudio', jackname='pyo'):
-        if os.environ.has_key("PYO_SERVER_AUDIO") and "offline" not in audio:
+        if os.environ.has_key("PYO_SERVER_AUDIO") and "offline" not in audio and "embedded" not in audio:
             audio = os.environ["PYO_SERVER_AUDIO"]
         self._time = time
         self._nchnls = nchnls
@@ -140,7 +140,7 @@ class Server(object):
         self._globalseed = 0
         self._server.__init__(sr, nchnls, buffersize, duplex, audio, jackname)
 
-    def gui(self, locals=None, meter=True, timer=True):
+    def gui(self, locals=None, meter=True, timer=True, exit=True):
         """
         Show the server's user interface.
         
@@ -155,10 +155,14 @@ class Server(object):
             timer : boolean, optional
                 If True, the interface will show a clock of the current time.
                 Defaults to True.
+            exit : boolean, optional
+                If True, the python interpreter will exit when the 'Quit' button is pressed,
+                Otherwise, the GUI will be closed leaving the interpreter alive.
+                Defaults to True.
             
         """
         f, win = createServerGUI(self._nchnls, self.start, self.stop, self.recstart, self.recstop,
-                                 self.setAmp, self.getIsStarted(), locals, self.shutdown, meter, timer, self._amp)
+                                 self.setAmp, self.getIsStarted(), locals, self.shutdown, meter, timer, self._amp, exit)
         if meter:
             self._server.setAmpCallable(f)
         if timer:
@@ -172,6 +176,9 @@ class Server(object):
     def setTimeCallable(self, func):
         self.setTime = func
         self._server.setTimeCallable(self)
+
+    def setMeter(self, meter):
+        self._server.setAmpCallable(meter)
         
     def setInOutDevice(self, x):
         """
@@ -261,6 +268,9 @@ class Server(object):
         """
         Set the Midi input device number. See `pm_list_devices()`.
         
+        A number greater than the highest portmidi device index
+        will opened all available input devices. 
+        
         :Args:
 
             x : int
@@ -349,7 +359,7 @@ class Server(object):
 
     def setJackAuto(self, xin=True, xout=True):
         """
-        Tells the server to auto-connect (or not) Jack ports.
+        Tells the server to auto-connect (or not) Jack ports to System ports.
         
         :Args:
 
@@ -361,6 +371,32 @@ class Server(object):
         """        
         self._server.setJackAuto(xin, xout)
 
+    def setJackAutoConnectInputPorts(self, ports):
+        """
+        Tells the server to auto-connect Jack input ports to pre-defined Jack ports.
+        
+        :Args:
+
+            ports : string or list of strings
+                Name of the Jack port(s) to auto-connect. Regular Expressions are allowed.
+
+        """
+        ports, lmax = convertArgsToLists(ports)
+        self._server.setJackAutoConnectInputPorts(ports)
+
+    def setJackAutoConnectOutputPorts(self, ports):
+        """
+        Tells the server to auto-connect Jack output ports to pre-defined Jack ports.
+        
+        :Args:
+
+            ports : string or list of strings
+                Name of the Jack port(s) to auto-connect. Regular Expressions are allowed.
+
+        """
+        ports, lmax = convertArgsToLists(ports)
+        self._server.setJackAutoConnectOutputPorts(ports)
+        
     def setGlobalSeed(self, x):
         """
         Set the server's global seed used by random objects.
@@ -543,9 +579,12 @@ class Server(object):
         """
         self._server.recstop()
 
-    def sendMidiNote(self, pitch, velocity, channel=0, timestamp=0):
+    def noteout(self, pitch, velocity, channel=0, timestamp=0):
         """
-        Send a MIDI note message to the selected output device. 
+        Send a MIDI note message to the selected midi output device. 
+        
+        Arguments can be list of values to generate multiple events
+        in one call.
         
         :Args:
         
@@ -556,10 +595,135 @@ class Server(object):
                 with a velocity of 0 is equivalent to a note off.
             channel : int, optional
                 The Midi channel, between 1 and 16, on which the 
-                note is sent. A channel of 0 means all channels. 
+                note is sent. A channel of 0 means all channels.
+                Defaults to 0. 
+            timestamp : int, optional
+                The delay time, in milliseconds, before the note
+                is sent on the portmidi stream. A value of 0 means
+                to play the note now. Defaults to 0.
+        """
+        pitch, velocity, channel, timestamp, lmax = convertArgsToLists(pitch, velocity, channel, timestamp)
+        [self._server.noteout(wrap(pitch,i), wrap(velocity,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+
+    def afterout(self, pitch, velocity, channel=0, timestamp=0):
+        """
+        Send an aftertouch message to the selected midi output device. 
+        
+        Arguments can be list of values to generate multiple events
+        in one call.
+        
+        :Args:
+        
+            pitch : int
+                Midi key pressed down, between 0 and 127.
+            velocity : int
+                Velocity of the pressure, between 0 and 127.
+            channel : int, optional
+                The Midi channel, between 1 and 16, on which the 
+                note is sent. A channel of 0 means all channels.
+                Defaults to 0. 
+            timestamp : int, optional
+                The delay time, in milliseconds, before the note
+                is sent on the portmidi stream. A value of 0 means
+                to play the note now. Defaults to 0.
+        """
+        pitch, velocity, channel, timestamp, lmax = convertArgsToLists(pitch, velocity, channel, timestamp)
+        [self._server.afterout(wrap(pitch,i), wrap(velocity,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+
+    def ctlout(self, ctlnum, value, channel=0, timestamp=0):
+        """
+        Send a control change message to the selected midi output device. 
+        
+        Arguments can be list of values to generate multiple events
+        in one call.
+        
+        :Args:
+        
+            ctlnum : int
+                Controller number, between 0 and 127.
+            value : int
+                Value of the controller, between 0 and 127.
+            channel : int, optional
+                The Midi channel, between 1 and 16, on which the 
+                message is sent. A channel of 0 means all channels.
+                Defaults to 0. 
+            timestamp : int, optional
+                The delay time, in milliseconds, before the message
+                is sent on the portmidi stream. A value of 0 means
+                to play the message now. Defaults to 0.
+        """
+        ctlnum, value, channel, timestamp, lmax = convertArgsToLists(ctlnum, value, channel, timestamp)
+        [self._server.ctlout(wrap(ctlnum,i), wrap(value,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+
+    def programout(self, value, channel=0, timestamp=0):
+        """
+        Send a program change message to the selected midi output device. 
+        
+        Arguments can be list of values to generate multiple events
+        in one call.
+        
+        :Args:
+        
+            value : int
+                New program number, between 0 and 127.
+            channel : int, optional
+                The Midi channel, between 1 and 16, on which the 
+                message is sent. A channel of 0 means all channels.
+                Defaults to 0. 
+            timestamp : int, optional
+                The delay time, in milliseconds, before the message
+                is sent on the portmidi stream. A value of 0 means
+                to play the message now. Defaults to 0.
+        """
+        value, channel, timestamp, lmax = convertArgsToLists(value, channel, timestamp)
+        [self._server.programout(wrap(value,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
+
+    def pressout(self, value, channel=0, timestamp=0):
+        """
+        Send a channel pressure message to the selected midi output device. 
+        
+        Arguments can be list of values to generate multiple events
+        in one call.
+        
+        :Args:
+
+            value : int
+                Single greatest pressure value, between 0 and 127.
+            channel : int, optional
+                The Midi channel, between 1 and 16, on which the 
+                message is sent. A channel of 0 means all channels.
+                Defaults to 0. 
+            timestamp : int, optional
+                The delay time, in milliseconds, before the message
+                is sent on the portmidi stream. A value of 0 means
+                to play the message now. Defaults to 0.
+        """
+        value, channel, timestamp, lmax = convertArgsToLists(value, channel, timestamp)
+        [self._server.pressout(wrap(value,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
 
+    def bendout(self, value, channel=0, timestamp=0):
         """
-        self._server.sendMidiNote(pitch, velocity, channel, timestamp)
+        Send a pitch bend message to the selected midi output device. 
+        
+        Arguments can be list of values to generate multiple events
+        in one call.
+        
+        :Args:
+
+            value : int
+                14 bits pitch bend value. 8192 is where there is no
+                bending, 0 is full down and 16383 is full up bending.
+            channel : int, optional
+                The Midi channel, between 1 and 16, on which the 
+                message is sent. A channel of 0 means all channels.
+                Defaults to 0. 
+            timestamp : int, optional
+                The delay time, in milliseconds, before the message
+                is sent on the portmidi stream. A value of 0 means
+                to play the message now. Defaults to 0.
+        """
+        value, channel, timestamp, lmax = convertArgsToLists(value, channel, timestamp)
+        [self._server.bendout(wrap(value,i), wrap(channel,i), wrap(timestamp,i)) for i in range(lmax)]
 
     def getStreams(self):
         """
@@ -637,13 +801,6 @@ class Server(object):
         
         """
         return self._server.setServer()
-        
-    def flush(self):
-        """
-        Flush the server objects. Need a shutdown before working. This is useful if want to flush a script without freeing the buffers
-        
-        """
-        return self._server.flush()
     
     def getInputAddr(self):
         """
diff --git a/pyolib/tableprocess.py b/pyolib/tableprocess.py
index 2b4fb7c..a9acdcd 100644
--- a/pyolib/tableprocess.py
+++ b/pyolib/tableprocess.py
@@ -136,6 +136,7 @@ class Osc(PyoObject):
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMapFreq(self._freq),
                           SLMapPhase(self._phase),
+                          SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -403,6 +404,7 @@ class OscTrig(PyoObject):
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMapFreq(self._freq),
                           SLMapPhase(self._phase),
+                          SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -854,7 +856,10 @@ class TableRead(PyoObject):
 
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMapFreq(self._freq), SLMapMul(self._mul)]
+        self._map_list = [SLMap(0.0001, 1000, 'log', 'freq', self._freq), 
+                          SLMap(0, 1, 'lin', 'loop', self._loop, res="int", dataOnly=True),
+                          SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
+                          SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
@@ -1019,7 +1024,11 @@ class Pulsar(PyoObject):
         :Args:
 
             x : int {1, 2, 3, 4}
-                new `interp` attribute.
+                Choice of the interpolation method.
+                    1. no interpolation
+                    2. linear
+                    3. cosinus
+                    4. cubic
         
         """
         self._interp = x
@@ -1030,6 +1039,7 @@ class Pulsar(PyoObject):
         self._map_list = [SLMapFreq(self._freq),
                           SLMap(0., 1., 'lin', 'frac', self._frac),
                           SLMapPhase(self._phase),
+                          SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -1149,6 +1159,144 @@ class Pointer(PyoObject):
     @index.setter
     def index(self, x): self.setIndex(x)
 
+class Pointer2(PyoObject):
+    """
+    High quality table reader with control on the pointer position.
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+
+        table : PyoTableObject
+            Table containing the waveform samples.
+        index : PyoObject
+            Normalized position in the table between 0 and 1.
+        interp : int {1, 2, 3, 4}, optional
+            Choice of the interpolation method. Defaults to 4.
+                1. no interpolation
+                2. linear
+                3. cosinus
+                4. cubic
+        autosmooth : boolean, optional
+            If True, a lowpass filter, following the pitch, is applied on 
+            
+            the output signal to reduce the quantization noise produced 
+            
+            by very low transpositions. Defaults to True.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> t = SndTable(SNDS_PATH + '/transparent.aif')
+    >>> freq = t.getRate()
+    >>> p = Phasor(freq=[freq*0.5, freq*0.45])
+    >>> a = Pointer2(table=t, index=p, mul=.3).out()
+
+    """
+    def __init__(self, table, index, interp=4, autosmooth=True, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._table = table
+        self._index = index
+        self._interp = interp
+        self._autosmooth = autosmooth
+        table, index, interp, autosmooth, mul, add, lmax = convertArgsToLists(table, index, interp, autosmooth, mul, add)
+        self._base_objs = [Pointer2_base(wrap(table,i), wrap(index,i), wrap(interp,i), wrap(autosmooth,i), wrap(mul,i), wrap(add,i)) for i in range(lmax)]
+
+    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 setIndex(self, x):
+        """
+        Replace the `index` attribute.
+        
+        :Args:
+
+            x : PyoObject
+                new `index` attribute.
+        
+        """
+        self._index = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setIndex(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.
+                    1. no interpolation
+                    2. linear interpolation
+                    3. cosine interpolation
+                    4. cubic interpolation (default)
+        
+        """
+        self._interp = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setInterp(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setAutoSmooth(self, x):
+        """
+        Replace the `autosmooth` attribute.
+        
+        If True, a lowpass filter, following the playback speed, is applied on 
+        the output signal to reduce the quantization noise produced by very 
+        low transpositions.
+        
+        :Args:
+
+            x : boolean
+                new `autosmooth` attribute.
+        
+        """
+        self._autosmooth = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setAutoSmooth(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMapMul(self._mul)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+    @property
+    def table(self):
+        """PyoTableObject. Table containing the waveform samples.""" 
+        return self._table
+    @table.setter
+    def table(self, x): self.setTable(x)
+
+    @property
+    def index(self):
+        """PyoObject. Index pointer position in the table.""" 
+        return self._index
+    @index.setter
+    def index(self, x): self.setIndex(x)
+
+    @property
+    def interp(self): 
+        """int {1, 2, 3, 4}. Interpolation method."""
+        return self._interp
+    @interp.setter
+    def interp(self, x): self.setInterp(x)
+
+    @property
+    def autosmooth(self): 
+        """boolean. Quantization noise filter."""
+        return self._autosmooth
+    @autosmooth.setter
+    def autosmooth(self, x): self.setAutoSmooth(x)
+
 class TableIndex(PyoObject):
     """
     Table reader by sample position without interpolation.
@@ -1710,6 +1858,8 @@ class Granulator(PyoObject):
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMap(0.1, 2., 'lin', 'pitch', self._pitch),
                           SLMap(0.01, 1., 'lin', 'dur', self._dur),
+                          SLMap(1, 256, 'lin', 'grains', self._grains, res="int", dataOnly=True),
+                          SLMap(0.001, 1, 'log', 'basedur', self._basedur, dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -2128,7 +2278,9 @@ class Looper(PyoObject):
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
         self._map_list = [SLMap(0.1, 2., 'lin', 'pitch', self._pitch),
                           SLMap(0., self._table.getDur(), 'lin', 'start', self._start),
-                          SLMap(0.01, 1., 'lin', 'dur', self._dur),
+                          SLMap(0.01, self._table.getDur(), 'lin', 'dur', self._dur),
+                          SLMap(0, 2, 'lin', 'xfadeshape', self._xfadeshape, res="int", dataOnly=True),
+                          SLMap(1, 4, 'lin', 'interp', self._interp, res="int", dataOnly=True),
                           SLMapMul(self._mul)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
@@ -2316,6 +2468,9 @@ class Granule(PyoObject):
     """
     Another granular synthesis generator.
 
+    As of pyo 0.7.4, users can call the `setSync` method to change the 
+    granulation mode (either synchronous or asynchronous) of the object.
+    
     :Parent: :py:class:`PyoObject`
     
     :Args:
@@ -2358,6 +2513,7 @@ class Granule(PyoObject):
         self._pitch = pitch
         self._pos = pos
         self._dur = dur
+        self._sync = 1
         table, env, dens, pitch, pos, dur, mul, add, lmax = convertArgsToLists(table, env, dens, pitch, pos, dur, mul, add)
         self._base_objs = [Granule_base(wrap(table,i), wrap(env,i), wrap(dens,i), wrap(pitch,i), wrap(pos,i), wrap(dur,i), 
                                            wrap(mul,i), wrap(add,i)) for i in range(lmax)]
@@ -2446,6 +2602,21 @@ class Granule(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setDur(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
+    def setSync(self, x):
+        """
+        Sets the granulation mode, synchronous or asynchronous.
+        
+        :Args:
+
+            x : boolean
+                True means synchronous granulation (the default) 
+                while False means asynchronous.
+        
+        """
+        self._sync = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setSync(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(1, 250, 'lin', 'dens', self._dens),
                           SLMap(0.25, 2., 'lin', 'pitch', self._pitch),
@@ -2577,3 +2748,260 @@ class TableScale(PyoObject):
         return self._outtable
     @outtable.setter
     def outtable(self, x): self.setOuttable(x)
+
+class Particle(PyoObject):
+    """
+    A full control granular synthesis generator.
+    
+    :Parent: :py:class:`PyoObject`
+    
+    :Args:
+
+        table : PyoTableObject
+            Table containing the waveform samples.
+        env : PyoTableObject
+            Table containing the grain envelope.
+        dens : float or PyoObject, optional
+            Density of grains per second. Defaults to 50.
+        pitch : float or PyoObject, optional
+            Pitch of the grains. Each grain sampled the current value 
+            of this stream at the beginning of its envelope and hold 
+            it until the end of the grain. Defaults to 1.
+        pos : float or PyoObject, optional
+            Pointer position, in samples, in the waveform table. Each 
+            grain sampled the current value of this stream at the beginning 
+            of its envelope and hold it until the end of the grain. 
+            Defaults to 0.
+        dur : float or PyoObject, optional
+            Duration, in seconds, of the grain. Each grain sampled the 
+            current value of this stream at the beginning of its envelope 
+            and hold it until the end of the grain. Defaults to 0.1.
+        dev : float or PyoObject, optional
+            Maximum deviation of the starting time of the grain, between 0 and
+            1 (relative to the current duration of the grain). Each grain sampled 
+            the current value of this stream at the beginning of its envelope 
+            and hold it until the end of the grain. Defaults to 0.01.
+        pan : float or PyoObject, optional
+            Panning factor of the grain (if chnls=1, this value is skipped). 
+            Each grain sampled the current value of this stream at the beginning 
+            of its envelope and hold it until the end of the grain. Defaults to 0.5.
+        chnls : integer, optional
+            Number of output channels per audio stream (if chnls=2 and a stereo sound 
+            table is given at the table argument, the objet will create 4 output 
+            streams, 2 per table channel). Available at initialization only. Defaults to 1. 
+
+    .. note::
+    
+        Particle object compensate for the difference between sampling rate of the
+        loaded sound and the current sampling rate of the Server. 
+            
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> snd = SndTable(SNDS_PATH+"/transparent.aif")
+    >>> end = snd.getSize() - s.getSamplingRate() * 0.25
+    >>> env = HannTable()
+    >>> dns = Randi(min=5, max=100, freq=.1)
+    >>> pit = Randh(min=0.99, max=1.01, freq=100)
+    >>> pos = Randi(min=0, max=1, freq=0.25, mul=end)
+    >>> dur = Randi(min=0.01, max=0.25, freq=0.15)
+    >>> dev = Randi(min=0, max=1, freq=0.2)
+    >>> pan = Noise(0.5, 0.5)
+    >>> grn = Particle(snd, env, dns, pit, pos, dur, dev, pan, chnls=2, mul=.2).out()
+
+    """
+    def __init__(self, table, env, dens=50, pitch=1, pos=0, dur=.1, dev=0.01, pan=0.5, chnls=1, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._table = table
+        self._env = env
+        self._dens = dens
+        self._pitch = pitch
+        self._pos = pos
+        self._dur = dur
+        self._dev = dev
+        self._pan = pan
+        self._chnls = chnls
+        table, env, dens, pitch, pos, dur, dev, pan, mul, add, lmax = convertArgsToLists(table, env, dens, pitch, pos, dur, dev, pan, mul, add)
+        self._base_players = [MainParticle_base(wrap(table,i), wrap(env,i), wrap(dens,i), wrap(pitch,i), wrap(pos,i), wrap(dur,i), wrap(dev,i), wrap(pan,i), chnls) for i in range(lmax)]
+        self._base_objs = []
+        for i in range(lmax):
+            for j in range(chnls):
+                self._base_objs.append(Particle_base(wrap(self._base_players,i), j, wrap(mul,i), wrap(add,i)))
+
+    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_players)]
+
+    def setEnv(self, x):
+        """
+        Replace the `env` attribute.
+        
+        :Args:
+
+            x : PyoTableObject
+                new `env` attribute.
+        
+        """
+        self._env = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setEnv(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setDens(self, x):
+        """
+        Replace the `dens` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                new `dens` attribute.
+        
+        """
+        self._dens = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setDens(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setPitch(self, x):
+        """
+        Replace the `pitch` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                new `pitch` attribute.
+        
+        """
+        self._pitch = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setPitch(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setPos(self, x):
+        """
+        Replace the `pos` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                new `pos` attribute.
+        
+        """
+        self._pos = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setPos(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    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_players)]
+
+    def setDev(self, x):
+        """
+        Replace the `dev` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                new `dev` attribute.
+        
+        """
+        self._dev = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setDev(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setPan(self, x):
+        """
+        Replace the `pan` attribute.
+        
+        :Args:
+
+            x : float or PyoObject
+                new `pan` attribute.
+        
+        """
+        self._pan = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setPan(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        tablesize = self._table.getSize(False)
+        self._map_list = [SLMap(1, 250, 'lin', 'dens', self._dens),
+                          SLMap(0.25, 2., 'lin', 'pitch', self._pitch),
+                          SLMap(0, tablesize, 'lin', 'pos', self._pos),
+                          SLMap(0.001, 1., 'lin', 'dur', self._dur),
+                          SLMap(0., 1., 'lin', 'dev', self._dev),
+                          SLMap(0., 1., 'lin', 'pan', self._pan),
+                          SLMapMul(self._mul)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+    @property
+    def table(self):
+        """PyoTableObject. Table containing the waveform samples."""
+        return self._table
+    @table.setter
+    def table(self, x): self.setTable(x)
+
+    @property
+    def env(self):
+        """PyoTableObject. Table containing the grain envelope."""
+        return self._env
+    @env.setter
+    def env(self, x): self.setEnv(x)
+
+    @property
+    def dens(self):
+        """float or PyoObject. Density of grains per second."""
+        return self._dens
+    @dens.setter
+    def dens(self, x): self.setDens(x)
+
+    @property
+    def pitch(self):
+        """float or PyoObject. Transposition factor of the grain."""
+        return self._pitch
+    @pitch.setter
+    def pitch(self, x): self.setPitch(x)
+
+    @property
+    def pos(self):
+        """float or PyoObject. Position of the pointer in the sound table."""
+        return self._pos
+    @pos.setter
+    def pos(self, x): self.setPos(x)
+
+    @property
+    def dur(self):
+        """float or PyoObject. Duration, in seconds, of the grain."""
+        return self._dur
+    @dur.setter
+    def dur(self, x): self.setDur(x)
+
+    @property
+    def dev(self):
+        """float or PyoObject. Deviation of the starting point of the grain in the table."""
+        return self._dev
+    @dev.setter
+    def dev(self, x): self.setDev(x)
+
+    @property
+    def pan(self):
+        """float or PyoObject.Panning of the grain."""
+        return self._pan
+    @pan.setter
+    def pan(self, x): self.setPan(x)
diff --git a/pyolib/tables.py b/pyolib/tables.py
index f3a4a3f..7119054 100644
--- a/pyolib/tables.py
+++ b/pyolib/tables.py
@@ -22,6 +22,7 @@ from _maps import *
 from _widgets import createGraphWindow, createDataGraphWindow, createSndViewTableWindow
 from types import ListType
 from math import pi
+import copy
 
 ######################################################################
 ### Tables
@@ -52,8 +53,8 @@ class HarmTable(PyoTableObject):
     """
     def __init__(self, list=[1., 0.], size=8192):
         PyoTableObject.__init__(self, size)
-        self._list = list
-        self._base_objs = [HarmTable_base(list, size)]
+        self._list = copy.deepcopy(list)
+        self._base_objs = [HarmTable_base(self._list, size)]
     
     def replace(self, list):
         """
@@ -217,8 +218,8 @@ class ChebyTable(PyoTableObject):
     """
     def __init__(self, list=[1., 0.], size=8192):
         PyoTableObject.__init__(self, size)
-        self._list = list
-        self._base_objs = [ChebyTable_base(list, size)]
+        self._list = copy.deepcopy(list)
+        self._base_objs = [ChebyTable_base(self._list, size)]
     
     def replace(self, list):
         """
@@ -466,7 +467,7 @@ class LinTable(PyoTableObject):
             print "                   Increased size to last point position + 1"
             size = list[-1][0] + 1
             self._size = size
-        self._base_objs = [LinTable_base(list, size)]
+        self._base_objs = [LinTable_base(copy.deepcopy(list), size)]
     
     def replace(self, list):
         """
@@ -596,7 +597,7 @@ class LogTable(PyoTableObject):
             print "                   Increased size to last point position + 1"
             size = list[-1][0] + 1
             self._size = size
-        self._base_objs = [LogTable_base(list, size)]
+        self._base_objs = [LogTable_base(copy.deepcopy(list), size)]
 
     def replace(self, list):
         """
@@ -726,7 +727,7 @@ class CosLogTable(PyoTableObject):
             print "                   Increased size to last point position + 1"
             size = list[-1][0] + 1
             self._size = size
-        self._base_objs = [CosLogTable_base(list, size)]
+        self._base_objs = [CosLogTable_base(copy.deepcopy(list), size)]
 
     def replace(self, list):
         """
@@ -855,7 +856,7 @@ class CosTable(PyoTableObject):
             print "                   Increased size to last point position + 1"
             size = list[-1][0] + 1
             self._size = size
-        self._base_objs = [CosTable_base(list, size)]
+        self._base_objs = [CosTable_base(copy.deepcopy(list), size)]
     
     def replace(self, list):
         """
@@ -1002,7 +1003,7 @@ class CurveTable(PyoTableObject):
             self._size = size
         self._tension = tension
         self._bias = bias
-        self._base_objs = [CurveTable_base(list, tension, bias, size)]
+        self._base_objs = [CurveTable_base(copy.deepcopy(list), tension, bias, size)]
 
     def setTension(self, x):
         """
@@ -1185,7 +1186,7 @@ class ExpTable(PyoTableObject):
             self._size = size
         self._exp = exp
         self._inverse = inverse
-        self._base_objs = [ExpTable_base(list, exp, inverse, size)]
+        self._base_objs = [ExpTable_base(copy.deepcopy(list), exp, inverse, size)]
 
     def setExp(self, x):
         """
@@ -1588,6 +1589,33 @@ class SndTable(PyoTableObject):
             else:
                 return _size
 
+    def getViewTable(self, size, begin=0, end=0):
+        """
+        Return a list of points (in X, Y pixel values) for each channel in the table.
+        These lists can be draw on a DC (WxPython) with a DrawLines method.
+
+        :Args:
+            
+            size : tuple
+                Size, (X, Y) pixel values, of the waveform container window.
+            begin : float, optional
+                First position in the the table, in seconds, where to get samples.
+                Defaults to 0.
+            end : float, optional
+                Last position in the table, in seconds, where to get samples. 
+                
+                if this value is set to 0, that means the end of the table. Defaults to 0.
+                 
+        """
+        w, h = size
+        chnls = len(self._base_objs)
+        img = []
+        imgHeight = h/chnls
+        for i in range(chnls):
+            off = h/chnls*i
+            img.append(self._base_objs[i].getViewTable((w, imgHeight), begin, end, off))
+        return img
+
     def getEnvelope(self, points):
         """
         Return the amplitude envelope of the table.
@@ -1759,10 +1787,13 @@ class NewTable(PyoTableObject):
         """
         return self._base_objs[0].getLength()
 
-    def getDur(self):
+    def getDur(self, all=True):
         """
         Returns the length of the table in seconds.
         
+        The `all` argument is there for compatibility with SndTable but
+        is not used for now.
+        
         """
         return self._base_objs[0].getLength()
         
@@ -1774,6 +1805,33 @@ class NewTable(PyoTableObject):
         """
         return self._base_objs[0].getRate()
 
+    def getViewTable(self, size, begin=0, end=0):
+        """
+        Return a list of points (in X, Y pixel values) for each channel in the table.
+        These lists can be draw on a DC (WxPython) with a DrawLines method.
+
+        :Args:
+            
+            size : tuple
+                Size, (X, Y) pixel values, of the waveform container window.
+            begin : float, optional
+                First position in the the table, in seconds, where to get samples.
+                Defaults to 0.
+            end : float, optional
+                Last position in the table, in seconds, where to get samples. 
+                
+                if this value is set to 0, that means the end of the table. Defaults to 0.
+
+        """
+        w, h = size
+        chnls = len(self._base_objs)
+        img = []
+        imgHeight = h/chnls
+        for i in range(chnls):
+            off = h/chnls*i
+            img.append(self._base_objs[i].getViewTable((w, imgHeight), begin, end, off))
+        return img
+
     def view(self, title="Sound waveform", wxnoserver=False, mouse_callback=None):
         """
         Opens a window showing the contents of the table.
diff --git a/pyolib/triggers.py b/pyolib/triggers.py
index dac00f0..a3a88f4 100644
--- a/pyolib/triggers.py
+++ b/pyolib/triggers.py
@@ -408,11 +408,11 @@ class Beat(PyoObject):
 
         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['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.
@@ -496,6 +496,13 @@ class Beat(PyoObject):
         else:
             return [obj._getStream().getValue() for obj in self.__getitem__(identifier).getBaseObjects()]
 
+    def reset(self):
+        """
+        Reset internal counters to initialization values.
+        
+        """
+        [obj.reset() for obj in self._base_players]
+
     def new(self):
         """
         Generates a new pattern with the current parameters.
@@ -676,7 +683,11 @@ class Beat(PyoObject):
         pass
 
     def ctrl(self, map_list=None, title=None, wxnoserver=False):
-        self._map_list = [SLMap(0.001, 1., 'lin', 'time', self._time)]
+        self._map_list = [SLMap(0.001, 1., 'lin', 'time', self._time),
+                          SLMap(2, 64, 'lin', 'taps', self._taps, res="int", dataOnly=True),
+                          SLMap(0, 100, 'lin', 'w1', self._w1, res="int", dataOnly=True),
+                          SLMap(0, 100, 'lin', 'w2', self._w2, res="int", dataOnly=True),
+                          SLMap(0, 100, 'lin', 'w3', self._w3, res="int", dataOnly=True)]
         PyoObject.ctrl(self, map_list, title, wxnoserver)
 
     @property
@@ -2261,6 +2272,14 @@ class Counter(PyoObject):
         value, lmax = convertArgsToLists(value)
         [obj.reset(wrap(value,i)) for i, obj in enumerate(self._base_objs)]
 
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0, 100, 'lin', 'min', self._min, res="int", dataOnly=True),
+                          SLMap(0, 1000, 'lin', 'max', self._max, res="int", dataOnly=True),
+                          SLMap(0, 2, 'lin', 'dir', self._dir, res="int", dataOnly=True),
+                          SLMap(0, 1000, 'lin', 'mul', self._mul),
+                          SLMap(0, 1000, 'lin', 'add', self._add)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def input(self): 
         """PyoObject. Audio trigger signal."""
@@ -2367,6 +2386,10 @@ class Select(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setValue(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0, 100, 'lin', 'value', self._value, res="int", dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def input(self): 
         """PyoObject. Audio signal."""
@@ -2923,6 +2946,12 @@ class Count(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setMax(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
+    def ctrl(self, map_list=None, title=None, wxnoserver=False):
+        self._map_list = [SLMap(0, 10000, 'lin', 'min', self._min, res="int", dataOnly=True),
+                          SLMap(10000, 1000000, 'lin', 'max', self._max, res="int", dataOnly=True),
+                          SLMapMul(self._mul)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
     @property
     def input(self): 
         """PyoObject. Trigger signal. Start/Restart the count."""
@@ -3122,3 +3151,526 @@ class TrigVal(PyoObject):
     @value.setter
     def value(self, x): 
         self.setValue(x)
+
+class Euclide(PyoObject):
+    """
+    Euclidean rhythm generator.
+    
+    This object generates euclidean trigger patterns, resulting in onsets 
+    in the rhythm to be as equidistant as possible.
+    
+    A trigger is an audio signal with a value of 1 surrounded by 0s.
+    
+    The play() method starts the Euclide and is not called at the object 
+    creation time.
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+
+        time : float or PyoObject, optional
+            Time, in seconds, between each beat of the pattern. Defaults to 0.125.
+        taps : int, optional
+            Number of beats in the generated pattern (measure length), max = 64. 
+            Defaults to 16.
+        onsets : int, optional
+            Number of onsets (a positive tap) in the generated pattern. 
+            Defaults to 10.
+        poly : int, optional
+            Beat polyphony. Denotes how many independent streams are 
+            generated by the object, allowing overlapping processes.
+            
+            Available only at initialization. Defaults to 1.
+
+    .. note::
+
+        Euclide outputs many signals identified with a string between brackets:
+
+        |  obj['tap'] returns audio stream of the current tap of the measure.  
+        |  obj['amp'] returns audio stream of the current beat amplitude.  
+        |  obj['dur'] returns audio stream of the current beat duration in seconds.  
+        |  obj['end'] returns audio stream with a trigger just before the end of the measure.
+        
+        obj without brackets returns the generated trigger stream of the measure.
+         
+        The out() method is bypassed. Euclide's signal can not be sent to audio outs.
+
+        Euclide has no `mul` and `add` attributes.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> t = CosTable([(0,0), (100,1), (500,.3), (8191,0)])
+    >>> beat = Euclide(time=.125, taps=16, onsets=[8,7], poly=1).play()
+    >>> trmid = TrigXnoiseMidi(beat, dist=12, mrange=(60, 96))
+    >>> trhz = Snap(trmid, choice=[0,2,3,5,7,8,10], scale=1)
+    >>> tr2 = TrigEnv(beat, table=t, dur=beat['dur'], mul=beat['amp'])
+    >>> a = Sine(freq=trhz, mul=tr2*0.3).out()
+
+    """
+    def __init__(self, time=.125, taps=16, onsets=10, poly=1):
+        PyoObject.__init__(self)
+        self._tap_dummy = []
+        self._amp_dummy = []
+        self._dur_dummy = []
+        self._end_dummy = []
+        self._time = time
+        self._taps = taps
+        self._onsets = onsets
+        self._poly = poly
+        time, taps, onsets, lmax = convertArgsToLists(time, taps, onsets)
+        self._base_players = [Beater_base(wrap(time,i), wrap(taps,i), wrap([100]*lmax,i), poly) for i in range(lmax)]
+        self._base_objs = [Beat_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        self._tap_objs = [BeatTapStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        self._amp_objs = [BeatAmpStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        self._dur_objs = [BeatDurStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        self._end_objs = [BeatEndStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        for i in range(lmax):
+            preset = [wrap(taps,i)] + self.__generate__(wrap(onsets,i), wrap(taps,i))
+            self._base_players[i].setPresets([preset])
+            self._base_players[i].recall(0)
+
+    def __generate__(self, m, k):
+        """
+        Generates the euclidean rhythm for `m` onsets 
+        in a measure of length `k` (number of taps). 
+        Looping implementation, faster than recursive.
+        """
+        if m > k: m = k
+        k -= m
+        mv, kv = [1], [0]
+        while k > 1:
+            if m > k:
+                m, k = k, m-k
+                mv, kv = mv+kv, mv  
+            else:
+                m, k = m, k-m
+                mv, kv = mv+kv, kv
+        return mv * m + kv * k
+
+    def __getitem__(self, i):
+        if i == 'tap':
+            self._tap_dummy.append(Dummy([obj for obj in self._tap_objs]))
+            return self._tap_dummy[-1]
+        if i == 'amp':
+            self._amp_dummy.append(Dummy([obj for obj in self._amp_objs]))
+            return self._amp_dummy[-1]
+        if i == 'dur':
+            self._dur_dummy.append(Dummy([obj for obj in self._dur_objs]))
+            return self._dur_dummy[-1]
+        if i == 'end':
+            self._end_dummy.append(Dummy([obj for obj in self._end_objs]))
+            return self._end_dummy[-1]
+        if type(i) == 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 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, onsets, lmax = convertArgsToLists(x, self._onsets)
+        for i in range(len(self._base_players)):
+            preset = [wrap(x,i)] + self.__generate__(wrap(onsets,i), wrap(x,i))
+            self._base_players[i].setPresets([preset])
+            self._base_players[i].recall(0)
+
+    def setOnsets(self, x):
+        """
+        Replace the `onsets` attribute.
+
+        :Args:
+
+            x : int
+                New `onsets` attribute.
+
+        """
+        self._onsets = x
+        x, taps, lmax = convertArgsToLists(x, self._taps)
+        for i in range(len(self._base_players)):
+            preset = [wrap(taps,i)] + self.__generate__(wrap(x,i), wrap(taps,i))
+            self._base_players[i].setPresets([preset])
+            self._base_players[i].recall(0)
+
+    def reset(self):
+        """
+        Reset internal counters to initialization values.
+        
+        """
+        [obj.reset() for obj in self._base_players]
+
+    def play(self, dur=0, delay=0):
+        dur, delay, lmax = convertArgsToLists(dur, delay)
+        self._tap_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._tap_objs)]
+        self._amp_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._amp_objs)]
+        self._dur_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._dur_objs)]
+        self._end_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._end_objs)]
+        return PyoObject.play(self, dur, delay)
+
+    def stop(self):
+        [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.01, 1., 'lin', 'time', self._time),
+                          SLMap(2, 64, 'lin', 'taps', self._taps, res="int", dataOnly=True),
+                          SLMap(0, 64, 'lin', 'onsets', self._onsets, res="int", dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+    @property
+    def time(self):
+        """float or PyoObject. Time, in seconds, between each beat.""" 
+        return self._time
+    @time.setter
+    def time(self, x): self.setTime(x)
+
+    @property
+    def taps(self):
+        """int. Number of beats in the generated pattern.""" 
+        return self._taps
+    @taps.setter
+    def taps(self, x): self.setTaps(x)
+
+    @property
+    def onsets(self):
+        """int. Number of onsets in the generated pattern.""" 
+        return self._onsets
+    @onsets.setter
+    def onsets(self, x): self.setOnsets(x)
+
+class TrigBurst(PyoObject):
+    """
+    Generates a time/amplitude expandable trigger pattern.
+    
+    A trigger is an audio signal with a value of 1 surrounded by 0s.
+    
+    When TrigBurst receives a trigger in its `input` argument, it starts
+    to output `count` triggers with a variable delay between each trigger
+    of the pattern. If `expand` is less than 1.0, the delay becomes shorter, 
+    if it is greater than 1.0, the delay becomes longer. 
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+
+        input : PyoObject
+            Input signal sending triggers.
+        time : float or PyoObject, optional
+            Base time, in seconds, between each trig of the serie. Defaults to 0.25.
+        count : int, optional
+            Number of trigs generated (length of the serie). Defaults to 10.
+        expand : float, optional
+            Timing power serie factor. Each delay before the next trig is the
+            current delay (starting with `time`) times `expand` factor. Defaults to 1.0.
+        ampfade : float, optional
+            Amplitude power serie factor. Each amplitude in the serie is the
+            current amplitude (starting at 1) times `ampfade` factor. Defaults to 1.0.
+        poly : int, optional
+            Voice polyphony. Denotes how many independent streams are 
+            generated by the object, allowing overlapping processes.
+            
+            Available only at initialization. Defaults to 1.
+
+    .. note::
+
+        TrigBurst outputs many signals identified with a string between brackets:
+        
+        |  obj['tap'] returns audio stream of the current tap of the serie.  
+        |  obj['amp'] returns audio stream of the current beat amplitude.  
+        |  obj['dur'] returns audio stream of the current beat duration in seconds.  
+        |  obj['end'] returns audio stream with a trigger just before the end of the serie.
+
+        obj without brackets returns the generated trigger stream of the serie.
+         
+        The out() method is bypassed. TrigBurst's signal can not be sent to audio outs.
+
+        TrigBurst has no `mul` and `add` attributes.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> env = CosTable([(0,0), (100,0.5), (500, 0.3), (4096,0.3), (8192,0)])
+    >>> m = Metro(2).play()
+    >>> tb = TrigBurst(m, time=0.15, count=[15,20], expand=[0.92,0.9], ampfade=0.85)
+    >>> amp = TrigEnv(tb, env, dur=tb["dur"], mul=tb["amp"]*0.3)
+    >>> a = Sine([800,600], mul=amp)
+    >>> rev = STRev(a, inpos=[0,1], revtime=1.5, cutoff=5000, bal=0.1).out()
+
+    """
+    def __init__(self, input, time=.25, count=10, expand=1.0, ampfade=1.0, poly=1):
+        PyoObject.__init__(self)
+        self._tap_dummy = []
+        self._amp_dummy = []
+        self._dur_dummy = []
+        self._end_dummy = []
+        self._input = input
+        self._time = time
+        self._count = count
+        self._expand = expand
+        self._ampfade = ampfade
+        self._poly = poly
+        self._in_fader = InputFader(input)
+        in_fader, time, count, expand, ampfade, lmax = convertArgsToLists(self._in_fader, time, count, expand, ampfade)
+        self._base_players = [TrigBurster_base(wrap(in_fader,i), wrap(time,i), wrap(count,i), wrap(expand,i), wrap(ampfade,i), poly) for i in range(lmax)]
+        self._base_objs = [TrigBurst_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        self._tap_objs = [TrigBurstTapStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        self._amp_objs = [TrigBurstAmpStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        self._dur_objs = [TrigBurstDurStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+        self._end_objs = [TrigBurstEndStream_base(wrap(self._base_players,j), i) for i in range(poly) for j in range(lmax)]
+
+    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 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 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 setCount(self, x):
+        """
+        Replace the `count` attribute.
+
+        :Args:
+
+            x : int
+                New `count` attribute.
+
+        """
+        self._count = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setCount(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setExpand(self, x):
+        """
+        Replace the `expand` attribute.
+
+        :Args:
+
+            x : int
+                New `expand` attribute.
+
+        """
+        self._expand = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setExpand(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def setAmpfade(self, x):
+        """
+        Replace the `ampfade` attribute.
+
+        :Args:
+
+            x : int
+                New `ampfade` attribute.
+
+        """
+        self._ampfade = x
+        x, lmax = convertArgsToLists(x)
+        [obj.setAmpfade(wrap(x,i)) for i, obj in enumerate(self._base_players)]
+
+    def play(self, dur=0, delay=0):
+        dur, delay, lmax = convertArgsToLists(dur, delay)
+        self._tap_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._tap_objs)]
+        self._amp_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._amp_objs)]
+        self._dur_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._dur_objs)]
+        self._end_objs = [obj.play(wrap(dur,i), wrap(delay,i)) for i, obj in enumerate(self._end_objs)]
+        return PyoObject.play(self, dur, delay)
+
+    def stop(self):
+        [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.1, 1., 'lin', 'time', self._time, dataOnly=True),
+                          SLMap(2, 128, 'lin', 'count', self._count, res="int", dataOnly=True),
+                          SLMap(0.5, 2.0, 'lin', 'expand', self._expand, dataOnly=True),
+                          SLMap(0.5, 1.0, 'lin', 'ampfade', self._ampfade, dataOnly=True)]
+        PyoObject.ctrl(self, map_list, title, wxnoserver)
+
+    @property
+    def input(self): 
+        """PyoObject. Audio trigger signal."""
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+    @property
+    def time(self):
+        """float or PyoObject. Base time, in seconds, between each trig.""" 
+        return self._time
+    @time.setter
+    def time(self, x): self.setTime(x)
+
+    @property
+    def count(self):
+        """int. Number of triggers in the generated serie.""" 
+        return self._count
+    @count.setter
+    def count(self, x): self.setCount(x)
+
+    @property
+    def expand(self):
+        """float. Time's power expansion factor.""" 
+        return self._expand
+    @expand.setter
+    def expand(self, x): self.setExpand(x)
+
+    @property
+    def ampfade(self):
+        """float. Amplitude's power expansion factor.""" 
+        return self._ampfade
+    @ampfade.setter
+    def ampfade(self, x): self.setAmpfade(x)
diff --git a/pyolib/utils.py b/pyolib/utils.py
index f1de462..fb2cd06 100644
--- a/pyolib/utils.py
+++ b/pyolib/utils.py
@@ -430,7 +430,7 @@ class SampHold(PyoObject):
 
     SampHold performs a sample-and-hold operation on its input according 
     to the value of `controlsig`. If `controlsig` equals `value`, the input 
-    is sampled and holded until next sampling.
+    is sampled and held until next sampling.
 
     :Parent: :py:class:`PyoObject`
 
@@ -441,7 +441,7 @@ class SampHold(PyoObject):
         controlsig : PyoObject
             Controls when to sample the signal.
         value : float or PyoObject, optional
-            Sampling targeted value. Default to 0.0.
+            Sampling target value. Default to 0.0.
 
     >>> s = Server().boot()
     >>> s.start()
@@ -521,7 +521,7 @@ class SampHold(PyoObject):
 
     @property
     def value(self):
-        """float or PyoObject. Targeted value.""" 
+        """float or PyoObject. Target value.""" 
         return self._value
     @value.setter
     def value(self, x): self.setValue(x)
@@ -1553,6 +1553,61 @@ class MToF(PyoObject):
     @input.setter
     def input(self, x): self.setInput(x)
 
+class FToM(PyoObject):
+    """
+    Returns the midi note equivalent to a frequency in Hz.
+
+    Returns the midi note equivalent to a frequency in Hz, 
+    440.0 (hz) = 69.
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+
+        input : PyoObject
+            Input signal as frequency in Hz.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> lfo = Sine([0.2,0.25], mul=300, add=600)
+    >>> src = SineLoop(freq=lfo, feedback=0.05)
+    >>> hz = Yin(src, minfreq=100, maxfreq=1000, cutoff=500)
+    >>> mid = FToM(hz)
+    >>> fr = Snap(mid, choice=[0,2,5,7,9], scale=1)
+    >>> freq = Port(fr, risetime=0.01, falltime=0.01)
+    >>> syn = SineLoop(freq, feedback=0.05, mul=0.3).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 = [FToM_base(wrap(in_fader,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)
+
+    @property
+    def input(self):
+        """PyoObject. Input signal to process.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
 class MToT(PyoObject):
     """
     Returns the transposition factor equivalent to a midi note.
@@ -1736,3 +1791,105 @@ class Between(PyoObject):
         return self._max
     @max.setter
     def max(self, x): self.setMax(x)
+
+class TrackHold(PyoObject):
+    """
+    Performs a track-and-hold operation on its input. 
+
+    TrackHold lets pass the signal in `input` without modification but hold
+    a sample according to the value of `controlsig`. If `controlsig` equals 
+    `value`, the input is sampled and held, otherwise, it passes thru.
+
+    :Parent: :py:class:`PyoObject`
+
+    :Args:
+
+        input : PyoObject
+            Input signal.
+        controlsig : PyoObject
+            Controls when to sample the signal.
+        value : float or PyoObject, optional
+            Sampling target value. Default to 0.0.
+
+    >>> s = Server().boot()
+    >>> s.start()
+    >>> ph = Phasor([3,4])
+    >>> lf = Sine(.2, mul=.5, add=.5)
+    >>> th = TrackHold(lf, ph > 0.5, 1, mul=500, add=300)
+    >>> a = Sine(th, mul=.3).out()
+
+    """
+    def __init__(self, input, controlsig, value=0.0, mul=1, add=0):
+        PyoObject.__init__(self, mul, add)
+        self._input = input
+        self._controlsig = controlsig
+        self._value = value
+        self._in_fader = InputFader(input)
+        self._in_fader2 = InputFader(controlsig)
+        in_fader, in_fader2, value, mul, add, lmax = convertArgsToLists(self._in_fader, self._in_fader2, value, mul, add)
+        self._base_objs = [TrackHold_base(wrap(in_fader,i), wrap(in_fader2,i), wrap(value,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 setControlsig(self, x, fadetime=0.05):
+        """
+        Replace the `controlsig` attribute.
+        
+        :Args:
+
+            x : PyoObject
+                New control signal.
+            fadetime : float, optional
+                Crossfade time between old and new input. Default to 0.05.
+
+        """
+        self._controlsig = x
+        self._in_fader2.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)]
+
+    @property
+    def input(self):
+        """PyoObject. Input signal.""" 
+        return self._input
+    @input.setter
+    def input(self, x): self.setInput(x)
+
+    @property
+    def controlsig(self):
+        """PyoObject. Control signal.""" 
+        return self._controlsig
+    @controlsig.setter
+    def controlsig(self, x): self.setControlsig(x)
+
+    @property
+    def value(self):
+        """float or PyoObject. Target value.""" 
+        return self._value
+    @value.setter
+    def value(self, x): self.setValue(x)
diff --git a/scripts/radiopyo-template.py b/scripts/radiopyo-template.py
new file mode 100644
index 0000000..bb07eec
--- /dev/null
+++ b/scripts/radiopyo-template.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# encoding: utf-8
+"""
+Template for a RadioPyo song (version 1.0).
+
+A RadioPyo song is a musical python script using the python-pyo 
+module to create the audio processing chain. You can connect to
+the radio here : http://radiopyo.acaia.ca/ 
+
+There is only a few rules:
+    1 - It must be a one-page script.
+    2 - No soundfile, only synthesis.
+    3 - The script must be finite in time, with fade-in and fade-out 
+        to avoid clicks between pieces. Use the DURATION variable.
+
+belangeo - 2014
+
+"""
+from pyo import *
+
+################### USER-DEFINED VARIABLES ###################
+### READY is used to manage the server behaviour depending ###
+### of the context. Set this variable to True when the     ###
+### music is ready for the radio. TITLE and ARTIST are the ###
+### infos shown by the radio player. DURATION set the      ###
+### duration of the audio file generated for the streaming.###
+##############################################################
+READY = False           # Set to True when ready for the radio
+TITLE = "Song Title"    # The title of the music
+ARTIST = "Artist Name"  # Your artist name
+DURATION = 300          # The duration of the music in seconds
+##################### These are optional #####################
+GENRE = "Electronic"    # Kind of your music, if there is any
+DATE = 2014             # Year of creation
+
+####################### SERVER CREATION ######################
+if READY:
+    s = Server(duplex=0, audio="offline").boot()
+    s.recordOptions(dur=DURATION, filename="radiopyo.ogg", fileformat=7)
+else:
+    s = Server(duplex=0).boot()
+
+
+##################### PROCESSING SECTION #####################
+# global volume (should be used to control the overall sound)
+fade = Fader(fadein=0.001, fadeout=10, dur=DURATION).play()
+
+
+###
+### Insert your algorithms here...
+###
+
+
+#################### START THE PROCESSING ###################
+s.start()
+if not READY:
+    s.gui(locals())
diff --git a/scripts/release_doc_src.sh b/scripts/release_doc_src.sh
index 9b8c344..78c8449 100644
--- a/scripts/release_doc_src.sh
+++ b/scripts/release_doc_src.sh
@@ -6,7 +6,7 @@
 # 3. Execute from pyo folder : ./scripts/release_doc_src.sh
 #
 
-version=0.6.8
+version=0.7.4
 replace=XXX
 
 doc_rep=pyo_XXX-doc
diff --git a/scripts/win/windows-build-routine.txt b/scripts/win/windows-7-build-routine.txt
similarity index 96%
copy from scripts/win/windows-build-routine.txt
copy to scripts/win/windows-7-build-routine.txt
index 2cac5e2..f2b08c2 100644
--- a/scripts/win/windows-build-routine.txt
+++ b/scripts/win/windows-7-build-routine.txt
@@ -1,12 +1,12 @@
 === STEP 1 ===
---- Install Python (2.5 -> 2.7)
+--- Install Python (2.6 and 2.7)
 
 === STEP 2 ===
---- Install Slick SVN (Slick-Subversion-1.6.12-win32.msi)
-http://www.sliksvn.com/pub/Slik-Subversion-1.6.12-win32.msi
+--- Install Slick SVN 1.8.10
+http://www.sliksvn.com
 
 === STEP 3 ===
---- Install scons 2.2.0 in the Python site-packages:
+--- Install scons 2.3.2 in the Python site-packages:
 http://www.scons.org/download.php
 
 === STEP 4 ===
diff --git a/setup.py b/setup.py
index 92bcd39..d67d090 100644
--- a/setup.py
+++ b/setup.py
@@ -23,7 +23,7 @@ from distutils.core import setup, Extension
 import os, sys, getopt
 import time
 
-pyo_version = "0.6.8"
+pyo_version = "0.7.4"
 build_osx_with_jack_support = False
 compile_externals = False
 
@@ -68,13 +68,14 @@ files = ['pyomodule.c', 'servermodule.c', 'pvstreammodule.c', 'streammodule.c',
 source_files = [path + f for f in files]
 
 path = 'src/objects/'
-files = ['phasevocmodule.c', 'fftmodule.c', 'oscilmodule.c', 'randommodule.c', 'oscmodule.c','analysismodule.c', 
-        'sfplayermodule.c', 'oscbankmodule.c', 'lfomodule.c', 'tablemodule.c',
+files = ['granulatormodule.c', 'tablemodule.c', 'wgverbmodule.c', 'freeverbmodule.c', 'phasevocmodule.c', 'fftmodule.c', 
+        'oscilmodule.c', 'randommodule.c', 'oscmodule.c','analysismodule.c', 
+        'sfplayermodule.c', 'oscbankmodule.c', 'lfomodule.c', 
          'matrixmodule.c', 'filtremodule.c', 'noisemodule.c', 'distomodule.c',
-        'inputmodule.c', 'fadermodule.c', 'midimodule.c', 'delaymodule.c','recordmodule.c', 'granulatormodule.c', 
+        'inputmodule.c', 'fadermodule.c', 'midimodule.c', 'delaymodule.c','recordmodule.c', 
         'metromodule.c', 'trigmodule.c', 'patternmodule.c', 'bandsplitmodule.c', 'hilbertmodule.c', 'panmodule.c',
-        'selectmodule.c', 'freeverbmodule.c', 'compressmodule.c', 'utilsmodule.c',
-        'convolvemodule.c', 'wgverbmodule.c', 'arithmeticmodule.c', 'sigmodule.c',
+        'selectmodule.c', 'compressmodule.c', 'utilsmodule.c',
+        'convolvemodule.c', 'arithmeticmodule.c', 'sigmodule.c',
         'matrixprocessmodule.c', 'harmonizermodule.c', 'chorusmodule.c']
 
 if compile_externals:
@@ -93,6 +94,8 @@ else:
     tsrt = time.strftime('"%d %b %Y %H:%M:%S"', time.localtime())
     macros.append(('TIMESTAMP', tsrt))
     include_dirs = ['include', '/usr/local/include']
+    if sys.platform == "darwin":
+        include_dirs.append('/opt/local/include')
     library_dirs = []
     libraries = ['portaudio', 'portmidi', 'sndfile', 'lo']
     if build_osx_with_jack_support:
diff --git a/src/engine/inputfadermodule.c b/src/engine/inputfadermodule.c
index 5f6b44e..a8b26f1 100644
--- a/src/engine/inputfadermodule.c
+++ b/src/engine/inputfadermodule.c
@@ -169,11 +169,8 @@ InputFader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE; 
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "server") == 0 ) {
-        PySys_WriteStderr("TypeError: \"input\" argument must be a PyoObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument must be a PyoObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input1);
diff --git a/src/engine/interpolation.c b/src/engine/interpolation.c
index a9ee2b5..00ee8c2 100644
--- a/src/engine/interpolation.c
+++ b/src/engine/interpolation.c
@@ -38,7 +38,7 @@ MYFLT cosine(MYFLT *buf, int index, MYFLT frac, int size) {
     MYFLT x2 = buf[index+1];
     
     frac2 = (1.0 - MYCOS(frac * M_PI)) * 0.5;
-    return (x1 * (1.0 - frac2) + x2 * frac2);
+    return (x1 + (x2 - x1) * frac2);
 }
 
 MYFLT cubic(MYFLT *buf, int index, MYFLT frac, int size) {
diff --git a/src/engine/pyomodule.c b/src/engine/pyomodule.c
index 208eff1..24c05c5 100644
--- a/src/engine/pyomodule.c
+++ b/src/engine/pyomodule.c
@@ -52,6 +52,28 @@ static void portaudio_assert(PaError ecode, const char* cmdName) {
 >>> print c\n\
 1\n\n"
 
+#define portaudio_get_version_info \
+"\nReturns the version number, as an integer, of the current portaudio installation.\n\n\
+>>> v = pa_get_version()\n\
+>>> print v\n\
+1899\n\n"
+
+static PyObject *
+portaudio_get_version() {
+    return PyInt_FromLong(Pa_GetVersion());
+}
+
+#define portaudio_get_version_text_info \
+"\nReturns the textual description of the current portaudio installation.\n\n\
+>>> desc = pa_get_version_text()\n\
+>>> print desc\n\
+PortAudio V19-devel (built Oct 8 2012 16:25:16)\n\n"
+
+static PyObject *
+portaudio_get_version_text() {
+    return PyString_FromString(Pa_GetVersionText());
+}
+
 static PyObject *
 portaudio_count_host_apis(){
     PaError err;
@@ -1296,7 +1318,7 @@ downsamp(PyObject *self, PyObject *args, PyObject *kwds)
 
     for (i=0; i<samples_per_channels; i++) {
         for (j=0; j<snd_chnls; j++) {
-            if (i < snd_size)
+            if (i*down < snd_size)
                 downsamples[j][i] = samples[j][i*down];
             else
                 downsamples[j][i] = 0.0;            
@@ -1745,9 +1767,10 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
         type = 0;
     else if (PyList_Check(data))
         type = 1;
-    else
-        Py_RETURN_NONE;
-
+    else {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
     if (xlog == 0 && ylog == 0) {
         datascl = xmax - xmin;
         curscl = ymax - ymin;
@@ -1832,9 +1855,47 @@ rescale(PyObject *self, PyObject *args, PyObject *kwds)
         }        
     }
     else {
-        Py_RETURN_NONE;
+        Py_INCREF(Py_None);
+        return Py_None;
     }
-    Py_RETURN_NONE;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+#define floatmap_info \
+"\nConverts values from a 0-1 range to an output range.\n\n\
+This function takes data in the range `0` - `1` and returns corresponding values\nin the range `min` - `max`.\n\n\
+:Argss:\n\n    \
+x : float\n        Value to convert, in the range 0 to 1.\n    \
+min : float, optional\n        Minimum value of the output range. Defaults to 0.\n    \
+max : float, optional\n        Maximum value of the output range. Defaults to 1.\n    \
+exp : float, optional\n        Power factor (1 (default) is linear, les than 1 is logarithmic, greter than 1 is exponential).\n\n\
+>>> a = 0.5\n\
+>>> b = floatmap(a, 0, 1, 4)\n\
+>>> print b\n\
+0.0625\n\n"
+
+static PyObject *
+floatmap(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    MYFLT x = 0.0;
+    MYFLT min = 0.0;
+    MYFLT max = 1.0;
+    MYFLT exp = 1.0;
+    
+    static char *kwlist[] = {"x", "min", "max", "exp", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F_FFF, kwlist, &x, &min, &max, &exp))
+        return PyInt_FromLong(-1);
+
+    if (x < 0.0)
+        x = 0.0;
+    else if (x > 1.0)
+        x = 1.0;
+    if (exp != 1.0)
+        x = MYPOW(x, exp);
+
+    return Py_BuildValue("d", x * (max - min) + min);
 }
 
 /****** Conversion utilities ******/
@@ -1860,13 +1921,58 @@ midiToHz(PyObject *self, PyObject *arg) {
     double x = 0.0;
     PyObject *newseq = NULL;
     if (PyNumber_Check(arg))
-        return Py_BuildValue("d", 8.1757989156437 * pow(1.0594630943593, PyFloat_AsDouble(PyNumber_Float(arg))));
+        return Py_BuildValue("d", 440.0 * MYPOW(2.0, (PyFloat_AsDouble(PyNumber_Float(arg)) - 69) / 12.0));
+    else if (PyList_Check(arg)) {
+        count = PyList_Size(arg);
+        newseq = PyList_New(count);
+        for (i=0; i<count; i++) {
+            x = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(arg, i)));
+            PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(440.0 * MYPOW(2.0, (x - 69) / 12.0)));
+        }
+        return newseq;
+    }
+    else if (PyTuple_Check(arg)) {
+        count = PyTuple_Size(arg);
+        newseq = PyTuple_New(count);
+        for (i=0; i<count; i++) {
+            x = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(arg, i)));
+            PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(440.0 * MYPOW(2.0, (x - 69) / 12.0)));
+        }
+        return newseq;
+    }
+    else
+        Py_RETURN_NONE;
+}    
+
+#define hzToMidi_info \
+"\nConverts a frequency in Hertz to a midi note value.\n\n:Args:\n\n    \
+x : float\n        Frequency in Hertz. `x` can be a number, a list or a tuple, otherwise the function returns None.\n\n\
+>>> a = (110.0, 220.0, 440.0, 880.0)\n\
+>>> b = hzToMidi(a)\n\
+>>> print b\n\
+(45.0, 57.0, 69.0, 81.0)\n\
+>>> a = [110.0, 220.0, 440.0, 880.0]\n\
+>>> b = hzToMidi(a)\n\
+>>> print b\n\
+[45.0, 57.0, 69.0, 81.0]\n\
+>>> b = hzToMidi(440.0)\n\
+>>> print b\n\
+69.0\n\n"
+
+static PyObject *
+hzToMidi(PyObject *self, PyObject *arg) {
+    int count = 0;
+    int i = 0;
+    double x = 0.0;
+    PyObject *newseq = NULL;
+    if (PyNumber_Check(arg))
+        return Py_BuildValue("d", 12.0 * MYLOG2(PyFloat_AsDouble(PyNumber_Float(arg)) / 440.0) + 69);
     else if (PyList_Check(arg)) {
         count = PyList_Size(arg);
         newseq = PyList_New(count);
         for (i=0; i<count; i++) {
             x = PyFloat_AsDouble(PyNumber_Float(PyList_GET_ITEM(arg, i)));
-            PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(8.1757989156437 * pow(1.0594630943593, x)));
+            PyList_SET_ITEM(newseq, i, PyFloat_FromDouble(12.0 * MYLOG2(x / 440.0) + 69));
         }
         return newseq;
     }
@@ -1875,7 +1981,7 @@ midiToHz(PyObject *self, PyObject *arg) {
         newseq = PyTuple_New(count);
         for (i=0; i<count; i++) {
             x = PyFloat_AsDouble(PyNumber_Float(PyTuple_GET_ITEM(arg, i)));
-            PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(8.1757989156437 * pow(1.0594630943593, x)));
+            PyTuple_SET_ITEM(newseq, i, PyFloat_FromDouble(12.0 * MYLOG2(x / 440.0) + 69));
         }
         return newseq;
     }
@@ -2077,6 +2183,8 @@ serverBooted(PyObject *self) {
 }
 
 static PyMethodDef pyo_functions[] = {
+{"pa_get_version", (PyCFunction)portaudio_get_version, METH_NOARGS, portaudio_get_version_info},
+{"pa_get_version_text", (PyCFunction)portaudio_get_version_text, METH_NOARGS, portaudio_get_version_text_info},
 {"pa_count_devices", (PyCFunction)portaudio_count_devices, METH_NOARGS, portaudio_count_devices_info},
 {"pa_count_host_apis", (PyCFunction)portaudio_count_host_apis, METH_NOARGS, portaudio_count_host_apis_info},
 {"pa_list_devices", (PyCFunction)portaudio_list_devices, METH_NOARGS, portaudio_list_devices_info},
@@ -2103,8 +2211,10 @@ static PyMethodDef pyo_functions[] = {
 {"reducePoints", (PyCFunction)reducePoints, METH_VARARGS|METH_KEYWORDS, reducePoints_info},
 {"distanceToSegment", (PyCFunction)distanceToSegment, METH_VARARGS|METH_KEYWORDS, distanceToSegment_info},
 {"rescale", (PyCFunction)rescale, METH_VARARGS|METH_KEYWORDS, rescale_info},
+{"floatmap", (PyCFunction)floatmap, METH_VARARGS|METH_KEYWORDS, floatmap_info},
 {"linToCosCurve", (PyCFunction)linToCosCurve, METH_VARARGS|METH_KEYWORDS, linToCosCurve_info},
 {"midiToHz", (PyCFunction)midiToHz, METH_O, midiToHz_info},
+{"hzToMidi", (PyCFunction)hzToMidi, METH_O, hzToMidi_info},
 {"midiToTranspo", (PyCFunction)midiToTranspo, METH_O, midiToTranspo_info},
 {"sampsToSec", (PyCFunction)sampsToSec, METH_O, sampsToSec_info},
 {"secToSamps", (PyCFunction)secToSamps, METH_O, secToSamps_info},
@@ -2275,6 +2385,7 @@ init_pyo64(void)
     module_add_object(m, "CtlScan2_base", &CtlScan2Type);
     module_add_object(m, "MidiNote_base", &MidiNoteType);
     module_add_object(m, "Notein_base", &NoteinType);
+    module_add_object(m, "NoteinTrig_base", &NoteinTrigType);
     module_add_object(m, "Bendin_base", &BendinType);
     module_add_object(m, "Touchin_base", &TouchinType);
     module_add_object(m, "Programin_base", &PrograminType);
@@ -2352,6 +2463,7 @@ init_pyo64(void)
     module_add_object(m, "M_Floor_base", &M_FloorType);
     module_add_object(m, "M_Ceil_base", &M_CeilType);
     module_add_object(m, "M_Round_base", &M_RoundType);
+    module_add_object(m, "M_Tanh_base", &M_TanhType);
     module_add_object(m, "Snap_base", &SnapType);
     module_add_object(m, "Interp_base", &InterpType);
     module_add_object(m, "SampHold_base", &SampHoldType);
@@ -2361,6 +2473,7 @@ init_pyo64(void)
     module_add_object(m, "CentsToTranspo_base", &CentsToTranspoType);
     module_add_object(m, "TranspoToCents_base", &TranspoToCentsType);
     module_add_object(m, "MToF_base", &MToFType);
+    module_add_object(m, "FToM_base", &FToMType);
     module_add_object(m, "MToT_base", &MToTType);
     module_add_object(m, "FFTMain_base", &FFTMainType);
     module_add_object(m, "FFT_base", &FFTType);
@@ -2408,6 +2521,24 @@ init_pyo64(void)
     module_add_object(m, "PVMix_base", &PVMixType);
     module_add_object(m, "Granule_base", &GranuleType);
     module_add_object(m, "TableScale_base", &TableScaleType);
+    module_add_object(m, "TrackHold_base", &TrackHoldType);
+    module_add_object(m, "ComplexRes_base", &ComplexResType);
+    module_add_object(m, "STReverb_base", &STReverbType);
+    module_add_object(m, "STRev_base", &STRevType);
+    module_add_object(m, "Pointer2_base", &Pointer2Type);
+    module_add_object(m, "Centroid_base", &CentroidType);
+    module_add_object(m, "AttackDetector_base", &AttackDetectorType);
+    module_add_object(m, "SmoothDelay_base", &SmoothDelayType);
+    module_add_object(m, "TrigBurster_base", &TrigBursterType);
+    module_add_object(m, "TrigBurst_base", &TrigBurstType);
+    module_add_object(m, "TrigBurstTapStream_base", &TrigBurstTapStreamType);
+    module_add_object(m, "TrigBurstAmpStream_base", &TrigBurstAmpStreamType);
+    module_add_object(m, "TrigBurstDurStream_base", &TrigBurstDurStreamType);
+    module_add_object(m, "TrigBurstEndStream_base", &TrigBurstEndStreamType);
+    module_add_object(m, "Scope_base", &ScopeType);
+    module_add_object(m, "PeakAmp_base", &PeakAmpType);
+    module_add_object(m, "MainParticle_base", &MainParticleType);
+    module_add_object(m, "Particle_base", &ParticleType);
 
     PyModule_AddStringConstant(m, "PYO_VERSION", PYO_VERSION);
 #ifdef COMPILE_EXTERNALS
diff --git a/src/engine/servermodule.c b/src/engine/servermodule.c
index 9148323..373fb3f 100644
--- a/src/engine/servermodule.c
+++ b/src/engine/servermodule.c
@@ -53,11 +53,11 @@ static inline void Server_process_buffers(Server *server);
 static int Server_start_rec_internal(Server *self, char *filename);
 
 /* random objects count and multiplier to assign different seed to each instance. */
-#define num_rnd_objs 27
+#define num_rnd_objs 29
 
-int rnd_objs_count[num_rnd_objs] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+int rnd_objs_count[num_rnd_objs] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 int rnd_objs_mult[num_rnd_objs] = {1993,1997,1999,2003,2011,2017,2027,2029,2039,2053,2063,2069,
-                         2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153, 2161,2179};
+                         2081,2083,2087,2089,2099,2111,2113,2129,2131,2137,2141,2143,2153,2161,2179,2203,2207};
 
 #ifdef USE_COREAUDIO
 static int coreaudio_stop_callback(Server *self);
@@ -127,17 +127,20 @@ Server_debug(Server *self, char * format, ...)
 /* Portmidi get input events */
 static void portmidiGetEvents(Server *self) 
 {
+    int i;
     PmError result;
     PmEvent buffer;
 
-    do {
-        result = Pm_Poll(self->in);
-        if (result) {
-            if (Pm_Read(self->in, &buffer, 1) == pmBufferOverflow) 
-                continue;
-            self->midiEvents[self->midi_count++] = buffer;
-        }    
-    } while (result);
+    for (i=0; i<self->midiin_count; i++) {
+        do {
+            result = Pm_Poll(self->midiin[i]);
+            if (result) {
+                if (Pm_Read(self->midiin[i], &buffer, 1) == pmBufferOverflow) 
+                    continue;
+                self->midiEvents[self->midi_count++] = buffer;
+            }    
+        } while (result);
+    }
 }
 
 /* Portaudio stuff */
@@ -578,19 +581,19 @@ int
 Server_jack_autoconnect (Server *self)
 {
     const char **ports;
-    int i, ret = 0;
+    int i, j, num = 0, ret = 0;
     PyoJackBackendData *be_data = (PyoJackBackendData *) self->audio_be_data;
     
     if (self->jackautoin) {
-        if ((ports = jack_get_ports (be_data->jack_client, NULL, NULL, JackPortIsOutput)) == NULL) {
-            Server_error(self, "Jack: Cannot find any physical capture ports\n");
+        if ((ports = jack_get_ports (be_data->jack_client, "system", NULL, JackPortIsOutput)) == NULL) {
+            Server_error(self, "Jack: Cannot find any physical capture ports called 'system'\n");
             ret = -1;
         }
 
         i=0;
         while(ports[i]!=NULL && be_data->jack_in_ports[i] != NULL){
             if (jack_connect (be_data->jack_client, ports[i], jack_port_name(be_data->jack_in_ports[i]))) {
-                Server_error(self, "Jack: cannot connect input ports\n");
+                Server_error(self, "Jack: cannot connect input ports to 'system'\n");
                 ret = -1;
             }
             i++;
@@ -599,21 +602,62 @@ Server_jack_autoconnect (Server *self)
     }
     
     if (self->jackautoout) {
-        if ((ports = jack_get_ports (be_data->jack_client, NULL, NULL, JackPortIsInput)) == NULL) {
-            Server_error(self, "Jack: Cannot find any physical playback ports\n");
+        if ((ports = jack_get_ports (be_data->jack_client, "system", NULL, JackPortIsInput)) == NULL) {
+            Server_error(self, "Jack: Cannot find any physical playback ports called 'system'\n");
             ret = -1;
         }
         
         i=0;
         while(ports[i]!=NULL && be_data->jack_out_ports[i] != NULL){
             if (jack_connect (be_data->jack_client, jack_port_name (be_data->jack_out_ports[i]), ports[i])) {
-                Server_error(self, "Jack: cannot connect output ports\n");
+                Server_error(self, "Jack: cannot connect output ports to 'system'\n");
                 ret = -1;
             }
             i++;
         }
         free (ports);
     }
+
+    num = PyList_Size(self->jackAutoConnectInputPorts);
+    if (num > 0) {
+        for (j=0; j<num; j++) {
+            if ((ports = jack_get_ports (be_data->jack_client, PyString_AsString(PyList_GetItem(self->jackAutoConnectInputPorts, j)), NULL, JackPortIsOutput)) == NULL) {
+                Server_error(self, "Jack: cannot connect input ports to %s\n", PyString_AsString(PyList_GetItem(self->jackAutoConnectInputPorts, j)));
+            }
+            else {
+                i = 0;
+                while(ports[i] != NULL && be_data->jack_in_ports[i] != NULL){
+                    if (jack_connect (be_data->jack_client, ports[i], jack_port_name (be_data->jack_in_ports[i]))) {
+                        Server_error(self, "Jack: cannot connect input ports\n");
+                        ret = -1;
+                    }
+                    i++;
+                }
+                free (ports);
+            }
+        }
+    }
+
+    num = PyList_Size(self->jackAutoConnectOutputPorts);
+    if (num > 0) {
+        for (j=0; j<num; j++) {
+            if ((ports = jack_get_ports (be_data->jack_client, PyString_AsString(PyList_GetItem(self->jackAutoConnectOutputPorts, j)), NULL, JackPortIsInput)) == NULL) {
+                Server_error(self, "Jack: cannot connect output ports to %s\n", PyString_AsString(PyList_GetItem(self->jackAutoConnectOutputPorts, j)));
+            }
+            else {
+                i = 0;
+                while(ports[i] != NULL && be_data->jack_out_ports[i] != NULL){
+                    if (jack_connect (be_data->jack_client, jack_port_name (be_data->jack_out_ports[i]), ports[i])) {
+                        Server_error(self, "Jack: cannot connect output ports\n");
+                        ret = -1;
+                    }
+                    i++;
+                }
+                free (ports);
+            }
+        }
+    }
+
     return ret;
 }
 
@@ -989,19 +1033,19 @@ Server_coreaudio_init(Server *self)
     
     /* Get output device stream configuration */
     count = sizeof(AudioStreamBasicDescription);
-	err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
+    err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
     if (err != kAudioHardwareNoError)
         Server_debug(self, "Get kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
 
     /*
     outputStreamDescription.mSampleRate = (Float64)self->samplingRate;
     
-	err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyStreamFormat, count, &outputStreamDescription);
+    err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyStreamFormat, count, &outputStreamDescription);
     if (err != kAudioHardwareNoError)
         Server_debug(self, "Set kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
     
     // Print new output stream description
-	err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
+    err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDescription);
     if (err != kAudioHardwareNoError)
         Server_debug(self, "Get kAudioDevicePropertyStreamFormat error %s\n", (char*)&err);
     */
@@ -1014,7 +1058,7 @@ Server_coreaudio_init(Server *self)
     /********* Set input and output callbacks *********/
     /**************************************************/
     if (self->duplex == 1) {
-        err = AudioDeviceAddIOProc(self->input, coreaudio_input_callback, (void *) self);	// setup our device with an IO proc
+        err = AudioDeviceAddIOProc(self->input, coreaudio_input_callback, (void *) self);    // setup our device with an IO proc
         if (err != kAudioHardwareNoError) {
             Server_error(self, "Input AudioDeviceAddIOProc failed %d\n", (int)err);
             return -1;
@@ -1029,7 +1073,7 @@ Server_coreaudio_init(Server *self)
         err = AudioDeviceSetProperty(self->input, &now, 0, true, kAudioDevicePropertyIOProcStreamUsage, propertySize, input_su);
     }
     
-    err = AudioDeviceAddIOProc(self->output, coreaudio_output_callback, (void *) self);	// setup our device with an IO proc
+    err = AudioDeviceAddIOProc(self->output, coreaudio_output_callback, (void *) self);    // setup our device with an IO proc
     if (err != kAudioHardwareNoError) {
         Server_error(self, "Output AudioDeviceAddIOProc failed %d\n", (int)err);
         return -1;
@@ -1219,7 +1263,7 @@ Server_embedded_ni_start(Server *self)
     /* Non-Interleaved */
     for (i=0; i<self->bufferSize; i++) {
         for (j=0; j<=self->nchnls; j++) {
-            /* This could probably be more efficient (ob) */
+            /* TODO: This could probably be more efficient (ob) */
             self->output_buffer[i+(self->bufferSize*(j+1))-self->bufferSize] = out[(i*self->nchnls)+j];
         }
     }
@@ -1465,10 +1509,14 @@ Server_shut_down(Server *self)
     return Py_None;
 }
 
+/* handling of PyObjects */
 static int
 Server_traverse(Server *self, visitproc visit, void *arg)
 {
+    /* GUI and TIME ? */
     Py_VISIT(self->streams);
+    Py_VISIT(self->jackAutoConnectInputPorts);
+    Py_VISIT(self->jackAutoConnectOutputPorts);
     return 0;
 }
 
@@ -1476,6 +1524,8 @@ static int
 Server_clear(Server *self)
 {    
     Py_CLEAR(self->streams);
+    Py_CLEAR(self->jackAutoConnectInputPorts);
+    Py_CLEAR(self->jackAutoConnectOutputPorts);
     return 0;
 }
 
@@ -1511,9 +1561,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     if (strcmp(audioType, "embedded") != 0)
     {
         if (PyServer_get_server() != NULL) {
-            Server_warning((Server *) PyServer_get_server(), "Warning: A Server is already created!\n"
-                "If you put this Server in a new variable, please delete it!\n");
-            return PyServer_get_server();
+            PyErr_SetString(PyExc_RuntimeError, "Warning: Trying to create a new Server object while one is already created!\n");
+            Py_RETURN_NONE;
         }
     }
 
@@ -1524,7 +1573,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         }
     }
     if(serverID == MAX_NBR_SERVER){
-        return PyString_FromString("You are already using the maximum number of server allowed!");
+        PyErr_SetString(PyExc_RuntimeError, "You are already using the maximum number of server allowed!\n");
+        Py_RETURN_NONE;
     }
 
     Server *self;
@@ -1534,6 +1584,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->serverName = (char *) calloc(32, sizeof(char));
     self->jackautoin = 1;
     self->jackautoout = 1;
+    self->jackAutoConnectInputPorts = PyList_New(0);
+    self->jackAutoConnectOutputPorts = PyList_New(0);
     self->samplingRate = 44100.0;
     self->nchnls = 2;
     self->record = 0;
@@ -1543,6 +1595,8 @@ Server_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->output = -1;
     self->input_offset = 0;
     self->output_offset = 0;
+    self->midiin_count = 0;
+    self->midiout_count = 0;
     self->midi_input = -1;
     self->midi_output = -1;
     self->amp = self->resetAmp = 1.;
@@ -1623,7 +1677,7 @@ Server_setInputOffset(Server *self, PyObject *arg)
         Py_INCREF(Py_None);
         return Py_None;
     }
-	if (arg != NULL) {
+    if (arg != NULL) {
         if (PyInt_Check(arg))
             self->input_offset = PyInt_AsLong(arg);
     }
@@ -1639,7 +1693,7 @@ Server_setOutputOffset(Server *self, PyObject *arg)
         Py_INCREF(Py_None);
         return Py_None;
     }
-	if (arg != NULL) {
+    if (arg != NULL) {
         if (PyInt_Check(arg))
             self->output_offset = PyInt_AsLong(arg);
     }
@@ -1650,7 +1704,7 @@ Server_setOutputOffset(Server *self, PyObject *arg)
 static PyObject *
 Server_setInputDevice(Server *self, PyObject *arg)
 {
-	if (arg != NULL) {
+    if (arg != NULL) {
         if (PyInt_Check(arg))
             self->input = PyInt_AsLong(arg);
     }
@@ -1661,7 +1715,7 @@ Server_setInputDevice(Server *self, PyObject *arg)
 static PyObject *
 Server_setInOutDevice(Server *self, PyObject *arg)
 {
-	if (arg != NULL) {
+    if (arg != NULL) {
         if (PyInt_Check(arg))
             self->input = PyInt_AsLong(arg);
             self->output = PyInt_AsLong(arg);
@@ -1673,7 +1727,7 @@ Server_setInOutDevice(Server *self, PyObject *arg)
 static PyObject *
 Server_setOutputDevice(Server *self, PyObject *arg)
 {
-	if (arg != NULL) {
+    if (arg != NULL) {
         if (PyInt_Check(arg))
             self->output = PyInt_AsLong(arg);
     }
@@ -1684,7 +1738,7 @@ Server_setOutputDevice(Server *self, PyObject *arg)
 static PyObject *
 Server_setMidiInputDevice(Server *self, PyObject *arg)
 {
-	if (arg != NULL) {
+    if (arg != NULL) {
         if (PyInt_Check(arg))
             self->midi_input = PyInt_AsLong(arg);
     }
@@ -1695,7 +1749,7 @@ Server_setMidiInputDevice(Server *self, PyObject *arg)
 static PyObject *
 Server_setMidiOutputDevice(Server *self, PyObject *arg)
 {
-	if (arg != NULL) {
+    if (arg != NULL) {
         if (PyInt_Check(arg))
             self->midi_output = PyInt_AsLong(arg);
     }
@@ -1791,6 +1845,42 @@ Server_setJackAuto(Server *self, PyObject *args)
 }
 
 static PyObject *
+Server_setJackAutoConnectInputPorts(Server *self, PyObject *arg)
+{
+    PyObject *tmp;
+
+    if (arg != NULL) {
+        if (PyList_Check(arg)) {
+            tmp = arg;
+            Py_XDECREF(self->jackAutoConnectInputPorts);
+            Py_INCREF(tmp);
+            self->jackAutoConnectInputPorts = tmp;
+        }
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
+Server_setJackAutoConnectOutputPorts(Server *self, PyObject *arg)
+{
+    PyObject *tmp;
+
+    if (arg != NULL) {
+        if (PyList_Check(arg)) {
+            tmp = arg;
+            Py_XDECREF(self->jackAutoConnectOutputPorts);
+            Py_INCREF(tmp);
+            self->jackAutoConnectOutputPorts = tmp;
+        }
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
 Server_setGlobalSeed(Server *self, PyObject *arg)
 {
     unsigned int tmp;
@@ -1949,6 +2039,7 @@ Server_setStartOffset(Server *self, PyObject *arg)
 int
 Server_pm_init(Server *self)
 {
+    int i = 0;
    /* Initializing MIDI */    
     PmError pmerr;
 
@@ -1966,61 +2057,123 @@ Server_pm_init(Server *self)
     }    
 
     if (self->withPortMidi == 1) {
+        self->midiin_count = self->midiout_count = 0;
         int num_devices = Pm_CountDevices();
+        Server_debug(self, "Portmidi number of devices: %d.\n", num_devices);
         if (num_devices > 0) {
-            if (self->midi_input == -1 || self->midi_input >= num_devices)
-                self->midi_input = Pm_GetDefaultInputDeviceID();
-            Server_debug(self, "Midi input device : %d.\n", self->midi_input);
-            const PmDeviceInfo *info = Pm_GetDeviceInfo(self->midi_input);
-            if (info != NULL) {
-                if (info->input) {
-                    pmerr = Pm_OpenInput(&self->in, self->midi_input, NULL, 100, NULL, NULL);
-                    if (pmerr) {
-                        Server_warning(self, 
+            if (self->midi_input < num_devices) {
+                if (self->midi_input == -1)
+                    self->midi_input = Pm_GetDefaultInputDeviceID();
+                Server_debug(self, "Midi input device : %d.\n", self->midi_input);
+                const PmDeviceInfo *info = Pm_GetDeviceInfo(self->midi_input);
+                if (info != NULL) {
+                    if (info->input) {
+                        pmerr = Pm_OpenInput(&self->midiin[0], self->midi_input, NULL, 100, NULL, NULL);
+                        if (pmerr) {
+                            Server_warning(self, 
                                  "Portmidi warning: could not open midi input %d (%s): %s\n",
-                                 0, info->name, Pm_GetErrorText(pmerr));
+                                 self->midi_input, info->name, Pm_GetErrorText(pmerr));
+                            self->withPortMidi = 0;
+                        }    
+                        else {
+                            Server_debug(self, "Midi input (%s) opened.\n", info->name);
+                            self->midiin_count = 1;
+                        }
+                    }
+                    else {
+                        Server_warning(self, "Portmidi warning: Midi Device (%s), not an input device!\n", info->name);
                         self->withPortMidi = 0;
-                    }    
-                    else
-                        Server_debug(self, "Midi input (%s) opened.\n", info->name);
+                    }
                 }
-                else {
-                    Server_warning(self, "Portmidi warning: something wrong with midi input device!\n");
-                    self->withPortMidi = 0;
+            }
+            else if (self->midi_input >= num_devices) {
+                Server_debug(self, "Midi input device : all!\n");
+                self->midiin_count = 0;
+                for (i=0; i<num_devices; i++) {
+                    const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+                    if (info != NULL) {
+                        if (info->input) {
+                            pmerr = Pm_OpenInput(&self->midiin[self->midiin_count], i, NULL, 100, NULL, NULL);
+                            if (pmerr) {
+                                Server_warning(self, 
+                                     "Portmidi warning: could not open midi input %d (%s): %s\n",
+                                     0, info->name, Pm_GetErrorText(pmerr));
+                            }    
+                            else {
+                                Server_debug(self, "Midi input (%s) opened.\n", info->name);
+                                self->midiin_count++;
+                            }
+                        }
+                    }
                 }
+                if (self->midiin_count == 0)
+                    self->withPortMidi = 0;
             }
             else {
                     Server_warning(self, "Portmidi warning: no input device!\n");
                     self->withPortMidi = 0;
             }
             
-            if (self->midi_output == -1 || self->midi_output >= num_devices)
-                self->midi_output = Pm_GetDefaultOutputDeviceID();
-            Server_debug(self, "Midi output device : %d.\n", self->midi_output);
-            const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(self->midi_output);
-            if (outinfo != NULL) {
-                if (outinfo->output) {
-                    Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
-                    pmerr = Pm_OpenOutput(&self->out, self->midi_output, NULL, 0, NULL, NULL, 1);
-                    if (pmerr) {
-                        Server_warning(self, 
-                                 "Portmidi warning: could not open midi output %d (%s): %s\n",
-                                 0, outinfo->name, Pm_GetErrorText(pmerr));
+            if (self->midi_output < num_devices) {
+                if (self->midi_output == -1)
+                    self->midi_output = Pm_GetDefaultOutputDeviceID();
+                Server_debug(self, "Midi output device : %d.\n", self->midi_output);
+                const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(self->midi_output);
+                if (outinfo != NULL) {
+                    if (outinfo->output) {
+                        Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+                        pmerr = Pm_OpenOutput(&self->midiout[0], self->midi_output, NULL, 0, NULL, NULL, 1);
+                        if (pmerr) {
+                            Server_warning(self, 
+                                     "Portmidi warning: could not open midi output %d (%s): %s\n",
+                                     self->midi_output, outinfo->name, Pm_GetErrorText(pmerr));
+                            self->withPortMidiOut = 0;
+                            if (Pt_Started())
+                                Pt_Stop();
+                        }    
+                        else {
+                            Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
+                            self->midiout_count = 1;
+                        }
+                    }
+                    else {
+                        Server_warning(self, "Portmidi warning: Midi Device (%s), not an output device!\n", outinfo->name);
                         self->withPortMidiOut = 0;
-                    }    
-                    else
-                        Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
+                    }
                 }
-                else {
-                    Server_warning(self, "Portmidi warning: something wrong with midi output device!\n");
+            }
+            else if (self->midi_output >= num_devices) {
+                Server_debug(self, "Midi output device : all!\n");
+                self->midiout_count = 0;
+                Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+                for (i=0; i<num_devices; i++) {
+                    const PmDeviceInfo *outinfo = Pm_GetDeviceInfo(i);
+                    if (outinfo != NULL) {
+                        if (outinfo->output) {
+                            pmerr = Pm_OpenOutput(&self->midiout[self->midiout_count], i, NULL, 100, NULL, NULL, 1);
+                            if (pmerr) {
+                                Server_warning(self, 
+                                     "Portmidi warning: could not open midi output %d (%s): %s\n",
+                                     0, outinfo->name, Pm_GetErrorText(pmerr));
+                            }    
+                            else {
+                                Server_debug(self, "Midi output (%s) opened.\n", outinfo->name);
+                                self->midiout_count++;
+                            }
+                        }
+                    }
+                }
+                if (self->midiout_count == 0) {
+                    if (Pt_Started())
+                        Pt_Stop();
                     self->withPortMidiOut = 0;
                 }
             }
             else {
                     Server_warning(self, "Portmidi warning: no output device!\n");
-                    self->withPortMidi = 0;
+                    self->withPortMidiOut = 0;
             }
-            
+
             if (self->withPortMidi == 0 && self->withPortMidiOut == 0) {
                 Pm_Terminate();
                 Server_warning(self, "Portmidi closed.\n");
@@ -2035,7 +2188,9 @@ Server_pm_init(Server *self)
     }
     if (self->withPortMidi == 1) {
         self->midi_count = 0;
-        Pm_SetFilter(self->in, PM_FILT_ACTIVE | PM_FILT_CLOCK);
+        for (i=0; i<self->midiin_count; i++) {
+            Pm_SetFilter(self->midiin[i], PM_FILT_ACTIVE | PM_FILT_CLOCK);
+        }
     } 
     return 0;
 }
@@ -2136,85 +2291,6 @@ Server_boot(Server *self, PyObject *arg)
     return Py_None;
 }
 
-/* Like the Server_boot() but without reinitializing the buffers */
-static PyObject *
-Server_flush(Server *self)
-{
-    int audioerr = 0;
-    int i;
-    if (self->server_booted == 1) {
-        Server_error(self, "Server already booted!\n");
-        Py_INCREF(Py_None);
-        return Py_None;
-    }
-    self->server_started = 0;
-    self->stream_count = 0;
-    self->elapsedSamples = 0;
-
-    self->streams = PyList_New(0);
-    switch (self->audio_be_type) {
-        case PyoPortaudio:
-            audioerr = Server_pa_init(self);
-            break;
-        case PyoJack:
-#ifdef USE_JACK
-            audioerr = Server_jack_init(self);
-            if (audioerr < 0) {
-                Server_jack_deinit(self);
-            }
-#else
-            audioerr = -1;
-            Server_error(self, "Pyo built without Jack support\n");
-#endif
-            break;
-        case PyoCoreaudio:
-#ifdef USE_COREAUDIO
-            audioerr = Server_coreaudio_init(self);
-            if (audioerr < 0) {
-                Server_coreaudio_deinit(self);
-            }
-#else
-            audioerr = -1;
-            Server_error(self, "Pyo built without Coreaudio support\n");
-#endif
-            break;
-        case PyoOffline:
-            audioerr = Server_offline_init(self);
-            if (audioerr < 0) {
-                Server_offline_deinit(self);
-            }
-            break;
-        case PyoOfflineNB:
-            audioerr = Server_offline_init(self);
-            if (audioerr < 0) {
-                Server_offline_deinit(self);
-            }
-            break;
-        case PyoEmbedded:
-            audioerr = Server_embedded_init(self);
-            if (audioerr < 0) {
-                Server_embedded_deinit(self);
-            }
-            break;
-    }
-
-    for (i=0; i<self->bufferSize*self->nchnls; i++) {
-        self->input_buffer[i] = 0.0;
-        self->output_buffer[i] = 0.0;
-    }
-    
-    if (audioerr == 0) {
-        self->server_booted = 1;
-    }
-    else {
-        self->server_booted = 0;
-        Server_error(self, "\nServer not booted.\n");
-    }    
-    
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
 static PyObject *
 Server_start(Server *self)
 {
@@ -2240,7 +2316,7 @@ Server_start(Server *self)
     self->server_started = 1;
     self->timeStep = (int)(0.01 * self->samplingRate);
 
-    if (self->audio_be_type != PyoOffline && self->audio_be_type != PyoOfflineNB) {
+    if (self->audio_be_type != PyoOffline && self->audio_be_type != PyoOfflineNB && self->audio_be_type != PyoEmbedded) {
         midierr = Server_pm_init(self);
         Server_debug(self, "PortMidi initialization return code : %d.\n", midierr);
     }
@@ -2293,6 +2369,7 @@ Server_start(Server *self)
 static PyObject *
 Server_stop(Server *self)
 {
+    int i;
     int err = -1;
     if (self->server_started == 0) {
         Server_warning(self, "The Server must be started!\n");
@@ -2330,12 +2407,18 @@ Server_stop(Server *self)
     else {
         self->server_stopped = 1;
         if (self->withPortMidi == 1) {
-            Pm_Close(self->in);
+            for (i=0; i<self->midiin_count; i++) {
+                Pm_Close(self->midiin[i]);
+            }
         }
         if (self->withPortMidiOut == 1) {
-            Pm_Close(self->out);
+            for (i=0; i<self->midiout_count; i++) {
+                Pm_Close(self->midiout[i]);
+            }
         }
         if (self->withPortMidi == 1 || self->withPortMidiOut == 1) {
+            if (Pt_Started())
+                Pt_Stop();
             Pm_Terminate();
         }
         self->withPortMidi = 0;
@@ -2550,23 +2633,153 @@ Server_changeStreamPosition(Server *self, PyObject *args)
 }
 
 PyObject *
-Server_sendMidiNote(Server *self, PyObject *args)
+Server_noteout(Server *self, PyObject *args)
 {
-    int pit, vel, chan, curtime;
+    int i, pit, vel, chan, curtime;
     PmEvent buffer[1];
     PmTimestamp timestamp;
 
     if (! PyArg_ParseTuple(args, "iiii", &pit, &vel, &chan, &timestamp))
         return PyInt_FromLong(-1); 
 
-    curtime = Pt_Time();
-    buffer[0].timestamp = curtime + timestamp;
-    if (chan == 0)
-        buffer[0].message = Pm_Message(0x90, pit, vel);
-    else
-        buffer[0].message = Pm_Message(0x90 | (chan - 1), pit, vel);
-    Pm_Write(self->out, buffer, 1);
+    if (self->withPortMidiOut) {
+        curtime = Pt_Time();
+        buffer[0].timestamp = curtime + timestamp;
+        if (chan == 0)
+            buffer[0].message = Pm_Message(0x90, pit, vel);
+        else
+            buffer[0].message = Pm_Message(0x90 | (chan - 1), pit, vel);
+        for (i=0; i<self->midiout_count; i++) {
+            Pm_Write(self->midiout[i], buffer, 1);
+        }
+    }
+    Py_INCREF(Py_None);
+    return Py_None;    
+}
 
+PyObject *
+Server_afterout(Server *self, PyObject *args)
+{
+    int i, pit, vel, chan, curtime;
+    PmEvent buffer[1];
+    PmTimestamp timestamp;
+
+    if (! PyArg_ParseTuple(args, "iiii", &pit, &vel, &chan, &timestamp))
+        return PyInt_FromLong(-1); 
+
+    if (self->withPortMidiOut) {
+        curtime = Pt_Time();
+        buffer[0].timestamp = curtime + timestamp;
+        if (chan == 0)
+            buffer[0].message = Pm_Message(0xA0, pit, vel);
+        else
+            buffer[0].message = Pm_Message(0xA0 | (chan - 1), pit, vel);
+        for (i=0; i<self->midiout_count; i++) {
+            Pm_Write(self->midiout[i], buffer, 1);
+        }
+    }
+    Py_INCREF(Py_None);
+    return Py_None;    
+}
+
+PyObject *
+Server_ctlout(Server *self, PyObject *args)
+{
+    int i, ctlnum, value, chan, curtime;
+    PmEvent buffer[1];
+    PmTimestamp timestamp;
+
+    if (! PyArg_ParseTuple(args, "iiii", &ctlnum, &value, &chan, &timestamp))
+        return PyInt_FromLong(-1); 
+
+    if (self->withPortMidiOut) {
+        curtime = Pt_Time();
+        buffer[0].timestamp = curtime + timestamp;
+        if (chan == 0)
+            buffer[0].message = Pm_Message(0xB0, ctlnum, value);
+        else
+            buffer[0].message = Pm_Message(0xB0 | (chan - 1), ctlnum, value);
+        for (i=0; i<self->midiout_count; i++) {
+            Pm_Write(self->midiout[i], buffer, 1);
+        }
+    }
+    Py_INCREF(Py_None);
+    return Py_None;    
+}
+
+PyObject *
+Server_programout(Server *self, PyObject *args)
+{
+    int i, value, chan, curtime;
+    PmEvent buffer[1];
+    PmTimestamp timestamp;
+
+    if (! PyArg_ParseTuple(args, "iii", &value, &chan, &timestamp))
+        return PyInt_FromLong(-1); 
+
+    if (self->withPortMidiOut) {
+        curtime = Pt_Time();
+        buffer[0].timestamp = curtime + timestamp;
+        if (chan == 0)
+            buffer[0].message = Pm_Message(0xC0, value, 0);
+        else
+            buffer[0].message = Pm_Message(0xC0 | (chan - 1), value, 0);
+        for (i=0; i<self->midiout_count; i++) {
+            Pm_Write(self->midiout[i], buffer, 1);
+        }
+    }
+    Py_INCREF(Py_None);
+    return Py_None;    
+}
+
+PyObject *
+Server_pressout(Server *self, PyObject *args)
+{
+    int i, value, chan, curtime;
+    PmEvent buffer[1];
+    PmTimestamp timestamp;
+
+    if (! PyArg_ParseTuple(args, "iii", &value, &chan, &timestamp))
+        return PyInt_FromLong(-1); 
+
+    if (self->withPortMidiOut) {
+        curtime = Pt_Time();
+        buffer[0].timestamp = curtime + timestamp;
+        if (chan == 0)
+            buffer[0].message = Pm_Message(0xD0, value, 0);
+        else
+            buffer[0].message = Pm_Message(0xD0 | (chan - 1), value, 0);
+        for (i=0; i<self->midiout_count; i++) {
+            Pm_Write(self->midiout[i], buffer, 1);
+        }
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyObject *
+Server_bendout(Server *self, PyObject *args)
+{
+    int i, lsb, msb, value, chan, curtime;
+    PmEvent buffer[1];
+    PmTimestamp timestamp;
+
+    if (! PyArg_ParseTuple(args, "iii", &value, &chan, &timestamp))
+        return PyInt_FromLong(-1); 
+
+    if (self->withPortMidiOut) {
+        curtime = Pt_Time();
+        buffer[0].timestamp = curtime + timestamp;
+        lsb = value & 0x007F;
+        msb = (value & (0x007F << 7)) >> 7;
+        if (chan == 0)
+            buffer[0].message = Pm_Message(0xE0, lsb, msb);
+        else
+            buffer[0].message = Pm_Message(0xE0 | (chan - 1), lsb, msb);
+        for (i=0; i<self->midiout_count; i++) {
+            Pm_Write(self->midiout[i], buffer, 1);
+        }
+    }
     Py_INCREF(Py_None);
     return Py_None;    
 }
@@ -2712,6 +2925,8 @@ static PyMethodDef Server_methods[] = {
     {"setNchnls", (PyCFunction)Server_setNchnls, METH_O, "Sets the server's number of channels."},
     {"setDuplex", (PyCFunction)Server_setDuplex, METH_O, "Sets the server's duplex mode (0 = only out, 1 = in/out)."},
     {"setJackAuto", (PyCFunction)Server_setJackAuto, METH_VARARGS, "Tells the server to auto-connect Jack ports (0 = disable, 1 = enable)."},
+    {"setJackAutoConnectInputPorts", (PyCFunction)Server_setJackAutoConnectInputPorts, METH_O, "Sets a list of ports to auto-connect inputs when using Jack."},
+    {"setJackAutoConnectOutputPorts", (PyCFunction)Server_setJackAutoConnectOutputPorts, METH_O, "Sets a list of ports to auto-connect outputs when using Jack."},
     {"setGlobalSeed", (PyCFunction)Server_setGlobalSeed, METH_O, "Sets the server's global seed for random objects."},
     {"setAmp", (PyCFunction)Server_setAmp, METH_O, "Sets the overall amplitude."},
     {"setAmpCallable", (PyCFunction)Server_setAmpCallable, METH_O, "Sets the Server's GUI callable object."},
@@ -2731,7 +2946,12 @@ static PyMethodDef Server_methods[] = {
                                                                 This is for internal use and must never be called by the user."},
     {"changeStreamPosition", (PyCFunction)Server_changeStreamPosition, METH_VARARGS, "Puts an audio stream before another in the stack. \
                                                                 This is for internal use and must never be called by the user."},
-    {"sendMidiNote", (PyCFunction)Server_sendMidiNote, METH_VARARGS, "Send a Midi note to Portmidi output stream."},
+    {"noteout", (PyCFunction)Server_noteout, METH_VARARGS, "Send a Midi note event to Portmidi output stream."},
+    {"afterout", (PyCFunction)Server_afterout, METH_VARARGS, "Send an aftertouch event to Portmidi output stream."},
+    {"ctlout", (PyCFunction)Server_ctlout, METH_VARARGS, "Send a control change event to Portmidi output stream."},
+    {"programout", (PyCFunction)Server_programout, METH_VARARGS, "Send a program change event to Portmidi output stream."},
+    {"pressout", (PyCFunction)Server_pressout, METH_VARARGS, "Send a channel pressure event to Portmidi output stream."},
+    {"bendout", (PyCFunction)Server_bendout, METH_VARARGS, "Send a pitch bend event to Portmidi output stream."},
     {"getStreams", (PyCFunction)Server_getStreams, METH_NOARGS, "Returns the list of streams added to the server."},
     {"getSamplingRate", (PyCFunction)Server_getSamplingRate, METH_NOARGS, "Returns the server's sampling rate."},
     {"getNchnls", (PyCFunction)Server_getNchnls, METH_NOARGS, "Returns the server's current number of channels."},
@@ -2742,7 +2962,6 @@ static PyMethodDef Server_methods[] = {
     {"getMidiActive", (PyCFunction)Server_getMidiActive, METH_NOARGS, "Returns 1 if midi callback is active, otherwise returns 0."},
     {"_setDefaultRecPath", (PyCFunction)Server_setDefaultRecPath, METH_VARARGS|METH_KEYWORDS, "Sets the default recording path."},
     {"setServer", (PyCFunction)Server_setServer, METH_NOARGS, "Sets this server as the one to use for new objects when using the embedded device"},
-    {"flush", (PyCFunction)Server_flush, METH_NOARGS, "Flush the server objects"},
     {"getInputAddr", (PyCFunction)Server_getInputAddr, METH_NOARGS, "Get the embedded device input buffer memory address"},
     {"getOutputAddr", (PyCFunction)Server_getOutputAddr, METH_NOARGS, "Get the embedded device output buffer memory address"},
     {"getServerID", (PyCFunction)Server_getServerID, METH_NOARGS, "Get the embedded device server memory address"},
@@ -2781,10 +3000,10 @@ PyTypeObject ServerType = {
     "Pyo Server object. Handles communication with Portaudio and processing callback loop.",           /* tp_doc */
     (traverseproc)Server_traverse,   /* tp_traverse */
     (inquiry)Server_clear,           /* tp_clear */
-    0,		               /* tp_richcompare */
-    0,		               /* tp_weaklistoffset */
-    0,		               /* tp_iter */
-    0,		               /* tp_iternext */
+    0,                       /* tp_richcompare */
+    0,                       /* tp_weaklistoffset */
+    0,                       /* tp_iter */
+    0,                       /* tp_iternext */
     Server_methods,             /* tp_methods */
     Server_members,             /* tp_members */
     0,                      /* tp_getset */
diff --git a/src/objects/analysismodule.c b/src/objects/analysismodule.c
index b4ef933..36509be 100644
--- a/src/objects/analysismodule.c
+++ b/src/objects/analysismodule.c
@@ -25,6 +25,8 @@
 #include "servermodule.h"
 #include "dummymodule.h"
 #include "interpolation.h"
+#include "fft.h"
+#include "wind.h"
 
 /************/
 /* Follower */
@@ -1630,4 +1632,1315 @@ Yin_members,                                 /* tp_members */
 0,                          /* tp_init */
 0,                                              /* tp_alloc */
 Yin_new,                                     /* tp_new */
-};
\ No newline at end of file
+};
+
+/********************/
+/* Centroid */
+/********************/
+
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    int size;
+    int hsize;
+    int incount;
+    MYFLT centroid;
+    MYFLT *inframe;
+    MYFLT *outframe;
+    MYFLT **twiddle;
+    MYFLT *input_buffer;
+    MYFLT *window;
+    int modebuffer[2];
+} Centroid;
+
+static void
+Centroid_alloc_memories(Centroid *self) {
+    int i, n8;
+    self->hsize = self->size / 2;
+    n8 = self->size >> 3;
+    self->inframe = (MYFLT *)realloc(self->inframe, self->size * sizeof(MYFLT));
+    self->outframe = (MYFLT *)realloc(self->outframe, self->size * sizeof(MYFLT));       
+    self->input_buffer = (MYFLT *)realloc(self->input_buffer, self->size * sizeof(MYFLT));    
+    for (i=0; i<self->size; i++)
+        self->inframe[i] = self->outframe[i] = self->input_buffer[i] = 0.0;
+    self->twiddle = (MYFLT **)realloc(self->twiddle, 4 * sizeof(MYFLT *));
+    for(i=0; i<4; i++)
+        self->twiddle[i] = (MYFLT *)malloc(n8 * sizeof(MYFLT));
+    fft_compute_split_twiddle(self->twiddle, self->size);
+    self->window = (MYFLT *)realloc(self->window, self->size * sizeof(MYFLT));
+    gen_window(self->window, self->size, 2);
+}
+
+static void
+Centroid_process_i(Centroid *self) {
+    int i;
+    MYFLT re, im, tmp, sum1, sum2;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+
+    for (i=0; i<self->bufsize; i++) {
+        self->input_buffer[self->incount] = in[i];
+        self->data[i] = self->centroid;
+        
+        self->incount++;
+        if (self->incount == self->size) {
+            self->incount = self->hsize;
+            
+            for (i=0; i<self->size; i++) {
+                self->inframe[i] = self->input_buffer[i] * self->window[i];
+            }
+            realfft_split(self->inframe, self->outframe, self->size, self->twiddle);
+            sum1 = sum2 = 0.0;
+            for (i=1; i<self->hsize; i++) {
+                re = self->outframe[i];
+                im = self->outframe[self->size - i];
+                tmp = MYSQRT(re*re + im*im);
+                sum1 += tmp * i;
+                sum2 += tmp;
+            }
+            tmp = sum1 / sum2;
+            self->centroid += tmp * self->sr / self->size;
+            self->centroid *= 0.5;
+            for (i=0; i<self->hsize; i++) {
+                self->input_buffer[i] = self->input_buffer[i + self->hsize];
+            }            
+        }
+    } 
+}
+
+static void Centroid_postprocessing_ii(Centroid *self) { POST_PROCESSING_II };
+static void Centroid_postprocessing_ai(Centroid *self) { POST_PROCESSING_AI };
+static void Centroid_postprocessing_ia(Centroid *self) { POST_PROCESSING_IA };
+static void Centroid_postprocessing_aa(Centroid *self) { POST_PROCESSING_AA };
+static void Centroid_postprocessing_ireva(Centroid *self) { POST_PROCESSING_IREVA };
+static void Centroid_postprocessing_areva(Centroid *self) { POST_PROCESSING_AREVA };
+static void Centroid_postprocessing_revai(Centroid *self) { POST_PROCESSING_REVAI };
+static void Centroid_postprocessing_revaa(Centroid *self) { POST_PROCESSING_REVAA };
+static void Centroid_postprocessing_revareva(Centroid *self) { POST_PROCESSING_REVAREVA };
+
+static void
+Centroid_setProcMode(Centroid *self)
+{        
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+    self->proc_func_ptr = Centroid_process_i;
+      
+    switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = Centroid_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = Centroid_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = Centroid_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = Centroid_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = Centroid_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = Centroid_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = Centroid_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = Centroid_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = Centroid_postprocessing_revareva;
+            break;
+    }
+}
+
+static void
+Centroid_compute_next_data_frame(Centroid *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+Centroid_traverse(Centroid *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    return 0;
+}
+
+static int 
+Centroid_clear(Centroid *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    return 0;
+}
+
+static void
+Centroid_dealloc(Centroid* self)
+{
+    int i;
+    pyo_DEALLOC
+    free(self->inframe);
+    free(self->outframe);
+    free(self->input_buffer);
+    for(i=0; i<4; i++) {
+        free(self->twiddle[i]);
+    }
+    free(self->twiddle);
+    free(self->window);
+    Centroid_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Centroid_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i, k;
+    PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+    Centroid *self;
+    self = (Centroid *)type->tp_alloc(type, 0);
+    
+    self->centroid = 0;
+    self->size = 1024;
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, Centroid_compute_next_data_frame);
+    self->mode_func_ptr = Centroid_setProcMode;
+
+    static char *kwlist[] = {"input", "size", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|iOO", kwlist, &inputtmp, &self->size, &multmp, &addtmp))
+        Py_RETURN_NONE;
+
+    if (self->size < self->bufsize) {
+        printf("Warning : Centroid size less than buffer size!\nCentroid size set to buffersize: %d\n", self->bufsize);
+        self->size = self->bufsize;
+    }
+    
+    k = 1;
+    while (k < self->size)
+        k <<= 1;
+    self->size = k;
+
+    INIT_INPUT_STREAM
+
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+ 
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    Centroid_alloc_memories(self);
+
+    self->incount = self->hsize;
+
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * Centroid_getServer(Centroid* self) { GET_SERVER };
+static PyObject * Centroid_getStream(Centroid* self) { GET_STREAM };
+static PyObject * Centroid_setMul(Centroid *self, PyObject *arg) { SET_MUL };    
+static PyObject * Centroid_setAdd(Centroid *self, PyObject *arg) { SET_ADD };    
+static PyObject * Centroid_setSub(Centroid *self, PyObject *arg) { SET_SUB };    
+static PyObject * Centroid_setDiv(Centroid *self, PyObject *arg) { SET_DIV };    
+
+static PyObject * Centroid_play(Centroid *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Centroid_stop(Centroid *self) { STOP };
+
+static PyObject * Centroid_multiply(Centroid *self, PyObject *arg) { MULTIPLY };
+static PyObject * Centroid_inplace_multiply(Centroid *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * Centroid_add(Centroid *self, PyObject *arg) { ADD };
+static PyObject * Centroid_inplace_add(Centroid *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * Centroid_sub(Centroid *self, PyObject *arg) { SUB };
+static PyObject * Centroid_inplace_sub(Centroid *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * Centroid_div(Centroid *self, PyObject *arg) { DIV };
+static PyObject * Centroid_inplace_div(Centroid *self, PyObject *arg) { INPLACE_DIV };
+
+
+static PyMemberDef Centroid_members[] = {
+{"server", T_OBJECT_EX, offsetof(Centroid, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Centroid, stream), 0, "Stream object."},
+{"mul", T_OBJECT_EX, offsetof(Centroid, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(Centroid, add), 0, "Add factor."},
+{"input", T_OBJECT_EX, offsetof(Centroid, input), 0, "Input sound object."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef Centroid_methods[] = {
+{"getServer", (PyCFunction)Centroid_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Centroid_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Centroid_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)Centroid_stop, METH_NOARGS, "Stops computing."},
+{"setMul", (PyCFunction)Centroid_setMul, METH_O, "Sets Centroid mul factor."},
+{"setAdd", (PyCFunction)Centroid_setAdd, METH_O, "Sets Centroid add factor."},
+{"setSub", (PyCFunction)Centroid_setSub, METH_O, "Sets Centroid add factor."},
+{"setDiv", (PyCFunction)Centroid_setDiv, METH_O, "Sets Centroid mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods Centroid_as_number = {
+    (binaryfunc)Centroid_add,                      /*nb_add*/
+    (binaryfunc)Centroid_sub,                 /*nb_subtract*/
+    (binaryfunc)Centroid_multiply,                 /*nb_multiply*/
+    (binaryfunc)Centroid_div,                   /*nb_divide*/
+    0,                /*nb_remainder*/
+    0,                   /*nb_divmod*/
+    0,                   /*nb_power*/
+    0,                  /*nb_neg*/
+    0,                /*nb_pos*/
+    0,                  /*(unaryfunc)array_abs,*/
+    0,                    /*nb_nonzero*/
+    0,                    /*nb_invert*/
+    0,               /*nb_lshift*/
+    0,              /*nb_rshift*/
+    0,              /*nb_and*/
+    0,              /*nb_xor*/
+    0,               /*nb_or*/
+    0,                                          /*nb_coerce*/
+    0,                       /*nb_int*/
+    0,                      /*nb_long*/
+    0,                     /*nb_float*/
+    0,                       /*nb_oct*/
+    0,                       /*nb_hex*/
+    (binaryfunc)Centroid_inplace_add,              /*inplace_add*/
+    (binaryfunc)Centroid_inplace_sub,         /*inplace_subtract*/
+    (binaryfunc)Centroid_inplace_multiply,         /*inplace_multiply*/
+    (binaryfunc)Centroid_inplace_div,           /*inplace_divide*/
+    0,        /*inplace_remainder*/
+    0,           /*inplace_power*/
+    0,       /*inplace_lshift*/
+    0,      /*inplace_rshift*/
+    0,      /*inplace_and*/
+    0,      /*inplace_xor*/
+    0,       /*inplace_or*/
+    0,             /*nb_floor_divide*/
+    0,              /*nb_true_divide*/
+    0,     /*nb_inplace_floor_divide*/
+    0,      /*nb_inplace_true_divide*/
+    0,                     /* nb_index */
+};
+
+PyTypeObject CentroidType = {
+PyObject_HEAD_INIT(NULL)
+0,                                              /*ob_size*/
+"_pyo.Centroid_base",                                   /*tp_name*/
+sizeof(Centroid),                                 /*tp_basicsize*/
+0,                                              /*tp_itemsize*/
+(destructor)Centroid_dealloc,                     /*tp_dealloc*/
+0,                                              /*tp_print*/
+0,                                              /*tp_getattr*/
+0,                                              /*tp_setattr*/
+0,                                              /*tp_compare*/
+0,                                              /*tp_repr*/
+&Centroid_as_number,                              /*tp_as_number*/
+0,                                              /*tp_as_sequence*/
+0,                                              /*tp_as_mapping*/
+0,                                              /*tp_hash */
+0,                                              /*tp_call*/
+0,                                              /*tp_str*/
+0,                                              /*tp_getattro*/
+0,                                              /*tp_setattro*/
+0,                                              /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"Centroid objects. FFT transform.",           /* tp_doc */
+(traverseproc)Centroid_traverse,                  /* tp_traverse */
+(inquiry)Centroid_clear,                          /* tp_clear */
+0,                                              /* tp_richcompare */
+0,                                              /* tp_weaklistoffset */
+0,                                              /* tp_iter */
+0,                                              /* tp_iternext */
+Centroid_methods,                                 /* tp_methods */
+Centroid_members,                                 /* tp_members */
+0,                                              /* tp_getset */
+0,                                              /* tp_base */
+0,                                              /* tp_dict */
+0,                                              /* tp_descr_get */
+0,                                              /* tp_descr_set */
+0,                                              /* tp_dictoffset */
+0,                          /* tp_init */
+0,                                              /* tp_alloc */
+Centroid_new,                                     /* tp_new */
+};
+
+/************/
+/* AttackDetector */
+/************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    MYFLT deltime;
+    MYFLT cutoff;
+    MYFLT maxthresh;
+    MYFLT minthresh;
+    MYFLT reltime;
+    MYFLT folfactor;
+    MYFLT follow;
+    MYFLT followdb;
+    MYFLT *buffer;
+    MYFLT previous;
+    int memsize;
+    int sampdel;
+    int incount;
+    int overminok;
+    int belowminok;
+    long maxtime;
+    long timer;
+    int modebuffer[2]; // need at least 2 slots for mul & add
+} AttackDetector;
+
+static void
+AttackDetector_process(AttackDetector *self) {
+    int i, ind;
+    MYFLT absin;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = 0.0;
+        absin = in[i];
+        // envelope follower
+        if (absin < 0.0)
+            absin = -absin;
+        self->follow = absin + self->folfactor * (self->follow - absin);
+        // follower in dB
+        if (self->follow <= 0.000001)
+            self->followdb = -120.0;
+        else
+            self->followdb = 20.0 * MYLOG10(self->follow);
+        // previous analysis
+        ind = self->incount - self->sampdel;
+        if (ind < 0)
+            ind += self->memsize;
+        self->previous = self->buffer[ind];
+        self->buffer[self->incount] = self->followdb;
+        self->incount++;
+        if (self->incount >= self->memsize)
+            self->incount = 0;
+        // if release time has past
+        if (self->timer >= self->maxtime) {
+            // if rms is over min threshold
+            if (self->overminok) {
+                // if rms is greater than previous + maxthresh
+                if (self->followdb > (self->previous + self->maxthresh)) {
+                    self->data[i] = 1.0;
+                    self->overminok = self->belowminok = 0;
+                    self->timer = 0;
+                }
+            }
+        }
+        if (self->belowminok == 0 && self->followdb < self->minthresh)
+            self->belowminok = 1;
+        else if (self->belowminok == 1 && self->followdb > self->minthresh)
+            self->overminok = 1;
+        self->timer++;
+    }
+}
+
+static void AttackDetector_postprocessing_ii(AttackDetector *self) { POST_PROCESSING_II };
+static void AttackDetector_postprocessing_ai(AttackDetector *self) { POST_PROCESSING_AI };
+static void AttackDetector_postprocessing_ia(AttackDetector *self) { POST_PROCESSING_IA };
+static void AttackDetector_postprocessing_aa(AttackDetector *self) { POST_PROCESSING_AA };
+static void AttackDetector_postprocessing_ireva(AttackDetector *self) { POST_PROCESSING_IREVA };
+static void AttackDetector_postprocessing_areva(AttackDetector *self) { POST_PROCESSING_AREVA };
+static void AttackDetector_postprocessing_revai(AttackDetector *self) { POST_PROCESSING_REVAI };
+static void AttackDetector_postprocessing_revaa(AttackDetector *self) { POST_PROCESSING_REVAA };
+static void AttackDetector_postprocessing_revareva(AttackDetector *self) { POST_PROCESSING_REVAREVA };
+
+static void
+AttackDetector_setProcMode(AttackDetector *self)
+{
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    self->proc_func_ptr = AttackDetector_process;
+ 
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = AttackDetector_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = AttackDetector_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = AttackDetector_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = AttackDetector_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = AttackDetector_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = AttackDetector_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = AttackDetector_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = AttackDetector_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = AttackDetector_postprocessing_revareva;
+            break;
+    }   
+}
+
+static void
+AttackDetector_compute_next_data_frame(AttackDetector *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+AttackDetector_traverse(AttackDetector *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    return 0;
+}
+
+static int 
+AttackDetector_clear(AttackDetector *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    return 0;
+}
+
+static void
+AttackDetector_dealloc(AttackDetector* self)
+{
+    pyo_DEALLOC
+    free(self->buffer);
+    AttackDetector_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+AttackDetector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+    AttackDetector *self;
+    self = (AttackDetector *)type->tp_alloc(type, 0);
+    
+    self->deltime = 0.005;
+    self->cutoff = 10.0;
+    self->maxthresh = 3.0;
+    self->minthresh = -30.0;
+    self->reltime = 0.1;
+    self->follow = 0.0;
+    self->followdb = -120.0;
+    self->previous = 0.0;
+    self->incount = 0;
+    self->overminok = 0;
+    self->belowminok = 0;
+    self->timer = 0;
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, AttackDetector_compute_next_data_frame);
+    self->mode_func_ptr = AttackDetector_setProcMode;
+
+    static char *kwlist[] = {"input", "deltime", "cutoff", "maxthresh", "minthresh", "reltime", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_FFFFFOO, kwlist, &inputtmp, &self->deltime, &self->cutoff, &self->maxthresh, &self->minthresh, &self->reltime, &multmp, &addtmp))
+        Py_RETURN_NONE; 
+
+    INIT_INPUT_STREAM
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+    self->memsize = (int)(0.055 * self->sr + 0.5);
+    self->buffer = (MYFLT *)realloc(self->buffer, (self->memsize+1) * sizeof(MYFLT));
+    for (i=0; i<(self->memsize+1); i++) {
+        self->buffer[i] = 0.0;
+    }    
+       
+    if (self->deltime < 0.001) self->deltime = 0.001;
+    else if (self->deltime > 0.05) self->deltime = 0.05;
+    self->sampdel = (int)(self->deltime * self->sr);
+
+    if (self->cutoff < 1.0) self->cutoff = 1.0;
+    else if (self->cutoff > 1000.0) self->cutoff = 1000.0;
+    self->folfactor = MYEXP(-TWOPI * self->cutoff / self->sr);
+
+    if (self->cutoff < 1.0) self->cutoff = 1.0;
+    else if (self->cutoff > 1000.0) self->cutoff = 1000.0;
+
+    if (self->maxthresh < 0.0) self->maxthresh = 0.0;
+    else if (self->maxthresh > 18.0) self->maxthresh = 18.0;
+
+    if (self->minthresh < -90.0) self->minthresh = -90.0;
+    else if (self->minthresh > 0.0) self->minthresh = 0.0;
+
+    if (self->reltime < 0.001) self->reltime = 0.001;
+    self->maxtime = (long)(self->reltime * self->sr + 0.5);
+
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * AttackDetector_getServer(AttackDetector* self) { GET_SERVER };
+static PyObject * AttackDetector_getStream(AttackDetector* self) { GET_STREAM };
+static PyObject * AttackDetector_setMul(AttackDetector *self, PyObject *arg) { SET_MUL };	
+static PyObject * AttackDetector_setAdd(AttackDetector *self, PyObject *arg) { SET_ADD };	
+static PyObject * AttackDetector_setSub(AttackDetector *self, PyObject *arg) { SET_SUB };	
+static PyObject * AttackDetector_setDiv(AttackDetector *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * AttackDetector_play(AttackDetector *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * AttackDetector_stop(AttackDetector *self) { STOP };
+
+static PyObject * AttackDetector_multiply(AttackDetector *self, PyObject *arg) { MULTIPLY };
+static PyObject * AttackDetector_inplace_multiply(AttackDetector *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * AttackDetector_add(AttackDetector *self, PyObject *arg) { ADD };
+static PyObject * AttackDetector_inplace_add(AttackDetector *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * AttackDetector_sub(AttackDetector *self, PyObject *arg) { SUB };
+static PyObject * AttackDetector_inplace_sub(AttackDetector *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * AttackDetector_div(AttackDetector *self, PyObject *arg) { DIV };
+static PyObject * AttackDetector_inplace_div(AttackDetector *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+AttackDetector_setDeltime(AttackDetector *self, PyObject *arg)
+{
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	if (isNumber == 1) {
+		self->deltime = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (self->deltime < 0.001) self->deltime = 0.001;
+        else if (self->deltime > 0.05) self->deltime = 0.05;
+        self->sampdel = (int)(self->deltime * self->sr);
+	}
+  
+	Py_RETURN_NONE;
+}
+
+static PyObject *
+AttackDetector_setCutoff(AttackDetector *self, PyObject *arg)
+{
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	if (isNumber == 1) {
+		self->cutoff = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (self->cutoff < 1.0) self->cutoff = 1.0;
+        else if (self->cutoff > 1000.0) self->cutoff = 1000.0;
+        self->folfactor = MYEXP(-TWOPI * self->cutoff / self->sr);
+	}
+  
+	Py_RETURN_NONE;
+}
+
+static PyObject *
+AttackDetector_setMaxthresh(AttackDetector *self, PyObject *arg)
+{
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	if (isNumber == 1) {
+		self->maxthresh = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (self->maxthresh < 0.0) self->maxthresh = 0.0;
+        else if (self->maxthresh > 18.0) self->maxthresh = 18.0;
+	}
+  
+	Py_RETURN_NONE;
+}
+
+static PyObject *
+AttackDetector_setMinthresh(AttackDetector *self, PyObject *arg)
+{
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	if (isNumber == 1) {
+		self->minthresh = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (self->minthresh < -90.0) self->minthresh = -90.0;
+        else if (self->minthresh > 0.0) self->minthresh = 0.0;
+	}
+  
+	Py_RETURN_NONE;
+}
+
+static PyObject *
+AttackDetector_setReltime(AttackDetector *self, PyObject *arg)
+{
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	if (isNumber == 1) {
+		self->reltime = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (self->reltime < 0.001) self->reltime = 0.001;
+        self->maxtime = (long)(self->reltime * self->sr + 0.5);
+	}
+  
+	Py_RETURN_NONE;
+}
+
+static PyMemberDef AttackDetector_members[] = {
+{"server", T_OBJECT_EX, offsetof(AttackDetector, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(AttackDetector, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(AttackDetector, input), 0, "Input sound object."},
+{"mul", T_OBJECT_EX, offsetof(AttackDetector, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(AttackDetector, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef AttackDetector_methods[] = {
+{"getServer", (PyCFunction)AttackDetector_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)AttackDetector_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)AttackDetector_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)AttackDetector_stop, METH_NOARGS, "Stops computing."},
+{"setDeltime", (PyCFunction)AttackDetector_setDeltime, METH_O, "Sets the delay time between current and previous analysis."},
+{"setCutoff", (PyCFunction)AttackDetector_setCutoff, METH_O, "Sets the frequency of the internal lowpass filter."},
+{"setMaxthresh", (PyCFunction)AttackDetector_setMaxthresh, METH_O, "Sets the higher threshold."},
+{"setMinthresh", (PyCFunction)AttackDetector_setMinthresh, METH_O, "Sets the lower threshold."},
+{"setReltime", (PyCFunction)AttackDetector_setReltime, METH_O, "Sets the release time (min time between two detected attacks)."},
+{"setMul", (PyCFunction)AttackDetector_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)AttackDetector_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)AttackDetector_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)AttackDetector_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods AttackDetector_as_number = {
+(binaryfunc)AttackDetector_add,                         /*nb_add*/
+(binaryfunc)AttackDetector_sub,                         /*nb_subtract*/
+(binaryfunc)AttackDetector_multiply,                    /*nb_multiply*/
+(binaryfunc)AttackDetector_div,                                              /*nb_divide*/
+0,                                              /*nb_remainder*/
+0,                                              /*nb_divmod*/
+0,                                              /*nb_power*/
+0,                                              /*nb_neg*/
+0,                                              /*nb_pos*/
+0,                                              /*(unaryfunc)array_abs,*/
+0,                                              /*nb_nonzero*/
+0,                                              /*nb_invert*/
+0,                                              /*nb_lshift*/
+0,                                              /*nb_rshift*/
+0,                                              /*nb_and*/
+0,                                              /*nb_xor*/
+0,                                              /*nb_or*/
+0,                                              /*nb_coerce*/
+0,                                              /*nb_int*/
+0,                                              /*nb_long*/
+0,                                              /*nb_float*/
+0,                                              /*nb_oct*/
+0,                                              /*nb_hex*/
+(binaryfunc)AttackDetector_inplace_add,                 /*inplace_add*/
+(binaryfunc)AttackDetector_inplace_sub,                 /*inplace_subtract*/
+(binaryfunc)AttackDetector_inplace_multiply,            /*inplace_multiply*/
+(binaryfunc)AttackDetector_inplace_div,                                              /*inplace_divide*/
+0,                                              /*inplace_remainder*/
+0,                                              /*inplace_power*/
+0,                                              /*inplace_lshift*/
+0,                                              /*inplace_rshift*/
+0,                                              /*inplace_and*/
+0,                                              /*inplace_xor*/
+0,                                              /*inplace_or*/
+0,                                              /*nb_floor_divide*/
+0,                                              /*nb_true_divide*/
+0,                                              /*nb_inplace_floor_divide*/
+0,                                              /*nb_inplace_true_divide*/
+0,                                              /* nb_index */
+};
+
+PyTypeObject AttackDetectorType = {
+PyObject_HEAD_INIT(NULL)
+0,                                              /*ob_size*/
+"_pyo.AttackDetector_base",                                   /*tp_name*/
+sizeof(AttackDetector),                                 /*tp_basicsize*/
+0,                                              /*tp_itemsize*/
+(destructor)AttackDetector_dealloc,                     /*tp_dealloc*/
+0,                                              /*tp_print*/
+0,                                              /*tp_getattr*/
+0,                                              /*tp_setattr*/
+0,                                              /*tp_compare*/
+0,                                              /*tp_repr*/
+&AttackDetector_as_number,                              /*tp_as_number*/
+0,                                              /*tp_as_sequence*/
+0,                                              /*tp_as_mapping*/
+0,                                              /*tp_hash */
+0,                                              /*tp_call*/
+0,                                              /*tp_str*/
+0,                                              /*tp_getattro*/
+0,                                              /*tp_setattro*/
+0,                                              /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"AttackDetector objects. Audio signal peak detection.",           /* tp_doc */
+(traverseproc)AttackDetector_traverse,                  /* tp_traverse */
+(inquiry)AttackDetector_clear,                          /* tp_clear */
+0,                                              /* tp_richcompare */
+0,                                              /* tp_weaklistoffset */
+0,                                              /* tp_iter */
+0,                                              /* tp_iternext */
+AttackDetector_methods,                                 /* tp_methods */
+AttackDetector_members,                                 /* tp_members */
+0,                                              /* tp_getset */
+0,                                              /* tp_base */
+0,                                              /* tp_dict */
+0,                                              /* tp_descr_get */
+0,                                              /* tp_descr_set */
+0,                                              /* tp_dictoffset */
+0,                          /* tp_init */
+0,                                              /* tp_alloc */
+AttackDetector_new,                                     /* tp_new */
+};
+
+/*********************************************************************************************/
+/* Scope ********************************************************************************/
+/*********************************************************************************************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    int size;
+    int width;
+    int height;
+    int pointer;
+    MYFLT gain;
+    MYFLT *buffer;
+} Scope;
+
+static void
+Scope_generate(Scope *self) {
+    int i;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    for (i=0; i<self->bufsize; i++) {
+        if (self->pointer >= self->size)
+            self->pointer = 0;
+        self->buffer[self->pointer] = in[i];
+        self->pointer++;
+    }
+}
+
+static PyObject *
+Scope_display(Scope *self) {
+    int i, ipos;
+    MYFLT pos, step, mag, h2;
+    PyObject *points, *tuple;
+    
+    step = self->size / (MYFLT)(self->width);
+    h2 = self->height * 0.5;
+
+    points = PyList_New(self->width);
+
+    for (i=0; i<self->width; i++) {
+        pos = i * step;
+        ipos = (int)pos;
+        tuple = PyTuple_New(2);
+        mag = ((self->buffer[ipos] + (self->buffer[ipos+1] - self->buffer[ipos]) * (pos - ipos)) * self->gain * h2 + h2);
+        PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(i));
+        PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(self->height - (int)mag));
+        PyList_SET_ITEM(points, i, tuple);
+    }
+    return points;
+}
+
+static void
+Scope_compute_next_data_frame(Scope *self)
+{
+    Scope_generate(self); 
+}
+
+static int
+Scope_traverse(Scope *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    return 0;
+}
+
+static int 
+Scope_clear(Scope *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    return 0;
+}
+
+static void
+Scope_dealloc(Scope* self)
+{
+    pyo_DEALLOC
+    free(self->buffer);
+    Scope_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Scope_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i, maxsize;
+    MYFLT length = 0.05;
+    PyObject *inputtmp, *input_streamtmp;
+    Scope *self;
+    self = (Scope *)type->tp_alloc(type, 0);
+
+    self->gain = 1.0;
+    self->width = 500;
+    self->height = 400;
+
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, Scope_compute_next_data_frame);
+
+    static char *kwlist[] = {"input", "length", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_F, kwlist, &inputtmp, &length))
+        Py_RETURN_NONE;
+    
+    INIT_INPUT_STREAM
+
+    maxsize = (int)(self->sr * 0.25);
+    self->buffer = (MYFLT *)realloc(self->buffer, maxsize * sizeof(MYFLT)); 
+    self->size = (int)(length * self->sr);
+    if (self->size > maxsize)
+        self->size = maxsize;
+    self->pointer = 0;
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+    return (PyObject *)self;
+}
+
+static PyObject * Scope_getServer(Scope* self) { GET_SERVER };
+static PyObject * Scope_getStream(Scope* self) { GET_STREAM };
+
+static PyObject * Scope_play(Scope *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Scope_stop(Scope *self) { STOP };
+
+static PyObject *
+Scope_setLength(Scope *self, PyObject *arg)
+{
+    MYFLT length;
+    int maxsize = (int)(self->sr * 0.25);
+
+    if (PyNumber_Check(arg)) {
+        length = PyFloat_AsDouble(PyNumber_Float(arg));
+        self->size = (int)(length * self->sr);
+        if (self->size > maxsize)
+            self->size = maxsize;
+        self->pointer = 0;
+    }    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+Scope_setGain(Scope *self, PyObject *arg)
+{
+    if (PyNumber_Check(arg)) {
+        self->gain = PyFloat_AsDouble(PyNumber_Float(arg));
+    }    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+Scope_setWidth(Scope *self, PyObject *arg)
+{
+    if (PyInt_Check(arg)) {
+        self->width = PyInt_AsLong(arg);
+    }    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+Scope_setHeight(Scope *self, PyObject *arg)
+{
+    if (PyInt_Check(arg)) {
+        self->height = PyInt_AsLong(arg);
+    }    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyMemberDef Scope_members[] = {
+{"server", T_OBJECT_EX, offsetof(Scope, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Scope, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(Scope, input), 0, "Input sound object."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef Scope_methods[] = {
+{"getServer", (PyCFunction)Scope_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Scope_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Scope_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)Scope_stop, METH_NOARGS, "Stops computing."},
+{"display", (PyCFunction)Scope_display, METH_NOARGS, "Computes the samples to draw."},
+{"setLength", (PyCFunction)Scope_setLength, METH_O, "Sets function's argument."},
+{"setGain", (PyCFunction)Scope_setGain, METH_O, "Sets gain compensation."},
+{"setWidth", (PyCFunction)Scope_setWidth, METH_O, "Sets the width of the display."},
+{"setHeight", (PyCFunction)Scope_setHeight, METH_O, "Sets the height of the display."},
+{NULL}  /* Sentinel */
+};
+
+PyTypeObject ScopeType = {
+PyObject_HEAD_INIT(NULL)
+0,                                              /*ob_size*/
+"_pyo.Scope_base",                                   /*tp_name*/
+sizeof(Scope),                                 /*tp_basicsize*/
+0,                                              /*tp_itemsize*/
+(destructor)Scope_dealloc,                     /*tp_dealloc*/
+0,                                              /*tp_print*/
+0,                                              /*tp_getattr*/
+0,                                              /*tp_setattr*/
+0,                                              /*tp_compare*/
+0,                                              /*tp_repr*/
+0,                              /*tp_as_number*/
+0,                                              /*tp_as_sequence*/
+0,                                              /*tp_as_mapping*/
+0,                                              /*tp_hash */
+0,                                              /*tp_call*/
+0,                                              /*tp_str*/
+0,                                              /*tp_getattro*/
+0,                                              /*tp_setattro*/
+0,                                              /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"Scope objects. Show the waveform of an input signal.",           /* tp_doc */
+(traverseproc)Scope_traverse,                  /* tp_traverse */
+(inquiry)Scope_clear,                          /* tp_clear */
+0,                                              /* tp_richcompare */
+0,                                              /* tp_weaklistoffset */
+0,                                              /* tp_iter */
+0,                                              /* tp_iternext */
+Scope_methods,                                 /* tp_methods */
+Scope_members,                                 /* tp_members */
+0,                                              /* tp_getset */
+0,                                              /* tp_base */
+0,                                              /* tp_dict */
+0,                                              /* tp_descr_get */
+0,                                              /* tp_descr_set */
+0,                                              /* tp_dictoffset */
+0,                          /* tp_init */
+0,                                              /* tp_alloc */
+Scope_new,                                     /* tp_new */
+};
+
+/************/
+/* PeakAmp */
+/************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    int modebuffer[2]; // need at least 2 slots for mul & add 
+    MYFLT follow;
+} PeakAmp;
+
+static void
+PeakAmp_filters_i(PeakAmp *self) {
+    MYFLT absin, peak;
+    int i;
+
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    
+    peak = 0.0;
+    for (i=0; i<self->bufsize; i++) {
+        absin = in[i];
+        if (absin < 0.0)
+            absin = -absin;
+        if (absin > peak)
+            peak = absin;
+        self->data[i] = self->follow;
+    }
+    self->follow = peak;
+}
+
+static void PeakAmp_postprocessing_ii(PeakAmp *self) { POST_PROCESSING_II };
+static void PeakAmp_postprocessing_ai(PeakAmp *self) { POST_PROCESSING_AI };
+static void PeakAmp_postprocessing_ia(PeakAmp *self) { POST_PROCESSING_IA };
+static void PeakAmp_postprocessing_aa(PeakAmp *self) { POST_PROCESSING_AA };
+static void PeakAmp_postprocessing_ireva(PeakAmp *self) { POST_PROCESSING_IREVA };
+static void PeakAmp_postprocessing_areva(PeakAmp *self) { POST_PROCESSING_AREVA };
+static void PeakAmp_postprocessing_revai(PeakAmp *self) { POST_PROCESSING_REVAI };
+static void PeakAmp_postprocessing_revaa(PeakAmp *self) { POST_PROCESSING_REVAA };
+static void PeakAmp_postprocessing_revareva(PeakAmp *self) { POST_PROCESSING_REVAREVA };
+
+static void
+PeakAmp_setProcMode(PeakAmp *self)
+{
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    self->proc_func_ptr = PeakAmp_filters_i;
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = PeakAmp_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = PeakAmp_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = PeakAmp_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = PeakAmp_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = PeakAmp_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = PeakAmp_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = PeakAmp_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = PeakAmp_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = PeakAmp_postprocessing_revareva;
+            break;
+    }   
+}
+
+static void
+PeakAmp_compute_next_data_frame(PeakAmp *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+PeakAmp_traverse(PeakAmp *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    return 0;
+}
+
+static int 
+PeakAmp_clear(PeakAmp *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    return 0;
+}
+
+static void
+PeakAmp_dealloc(PeakAmp* self)
+{
+    pyo_DEALLOC
+    PeakAmp_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+PeakAmp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+    PeakAmp *self;
+    self = (PeakAmp *)type->tp_alloc(type, 0);
+    
+    self->follow = 0.0;
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, PeakAmp_compute_next_data_frame);
+    self->mode_func_ptr = PeakAmp_setProcMode;
+
+    static char *kwlist[] = {"input", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &inputtmp, &multmp, &addtmp))
+        Py_RETURN_NONE; 
+    
+    INIT_INPUT_STREAM
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * PeakAmp_getServer(PeakAmp* self) { GET_SERVER };
+static PyObject * PeakAmp_getStream(PeakAmp* self) { GET_STREAM };
+static PyObject * PeakAmp_setMul(PeakAmp *self, PyObject *arg) { SET_MUL };	
+static PyObject * PeakAmp_setAdd(PeakAmp *self, PyObject *arg) { SET_ADD };	
+static PyObject * PeakAmp_setSub(PeakAmp *self, PyObject *arg) { SET_SUB };	
+static PyObject * PeakAmp_setDiv(PeakAmp *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * PeakAmp_play(PeakAmp *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * PeakAmp_stop(PeakAmp *self) { STOP };
+
+static PyObject * PeakAmp_multiply(PeakAmp *self, PyObject *arg) { MULTIPLY };
+static PyObject * PeakAmp_inplace_multiply(PeakAmp *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * PeakAmp_add(PeakAmp *self, PyObject *arg) { ADD };
+static PyObject * PeakAmp_inplace_add(PeakAmp *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * PeakAmp_sub(PeakAmp *self, PyObject *arg) { SUB };
+static PyObject * PeakAmp_inplace_sub(PeakAmp *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * PeakAmp_div(PeakAmp *self, PyObject *arg) { DIV };
+static PyObject * PeakAmp_inplace_div(PeakAmp *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+PeakAmp_getValue(PeakAmp *self)
+{
+    return PyFloat_FromDouble(self->follow);
+}
+
+static PyMemberDef PeakAmp_members[] = {
+{"server", T_OBJECT_EX, offsetof(PeakAmp, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(PeakAmp, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(PeakAmp, input), 0, "Input sound object."},
+{"mul", T_OBJECT_EX, offsetof(PeakAmp, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(PeakAmp, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef PeakAmp_methods[] = {
+{"getServer", (PyCFunction)PeakAmp_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)PeakAmp_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)PeakAmp_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)PeakAmp_stop, METH_NOARGS, "Stops computing."},
+{"getValue", (PyCFunction)PeakAmp_getValue, METH_NOARGS, "Returns the current peaking value."},
+{"setMul", (PyCFunction)PeakAmp_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)PeakAmp_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)PeakAmp_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)PeakAmp_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods PeakAmp_as_number = {
+(binaryfunc)PeakAmp_add,                         /*nb_add*/
+(binaryfunc)PeakAmp_sub,                         /*nb_subtract*/
+(binaryfunc)PeakAmp_multiply,                    /*nb_multiply*/
+(binaryfunc)PeakAmp_div,                                              /*nb_divide*/
+0,                                              /*nb_remainder*/
+0,                                              /*nb_divmod*/
+0,                                              /*nb_power*/
+0,                                              /*nb_neg*/
+0,                                              /*nb_pos*/
+0,                                              /*(unaryfunc)array_abs,*/
+0,                                              /*nb_nonzero*/
+0,                                              /*nb_invert*/
+0,                                              /*nb_lshift*/
+0,                                              /*nb_rshift*/
+0,                                              /*nb_and*/
+0,                                              /*nb_xor*/
+0,                                              /*nb_or*/
+0,                                              /*nb_coerce*/
+0,                                              /*nb_int*/
+0,                                              /*nb_long*/
+0,                                              /*nb_float*/
+0,                                              /*nb_oct*/
+0,                                              /*nb_hex*/
+(binaryfunc)PeakAmp_inplace_add,                 /*inplace_add*/
+(binaryfunc)PeakAmp_inplace_sub,                 /*inplace_subtract*/
+(binaryfunc)PeakAmp_inplace_multiply,            /*inplace_multiply*/
+(binaryfunc)PeakAmp_inplace_div,                                              /*inplace_divide*/
+0,                                              /*inplace_remainder*/
+0,                                              /*inplace_power*/
+0,                                              /*inplace_lshift*/
+0,                                              /*inplace_rshift*/
+0,                                              /*inplace_and*/
+0,                                              /*inplace_xor*/
+0,                                              /*inplace_or*/
+0,                                              /*nb_floor_divide*/
+0,                                              /*nb_true_divide*/
+0,                                              /*nb_inplace_floor_divide*/
+0,                                              /*nb_inplace_true_divide*/
+0,                                              /* nb_index */
+};
+
+PyTypeObject PeakAmpType = {
+PyObject_HEAD_INIT(NULL)
+0,                                              /*ob_size*/
+"_pyo.PeakAmp_base",                                   /*tp_name*/
+sizeof(PeakAmp),                                 /*tp_basicsize*/
+0,                                              /*tp_itemsize*/
+(destructor)PeakAmp_dealloc,                     /*tp_dealloc*/
+0,                                              /*tp_print*/
+0,                                              /*tp_getattr*/
+0,                                              /*tp_setattr*/
+0,                                              /*tp_compare*/
+0,                                              /*tp_repr*/
+&PeakAmp_as_number,                              /*tp_as_number*/
+0,                                              /*tp_as_sequence*/
+0,                                              /*tp_as_mapping*/
+0,                                              /*tp_hash */
+0,                                              /*tp_call*/
+0,                                              /*tp_str*/
+0,                                              /*tp_getattro*/
+0,                                              /*tp_setattro*/
+0,                                              /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"PeakAmp objects. Envelope follower.",           /* tp_doc */
+(traverseproc)PeakAmp_traverse,                  /* tp_traverse */
+(inquiry)PeakAmp_clear,                          /* tp_clear */
+0,                                              /* tp_richcompare */
+0,                                              /* tp_weaklistoffset */
+0,                                              /* tp_iter */
+0,                                              /* tp_iternext */
+PeakAmp_methods,                                 /* tp_methods */
+PeakAmp_members,                                 /* tp_members */
+0,                                              /* tp_getset */
+0,                                              /* tp_base */
+0,                                              /* tp_dict */
+0,                                              /* tp_descr_get */
+0,                                              /* tp_descr_set */
+0,                                              /* tp_dictoffset */
+0,                          /* tp_init */
+0,                                              /* tp_alloc */
+PeakAmp_new,                                     /* tp_new */
+};
diff --git a/src/objects/arithmeticmodule.c b/src/objects/arithmeticmodule.c
index 1c06284..79157db 100644
--- a/src/objects/arithmeticmodule.c
+++ b/src/objects/arithmeticmodule.c
@@ -3771,3 +3771,268 @@ PyTypeObject M_RoundType = {
     0,                                              /* tp_alloc */
     M_Round_new,                                     /* tp_new */
 };
+
+/************/
+/* M_Tanh */
+/************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    int modebuffer[2]; // need at least 2 slots for mul & add
+} M_Tanh;
+
+static void
+M_Tanh_process(M_Tanh *self) {
+    int i;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = MYTANH(in[i]);
+    }
+}
+
+static void M_Tanh_postprocessing_ii(M_Tanh *self) { POST_PROCESSING_II };
+static void M_Tanh_postprocessing_ai(M_Tanh *self) { POST_PROCESSING_AI };
+static void M_Tanh_postprocessing_ia(M_Tanh *self) { POST_PROCESSING_IA };
+static void M_Tanh_postprocessing_aa(M_Tanh *self) { POST_PROCESSING_AA };
+static void M_Tanh_postprocessing_ireva(M_Tanh *self) { POST_PROCESSING_IREVA };
+static void M_Tanh_postprocessing_areva(M_Tanh *self) { POST_PROCESSING_AREVA };
+static void M_Tanh_postprocessing_revai(M_Tanh *self) { POST_PROCESSING_REVAI };
+static void M_Tanh_postprocessing_revaa(M_Tanh *self) { POST_PROCESSING_REVAA };
+static void M_Tanh_postprocessing_revareva(M_Tanh *self) { POST_PROCESSING_REVAREVA };
+
+static void
+M_Tanh_setProcMode(M_Tanh *self)
+{
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    self->proc_func_ptr = M_Tanh_process;
+ 
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = M_Tanh_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = M_Tanh_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = M_Tanh_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = M_Tanh_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = M_Tanh_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = M_Tanh_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = M_Tanh_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = M_Tanh_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = M_Tanh_postprocessing_revareva;
+            break;
+    }   
+}
+
+static void
+M_Tanh_compute_next_data_frame(M_Tanh *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+M_Tanh_traverse(M_Tanh *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    return 0;
+}
+
+static int 
+M_Tanh_clear(M_Tanh *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    return 0;
+}
+
+static void
+M_Tanh_dealloc(M_Tanh* self)
+{
+    pyo_DEALLOC
+    M_Tanh_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+M_Tanh_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+    M_Tanh *self;
+    self = (M_Tanh *)type->tp_alloc(type, 0);
+
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, M_Tanh_compute_next_data_frame);
+    self->mode_func_ptr = M_Tanh_setProcMode;
+
+    static char *kwlist[] = {"input", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &inputtmp, &multmp, &addtmp))
+        Py_RETURN_NONE;
+
+    INIT_INPUT_STREAM
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * M_Tanh_getServer(M_Tanh* self) { GET_SERVER };
+static PyObject * M_Tanh_getStream(M_Tanh* self) { GET_STREAM };
+static PyObject * M_Tanh_setMul(M_Tanh *self, PyObject *arg) { SET_MUL };	
+static PyObject * M_Tanh_setAdd(M_Tanh *self, PyObject *arg) { SET_ADD };	
+static PyObject * M_Tanh_setSub(M_Tanh *self, PyObject *arg) { SET_SUB };	
+static PyObject * M_Tanh_setDiv(M_Tanh *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * M_Tanh_play(M_Tanh *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * M_Tanh_out(M_Tanh *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * M_Tanh_stop(M_Tanh *self) { STOP };
+
+static PyObject * M_Tanh_multiply(M_Tanh *self, PyObject *arg) { MULTIPLY };
+static PyObject * M_Tanh_inplace_multiply(M_Tanh *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * M_Tanh_add(M_Tanh *self, PyObject *arg) { ADD };
+static PyObject * M_Tanh_inplace_add(M_Tanh *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * M_Tanh_sub(M_Tanh *self, PyObject *arg) { SUB };
+static PyObject * M_Tanh_inplace_sub(M_Tanh *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * M_Tanh_div(M_Tanh *self, PyObject *arg) { DIV };
+static PyObject * M_Tanh_inplace_div(M_Tanh *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef M_Tanh_members[] = {
+{"server", T_OBJECT_EX, offsetof(M_Tanh, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(M_Tanh, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(M_Tanh, input), 0, "Input sound object."},
+{"mul", T_OBJECT_EX, offsetof(M_Tanh, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(M_Tanh, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef M_Tanh_methods[] = {
+{"getServer", (PyCFunction)M_Tanh_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)M_Tanh_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)M_Tanh_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)M_Tanh_stop, METH_NOARGS, "Stops computing."},
+{"out", (PyCFunction)M_Tanh_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"setMul", (PyCFunction)M_Tanh_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)M_Tanh_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)M_Tanh_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)M_Tanh_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods M_Tanh_as_number = {
+(binaryfunc)M_Tanh_add,                         /*nb_add*/
+(binaryfunc)M_Tanh_sub,                         /*nb_subtract*/
+(binaryfunc)M_Tanh_multiply,                    /*nb_multiply*/
+(binaryfunc)M_Tanh_div,                                              /*nb_divide*/
+0,                                              /*nb_remainder*/
+0,                                              /*nb_divmod*/
+0,                                              /*nb_power*/
+0,                                              /*nb_neg*/
+0,                                              /*nb_pos*/
+0,                                              /*(unaryfunc)array_abs,*/
+0,                                              /*nb_nonzero*/
+0,                                              /*nb_invert*/
+0,                                              /*nb_lshift*/
+0,                                              /*nb_rshift*/
+0,                                              /*nb_and*/
+0,                                              /*nb_xor*/
+0,                                              /*nb_or*/
+0,                                              /*nb_coerce*/
+0,                                              /*nb_int*/
+0,                                              /*nb_long*/
+0,                                              /*nb_float*/
+0,                                              /*nb_oct*/
+0,                                              /*nb_hex*/
+(binaryfunc)M_Tanh_inplace_add,                 /*inplace_add*/
+(binaryfunc)M_Tanh_inplace_sub,                 /*inplace_subtract*/
+(binaryfunc)M_Tanh_inplace_multiply,            /*inplace_multiply*/
+(binaryfunc)M_Tanh_inplace_div,                                              /*inplace_divide*/
+0,                                              /*inplace_remainder*/
+0,                                              /*inplace_power*/
+0,                                              /*inplace_lshift*/
+0,                                              /*inplace_rshift*/
+0,                                              /*inplace_and*/
+0,                                              /*inplace_xor*/
+0,                                              /*inplace_or*/
+0,                                              /*nb_floor_divide*/
+0,                                              /*nb_true_divide*/
+0,                                              /*nb_inplace_floor_divide*/
+0,                                              /*nb_inplace_true_divide*/
+0,                                              /* nb_index */
+};
+
+PyTypeObject M_TanhType = {
+PyObject_HEAD_INIT(NULL)
+0,                                              /*ob_size*/
+"_pyo.M_Tanh_base",                                   /*tp_name*/
+sizeof(M_Tanh),                                 /*tp_basicsize*/
+0,                                              /*tp_itemsize*/
+(destructor)M_Tanh_dealloc,                     /*tp_dealloc*/
+0,                                              /*tp_print*/
+0,                                              /*tp_getattr*/
+0,                                              /*tp_setattr*/
+0,                                              /*tp_compare*/
+0,                                              /*tp_repr*/
+&M_Tanh_as_number,                              /*tp_as_number*/
+0,                                              /*tp_as_sequence*/
+0,                                              /*tp_as_mapping*/
+0,                                              /*tp_hash */
+0,                                              /*tp_call*/
+0,                                              /*tp_str*/
+0,                                              /*tp_getattro*/
+0,                                              /*tp_setattro*/
+0,                                              /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"M_Tanh objects. Performs tanh function on audio samples.",           /* tp_doc */
+(traverseproc)M_Tanh_traverse,                  /* tp_traverse */
+(inquiry)M_Tanh_clear,                          /* tp_clear */
+0,                                              /* tp_richcompare */
+0,                                              /* tp_weaklistoffset */
+0,                                              /* tp_iter */
+0,                                              /* tp_iternext */
+M_Tanh_methods,                                 /* tp_methods */
+M_Tanh_members,                                 /* tp_members */
+0,                                              /* tp_getset */
+0,                                              /* tp_base */
+0,                                              /* tp_dict */
+0,                                              /* tp_descr_get */
+0,                                              /* tp_descr_set */
+0,                                              /* tp_dictoffset */
+0,                          /* tp_init */
+0,                                              /* tp_alloc */
+M_Tanh_new,                                     /* tp_new */
+};
diff --git a/src/objects/convolvemodule.c b/src/objects/convolvemodule.c
index 63b3fc3..f19da5a 100644
--- a/src/objects/convolvemodule.c
+++ b/src/objects/convolvemodule.c
@@ -174,11 +174,8 @@ Convolve_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
 
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of Convolve must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Convolve must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
diff --git a/src/objects/delaymodule.c b/src/objects/delaymodule.c
index f4a0302..bec9a2b 100644
--- a/src/objects/delaymodule.c
+++ b/src/objects/delaymodule.c
@@ -35,6 +35,7 @@ typedef struct {
     PyObject *feedback;
     Stream *feedback_stream;
     MYFLT maxdelay;
+    MYFLT oneOverSr;
     long size;
     long in_count;
     int modebuffer[4];
@@ -50,8 +51,8 @@ Delay_process_ii(Delay *self) {
     MYFLT del = PyFloat_AS_DOUBLE(self->delay);
     MYFLT feed = PyFloat_AS_DOUBLE(self->feedback);
     
-    if (del < 0.)
-        del = 0.;
+    if (del < self->oneOverSr)
+        del = self->oneOverSr;
     else if (del > self->maxdelay)
         del = self->maxdelay;
     MYFLT sampdel = del * self->sr;
@@ -99,8 +100,8 @@ Delay_process_ai(Delay *self) {
     
     for (i=0; i<self->bufsize; i++) {
         del = delobj[i];
-        if (del < 0.)
-            del = 0.;
+        if (del < self->oneOverSr)
+            del = self->oneOverSr;
         else if (del > self->maxdelay)
             del = self->maxdelay;
         sampdel = del * self->sr;
@@ -130,8 +131,8 @@ Delay_process_ia(Delay *self) {
     MYFLT del = PyFloat_AS_DOUBLE(self->delay);
     MYFLT *fdb = Stream_getData((Stream *)self->feedback_stream);    
     
-    if (del < 0.)
-        del = 0.;
+    if (del < self->oneOverSr)
+        del = self->oneOverSr;
     else if (del > self->maxdelay)
         del = self->maxdelay;
     MYFLT sampdel = del * self->sr;
@@ -175,8 +176,8 @@ Delay_process_aa(Delay *self) {
     
     for (i=0; i<self->bufsize; i++) {
         del = delobj[i];
-        if (del < 0.)
-            del = 0.;
+        if (del < self->oneOverSr)
+            del = self->oneOverSr;
         else if (del > self->maxdelay)
             del = self->maxdelay;
         sampdel = del * self->sr;
@@ -325,6 +326,9 @@ Delay_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 	self->modebuffer[3] = 0;
 
     INIT_OBJECT_COMMON
+    
+    self->oneOverSr = 1.0 / self->sr;
+
     Stream_setFunctionPtr(self->stream, Delay_compute_next_data_frame);
     self->mode_func_ptr = Delay_setProcMode;
 
@@ -615,7 +619,7 @@ SDelay_process_i(SDelay *self) {
         for (i=0; i<self->bufsize; i++) {
             ind = self->in_count - sampdel;
             if (ind < 0)
-                ind += (self->size-1);
+                ind += self->size;
             self->data[i] = self->buffer[ind];
         
             self->buffer[self->in_count] = in[i];
@@ -648,7 +652,7 @@ SDelay_process_a(SDelay *self) {
         else {
             ind = self->in_count - sampdel;
             if (ind < 0)
-                ind += (self->size-1);
+                ind += self->size;
             self->data[i] = self->buffer[ind];
         }
         self->buffer[self->in_count++] = in[i];
@@ -3031,3 +3035,716 @@ Delay1_members,                                 /* tp_members */
 0,                                              /* tp_alloc */
 Delay1_new,                                     /* tp_new */
 };
+
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    PyObject *delay;
+    Stream *delay_stream;
+    PyObject *feedback;
+    Stream *feedback_stream;
+    MYFLT crossfade;
+    MYFLT maxdelay;
+    MYFLT oneOverSr;
+    MYFLT amp1;
+    MYFLT amp2;
+    MYFLT inc1;
+    MYFLT inc2;
+    int current;
+    long timer;
+    long size;
+    long in_count;
+    long sampdel;
+    MYFLT sampdel1;
+    MYFLT sampdel2;
+    int modebuffer[4];
+    MYFLT *buffer; // samples memory
+} SmoothDelay;
+
+static void
+SmoothDelay_process_ii(SmoothDelay *self) {
+    MYFLT val, xind, frac, sum;
+    int i;
+    long ind, xsamps = 0;
+
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT del = PyFloat_AS_DOUBLE(self->delay);
+    MYFLT feed = PyFloat_AS_DOUBLE(self->feedback);
+    
+    if (del < self->oneOverSr) del = self->oneOverSr;
+    else if (del > self->maxdelay) del = self->maxdelay;
+
+    if (feed < 0) feed = 0.0;
+    else if (feed > 1) feed = 1.0;
+
+    for (i=0; i<self->bufsize; i++) {
+        if (self->timer == 0) {
+            self->current = (self->current + 1) % 2;
+            self->sampdel = (long)(del * self->sr + 0.5);
+            xsamps = (long)(self->crossfade * self->sr + 0.5);
+            if (xsamps > self->sampdel) xsamps = self->sampdel;
+            if (xsamps <= 0) xsamps = 1;
+            if (self->current == 0) {
+                self->sampdel1 = del * self->sr;
+                self->inc1 = 1.0 / xsamps;
+                self->inc2 = -self->inc1;
+            }
+            else {
+                self->sampdel2 = del * self->sr;
+                self->inc2 = 1.0 / xsamps;
+                self->inc1 = -self->inc2;
+            }
+        }
+
+        xind = self->in_count - self->sampdel1;
+        while (xind < 0)
+            xind += self->size;
+        ind = (long)xind;
+        frac = xind - ind;
+        val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+        sum = val * self->amp1;
+        self->amp1 += self->inc1;
+        if (self->amp1 < 0) self->amp1 = 0.0;
+        else if (self->amp1 > 1) self->amp1 = 1.0; 
+
+        xind = self->in_count - self->sampdel2;
+        while (xind < 0)
+            xind += self->size;
+        ind = (long)xind;
+        frac = xind - ind;
+        val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+        sum += val * self->amp2;
+        self->amp2 += self->inc2;
+        if (self->amp2 < 0) self->amp2 = 0.0;
+        else if (self->amp2 > 1) self->amp2 = 1.0; 
+        
+        self->data[i] = sum;
+        
+        self->buffer[self->in_count] = in[i] + (sum * feed);
+        if (self->in_count == 0)
+            self->buffer[self->size] = self->buffer[0];
+        self->in_count++;
+        if (self->in_count >= self->size)
+            self->in_count = 0;
+            
+        self->timer++;
+        if (self->timer == self->sampdel)
+            self->timer = 0;
+    }
+}
+
+static void
+SmoothDelay_process_ai(SmoothDelay *self) {
+    MYFLT val, xind, frac, sum, del;
+    int i;
+    long ind, xsamps = 0;
+
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT *dl = Stream_getData((Stream *)self->delay_stream);
+    MYFLT feed = PyFloat_AS_DOUBLE(self->feedback);
+
+    if (feed < 0) feed = 0.0;
+    else if (feed > 1) feed = 1.0;
+
+    for (i=0; i<self->bufsize; i++) {
+        if (self->timer == 0) {
+            del = dl[i];
+            if (del < self->oneOverSr) del = self->oneOverSr;
+            else if (del > self->maxdelay) del = self->maxdelay;
+            self->current = (self->current + 1) % 2;
+            self->sampdel = (long)(del * self->sr + 0.5);
+            xsamps = (long)(self->crossfade * self->sr + 0.5);
+            if (xsamps > self->sampdel) xsamps = self->sampdel;
+            if (xsamps <= 0) xsamps = 1;
+            if (self->current == 0) {
+                self->sampdel1 = del * self->sr;
+                self->inc1 = 1.0 / xsamps;
+                self->inc2 = -self->inc1;
+            }
+            else {
+                self->sampdel2 = del * self->sr;
+                self->inc2 = 1.0 / xsamps;
+                self->inc1 = -self->inc2;
+            }
+        }
+
+        xind = self->in_count - self->sampdel1;
+        while (xind < 0)
+            xind += self->size;
+        ind = (long)xind;
+        frac = xind - ind;
+        val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+        sum = val * self->amp1;
+        self->amp1 += self->inc1;
+        if (self->amp1 < 0) self->amp1 = 0.0;
+        else if (self->amp1 > 1) self->amp1 = 1.0; 
+
+        xind = self->in_count - self->sampdel2;
+        while (xind < 0)
+            xind += self->size;
+        ind = (long)xind;
+        frac = xind - ind;
+        val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+        sum += val * self->amp2;
+        self->amp2 += self->inc2;
+        if (self->amp2 < 0) self->amp2 = 0.0;
+        else if (self->amp2 > 1) self->amp2 = 1.0; 
+        
+        self->data[i] = sum;
+        
+        self->buffer[self->in_count] = in[i] + (sum * feed);
+        if (self->in_count == 0)
+            self->buffer[self->size] = self->buffer[0];
+        self->in_count++;
+        if (self->in_count >= self->size)
+            self->in_count = 0;
+            
+        self->timer++;
+        if (self->timer == self->sampdel)
+            self->timer = 0;
+    }
+}
+
+static void
+SmoothDelay_process_ia(SmoothDelay *self) {
+    MYFLT val, xind, frac, sum, feed;
+    int i;
+    long ind, xsamps = 0;
+
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT del = PyFloat_AS_DOUBLE(self->delay);
+    MYFLT *fd = Stream_getData((Stream *)self->feedback_stream);
+    
+    if (del < self->oneOverSr) del = self->oneOverSr;
+    else if (del > self->maxdelay) del = self->maxdelay;
+
+    for (i=0; i<self->bufsize; i++) {
+        feed = fd[i];
+        if (feed < 0) feed = 0.0;
+        else if (feed > 1) feed = 1.0;
+        if (self->timer == 0) {
+            self->current = (self->current + 1) % 2;
+            self->sampdel = (long)(del * self->sr + 0.5);
+            xsamps = (long)(self->crossfade * self->sr + 0.5);
+            if (xsamps > self->sampdel) xsamps = self->sampdel;
+            if (xsamps <= 0) xsamps = 1;
+            if (self->current == 0) {
+                self->sampdel1 = del * self->sr;
+                self->inc1 = 1.0 / xsamps;
+                self->inc2 = -self->inc1;
+            }
+            else {
+                self->sampdel2 = del * self->sr;
+                self->inc2 = 1.0 / xsamps;
+                self->inc1 = -self->inc2;
+            }
+        }
+
+        xind = self->in_count - self->sampdel1;
+        while (xind < 0)
+            xind += self->size;
+        ind = (long)xind;
+        frac = xind - ind;
+        val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+        sum = val * self->amp1;
+        self->amp1 += self->inc1;
+        if (self->amp1 < 0) self->amp1 = 0.0;
+        else if (self->amp1 > 1) self->amp1 = 1.0; 
+
+        xind = self->in_count - self->sampdel2;
+        while (xind < 0)
+            xind += self->size;
+        ind = (long)xind;
+        frac = xind - ind;
+        val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+        sum += val * self->amp2;
+        self->amp2 += self->inc2;
+        if (self->amp2 < 0) self->amp2 = 0.0;
+        else if (self->amp2 > 1) self->amp2 = 1.0; 
+        
+        self->data[i] = sum;
+        
+        self->buffer[self->in_count] = in[i] + (sum * feed);
+        if (self->in_count == 0)
+            self->buffer[self->size] = self->buffer[0];
+        self->in_count++;
+        if (self->in_count >= self->size)
+            self->in_count = 0;
+            
+        self->timer++;
+        if (self->timer == self->sampdel)
+            self->timer = 0;
+    }
+}
+
+static void
+SmoothDelay_process_aa(SmoothDelay *self) {
+    MYFLT val, xind, frac, sum, del, feed;
+    int i;
+    long ind, xsamps = 0;
+
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT *dl = Stream_getData((Stream *)self->delay_stream);
+    MYFLT *fd = Stream_getData((Stream *)self->feedback_stream);
+
+    for (i=0; i<self->bufsize; i++) {
+        feed = fd[i];
+        if (feed < 0) feed = 0.0;
+        else if (feed > 1) feed = 1.0;
+        if (self->timer == 0) {
+            del = dl[i];
+            if (del < self->oneOverSr) del = self->oneOverSr;
+            else if (del > self->maxdelay) del = self->maxdelay;
+            self->current = (self->current + 1) % 2;
+            self->sampdel = (long)(del * self->sr + 0.5);
+            xsamps = (long)(self->crossfade * self->sr + 0.5);
+            if (xsamps > self->sampdel) xsamps = self->sampdel;
+            if (xsamps <= 0) xsamps = 1;
+            if (self->current == 0) {
+                self->sampdel1 = del * self->sr;
+                self->inc1 = 1.0 / xsamps;
+                self->inc2 = -self->inc1;
+            }
+            else {
+                self->sampdel2 = del * self->sr;
+                self->inc2 = 1.0 / xsamps;
+                self->inc1 = -self->inc2;
+            }
+        }
+
+        xind = self->in_count - self->sampdel1;
+        while (xind < 0)
+            xind += self->size;
+        ind = (long)xind;
+        frac = xind - ind;
+        val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+        sum = val * self->amp1;
+        self->amp1 += self->inc1;
+        if (self->amp1 < 0) self->amp1 = 0.0;
+        else if (self->amp1 > 1) self->amp1 = 1.0; 
+
+        xind = self->in_count - self->sampdel2;
+        while (xind < 0)
+            xind += self->size;
+        ind = (long)xind;
+        frac = xind - ind;
+        val = self->buffer[ind] + (self->buffer[ind+1] - self->buffer[ind]) * frac;
+        sum += val * self->amp2;
+        self->amp2 += self->inc2;
+        if (self->amp2 < 0) self->amp2 = 0.0;
+        else if (self->amp2 > 1) self->amp2 = 1.0; 
+        
+        self->data[i] = sum;
+        
+        self->buffer[self->in_count] = in[i] + (sum * feed);
+        if (self->in_count == 0)
+            self->buffer[self->size] = self->buffer[0];
+        self->in_count++;
+        if (self->in_count >= self->size)
+            self->in_count = 0;
+            
+        self->timer++;
+        if (self->timer == self->sampdel)
+            self->timer = 0;
+    }
+}
+
+static void SmoothDelay_postprocessing_ii(SmoothDelay *self) { POST_PROCESSING_II };
+static void SmoothDelay_postprocessing_ai(SmoothDelay *self) { POST_PROCESSING_AI };
+static void SmoothDelay_postprocessing_ia(SmoothDelay *self) { POST_PROCESSING_IA };
+static void SmoothDelay_postprocessing_aa(SmoothDelay *self) { POST_PROCESSING_AA };
+static void SmoothDelay_postprocessing_ireva(SmoothDelay *self) { POST_PROCESSING_IREVA };
+static void SmoothDelay_postprocessing_areva(SmoothDelay *self) { POST_PROCESSING_AREVA };
+static void SmoothDelay_postprocessing_revai(SmoothDelay *self) { POST_PROCESSING_REVAI };
+static void SmoothDelay_postprocessing_revaa(SmoothDelay *self) { POST_PROCESSING_REVAA };
+static void SmoothDelay_postprocessing_revareva(SmoothDelay *self) { POST_PROCESSING_REVAREVA };
+
+static void
+SmoothDelay_setProcMode(SmoothDelay *self)
+{
+    int procmode, muladdmode;
+    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+	switch (procmode) {
+        case 0:    
+            self->proc_func_ptr = SmoothDelay_process_ii;
+            break;
+        case 1:    
+            self->proc_func_ptr = SmoothDelay_process_ai;
+            break;
+        case 10:    
+            self->proc_func_ptr = SmoothDelay_process_ia;
+            break;
+        case 11:    
+            self->proc_func_ptr = SmoothDelay_process_aa;
+            break;
+    } 
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = SmoothDelay_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = SmoothDelay_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = SmoothDelay_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = SmoothDelay_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = SmoothDelay_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = SmoothDelay_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = SmoothDelay_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = SmoothDelay_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = SmoothDelay_postprocessing_revareva;
+            break;
+    } 
+}
+
+static void
+SmoothDelay_compute_next_data_frame(SmoothDelay *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+SmoothDelay_traverse(SmoothDelay *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);    
+    Py_VISIT(self->delay);    
+    Py_VISIT(self->delay_stream);    
+    Py_VISIT(self->feedback);    
+    Py_VISIT(self->feedback_stream);    
+    return 0;
+}
+
+static int 
+SmoothDelay_clear(SmoothDelay *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);    
+    Py_CLEAR(self->delay);    
+    Py_CLEAR(self->delay_stream);    
+    Py_CLEAR(self->feedback);    
+    Py_CLEAR(self->feedback_stream);    
+    return 0;
+}
+
+static void
+SmoothDelay_dealloc(SmoothDelay* self)
+{
+    pyo_DEALLOC
+    free(self->buffer);
+    SmoothDelay_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+SmoothDelay_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *inputtmp, *input_streamtmp, *delaytmp=NULL, *feedbacktmp=NULL, *multmp=NULL, *addtmp=NULL;
+    SmoothDelay *self;
+    self = (SmoothDelay *)type->tp_alloc(type, 0);
+
+    self->delay = PyFloat_FromDouble(0.25);
+    self->feedback = PyFloat_FromDouble(0);
+    self->crossfade = 0.05;
+    self->maxdelay = 1;
+    self->in_count = 0;
+    self->current = 1;
+    self->timer = 0;
+    self->amp1 = 0.0;
+    self->amp2 = 1.0;
+    self->inc1 = self->inc2 = 0.0;
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+	self->modebuffer[2] = 0;
+	self->modebuffer[3] = 0;
+
+    INIT_OBJECT_COMMON
+    
+    self->oneOverSr = self->sampdel1 = self->sampdel2 = 1.0 / self->sr;
+
+    Stream_setFunctionPtr(self->stream, SmoothDelay_compute_next_data_frame);
+    self->mode_func_ptr = SmoothDelay_setProcMode;
+
+    static char *kwlist[] = {"input", "delay", "feedback", "crossfade", "maxdelay", "mul", "add", NULL};
+
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_OOFFOO, kwlist, &inputtmp, &delaytmp, &feedbacktmp, &self->crossfade, &self->maxdelay, &multmp, &addtmp))
+        Py_RETURN_NONE;
+
+    INIT_INPUT_STREAM
+
+    if (delaytmp) {
+        PyObject_CallMethod((PyObject *)self, "setDelay", "O", delaytmp);
+    }
+
+    if (feedbacktmp) {
+        PyObject_CallMethod((PyObject *)self, "setFeedback", "O", feedbacktmp);
+    }
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+            
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+    self->size = (long)(self->maxdelay * self->sr + 0.5);
+
+    self->buffer = (MYFLT *)realloc(self->buffer, (self->size+1) * sizeof(MYFLT));
+    for (i=0; i<(self->size+1); i++) {
+        self->buffer[i] = 0.;
+    }    
+
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * SmoothDelay_getServer(SmoothDelay* self) { GET_SERVER };
+static PyObject * SmoothDelay_getStream(SmoothDelay* self) { GET_STREAM };
+static PyObject * SmoothDelay_setMul(SmoothDelay *self, PyObject *arg) { SET_MUL };	
+static PyObject * SmoothDelay_setAdd(SmoothDelay *self, PyObject *arg) { SET_ADD };	
+static PyObject * SmoothDelay_setSub(SmoothDelay *self, PyObject *arg) { SET_SUB };	
+static PyObject * SmoothDelay_setDiv(SmoothDelay *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * SmoothDelay_play(SmoothDelay *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * SmoothDelay_out(SmoothDelay *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * SmoothDelay_stop(SmoothDelay *self) { STOP };
+
+static PyObject * SmoothDelay_multiply(SmoothDelay *self, PyObject *arg) { MULTIPLY };
+static PyObject * SmoothDelay_inplace_multiply(SmoothDelay *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * SmoothDelay_add(SmoothDelay *self, PyObject *arg) { ADD };
+static PyObject * SmoothDelay_inplace_add(SmoothDelay *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * SmoothDelay_sub(SmoothDelay *self, PyObject *arg) { SUB };
+static PyObject * SmoothDelay_inplace_sub(SmoothDelay *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * SmoothDelay_div(SmoothDelay *self, PyObject *arg) { DIV };
+static PyObject * SmoothDelay_inplace_div(SmoothDelay *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+SmoothDelay_setDelay(SmoothDelay *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->delay);
+	if (isNumber == 1) {
+		self->delay = PyNumber_Float(tmp);
+        self->modebuffer[2] = 0;
+	}
+	else {
+		self->delay = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->delay, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->delay_stream);
+        self->delay_stream = (Stream *)streamtmp;
+		self->modebuffer[2] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+SmoothDelay_setFeedback(SmoothDelay *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+    
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->feedback);
+	if (isNumber == 1) {
+		self->feedback = PyNumber_Float(tmp);
+        self->modebuffer[3] = 0;
+	}
+	else {
+		self->feedback = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->feedback, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->feedback_stream);
+        self->feedback_stream = (Stream *)streamtmp;
+		self->modebuffer[3] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+SmoothDelay_setCrossfade(SmoothDelay *self, PyObject *arg)
+{
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	if (isNumber == 1) {
+		self->crossfade = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+	}
+  
+	Py_RETURN_NONE;
+}
+
+static PyObject *
+SmoothDelay_reset(SmoothDelay *self)
+{
+    int i;
+    for (i=0; i<(self->size+1); i++) {
+        self->buffer[i] = 0.;
+    }    
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMemberDef SmoothDelay_members[] = {
+    {"server", T_OBJECT_EX, offsetof(SmoothDelay, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(SmoothDelay, stream), 0, "Stream object."},
+    {"input", T_OBJECT_EX, offsetof(SmoothDelay, input), 0, "Input sound object."},
+    {"delay", T_OBJECT_EX, offsetof(SmoothDelay, delay), 0, "SmoothDelay time in seconds."},
+    {"feedback", T_OBJECT_EX, offsetof(SmoothDelay, feedback), 0, "Feedback value."},
+    {"mul", T_OBJECT_EX, offsetof(SmoothDelay, mul), 0, "Mul factor."},
+    {"add", T_OBJECT_EX, offsetof(SmoothDelay, add), 0, "Add factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef SmoothDelay_methods[] = {
+    {"getServer", (PyCFunction)SmoothDelay_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)SmoothDelay_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)SmoothDelay_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"out", (PyCFunction)SmoothDelay_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+    {"stop", (PyCFunction)SmoothDelay_stop, METH_NOARGS, "Stops computing."},
+	{"setDelay", (PyCFunction)SmoothDelay_setDelay, METH_O, "Sets delay time in seconds."},
+    {"setFeedback", (PyCFunction)SmoothDelay_setFeedback, METH_O, "Sets feedback value between 0 -> 1."},
+    {"setCrossfade", (PyCFunction)SmoothDelay_setCrossfade, METH_O, "Sets crossfade time."},
+    {"reset", (PyCFunction)SmoothDelay_reset, METH_NOARGS, "Resets the memory buffer to zeros."},
+	{"setMul", (PyCFunction)SmoothDelay_setMul, METH_O, "Sets oscillator mul factor."},
+	{"setAdd", (PyCFunction)SmoothDelay_setAdd, METH_O, "Sets oscillator add factor."},
+    {"setSub", (PyCFunction)SmoothDelay_setSub, METH_O, "Sets inverse add factor."},
+    {"setDiv", (PyCFunction)SmoothDelay_setDiv, METH_O, "Sets inverse mul factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyNumberMethods SmoothDelay_as_number = {
+    (binaryfunc)SmoothDelay_add,                      /*nb_add*/
+    (binaryfunc)SmoothDelay_sub,                 /*nb_subtract*/
+    (binaryfunc)SmoothDelay_multiply,                 /*nb_multiply*/
+    (binaryfunc)SmoothDelay_div,                   /*nb_divide*/
+    0,                /*nb_remainder*/
+    0,                   /*nb_divmod*/
+    0,                   /*nb_power*/
+    0,                  /*nb_neg*/
+    0,                /*nb_pos*/
+    0,                  /*(unaryfunc)array_abs,*/
+    0,                    /*nb_nonzero*/
+    0,                    /*nb_invert*/
+    0,               /*nb_lshift*/
+    0,              /*nb_rshift*/
+    0,              /*nb_and*/
+    0,              /*nb_xor*/
+    0,               /*nb_or*/
+    0,                                          /*nb_coerce*/
+    0,                       /*nb_int*/
+    0,                      /*nb_long*/
+    0,                     /*nb_float*/
+    0,                       /*nb_oct*/
+    0,                       /*nb_hex*/
+    (binaryfunc)SmoothDelay_inplace_add,              /*inplace_add*/
+    (binaryfunc)SmoothDelay_inplace_sub,         /*inplace_subtract*/
+    (binaryfunc)SmoothDelay_inplace_multiply,         /*inplace_multiply*/
+    (binaryfunc)SmoothDelay_inplace_div,           /*inplace_divide*/
+    0,        /*inplace_remainder*/
+    0,           /*inplace_power*/
+    0,       /*inplace_lshift*/
+    0,      /*inplace_rshift*/
+    0,      /*inplace_and*/
+    0,      /*inplace_xor*/
+    0,       /*inplace_or*/
+    0,             /*nb_floor_divide*/
+    0,              /*nb_true_divide*/
+    0,     /*nb_inplace_floor_divide*/
+    0,      /*nb_inplace_true_divide*/
+    0,                     /* nb_index */
+};
+
+PyTypeObject SmoothDelayType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "_pyo.SmoothDelay_base",         /*tp_name*/
+    sizeof(SmoothDelay),         /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)SmoothDelay_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    &SmoothDelay_as_number,             /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+    "SmoothDelay objects. Delay signal by x samples.",           /* tp_doc */
+    (traverseproc)SmoothDelay_traverse,   /* tp_traverse */
+    (inquiry)SmoothDelay_clear,           /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    SmoothDelay_methods,             /* tp_methods */
+    SmoothDelay_members,             /* tp_members */
+    0,                      /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,      /* tp_init */
+    0,                         /* tp_alloc */
+    SmoothDelay_new,                 /* tp_new */
+};
diff --git a/src/objects/fadermodule.c b/src/objects/fadermodule.c
index 906d3c8..bd6310e 100644
--- a/src/objects/fadermodule.c
+++ b/src/objects/fadermodule.c
@@ -29,6 +29,7 @@ typedef struct {
     pyo_audio_HEAD
     int modebuffer[2];
     int fademode;
+    int ended;
     MYFLT topValue;
     MYFLT attack;
     MYFLT release;
@@ -52,11 +53,18 @@ Fader_generate_auto(Fader *self) {
     MYFLT val;
     int i;
 
+    if (self->ended == 1) {
+        Fader_internal_stop((Fader *)self);
+        return;
+    }
+
     for (i=0; i<self->bufsize; i++) {
         if (self->currentTime <= self->attack)
             val = self->currentTime / self->attack;
-        else if (self->currentTime > self->duration)
+        else if (self->currentTime > self->duration) {
             val = 0.;
+            self->ended = 1;
+        }
         else if (self->currentTime >= (self->duration - self->release))
             val = (self->duration - self->currentTime) / self->release;
         else
@@ -71,6 +79,11 @@ static void
 Fader_generate_wait(Fader *self) {
     MYFLT val;
     int i;
+
+    if (self->fademode == 1 && self->currentTime > self->release) {
+        Fader_internal_stop((Fader *)self);
+        return;
+    }
     
     for (i=0; i<self->bufsize; i++) {
         if (self->fademode == 0) {
@@ -90,8 +103,6 @@ Fader_generate_wait(Fader *self) {
         self->data[i] = val;
         self->currentTime += self->sampleToSec;    
     }
-    if (self->fademode == 1 && self->currentTime > self->release)
-        Fader_internal_stop((Fader *)self);
 }
 
 static void Fader_postprocessing_ii(Fader *self) { POST_PROCESSING_II };
@@ -187,6 +198,7 @@ Fader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 	self->modebuffer[1] = 0;
     self->topValue = 0.0;
     self->fademode = 0;
+    self->ended = 0;
     self->attack = 0.01;
     self->release = 0.1;
     self->duration = 0.0;
@@ -230,6 +242,7 @@ static PyObject * Fader_setDiv(Fader *self, PyObject *arg) { SET_DIV };
 static PyObject * Fader_play(Fader *self, PyObject *args, PyObject *kwds) 
 {
     self->fademode = 0;
+    self->ended = 0;
     self->currentTime = 0.0;
     (*self->mode_func_ptr)(self);
     PLAY
@@ -427,8 +440,10 @@ Adsr_generate_auto(Adsr *self) {
             val = self->currentTime * invatt;
         else if (self->currentTime <= (self->attack + self->decay))
             val = (self->decay - (self->currentTime - self->attack)) * invdec * (1. - self->sustain) + self->sustain;
-        else if (self->currentTime > self->duration)
+        else if (self->currentTime > self->duration) {
             val = 0.;
+            Adsr_internal_stop((Adsr *)self);
+        }
         else if (self->currentTime >= (self->duration - self->release))
             val = (self->duration - self->currentTime) * invrel * self->sustain;
         else
diff --git a/src/objects/fftmodule.c b/src/objects/fftmodule.c
index 39ca586..f9e6106 100644
--- a/src/objects/fftmodule.c
+++ b/src/objects/fftmodule.c
@@ -3279,7 +3279,7 @@ CvlVerb_alloc_memories(CvlVerb *self) {
     self->inframe = (MYFLT *)realloc(self->inframe, self->size2 * sizeof(MYFLT));
     self->outframe = (MYFLT *)realloc(self->outframe, self->size2 * sizeof(MYFLT));       
     self->last_half_frame = (MYFLT *)realloc(self->last_half_frame, self->size * sizeof(MYFLT));    
-    self->input_buffer = (MYFLT *)realloc(self->output_buffer, self->size * sizeof(MYFLT));    
+    self->input_buffer = (MYFLT *)realloc(self->input_buffer, self->size * sizeof(MYFLT));    
     self->output_buffer = (MYFLT *)realloc(self->output_buffer, self->size2 * sizeof(MYFLT));    
     for (i=0; i<self->size2; i++)
         self->inframe[i] = self->outframe[i] = self->output_buffer[i] = 0.0;
diff --git a/src/objects/filtremodule.c b/src/objects/filtremodule.c
index d848581..eb8fb7f 100644
--- a/src/objects/filtremodule.c
+++ b/src/objects/filtremodule.c
@@ -5792,6 +5792,7 @@ typedef struct {
     MYFLT factor;
     int stages;
     int last_stages;
+    int flag;
     MYFLT nyquist;
     MYFLT twoPiOnSr;
     int modebuffer[6]; // need at least 2 slots for mul & add 
@@ -5829,9 +5830,9 @@ Vocoder_allocate_memories(Vocoder *self)
         for (j=0; j<2; j++) {
             i2j = i * 2 + j;
             self->yy1[i2j] = self->yy2[i2j] = self->y1[i2j] = self->y2[i2j] = 0.0;
-
         }
-    }    
+    }
+    self->flag = 1; 
 }
 
 static void
@@ -5887,11 +5888,12 @@ Vocoder_filters_iii(Vocoder *self) {
         self->factor = MYEXP(-1.0 / (self->sr / ((slope * 48.0) + 2.0)));
     }
 
-    if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+    if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
         self->last_freq = freq;
         self->last_spread = spread;
         self->last_q = q;
         self->last_stages = self->stages;
+        self->flag = 0;
         Vocoder_compute_variables(self, freq, spread, q);
     }
     
@@ -5971,11 +5973,12 @@ Vocoder_filters_aii(Vocoder *self) {
         else if (count >= maxcount)
             count = 0;
         count++;
-        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
             self->last_freq = freq;
             self->last_spread = spread;
             self->last_q = q;
             self->last_stages = self->stages;
+            self->flag = 0;
             Vocoder_compute_variables(self, freq, spread, q);
         }
         output = 0.0;
@@ -6053,11 +6056,12 @@ Vocoder_filters_iai(Vocoder *self) {
         else if (count >= maxcount)
             count = 0;
         count++;
-        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
             self->last_freq = freq;
             self->last_spread = spread;
             self->last_q = q;
             self->last_stages = self->stages;
+            self->flag = 0;
             Vocoder_compute_variables(self, freq, spread, q);
         }
         output = 0.0;
@@ -6138,11 +6142,12 @@ Vocoder_filters_aai(Vocoder *self) {
         else if (count >= maxcount)
             count = 0;
         count++;
-        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
             self->last_freq = freq;
             self->last_spread = spread;
             self->last_q = q;
             self->last_stages = self->stages;
+            self->flag = 0;
             Vocoder_compute_variables(self, freq, spread, q);
         }
         output = 0.0;
@@ -6220,11 +6225,12 @@ Vocoder_filters_iia(Vocoder *self) {
         else if (count >= maxcount)
             count = 0;
         count++;
-        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
             self->last_freq = freq;
             self->last_spread = spread;
             self->last_q = q;
             self->last_stages = self->stages;
+            self->flag = 0;
             Vocoder_compute_variables(self, freq, spread, q);
         }
         output = 0.0;
@@ -6304,11 +6310,12 @@ Vocoder_filters_aia(Vocoder *self) {
         else if (count >= maxcount)
             count = 0;
         count++;
-        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
             self->last_freq = freq;
             self->last_spread = spread;
             self->last_q = q;
             self->last_stages = self->stages;
+            self->flag = 0;
             Vocoder_compute_variables(self, freq, spread, q);
         }
         output = 0.0;
@@ -6388,11 +6395,12 @@ Vocoder_filters_iaa(Vocoder *self) {
         else if (count >= maxcount)
             count = 0;
         count++;
-        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
             self->last_freq = freq;
             self->last_spread = spread;
             self->last_q = q;
             self->last_stages = self->stages;
+            self->flag = 0;
             Vocoder_compute_variables(self, freq, spread, q);
         }
         output = 0.0;
@@ -6474,11 +6482,12 @@ Vocoder_filters_aaa(Vocoder *self) {
         else if (count >= maxcount)
             count = 0;
         count++;
-        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages) {
+        if (freq != self->last_freq || spread != self->last_spread || q != self->last_q || self->stages != self->last_stages || self->flag) {
             self->last_freq = freq;
             self->last_spread = spread;
             self->last_q = q;
             self->last_stages = self->stages;
+            self->flag = 0;
             Vocoder_compute_variables(self, freq, spread, q);
         }
         output = 0.0;
@@ -6674,6 +6683,7 @@ Vocoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->factor = 0.99;
     self->stages = 24;
     self->last_stages = -1;
+    self->flag = 0;
 	self->modebuffer[0] = 0;
 	self->modebuffer[1] = 0;
 	self->modebuffer[2] = 0;
@@ -6697,11 +6707,8 @@ Vocoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
 
     if ( PyObject_HasAttrString((PyObject *)input2tmp, "server") == 0 ) {
-        PySys_WriteStderr("TypeError: \"input2\" argument of Vocoder must be a PyoObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of Vocoder must be a PyoObject.\n");
+        Py_RETURN_NONE;
     }    
     Py_XDECREF(self->input2);
     self->input2 = input2tmp;
@@ -11024,3 +11031,510 @@ PyTypeObject ButBRType = {
     0,                                              /* tp_alloc */
     ButBR_new,                                     /* tp_new */
 };
+
+/****************/
+/** ComplexRes **/
+/****************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    PyObject *freq;
+    Stream *freq_stream;
+    PyObject *decay;
+    Stream *decay_stream;
+    int modebuffer[4]; // need at least 2 slots for mul & add 
+    MYFLT last_freq;
+    MYFLT last_decay;
+    MYFLT oneOnSr;
+    // variables
+    MYFLT res;
+    MYFLT norm;
+    MYFLT coeffx;
+    MYFLT coeffy;
+    // sample memories
+    MYFLT x;
+    MYFLT y;
+} ComplexRes;
+
+static void
+ComplexRes_filters_ii(ComplexRes *self) {
+    int i;
+    MYFLT ang, x, y;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT freq = PyFloat_AS_DOUBLE(self->freq); 
+    MYFLT decay = PyFloat_AS_DOUBLE(self->decay);
+    
+    if (decay <= 0.0001)
+        decay = 0.0001;
+
+    if (decay != self->last_decay || freq != self->last_freq) {
+        self->res = MYEXP(-1.0/(decay*self->sr));
+        //self->norm = (1.0-self->res*self->res)/self->res;
+        self->last_decay = decay;
+        ang = (freq*self->oneOnSr)*TWOPI;
+        self->coeffx = self->res * MYCOS(ang);
+        self->coeffy = self->res * MYSIN(ang);
+        self->last_freq = freq;
+    }
+
+    for (i=0; i<self->bufsize; i++) {
+        x = self->coeffx * self->x - self->coeffy * self->y + in[i];
+        y = self->coeffy * self->x + self->coeffx * self->y;
+        self->data[i] = y * self->norm;        
+        self->x = x;
+        self->y = y;
+    }
+}
+
+static void
+ComplexRes_filters_ai(ComplexRes *self) {
+    int i, check = 0;
+    MYFLT freq, ang, x, y;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
+    MYFLT decay = PyFloat_AS_DOUBLE(self->decay);
+
+    if (decay <= 0.0001)
+        decay = 0.0001;
+
+    if (decay != self->last_decay) {
+        self->res = MYEXP(-1.0/(decay*self->sr));
+        //self->norm = (1.0-self->res*self->res)/self->res;
+        self->last_decay = decay;
+        check = 1;
+    }
+    
+    for (i=0; i<self->bufsize; i++) {
+        freq = fr[i];
+        if (freq != self->last_freq || check) {
+            ang = (freq*self->oneOnSr)*TWOPI;
+            self->coeffx = self->res * MYCOS(ang);
+            self->coeffy = self->res * MYSIN(ang);
+            self->last_freq = freq;
+            check = 0;
+        }
+        x = self->coeffx * self->x - self->coeffy * self->y + in[i];
+        y = self->coeffy * self->x + self->coeffx * self->y;
+        self->data[i] = y * self->norm;        
+        self->x = x;
+        self->y = y;
+    }
+}
+
+static void
+ComplexRes_filters_ia(ComplexRes *self) {
+    int i;
+    MYFLT decay, ang, x, y;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT freq = PyFloat_AS_DOUBLE(self->freq);
+    MYFLT *dec = Stream_getData((Stream *)self->decay_stream);
+    
+    for (i=0; i<self->bufsize; i++) {
+        decay = dec[i];
+        if (decay <= 0.0001)
+            decay = 0.0001;
+        if (freq != self->last_freq || decay != self->last_decay) {
+            self->res = MYEXP(-1.0/(decay*self->sr));
+            //self->norm = (1.0-self->res*self->res)/self->res;
+            self->last_decay = decay;
+            ang = (freq*self->oneOnSr)*TWOPI;
+            self->coeffx = self->res * MYCOS(ang);
+            self->coeffy = self->res * MYSIN(ang);
+            self->last_freq = freq;
+        }
+        x = self->coeffx * self->x - self->coeffy * self->y + in[i];
+        y = self->coeffy * self->x + self->coeffx * self->y;
+        self->data[i] = y * self->norm;        
+        self->x = x;
+        self->y = y;
+    }
+}
+
+static void
+ComplexRes_filters_aa(ComplexRes *self) {
+    int i;
+    MYFLT freq, decay, ang, x, y;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT *fr = Stream_getData((Stream *)self->freq_stream);
+    MYFLT *dec = Stream_getData((Stream *)self->decay_stream);
+    
+    for (i=0; i<self->bufsize; i++) {
+        freq = fr[i];
+        decay = dec[i];
+        if (decay <= 0.0001)
+            decay = 0.0001;
+        if (freq != self->last_freq || decay != self->last_decay) {
+            self->res = MYEXP(-1.0/(decay*self->sr));
+            //self->norm = (1.0-self->res*self->res)/self->res;
+            self->last_decay = decay;
+            ang = (freq*self->oneOnSr)*TWOPI;
+            self->coeffx = self->res * MYCOS(ang);
+            self->coeffy = self->res * MYSIN(ang);
+            self->last_freq = freq;
+        }
+        x = self->coeffx * self->x - self->coeffy * self->y + in[i];
+        y = self->coeffy * self->x + self->coeffx * self->y;
+        self->data[i] = y * self->norm;        
+        self->x = x;
+        self->y = y;
+    }
+}
+
+static void ComplexRes_postprocessing_ii(ComplexRes *self) { POST_PROCESSING_II };
+static void ComplexRes_postprocessing_ai(ComplexRes *self) { POST_PROCESSING_AI };
+static void ComplexRes_postprocessing_ia(ComplexRes *self) { POST_PROCESSING_IA };
+static void ComplexRes_postprocessing_aa(ComplexRes *self) { POST_PROCESSING_AA };
+static void ComplexRes_postprocessing_ireva(ComplexRes *self) { POST_PROCESSING_IREVA };
+static void ComplexRes_postprocessing_areva(ComplexRes *self) { POST_PROCESSING_AREVA };
+static void ComplexRes_postprocessing_revai(ComplexRes *self) { POST_PROCESSING_REVAI };
+static void ComplexRes_postprocessing_revaa(ComplexRes *self) { POST_PROCESSING_REVAA };
+static void ComplexRes_postprocessing_revareva(ComplexRes *self) { POST_PROCESSING_REVAREVA };
+
+static void
+ComplexRes_setProcMode(ComplexRes *self)
+{
+    int procmode, muladdmode;
+    procmode = self->modebuffer[2] + self->modebuffer[3] * 10;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+	switch (procmode) {
+        case 0:    
+            self->proc_func_ptr = ComplexRes_filters_ii;
+            break;
+        case 1:    
+            self->proc_func_ptr = ComplexRes_filters_ai;
+            break;
+        case 10:        
+            self->proc_func_ptr = ComplexRes_filters_ia;
+            break;
+        case 11:    
+            self->proc_func_ptr = ComplexRes_filters_aa;
+            break;
+    } 
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = ComplexRes_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = ComplexRes_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = ComplexRes_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = ComplexRes_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = ComplexRes_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = ComplexRes_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = ComplexRes_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = ComplexRes_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = ComplexRes_postprocessing_revareva;
+            break;
+    }   
+}
+
+static void
+ComplexRes_compute_next_data_frame(ComplexRes *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+ComplexRes_traverse(ComplexRes *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    Py_VISIT(self->freq);    
+    Py_VISIT(self->freq_stream);    
+    Py_VISIT(self->decay);    
+    Py_VISIT(self->decay_stream);    
+    return 0;
+}
+
+static int 
+ComplexRes_clear(ComplexRes *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    Py_CLEAR(self->freq);    
+    Py_CLEAR(self->freq_stream);    
+    Py_CLEAR(self->decay);    
+    Py_CLEAR(self->decay_stream);    
+    return 0;
+}
+
+static void
+ComplexRes_dealloc(ComplexRes* self)
+{
+    pyo_DEALLOC
+    ComplexRes_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+ComplexRes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *inputtmp, *input_streamtmp, *freqtmp=NULL, *decaytmp=NULL, *multmp=NULL, *addtmp=NULL;
+    ComplexRes *self;
+    self = (ComplexRes *)type->tp_alloc(type, 0);
+    
+    self->freq = PyFloat_FromDouble(1000);
+    self->decay = PyFloat_FromDouble(.25);
+    self->last_freq = self->last_decay = -1.0;
+    self->x = self->y = 0.0;
+    self->res = 1.0;
+    self->norm = 0.01; /* normalization factor fixed at -40 dB */
+    self->coeffx = self->coeffy = 0.0;
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+	self->modebuffer[2] = 0;
+	self->modebuffer[3] = 0;
+    
+    INIT_OBJECT_COMMON
+    
+    self->oneOnSr = 1.0 / self->sr;
+
+    Stream_setFunctionPtr(self->stream, ComplexRes_compute_next_data_frame);
+    self->mode_func_ptr = ComplexRes_setProcMode;
+
+    static char *kwlist[] = {"input", "freq", "decay", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OOOO", kwlist, &inputtmp, &freqtmp, &decaytmp, &multmp, &addtmp))
+        Py_RETURN_NONE;
+    
+    INIT_INPUT_STREAM
+    
+    if (freqtmp) {
+        PyObject_CallMethod((PyObject *)self, "setFreq", "O", freqtmp);
+    }
+    
+    if (decaytmp) {
+        PyObject_CallMethod((PyObject *)self, "setDecay", "O", decaytmp);
+    }
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * ComplexRes_getServer(ComplexRes* self) { GET_SERVER };
+static PyObject * ComplexRes_getStream(ComplexRes* self) { GET_STREAM };
+static PyObject * ComplexRes_setMul(ComplexRes *self, PyObject *arg) { SET_MUL };	
+static PyObject * ComplexRes_setAdd(ComplexRes *self, PyObject *arg) { SET_ADD };	
+static PyObject * ComplexRes_setSub(ComplexRes *self, PyObject *arg) { SET_SUB };	
+static PyObject * ComplexRes_setDiv(ComplexRes *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * ComplexRes_play(ComplexRes *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * ComplexRes_out(ComplexRes *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * ComplexRes_stop(ComplexRes *self) { STOP };
+
+static PyObject * ComplexRes_multiply(ComplexRes *self, PyObject *arg) { MULTIPLY };
+static PyObject * ComplexRes_inplace_multiply(ComplexRes *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * ComplexRes_add(ComplexRes *self, PyObject *arg) { ADD };
+static PyObject * ComplexRes_inplace_add(ComplexRes *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * ComplexRes_sub(ComplexRes *self, PyObject *arg) { SUB };
+static PyObject * ComplexRes_inplace_sub(ComplexRes *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * ComplexRes_div(ComplexRes *self, PyObject *arg) { DIV };
+static PyObject * ComplexRes_inplace_div(ComplexRes *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+ComplexRes_setFreq(ComplexRes *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->freq);
+	if (isNumber == 1) {
+		self->freq = PyNumber_Float(tmp);
+        self->modebuffer[2] = 0;
+	}
+	else {
+		self->freq = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->freq, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->freq_stream);
+        self->freq_stream = (Stream *)streamtmp;
+		self->modebuffer[2] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+ComplexRes_setDecay(ComplexRes *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->decay);
+	if (isNumber == 1) {
+		self->decay = PyNumber_Float(tmp);
+        self->modebuffer[3] = 0;
+	}
+	else {
+		self->decay = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->decay, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->decay_stream);
+        self->decay_stream = (Stream *)streamtmp;
+		self->modebuffer[3] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyMemberDef ComplexRes_members[] = {
+{"server", T_OBJECT_EX, offsetof(ComplexRes, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(ComplexRes, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(ComplexRes, input), 0, "Input sound object."},
+{"freq", T_OBJECT_EX, offsetof(ComplexRes, freq), 0, "Center frequency in cycle per second."},
+{"decay", T_OBJECT_EX, offsetof(ComplexRes, decay), 0, "Decaying envelope time in seconds."},
+{"mul", T_OBJECT_EX, offsetof(ComplexRes, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(ComplexRes, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef ComplexRes_methods[] = {
+{"getServer", (PyCFunction)ComplexRes_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)ComplexRes_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)ComplexRes_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)ComplexRes_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)ComplexRes_stop, METH_NOARGS, "Stops computing."},
+{"setFreq", (PyCFunction)ComplexRes_setFreq, METH_O, "Sets filter center frequency in cycle per second."},
+{"setDecay", (PyCFunction)ComplexRes_setDecay, METH_O, "Sets filter decaying envelope time."},
+{"setMul", (PyCFunction)ComplexRes_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)ComplexRes_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)ComplexRes_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)ComplexRes_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods ComplexRes_as_number = {
+(binaryfunc)ComplexRes_add,                         /*nb_add*/
+(binaryfunc)ComplexRes_sub,                         /*nb_subtract*/
+(binaryfunc)ComplexRes_multiply,                    /*nb_multiply*/
+(binaryfunc)ComplexRes_div,                                              /*nb_divide*/
+0,                                              /*nb_remainder*/
+0,                                              /*nb_divmod*/
+0,                                              /*nb_power*/
+0,                                              /*nb_neg*/
+0,                                              /*nb_pos*/
+0,                                              /*(unaryfunc)array_abs,*/
+0,                                              /*nb_nonzero*/
+0,                                              /*nb_invert*/
+0,                                              /*nb_lshift*/
+0,                                              /*nb_rshift*/
+0,                                              /*nb_and*/
+0,                                              /*nb_xor*/
+0,                                              /*nb_or*/
+0,                                              /*nb_coerce*/
+0,                                              /*nb_int*/
+0,                                              /*nb_long*/
+0,                                              /*nb_float*/
+0,                                              /*nb_oct*/
+0,                                              /*nb_hex*/
+(binaryfunc)ComplexRes_inplace_add,                 /*inplace_add*/
+(binaryfunc)ComplexRes_inplace_sub,                 /*inplace_subtract*/
+(binaryfunc)ComplexRes_inplace_multiply,            /*inplace_multiply*/
+(binaryfunc)ComplexRes_inplace_div,                                              /*inplace_divide*/
+0,                                              /*inplace_remainder*/
+0,                                              /*inplace_power*/
+0,                                              /*inplace_lshift*/
+0,                                              /*inplace_rshift*/
+0,                                              /*inplace_and*/
+0,                                              /*inplace_xor*/
+0,                                              /*inplace_or*/
+0,                                              /*nb_floor_divide*/
+0,                                              /*nb_true_divide*/
+0,                                              /*nb_inplace_floor_divide*/
+0,                                              /*nb_inplace_true_divide*/
+0,                                              /* nb_index */
+};
+
+PyTypeObject ComplexResType = {
+PyObject_HEAD_INIT(NULL)
+0,                                              /*ob_size*/
+"_pyo.ComplexRes_base",                                   /*tp_name*/
+sizeof(ComplexRes),                                 /*tp_basicsize*/
+0,                                              /*tp_itemsize*/
+(destructor)ComplexRes_dealloc,                     /*tp_dealloc*/
+0,                                              /*tp_print*/
+0,                                              /*tp_getattr*/
+0,                                              /*tp_setattr*/
+0,                                              /*tp_compare*/
+0,                                              /*tp_repr*/
+&ComplexRes_as_number,                              /*tp_as_number*/
+0,                                              /*tp_as_sequence*/
+0,                                              /*tp_as_mapping*/
+0,                                              /*tp_hash */
+0,                                              /*tp_call*/
+0,                                              /*tp_str*/
+0,                                              /*tp_getattro*/
+0,                                              /*tp_setattro*/
+0,                                              /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"ComplexRes objects. Second order allpass filter.",           /* tp_doc */
+(traverseproc)ComplexRes_traverse,                  /* tp_traverse */
+(inquiry)ComplexRes_clear,                          /* tp_clear */
+0,                                              /* tp_richcompare */
+0,                                              /* tp_weaklistoffset */
+0,                                              /* tp_iter */
+0,                                              /* tp_iternext */
+ComplexRes_methods,                                 /* tp_methods */
+ComplexRes_members,                                 /* tp_members */
+0,                                              /* tp_getset */
+0,                                              /* tp_base */
+0,                                              /* tp_dict */
+0,                                              /* tp_descr_get */
+0,                                              /* tp_descr_set */
+0,                                              /* tp_dictoffset */
+0,                          /* tp_init */
+0,                                              /* tp_alloc */
+ComplexRes_new,                                     /* tp_new */
+};
diff --git a/src/objects/freeverbmodule.c b/src/objects/freeverbmodule.c
index 8ba510b..9f98523 100644
--- a/src/objects/freeverbmodule.c
+++ b/src/objects/freeverbmodule.c
@@ -50,7 +50,7 @@ static const MYFLT allpass_delays[NUM_ALLPASS] = {
 
 static const MYFLT fixedGain   = 0.015;
 static const MYFLT scaleDamp   = 0.5;
-static const MYFLT scaleRoom   = 0.28;
+static const MYFLT scaleRoom   = 0.29;
 static const MYFLT offsetRoom  = 0.7;
 static const MYFLT allPassFeedBack = 0.5;
 
@@ -929,4 +929,3 @@ PyTypeObject FreeverbType = {
     0,                         /* tp_alloc */
     Freeverb_new,                 /* tp_new */
 };
-
diff --git a/src/objects/granulatormodule.c b/src/objects/granulatormodule.c
index 44eaf46..a996aea 100644
--- a/src/objects/granulatormodule.c
+++ b/src/objects/granulatormodule.c
@@ -711,21 +711,15 @@ Granulator_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of Granulator must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Granulator must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
 
     if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"env\" argument of Granulator must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"env\" argument of Granulator must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->env);
     self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");
@@ -1866,11 +1860,8 @@ Looper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of Looper must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Looper must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -2304,7 +2295,7 @@ PyTypeObject LooperType = {
     Looper_new,                 /* tp_new */
 };
 
-static const MYFLT Granule_MAX_GRAINS = 1024; 
+static const MYFLT Granule_MAX_GRAINS = 4096; 
 typedef struct {
     pyo_audio_HEAD
     PyObject *table;
@@ -2323,16 +2314,17 @@ typedef struct {
     MYFLT *phase;
     int *flags;
     int num;
+    int sync;
     double timer;
     MYFLT oneOnSr;
+    MYFLT srOnRandMax;
     int modebuffer[6];
 } Granule;
 
 static void
 Granule_transform_i(Granule *self) {
     MYFLT dens, inc, index, amp, phase;
-    int i, j, ipart;
-    int flag = 0; 
+    int i, j, ipart, flag = 0; 
     MYFLT pit = 0, pos = 0, dur = 0; 
     
     MYFLT *tablelist = TableStream_getData(self->table);
@@ -2343,18 +2335,24 @@ Granule_transform_i(Granule *self) {
     
     dens = PyFloat_AS_DOUBLE(self->dens);
     if (dens < 0.0)
-        dens = -dens;
+        dens = 0.0;
     
     inc = dens * self->oneOnSr;
     
     for (i=0; i<self->bufsize; i++) {
         self->data[i] = 0.0;
 
-        /* clocker */
-        self->timer += inc;
-        if (self->timer >= 1.0) {
-            self->timer -= 1.0;
-            flag = 1;
+        if (self->sync == 1) {
+            /* synchronous */
+            self->timer += inc;
+            if (self->timer >= 1.0) {
+                self->timer -= 1.0;
+                flag = 1;
+            }
+        } else {
+            /* asynchronous */
+            if ((rand() * self->srOnRandMax) < dens)
+                flag = 1;
         }
 
         /* need to start a new grain */
@@ -2376,10 +2374,14 @@ Granule_transform_i(Granule *self) {
                         dur = PyFloat_AS_DOUBLE(self->dur);
                     else
                         dur = Stream_getData((Stream *)self->dur_stream)[i];
+                    if (pit < 0.0)
+                        pit = -pit;
                     if (pos < 0.0)
                         pos = 0.0;
                     else if (pos >= size)
                         pos = (MYFLT)size;
+                    if (dur < 0.0001)
+                        dur = 0.0001;
                     self->gpos[j] = pos;
                     self->glen[j] = dur * self->sr * pit;
                     if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
@@ -2395,23 +2397,19 @@ Granule_transform_i(Granule *self) {
         for (j=0; j<self->num; j++) {
             if (self->flags[j]) {
                 phase = self->phase[j];
-                if (phase >= 0.0 && phase < 1.0) {
-                    // compute envelope
-                    index = phase * envsize;
-                    ipart = (int)index;
-                    amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
-
-                    // compute sampling
-                    index = phase * self->glen[j] + self->gpos[j];
-                    ipart = (int)index;
-                    self->data[i] += (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
-
-                    phase += self->inc[j];
-                    if (phase >= 1.0)
-                        self->flags[j] = 0;
-                    else
-                        self->phase[j] = phase;
-                }
+                /* compute envelope */
+                index = phase * envsize;
+                ipart = (int)index;
+                amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+                /* compute sampling */
+                index = phase * self->glen[j] + self->gpos[j];
+                ipart = (int)index;
+                self->data[i] += (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+                phase += self->inc[j];
+                if (phase >= 1.0)
+                    self->flags[j] = 0;
+                else
+                    self->phase[j] = phase;
             }
         }
         flag = 0;
@@ -2421,8 +2419,7 @@ Granule_transform_i(Granule *self) {
 static void
 Granule_transform_a(Granule *self) {
     MYFLT index, amp, phase;
-    int i, j, ipart;
-    int flag = 0;
+    int i, j, ipart, flag = 0;
     MYFLT pit = 0, pos = 0, dur = 0; 
     
     MYFLT *tablelist = TableStream_getData(self->table);
@@ -2436,11 +2433,17 @@ Granule_transform_a(Granule *self) {
     for (i=0; i<self->bufsize; i++) {
         self->data[i] = 0.0;
 
-        /* clocker */
-        self->timer += density[i] * self->oneOnSr;
-        if (self->timer >= 1.0) {
-            self->timer -= 1.0;
-            flag = 1;
+        if (self->sync == 1) {
+            /* synchronous */
+            self->timer += density[i] * self->oneOnSr;
+            if (self->timer >= 1.0) {
+                self->timer -= 1.0;
+                flag = 1;
+            }
+        } else {
+            /* asynchronous */
+            if ((rand() * self->srOnRandMax) < density[i])
+                flag = 1;
         }
 
         /* need to start a new grain */
@@ -2462,10 +2465,14 @@ Granule_transform_a(Granule *self) {
                         dur = PyFloat_AS_DOUBLE(self->dur);
                     else
                         dur = Stream_getData((Stream *)self->dur_stream)[i];
+                    if (pit < 0.0)
+                        pit = -pit;
                     if (pos < 0.0)
                         pos = 0.0;
                     else if (pos >= size)
                         pos = (MYFLT)size;
+                    if (dur < 0.0001)
+                        dur = 0.0001;
                     self->gpos[j] = pos;
                     self->glen[j] = dur * self->sr * pit;
                     if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
@@ -2481,23 +2488,19 @@ Granule_transform_a(Granule *self) {
         for (j=0; j<self->num; j++) {
             if (self->flags[j]) {
                 phase = self->phase[j];
-                if (phase >= 0.0 && phase < 1.0) {
-                    // compute envelope
-                    index = phase * envsize;
-                    ipart = (int)index;
-                    amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
-
-                    // compute sampling
-                    index = phase * self->glen[j] + self->gpos[j];
-                    ipart = (int)index;
-                    self->data[i] += (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
-
-                    phase += self->inc[j];
-                    if (phase >= 1.0)
-                        self->flags[j] = 0;
-                    else
-                        self->phase[j] = phase;
-                }
+                // compute envelope
+                index = phase * envsize;
+                ipart = (int)index;
+                amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+                // compute sampling
+                index = phase * self->glen[j] + self->gpos[j];
+                ipart = (int)index;
+                self->data[i] += (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+                phase += self->inc[j];
+                if (phase >= 1.0)
+                    self->flags[j] = 0;
+                else
+                    self->phase[j] = phase;
             }
         }
         flag = 0;
@@ -2628,6 +2631,7 @@ Granule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->dur = PyFloat_FromDouble(0.1);
     self->timer = 1.0;
     self->num = 0;
+    self->sync = 1;
 	self->modebuffer[0] = 0;
 	self->modebuffer[1] = 0;
 	self->modebuffer[2] = 0;
@@ -2638,6 +2642,7 @@ Granule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_OBJECT_COMMON
     
     self->oneOnSr = 1.0 / self->sr;
+    self->srOnRandMax = self->sr / (MYFLT)RAND_MAX;
 
     Stream_setFunctionPtr(self->stream, Granule_compute_next_data_frame);
     self->mode_func_ptr = Granule_setProcMode;
@@ -2648,21 +2653,15 @@ Granule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of Granule must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Granule must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
 
     if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"env\" argument of Granule must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"env\" argument of Granule must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->env);
     self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");
@@ -2703,7 +2702,9 @@ Granule_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         self->gpos[i] = self->glen[i] = self->inc[i] = self->phase[i] = 0.0;
         self->flags[i] = 0;
     }
-    
+  
+    Server_generateSeed((Server *)self->server, GRANULE_ID);
+  
     (*self->mode_func_ptr)(self);
     
     return (PyObject *)self;
@@ -2909,6 +2910,21 @@ Granule_setEnv(Granule *self, PyObject *arg)
 	return Py_None;
 }	
 
+static PyObject *
+Granule_setSync(Granule *self, PyObject *arg)
+{
+	if (PyLong_Check(arg) || PyInt_Check(arg)) {
+        self->sync = PyLong_AsLong(arg);
+        if (self->sync <= 0)
+            self->sync = 0;
+        else
+            self->sync = 1;
+    }
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
 static PyMemberDef Granule_members[] = {
     {"server", T_OBJECT_EX, offsetof(Granule, server), 0, "Pyo server."},
     {"stream", T_OBJECT_EX, offsetof(Granule, stream), 0, "Stream object."},
@@ -2937,6 +2953,7 @@ static PyMethodDef Granule_methods[] = {
 	{"setPitch", (PyCFunction)Granule_setPitch, METH_O, "Sets global pitch factor."},
     {"setPos", (PyCFunction)Granule_setPos, METH_O, "Sets position in the sound table."},
     {"setDur", (PyCFunction)Granule_setDur, METH_O, "Sets the grain duration."},
+    {"setSync", (PyCFunction)Granule_setSync, METH_O, "Sets the granulator mode: synchronous or asynchronous."},
 	{"setMul", (PyCFunction)Granule_setMul, METH_O, "Sets Granule mul factor."},
 	{"setAdd", (PyCFunction)Granule_setAdd, METH_O, "Sets Granule add factor."},
     {"setSub", (PyCFunction)Granule_setSub, METH_O, "Sets inverse add factor."},
@@ -3028,3 +3045,1289 @@ PyTypeObject GranuleType = {
     Granule_new,                 /* tp_new */
 };
 
+static const MYFLT MAINPARTICLE_MAX_GRAINS = 4096; 
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *table;
+    PyObject *env;
+    PyObject *dens;
+    Stream *dens_stream;
+    PyObject *pitch;
+    Stream *pitch_stream;
+    PyObject *pos;
+    Stream *pos_stream;
+    PyObject *dur;
+    Stream *dur_stream;
+    PyObject *dev;
+    Stream *dev_stream;
+    PyObject *pan;
+    Stream *pan_stream;
+    MYFLT *gpos;
+    MYFLT *glen;
+    MYFLT *inc;
+    MYFLT *phase;
+    MYFLT *amp1;
+    MYFLT *amp2;
+    int *flags;
+    int *k1;
+    int *k2;
+    int num;
+    int chnls;
+    double timer;
+    double devFactor;
+    double srScale;
+    MYFLT oneOnSr;
+    MYFLT srOnRandMax;
+    MYFLT *buffer_streams;
+    int modebuffer[6];
+} MainParticle;
+
+static void
+MainParticle_transform_mono_i(MainParticle *self) {
+    MYFLT dens, inc, index, amp, phase, val;
+    int i, j, ipart, flag = 0; 
+    MYFLT pit = 0, pos = 0, dur = 0, dev = 0; 
+    
+    MYFLT *tablelist = TableStream_getData(self->table);
+    int size = TableStream_getSize(self->table);
+    
+    MYFLT *envlist = TableStream_getData(self->env);
+    int envsize = TableStream_getSize(self->env);
+    
+    dens = PyFloat_AS_DOUBLE(self->dens);
+    if (dens < 0.0)
+        dens = 0.0;
+    
+    inc = dens * self->oneOnSr * self->devFactor;
+
+    for (i=0; i<self->bufsize*self->chnls; i++) {
+        self->buffer_streams[i] = 0.0;
+    }
+    
+    for (i=0; i<self->bufsize; i++) {
+        self->timer += inc;
+        if (self->timer >= 1.0) {
+            self->timer -= 1.0;
+            flag = 1;
+        }
+
+        /* need to start a new grain */
+        if (flag) {
+            for (j=0; j<MAINPARTICLE_MAX_GRAINS; j++) {
+                if (self->flags[j] == 0) {
+                    self->flags[j] = 1;
+                    if (j >= self->num)
+                        self->num = j + 1;
+                    if (self->modebuffer[1] == 0)
+                        pit = PyFloat_AS_DOUBLE(self->pitch);
+                    else
+                        pit = Stream_getData((Stream *)self->pitch_stream)[i];
+                    if (self->modebuffer[2] == 0)
+                        pos = PyFloat_AS_DOUBLE(self->pos);
+                    else
+                        pos = Stream_getData((Stream *)self->pos_stream)[i];
+                    if (self->modebuffer[3] == 0)
+                        dur = PyFloat_AS_DOUBLE(self->dur);
+                    else
+                        dur = Stream_getData((Stream *)self->dur_stream)[i];
+                    if (self->modebuffer[4] == 0)
+                        dev = PyFloat_AS_DOUBLE(self->dev);
+                    else
+                        dev = Stream_getData((Stream *)self->dev_stream)[i];
+                    if (pit < 0.0)
+                        pit = -pit;
+                    if (pos < 0.0)
+                        pos = 0.0;
+                    else if (pos >= size)
+                        pos = (MYFLT)size;
+                    if (dur < 0.0001)
+                        dur = 0.0001;
+                    if (dev < 0.0)
+                        dev = 0.0;
+                    else if (dev > 1.0)
+                        dev = 1.0;
+                    self->gpos[j] = pos;
+                    self->glen[j] = dur * self->sr * pit * self->srScale;
+                    if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
+                        self->flags[j] = 0;
+                    self->phase[j] = 0.0;
+                    self->inc[j] = 1.0 / (dur * self->sr);
+                    self->devFactor = (rand() / (MYFLT)RAND_MAX * 2.0 - 1.0) * dev + 1.0;
+                    break;
+                }
+            }
+        }
+
+        /* compute active grains */
+        for (j=0; j<self->num; j++) {
+            if (self->flags[j]) {
+                phase = self->phase[j];
+                /* compute envelope */
+                index = phase * envsize;
+                ipart = (int)index;
+                amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+                /* compute sampling */
+                index = phase * self->glen[j] + self->gpos[j];
+                ipart = (int)index;
+                val = (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+                self->buffer_streams[i] += val;
+                phase += self->inc[j];
+                if (phase >= 1.0)
+                    self->flags[j] = 0;
+                else
+                    self->phase[j] = phase;
+            }
+        }
+        flag = 0;
+    }    
+}
+
+static void
+MainParticle_transform_mono_a(MainParticle *self) {
+    MYFLT dens, index, amp, phase, val;
+    int i, j, ipart, flag = 0; 
+    MYFLT pit = 0, pos = 0, dur = 0, dev = 0; 
+    
+    MYFLT *tablelist = TableStream_getData(self->table);
+    int size = TableStream_getSize(self->table);
+    
+    MYFLT *envlist = TableStream_getData(self->env);
+    int envsize = TableStream_getSize(self->env);
+    
+    MYFLT *density = Stream_getData((Stream *)self->dens_stream);
+
+    for (i=0; i<self->bufsize*self->chnls; i++) {
+        self->buffer_streams[i] = 0.0;
+    }
+    
+    for (i=0; i<self->bufsize; i++) {
+        if (density[i] < 0.0)
+            dens = 0.0;
+        else
+            dens = density[i];
+        self->timer += dens * self->oneOnSr * self->devFactor;
+        if (self->timer >= 1.0) {
+            self->timer -= 1.0;
+            flag = 1;
+        }
+
+        /* need to start a new grain */
+        if (flag) {
+            for (j=0; j<MAINPARTICLE_MAX_GRAINS; j++) {
+                if (self->flags[j] == 0) {
+                    self->flags[j] = 1;
+                    if (j >= self->num)
+                        self->num = j + 1;
+                    if (self->modebuffer[1] == 0)
+                        pit = PyFloat_AS_DOUBLE(self->pitch);
+                    else
+                        pit = Stream_getData((Stream *)self->pitch_stream)[i];
+                    if (self->modebuffer[2] == 0)
+                        pos = PyFloat_AS_DOUBLE(self->pos);
+                    else
+                        pos = Stream_getData((Stream *)self->pos_stream)[i];
+                    if (self->modebuffer[3] == 0)
+                        dur = PyFloat_AS_DOUBLE(self->dur);
+                    else
+                        dur = Stream_getData((Stream *)self->dur_stream)[i];
+                    if (self->modebuffer[4] == 0)
+                        dev = PyFloat_AS_DOUBLE(self->dev);
+                    else
+                        dev = Stream_getData((Stream *)self->dev_stream)[i];
+                    if (pit < 0.0)
+                        pit = -pit;
+                    if (pos < 0.0)
+                        pos = 0.0;
+                    else if (pos >= size)
+                        pos = (MYFLT)size;
+                    if (dur < 0.0001)
+                        dur = 0.0001;
+                    if (dev < 0.0)
+                        dev = 0.0;
+                    else if (dev > 1.0)
+                        dev = 1.0;
+                    self->gpos[j] = pos;
+                    self->glen[j] = dur * self->sr * pit * self->srScale;
+                    if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
+                        self->flags[j] = 0;
+                    self->phase[j] = 0.0;
+                    self->inc[j] = 1.0 / (dur * self->sr);
+                    self->devFactor = (rand() / (MYFLT)RAND_MAX * 2.0 - 1.0) * dev + 1.0;
+                    break;
+                }
+            }
+        }
+
+        /* compute active grains */
+        for (j=0; j<self->num; j++) {
+            if (self->flags[j]) {
+                phase = self->phase[j];
+                /* compute envelope */
+                index = phase * envsize;
+                ipart = (int)index;
+                amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+                /* compute sampling */
+                index = phase * self->glen[j] + self->gpos[j];
+                ipart = (int)index;
+                val = (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+                self->buffer_streams[i] += val;
+                phase += self->inc[j];
+                if (phase >= 1.0)
+                    self->flags[j] = 0;
+                else
+                    self->phase[j] = phase;
+            }
+        }
+        flag = 0;
+    }    
+}
+
+static void
+MainParticle_transform_i(MainParticle *self) {
+    MYFLT dens, inc, index, amp, phase, val, min = 0;
+    int i, j, l, l1, ipart, flag = 0; 
+    MYFLT pit = 0, pos = 0, dur = 0, dev = 0, pan = 0; 
+    
+    MYFLT *tablelist = TableStream_getData(self->table);
+    int size = TableStream_getSize(self->table);
+    
+    MYFLT *envlist = TableStream_getData(self->env);
+    int envsize = TableStream_getSize(self->env);
+    
+    dens = PyFloat_AS_DOUBLE(self->dens);
+    if (dens < 0.0)
+        dens = 0.0;
+    
+    inc = dens * self->oneOnSr * self->devFactor;
+
+    for (i=0; i<self->bufsize*self->chnls; i++) {
+        self->buffer_streams[i] = 0.0;
+    }
+    
+    for (i=0; i<self->bufsize; i++) {
+        self->timer += inc;
+        if (self->timer >= 1.0) {
+            self->timer -= 1.0;
+            flag = 1;
+        }
+
+        /* need to start a new grain */
+        if (flag) {
+            for (j=0; j<MAINPARTICLE_MAX_GRAINS; j++) {
+                if (self->flags[j] == 0) {
+                    self->flags[j] = 1;
+                    if (j >= self->num)
+                        self->num = j + 1;
+                    if (self->modebuffer[1] == 0)
+                        pit = PyFloat_AS_DOUBLE(self->pitch);
+                    else
+                        pit = Stream_getData((Stream *)self->pitch_stream)[i];
+                    if (self->modebuffer[2] == 0)
+                        pos = PyFloat_AS_DOUBLE(self->pos);
+                    else
+                        pos = Stream_getData((Stream *)self->pos_stream)[i];
+                    if (self->modebuffer[3] == 0)
+                        dur = PyFloat_AS_DOUBLE(self->dur);
+                    else
+                        dur = Stream_getData((Stream *)self->dur_stream)[i];
+                    if (self->modebuffer[4] == 0)
+                        dev = PyFloat_AS_DOUBLE(self->dev);
+                    else
+                        dev = Stream_getData((Stream *)self->dev_stream)[i];
+                    if (self->modebuffer[5] == 0)
+                        pan = PyFloat_AS_DOUBLE(self->pan);
+                    else
+                        pan = Stream_getData((Stream *)self->pan_stream)[i];
+                    if (pit < 0.0)
+                        pit = -pit;
+                    if (pos < 0.0)
+                        pos = 0.0;
+                    else if (pos >= size)
+                        pos = (MYFLT)size;
+                    if (dur < 0.0001)
+                        dur = 0.0001;
+                    if (dev < 0.0)
+                        dev = 0.0;
+                    else if (dev > 1.0)
+                        dev = 1.0;
+                    if (pan < 0.0)
+                        pan = 0.0;
+                    else if (pan > 1.0)
+                        pan = 1.0;
+                    self->gpos[j] = pos;
+                    self->glen[j] = dur * self->sr * pit * self->srScale;
+                    if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
+                        self->flags[j] = 0;
+                    self->phase[j] = 0.0;
+                    self->inc[j] = 1.0 / (dur * self->sr);
+                    self->devFactor = (rand() / (MYFLT)RAND_MAX * 2.0 - 1.0) * dev + 1.0;
+                    if (self->chnls == 2) {
+                        self->k1[j] = 0;
+                        self->k2[j] = self->bufsize;
+                        self->amp1[j] = MYSQRT(1.0 - pan);
+                        self->amp2[j] = MYSQRT(pan);
+                    }
+                    else {
+                        self->amp1[j] = MYSQRT(1.0 - pan);
+                        self->amp2[j] = MYSQRT(pan);
+                        min = 0;
+                        self->k1[j] = 0;
+                        self->k2[j] = self->bufsize;
+                        for (l=self->chnls; l>0; l--) {
+                            l1 = l - 1;
+                            min = l1 / (MYFLT)self->chnls;
+                            if (pan > min) {
+                                self->k1[j] = l1 * self->bufsize;
+                                if (l == self->chnls)
+                                    self->k2[j] = 0;
+                                else                    
+                                    self->k2[j] = l * self->bufsize;
+                                break;
+                            }
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+
+        /* compute active grains */
+        for (j=0; j<self->num; j++) {
+            if (self->flags[j]) {
+                phase = self->phase[j];
+                /* compute envelope */
+                index = phase * envsize;
+                ipart = (int)index;
+                amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+                /* compute sampling */
+                index = phase * self->glen[j] + self->gpos[j];
+                ipart = (int)index;
+                val = (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+                self->buffer_streams[i+self->k1[j]] += val * self->amp1[j];
+                self->buffer_streams[i+self->k2[j]] += val * self->amp2[j];
+                phase += self->inc[j];
+                if (phase >= 1.0)
+                    self->flags[j] = 0;
+                else
+                    self->phase[j] = phase;
+            }
+        }
+        flag = 0;
+    }    
+}
+
+static void
+MainParticle_transform_a(MainParticle *self) {
+    MYFLT dens, index, amp, phase, val, min = 0;
+    int i, j, l, l1, ipart, flag = 0; 
+    MYFLT pit = 0, pos = 0, dur = 0, dev = 0, pan = 0; 
+    
+    MYFLT *tablelist = TableStream_getData(self->table);
+    int size = TableStream_getSize(self->table);
+    
+    MYFLT *envlist = TableStream_getData(self->env);
+    int envsize = TableStream_getSize(self->env);
+    
+    MYFLT *density = Stream_getData((Stream *)self->dens_stream);
+
+    for (i=0; i<self->bufsize*self->chnls; i++) {
+        self->buffer_streams[i] = 0.0;
+    }
+    
+    for (i=0; i<self->bufsize; i++) {
+        if (density[i] < 0.0)
+            dens = 0.0;
+        else
+            dens = density[i];
+        self->timer += dens * self->oneOnSr * self->devFactor;
+        if (self->timer >= 1.0) {
+            self->timer -= 1.0;
+            flag = 1;
+        }
+
+        /* need to start a new grain */
+        if (flag) {
+            for (j=0; j<MAINPARTICLE_MAX_GRAINS; j++) {
+                if (self->flags[j] == 0) {
+                    self->flags[j] = 1;
+                    if (j >= self->num)
+                        self->num = j + 1;
+                    if (self->modebuffer[1] == 0)
+                        pit = PyFloat_AS_DOUBLE(self->pitch);
+                    else
+                        pit = Stream_getData((Stream *)self->pitch_stream)[i];
+                    if (self->modebuffer[2] == 0)
+                        pos = PyFloat_AS_DOUBLE(self->pos);
+                    else
+                        pos = Stream_getData((Stream *)self->pos_stream)[i];
+                    if (self->modebuffer[3] == 0)
+                        dur = PyFloat_AS_DOUBLE(self->dur);
+                    else
+                        dur = Stream_getData((Stream *)self->dur_stream)[i];
+                    if (self->modebuffer[4] == 0)
+                        dev = PyFloat_AS_DOUBLE(self->dev);
+                    else
+                        dev = Stream_getData((Stream *)self->dev_stream)[i];
+                    if (self->modebuffer[5] == 0)
+                        pan = PyFloat_AS_DOUBLE(self->pan);
+                    else
+                        pan = Stream_getData((Stream *)self->pan_stream)[i];
+                    if (pit < 0.0)
+                        pit = -pit;
+                    if (pos < 0.0)
+                        pos = 0.0;
+                    else if (pos >= size)
+                        pos = (MYFLT)size;
+                    if (dur < 0.0001)
+                        dur = 0.0001;
+                    if (dev < 0.0)
+                        dev = 0.0;
+                    else if (dev > 1.0)
+                        dev = 1.0;
+                    if (pan < 0.0)
+                        pan = 0.0;
+                    else if (pan > 1.0)
+                        pan = 1.0;
+                    self->gpos[j] = pos;
+                    self->glen[j] = dur * self->sr * pit * self->srScale;
+                    if ((pos + self->glen[j]) >= size || (pos + self->glen[j]) < 0)
+                        self->flags[j] = 0;
+                    self->phase[j] = 0.0;
+                    self->inc[j] = 1.0 / (dur * self->sr);
+                    self->devFactor = (rand() / (MYFLT)RAND_MAX * 2.0 - 1.0) * dev + 1.0;
+                    if (self->chnls == 2) {
+                        self->k1[j] = 0;
+                        self->k2[j] = self->bufsize;
+                        self->amp1[j] = MYSQRT(1.0 - pan);
+                        self->amp2[j] = MYSQRT(pan);
+                    }
+                    else {
+                        self->amp1[j] = MYSQRT(1.0 - pan);
+                        self->amp2[j] = MYSQRT(pan);
+                        min = 0;
+                        self->k1[j] = 0;
+                        self->k2[j] = self->bufsize;
+                        for (l=self->chnls; l>0; l--) {
+                            l1 = l - 1;
+                            min = l1 / (MYFLT)self->chnls;
+                            if (pan > min) {
+                                self->k1[j] = l1 * self->bufsize;
+                                if (l == self->chnls)
+                                    self->k2[j] = 0;
+                                else                    
+                                    self->k2[j] = l * self->bufsize;
+                                break;
+                            }
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+
+        /* compute active grains */
+        for (j=0; j<self->num; j++) {
+            if (self->flags[j]) {
+                phase = self->phase[j];
+                /* compute envelope */
+                index = phase * envsize;
+                ipart = (int)index;
+                amp = envlist[ipart] + (envlist[ipart+1] - envlist[ipart]) * (index - ipart);
+                /* compute sampling */
+                index = phase * self->glen[j] + self->gpos[j];
+                ipart = (int)index;
+                val = (tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * (index - ipart)) * amp;
+                self->buffer_streams[i+self->k1[j]] += val * self->amp1[j];
+                self->buffer_streams[i+self->k2[j]] += val * self->amp2[j];
+                phase += self->inc[j];
+                if (phase >= 1.0)
+                    self->flags[j] = 0;
+                else
+                    self->phase[j] = phase;
+            }
+        }
+        flag = 0;
+    }    
+}
+
+static void
+MainParticle_setProcMode(MainParticle *self)
+{
+    int procmode = self->modebuffer[0];
+
+	switch (procmode) {
+        case 0:
+            if (self->chnls == 1)
+                self->proc_func_ptr = MainParticle_transform_mono_i;
+            else
+                self->proc_func_ptr = MainParticle_transform_i;
+            break;
+        case 1:    
+            if (self->chnls == 1)
+                self->proc_func_ptr = MainParticle_transform_mono_a;
+            else
+                self->proc_func_ptr = MainParticle_transform_a;
+            break;
+    } 
+}
+
+static void
+MainParticle_compute_next_data_frame(MainParticle *self)
+{
+    (*self->proc_func_ptr)(self); 
+}
+
+static int
+MainParticle_traverse(MainParticle *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->table);
+    Py_VISIT(self->env);
+    Py_VISIT(self->dens);    
+    Py_VISIT(self->dens_stream);    
+    Py_VISIT(self->pitch);    
+    Py_VISIT(self->pitch_stream);    
+    Py_VISIT(self->pos);    
+    Py_VISIT(self->pos_stream);    
+    Py_VISIT(self->dur);    
+    Py_VISIT(self->dur_stream);    
+    Py_VISIT(self->dev);    
+    Py_VISIT(self->dev_stream);    
+    Py_VISIT(self->pan);    
+    Py_VISIT(self->pan_stream);    
+    return 0;
+}
+
+static int 
+MainParticle_clear(MainParticle *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->table);
+    Py_CLEAR(self->env);
+    Py_CLEAR(self->dens);    
+    Py_CLEAR(self->dens_stream);    
+    Py_CLEAR(self->pitch);    
+    Py_CLEAR(self->pitch_stream);    
+    Py_CLEAR(self->pos);    
+    Py_CLEAR(self->pos_stream);    
+    Py_CLEAR(self->dur);    
+    Py_CLEAR(self->dur_stream);    
+    Py_CLEAR(self->dev);    
+    Py_CLEAR(self->dev_stream);    
+    Py_CLEAR(self->pan);    
+    Py_CLEAR(self->pan_stream);    
+    return 0;
+}
+
+static void
+MainParticle_dealloc(MainParticle* self)
+{
+    pyo_DEALLOC
+    free(self->gpos);   
+    free(self->glen);
+    free(self->inc);
+    free(self->flags);
+    free(self->k1);
+    free(self->k2);
+    free(self->phase);
+    free(self->amp1);
+    free(self->amp2);
+    free(self->buffer_streams);
+    MainParticle_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+MYFLT *
+MainParticle_getSamplesBuffer(MainParticle *self)
+{
+    return (MYFLT *)self->buffer_streams;
+}
+
+static PyObject *
+MainParticle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *tabletmp, *envtmp, *denstmp=NULL, *pitchtmp=NULL, *postmp=NULL, *durtmp=NULL, *devtmp=NULL, *pantmp=NULL;
+    MainParticle *self;
+    self = (MainParticle *)type->tp_alloc(type, 0);
+
+    self->dens = PyFloat_FromDouble(50);
+    self->pitch = PyFloat_FromDouble(1);
+    self->pos = PyFloat_FromDouble(0.0);
+    self->dur = PyFloat_FromDouble(0.1);
+    self->dev = PyFloat_FromDouble(0);
+    self->pan = PyFloat_FromDouble(0.5);
+    self->timer = self->devFactor = 1.0;
+    self->srScale = 1.0;
+    self->num = 0;
+    self->chnls = 1;
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+	self->modebuffer[2] = 0;
+	self->modebuffer[3] = 0;
+	self->modebuffer[4] = 0;
+	self->modebuffer[5] = 0;
+
+    INIT_OBJECT_COMMON
+    
+    self->oneOnSr = 1.0 / self->sr;
+    self->srOnRandMax = self->sr / (MYFLT)RAND_MAX;
+
+    Stream_setFunctionPtr(self->stream, MainParticle_compute_next_data_frame);
+    self->mode_func_ptr = MainParticle_setProcMode;
+
+    static char *kwlist[] = {"table", "env", "dens", "pitch", "pos", "dur", "dev", "pan", "chnls", NULL};
+
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOOOOOi", kwlist, &tabletmp, &envtmp, &denstmp, &pitchtmp, &postmp, &durtmp, &devtmp, &pantmp, &self->chnls))
+        Py_RETURN_NONE;
+
+    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of MainParticle must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
+    }
+    Py_XDECREF(self->table);
+    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
+    self->srScale = TableStream_getSamplingRate(self->table) / self->sr;
+
+    if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 ) {
+        PyErr_SetString(PyExc_TypeError, "\"env\" argument of MainParticle must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
+    }
+    Py_XDECREF(self->env);
+    self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");
+
+    if (denstmp) {
+        PyObject_CallMethod((PyObject *)self, "setDens", "O", denstmp);
+    }
+    
+    if (pitchtmp) {
+        PyObject_CallMethod((PyObject *)self, "setPitch", "O", pitchtmp);
+    }
+
+    if (postmp) {
+        PyObject_CallMethod((PyObject *)self, "setPos", "O", postmp);
+    }
+
+    if (durtmp) {
+        PyObject_CallMethod((PyObject *)self, "setDur", "O", durtmp);
+    }
+    
+    if (devtmp) {
+        PyObject_CallMethod((PyObject *)self, "setDev", "O", devtmp);
+    }
+
+    if (pantmp) {
+        PyObject_CallMethod((PyObject *)self, "setPan", "O", pantmp);
+    }
+ 
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+    if (self->chnls < 1)
+        self->chnls = 1;
+
+    self->gpos = (MYFLT *)realloc(self->gpos, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+    self->glen = (MYFLT *)realloc(self->glen, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+    self->inc = (MYFLT *)realloc(self->inc, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+    self->phase = (MYFLT *)realloc(self->phase, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+    self->amp1 = (MYFLT *)realloc(self->amp1, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+    self->amp2 = (MYFLT *)realloc(self->amp2, MAINPARTICLE_MAX_GRAINS * sizeof(MYFLT));
+    self->flags = (int *)realloc(self->flags, MAINPARTICLE_MAX_GRAINS * sizeof(int));
+    self->k1 = (int *)realloc(self->k1, MAINPARTICLE_MAX_GRAINS * sizeof(int));
+    self->k2 = (int *)realloc(self->k2, MAINPARTICLE_MAX_GRAINS * sizeof(int));
+    
+    for (i=0; i<MAINPARTICLE_MAX_GRAINS; i++) {
+        self->gpos[i] = self->glen[i] = self->inc[i] = self->phase[i] = self->amp1[i] = self->amp2[i] = 0.0;
+        self->flags[i] = self->k1[i] = self->k2[i] = 0;
+    }
+  
+    self->buffer_streams = (MYFLT *)realloc(self->buffer_streams, self->bufsize * self->chnls * sizeof(MYFLT));
+    for (i=0; i<self->bufsize*self->chnls; i++) {
+        self->buffer_streams[i] = 0.0;
+    }
+
+    Server_generateSeed((Server *)self->server, MAINPARTICLE_ID);
+  
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * MainParticle_getServer(MainParticle* self) { GET_SERVER };
+static PyObject * MainParticle_getStream(MainParticle* self) { GET_STREAM };
+
+static PyObject * MainParticle_play(MainParticle *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * MainParticle_stop(MainParticle *self) { STOP };
+
+static PyObject *
+MainParticle_setDens(MainParticle *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->dens);
+	if (isNumber == 1) {
+		self->dens = PyNumber_Float(tmp);
+        self->modebuffer[0] = 0;
+	}
+	else {
+		self->dens = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->dens, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->dens_stream);
+        self->dens_stream = (Stream *)streamtmp;
+		self->modebuffer[0] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+MainParticle_setPitch(MainParticle *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->pitch);
+	if (isNumber == 1) {
+		self->pitch = PyNumber_Float(tmp);
+        self->modebuffer[1] = 0;
+	}
+	else {
+		self->pitch = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->pitch, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->pitch_stream);
+        self->pitch_stream = (Stream *)streamtmp;
+		self->modebuffer[1] = 1;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+MainParticle_setPos(MainParticle *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->pos);
+	if (isNumber == 1) {
+		self->pos = PyNumber_Float(tmp);
+        self->modebuffer[2] = 0;
+	}
+	else {
+		self->pos = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->pos, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->pos_stream);
+        self->pos_stream = (Stream *)streamtmp;
+		self->modebuffer[2] = 1;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+MainParticle_setDur(MainParticle *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->dur);
+	if (isNumber == 1) {
+		self->dur = PyNumber_Float(tmp);
+        self->modebuffer[3] = 0;
+	}
+	else {
+		self->dur = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->dur, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->dur_stream);
+        self->dur_stream = (Stream *)streamtmp;
+		self->modebuffer[3] = 1;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+MainParticle_setDev(MainParticle *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->dev);
+	if (isNumber == 1) {
+		self->dev = PyNumber_Float(tmp);
+        self->modebuffer[4] = 0;
+	}
+	else {
+		self->dev = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->dev, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->dev_stream);
+        self->dev_stream = (Stream *)streamtmp;
+		self->modebuffer[4] = 1;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+MainParticle_setPan(MainParticle *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->pan);
+	if (isNumber == 1) {
+		self->pan = PyNumber_Float(tmp);
+        self->modebuffer[5] = 0;
+	}
+	else {
+		self->pan = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->pan, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->pan_stream);
+        self->pan_stream = (Stream *)streamtmp;
+		self->modebuffer[5] = 1;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+MainParticle_getTable(MainParticle* self)
+{
+    Py_INCREF(self->table);
+    return self->table;
+};
+
+static PyObject *
+MainParticle_setTable(MainParticle *self, PyObject *arg)
+{
+	PyObject *tmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	tmp = arg;
+	Py_DECREF(self->table);
+    self->table = PyObject_CallMethod((PyObject *)tmp, "getTableStream", "");    
+    self->srScale = TableStream_getSamplingRate(self->table) / self->sr;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+MainParticle_getEnv(MainParticle* self)
+{
+    Py_INCREF(self->env);
+    return self->env;
+};
+
+static PyObject *
+MainParticle_setEnv(MainParticle *self, PyObject *arg)
+{
+	PyObject *tmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	tmp = arg;
+	Py_DECREF(self->env);
+    self->env = PyObject_CallMethod((PyObject *)tmp, "getTableStream", "");
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMemberDef MainParticle_members[] = {
+    {"server", T_OBJECT_EX, offsetof(MainParticle, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(MainParticle, stream), 0, "Stream object."},
+    {"table", T_OBJECT_EX, offsetof(MainParticle, table), 0, "Sound table."},
+    {"env", T_OBJECT_EX, offsetof(MainParticle, env), 0, "Envelope table."},
+    {"dens", T_OBJECT_EX, offsetof(MainParticle, dens), 0, "Density of grains per second."},
+    {"pitch", T_OBJECT_EX, offsetof(MainParticle, pitch), 0, "Speed of the reading pointer."},
+    {"pos", T_OBJECT_EX, offsetof(MainParticle, pos), 0, "Position in the sound table."},
+    {"dur", T_OBJECT_EX, offsetof(MainParticle, dur), 0, "Duration of each grains."},
+    {"dev", T_OBJECT_EX, offsetof(MainParticle, dev), 0, "Grain start point deviation factor."},
+    {"pan", T_OBJECT_EX, offsetof(MainParticle, pan), 0, "Grain panning factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef MainParticle_methods[] = {
+    {"getTable", (PyCFunction)MainParticle_getTable, METH_NOARGS, "Returns sound table object."},
+    {"setTable", (PyCFunction)MainParticle_setTable, METH_O, "Sets sound table."},
+    {"getEnv", (PyCFunction)MainParticle_getEnv, METH_NOARGS, "Returns envelope table object."},
+    {"setEnv", (PyCFunction)MainParticle_setEnv, METH_O, "Sets envelope table."},
+    {"getServer", (PyCFunction)MainParticle_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)MainParticle_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)MainParticle_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"stop", (PyCFunction)MainParticle_stop, METH_NOARGS, "Stops computing."},
+	{"setDens", (PyCFunction)MainParticle_setDens, METH_O, "Sets the density of grains per second."},
+	{"setPitch", (PyCFunction)MainParticle_setPitch, METH_O, "Sets global pitch factor."},
+    {"setPos", (PyCFunction)MainParticle_setPos, METH_O, "Sets position in the sound table."},
+    {"setDur", (PyCFunction)MainParticle_setDur, METH_O, "Sets the grain duration."},
+	{"setDev", (PyCFunction)MainParticle_setDev, METH_O, "Sets grain start point deviation factor."},
+	{"setPan", (PyCFunction)MainParticle_setPan, METH_O, "Sets grain panning factor."},
+    {NULL}  /* Sentinel */
+};
+
+PyTypeObject MainParticleType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_pitch*/
+    "_pyo.MainParticle_base",         /*tp_name*/
+    sizeof(MainParticle),         /*tp_basicpitch*/
+    0,                         /*tp_itempitch*/
+    (destructor)MainParticle_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,             /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+    "MainParticle objects. Accumulation of multiples grains of sound.",           /* tp_doc */
+    (traverseproc)MainParticle_traverse,   /* tp_traverse */
+    (inquiry)MainParticle_clear,           /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    MainParticle_methods,             /* tp_methods */
+    MainParticle_members,             /* tp_members */
+    0,                      /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,      /* tp_init */
+    0,                         /* tp_alloc */
+    MainParticle_new,                 /* tp_new */
+};
+
+typedef struct {
+    pyo_audio_HEAD
+    MainParticle *mainSplitter;
+    int modebuffer[2];
+    int chnl; // panning order
+} Particle;
+
+static void Particle_postprocessing_ii(Particle *self) { POST_PROCESSING_II };
+static void Particle_postprocessing_ai(Particle *self) { POST_PROCESSING_AI };
+static void Particle_postprocessing_ia(Particle *self) { POST_PROCESSING_IA };
+static void Particle_postprocessing_aa(Particle *self) { POST_PROCESSING_AA };
+static void Particle_postprocessing_ireva(Particle *self) { POST_PROCESSING_IREVA };
+static void Particle_postprocessing_areva(Particle *self) { POST_PROCESSING_AREVA };
+static void Particle_postprocessing_revai(Particle *self) { POST_PROCESSING_REVAI };
+static void Particle_postprocessing_revaa(Particle *self) { POST_PROCESSING_REVAA };
+static void Particle_postprocessing_revareva(Particle *self) { POST_PROCESSING_REVAREVA };
+
+static void
+Particle_setProcMode(Particle *self)
+{
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = Particle_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = Particle_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = Particle_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = Particle_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = Particle_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = Particle_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = Particle_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = Particle_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = Particle_postprocessing_revareva;
+            break;
+    }
+}
+
+static void
+Particle_compute_next_data_frame(Particle *self)
+{
+    int i;
+    MYFLT *tmp;
+    int offset = self->chnl * self->bufsize;
+    tmp = MainParticle_getSamplesBuffer((MainParticle *)self->mainSplitter);
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = tmp[i + offset];
+    }    
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+Particle_traverse(Particle *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->mainSplitter);
+    return 0;
+}
+
+static int 
+Particle_clear(Particle *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->mainSplitter);    
+    return 0;
+}
+
+static void
+Particle_dealloc(Particle* self)
+{
+    pyo_DEALLOC
+    Particle_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Particle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *maintmp=NULL, *multmp=NULL, *addtmp=NULL;
+    Particle *self;
+    self = (Particle *)type->tp_alloc(type, 0);
+    
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, Particle_compute_next_data_frame);
+    self->mode_func_ptr = Particle_setProcMode;
+
+    static char *kwlist[] = {"mainSplitter", "chnl", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi|OO", kwlist, &maintmp, &self->chnl, &multmp, &addtmp))
+        Py_RETURN_NONE;
+    
+    Py_XDECREF(self->mainSplitter);
+    Py_INCREF(maintmp);
+    self->mainSplitter = (MainParticle *)maintmp;
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * Particle_getServer(Particle* self) { GET_SERVER };
+static PyObject * Particle_getStream(Particle* self) { GET_STREAM };
+static PyObject * Particle_setMul(Particle *self, PyObject *arg) { SET_MUL };	
+static PyObject * Particle_setAdd(Particle *self, PyObject *arg) { SET_ADD };	
+static PyObject * Particle_setSub(Particle *self, PyObject *arg) { SET_SUB };	
+static PyObject * Particle_setDiv(Particle *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * Particle_play(Particle *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Particle_out(Particle *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * Particle_stop(Particle *self) { STOP };
+
+static PyObject * Particle_multiply(Particle *self, PyObject *arg) { MULTIPLY };
+static PyObject * Particle_inplace_multiply(Particle *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * Particle_add(Particle *self, PyObject *arg) { ADD };
+static PyObject * Particle_inplace_add(Particle *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * Particle_sub(Particle *self, PyObject *arg) { SUB };
+static PyObject * Particle_inplace_sub(Particle *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * Particle_div(Particle *self, PyObject *arg) { DIV };
+static PyObject * Particle_inplace_div(Particle *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef Particle_members[] = {
+{"server", T_OBJECT_EX, offsetof(Particle, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Particle, stream), 0, "Stream object."},
+{"mul", T_OBJECT_EX, offsetof(Particle, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(Particle, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef Particle_methods[] = {
+{"getServer", (PyCFunction)Particle_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Particle_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Particle_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)Particle_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)Particle_stop, METH_NOARGS, "Stops computing."},
+{"setMul", (PyCFunction)Particle_setMul, METH_O, "Sets Particle mul factor."},
+{"setAdd", (PyCFunction)Particle_setAdd, METH_O, "Sets Particle add factor."},
+{"setSub", (PyCFunction)Particle_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)Particle_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods Particle_as_number = {
+(binaryfunc)Particle_add,                      /*nb_add*/
+(binaryfunc)Particle_sub,                 /*nb_subtract*/
+(binaryfunc)Particle_multiply,                 /*nb_multiply*/
+(binaryfunc)Particle_div,                   /*nb_divide*/
+0,                /*nb_remainder*/
+0,                   /*nb_divmod*/
+0,                   /*nb_power*/
+0,                  /*nb_neg*/
+0,                /*nb_pos*/
+0,                  /*(unaryfunc)array_abs,*/
+0,                    /*nb_nonzero*/
+0,                    /*nb_invert*/
+0,               /*nb_lshift*/
+0,              /*nb_rshift*/
+0,              /*nb_and*/
+0,              /*nb_xor*/
+0,               /*nb_or*/
+0,                                          /*nb_coerce*/
+0,                       /*nb_int*/
+0,                      /*nb_long*/
+0,                     /*nb_float*/
+0,                       /*nb_oct*/
+0,                       /*nb_hex*/
+(binaryfunc)Particle_inplace_add,              /*inplace_add*/
+(binaryfunc)Particle_inplace_sub,         /*inplace_subtract*/
+(binaryfunc)Particle_inplace_multiply,         /*inplace_multiply*/
+(binaryfunc)Particle_inplace_div,           /*inplace_divide*/
+0,        /*inplace_remainder*/
+0,           /*inplace_power*/
+0,       /*inplace_lshift*/
+0,      /*inplace_rshift*/
+0,      /*inplace_and*/
+0,      /*inplace_xor*/
+0,       /*inplace_or*/
+0,             /*nb_floor_divide*/
+0,              /*nb_true_divide*/
+0,     /*nb_inplace_floor_divide*/
+0,      /*nb_inplace_true_divide*/
+0,                     /* nb_index */
+};
+
+PyTypeObject ParticleType = {
+PyObject_HEAD_INIT(NULL)
+0,                         /*ob_size*/
+"_pyo.Particle_base",         /*tp_name*/
+sizeof(Particle),         /*tp_basicsize*/
+0,                         /*tp_itemsize*/
+(destructor)Particle_dealloc, /*tp_dealloc*/
+0,                         /*tp_print*/
+0,                         /*tp_getattr*/
+0,                         /*tp_setattr*/
+0,                         /*tp_compare*/
+0,                         /*tp_repr*/
+&Particle_as_number,             /*tp_as_number*/
+0,                         /*tp_as_sequence*/
+0,                         /*tp_as_mapping*/
+0,                         /*tp_hash */
+0,                         /*tp_call*/
+0,                         /*tp_str*/
+0,                         /*tp_getattro*/
+0,                         /*tp_setattro*/
+0,                         /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,  /*tp_flags*/
+"Particle objects. Reads one band from a MainParticle object.",           /* tp_doc */
+(traverseproc)Particle_traverse,   /* tp_traverse */
+(inquiry)Particle_clear,           /* tp_clear */
+0,		               /* tp_richcompare */
+0,		               /* tp_weaklistoffset */
+0,		               /* tp_iter */
+0,		               /* tp_iternext */
+Particle_methods,             /* tp_methods */
+Particle_members,             /* tp_members */
+0,                      /* tp_getset */
+0,                         /* tp_base */
+0,                         /* tp_dict */
+0,                         /* tp_descr_get */
+0,                         /* tp_descr_set */
+0,                         /* tp_dictoffset */
+0,      /* tp_init */
+0,                         /* tp_alloc */
+Particle_new,                 /* tp_new */
+};
diff --git a/src/objects/matrixmodule.c b/src/objects/matrixmodule.c
index dc1a8d6..9178518 100644
--- a/src/objects/matrixmodule.c
+++ b/src/objects/matrixmodule.c
@@ -595,6 +595,7 @@ MatrixRec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
 
     Py_XDECREF(self->matrix);
+    Py_INCREF(matrixtmp);
     self->matrix = (NewMatrix *)matrixtmp;
     
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
@@ -801,6 +802,7 @@ MatrixRecLoop_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
 
     Py_XDECREF(self->matrix);
+    Py_INCREF(matrixtmp);
     self->matrix = (NewMatrix *)matrixtmp;
     
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
@@ -1013,6 +1015,7 @@ MatrixMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
 
     Py_XDECREF(self->matrix);
+    Py_INCREF(matrixtmp);
     self->matrix = (PyObject *)matrixtmp;
 
     width = NewMatrix_getWidth((NewMatrix *)self->matrix);
@@ -1021,6 +1024,7 @@ MatrixMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->buffer = (MYFLT *)realloc(self->buffer, (numsamps) * sizeof(MYFLT));
 
     Py_XDECREF(self->sources);
+    Py_INCREF(sourcestmp);
     self->sources = (PyObject *)sourcestmp;
     
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
diff --git a/src/objects/matrixprocessmodule.c b/src/objects/matrixprocessmodule.c
index 19a5018..ef30191 100644
--- a/src/objects/matrixprocessmodule.c
+++ b/src/objects/matrixprocessmodule.c
@@ -159,6 +159,10 @@ MatrixPointer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     if (! PyArg_ParseTupleAndKeywords(args, kwds, "OOO|OO", kwlist, &matrixtmp, &xtmp, &ytmp, &multmp, &addtmp))
         Py_RETURN_NONE;
     
+    if ( PyObject_HasAttrString((PyObject *)matrixtmp, "getMatrixStream") == 0 ) {
+        PyErr_SetString(PyExc_TypeError, "\"matrix\" argument of MatrixPointer must be a PyoMatrixObject.\n");
+        Py_RETURN_NONE;
+    }
     Py_XDECREF(self->matrix);
     self->matrix = PyObject_CallMethod((PyObject *)matrixtmp, "getMatrixStream", "");
     
@@ -221,6 +225,11 @@ MatrixPointer_setMatrix(MatrixPointer *self, PyObject *arg)
 	}
     
 	tmp = arg;
+    if ( PyObject_HasAttrString((PyObject *)tmp, "getMatrixStream") == 0 ) {
+        PyErr_SetString(PyExc_TypeError, "\"matrix\" argument of MatrixPointer must be a PyoMatrixObject.\n");
+        Py_RETURN_NONE;
+    }
+
 	Py_DECREF(self->matrix);
     self->matrix = PyObject_CallMethod((PyObject *)tmp, "getMatrixStream", "");
     
@@ -238,16 +247,13 @@ MatrixPointer_setX(MatrixPointer *self, PyObject *arg)
 		return Py_None;
 	}
     
-	int isNumber = PyNumber_Check(arg);
-	if (isNumber == 1) {
-		PySys_WriteStderr("MatrixPointer x attributes must be a PyoObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+	tmp = arg;
+
+	if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+        PyErr_SetString(PyExc_TypeError, "\"x\" attribute of MatrixPointer must be a PyoObject.\n");
+        Py_RETURN_NONE;
 	}
 	
-	tmp = arg;
 	Py_INCREF(tmp);
 	Py_XDECREF(self->x);
 
@@ -271,16 +277,13 @@ MatrixPointer_setY(MatrixPointer *self, PyObject *arg)
 		return Py_None;
 	}
     
-	int isNumber = PyNumber_Check(arg);
-	if (isNumber == 1) {
-		PySys_WriteStderr("MatrixPointer y attributes must be a PyoObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+	tmp = arg;
+
+	if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+        PyErr_SetString(PyExc_TypeError, "\"y\" attribute of MatrixPointer must be a PyoObject.\n");
+        Py_RETURN_NONE;
 	}
 	
-	tmp = arg;
 	Py_INCREF(tmp);
 	Py_XDECREF(self->y);
     
diff --git a/src/objects/metromodule.c b/src/objects/metromodule.c
index 2279b70..2deeb00 100644
--- a/src/objects/metromodule.c
+++ b/src/objects/metromodule.c
@@ -1987,7 +1987,7 @@ Beater_generate_i(Beater *self) {
         self->dur_buffer_streams[i + self->voiceCount * self->bufsize] = self->durations[self->tapCount];
         if (self->currentTime >= tm) {
             self->currentTime -= tm;
-            if (self->tapCount == (self->last_taps-1))
+            if (self->tapCount == (self->last_taps-2))
                 self->end_buffer_streams[i + self->voiceCount * self->bufsize] = 1.0;
             if (self->sequence[self->tapCount] == 1) {
                 self->currentTap = self->tapCount;
@@ -2057,7 +2057,7 @@ Beater_generate_a(Beater *self) {
         self->dur_buffer_streams[i + self->voiceCount * self->bufsize] = self->durations[self->tapCount];
         if (self->currentTime >= tm) {
             self->currentTime -= tm;
-            if (self->tapCount == (self->last_taps-1))
+            if (self->tapCount == (self->last_taps-2))
                 self->end_buffer_streams[i + self->voiceCount * self->bufsize] = 1.0;
             if (self->sequence[self->tapCount] == 1) {
                 self->currentTap = self->tapCount;
@@ -2301,6 +2301,17 @@ Beater_setTime(Beater *self, PyObject *arg)
 }	
 
 static PyObject *
+Beater_reset(Beater *self)
+{
+    self->voiceCount = 0;
+    self->tapCount = 0;
+    self->currentTap = 0;
+    self->currentTime = -1.0;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
 Beater_setTaps(Beater *self, PyObject *arg)
 {    
 	if (PyInt_Check(arg))
@@ -2449,6 +2460,7 @@ static PyMethodDef Beater_methods[] = {
     {"recall", (PyCFunction)Beater_recallPreset, METH_O, "Recall a pattern previously stored in a memory slot."},
     {"getPresets", (PyCFunction)Beater_getPresets, METH_NOARGS, "Returns the list of stored presets."},
     {"setPresets", (PyCFunction)Beater_setPresets, METH_O, "Store a list of presets."},
+    {"reset", (PyCFunction)Beater_reset, METH_NOARGS, "Resets counters to 0."},
     {NULL}  /* Sentinel */
 };
 
@@ -3743,3 +3755,1582 @@ PyTypeObject BeatEndStreamType = {
     0,                         /* tp_alloc */
     BeatEndStream_new,                 /* tp_new */
 };
+
+/****************/
+/**** TrigBurster *****/
+/****************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    int modebuffer[1];
+    int poly;
+    int voiceCount;
+    MYFLT time;
+    MYFLT a_time;
+    int count;
+    int a_count;
+    MYFLT expand;
+    MYFLT a_expand;
+    MYFLT ampfade;
+    MYFLT a_ampfade;
+    int flag;
+    double sampleToSec;
+    double currentTime;
+    double targetTime;
+    int currentCount;
+    int *currentTap;
+    MYFLT *currentAmp;
+    MYFLT *currentDur;
+    MYFLT *buffer_streams;
+    MYFLT *tap_buffer_streams;
+    MYFLT *amp_buffer_streams;
+    MYFLT *dur_buffer_streams;
+    MYFLT *end_buffer_streams;
+} TrigBurster;
+
+static void
+TrigBurster_generate_i(TrigBurster *self) {
+    int i, j;
+    
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    
+    for (i=0; i<(self->poly*self->bufsize); i++) {
+        self->buffer_streams[i] = self->end_buffer_streams[i] = 0.0;
+    }
+    
+    for (i=0; i<self->bufsize; i++) {
+        if (in[i] == 1.0) {
+            self->flag = 1;
+            self->currentCount = 0;
+            self->a_time = self->targetTime = self->currentTime = self->time;
+            self->a_count = self->count;
+            self->a_expand = self->expand;
+            self->a_ampfade = self->ampfade;
+        }
+        if (self->flag == 1) {
+            if (self->currentTime >= self->targetTime) {
+                self->currentTime -= self->targetTime;
+                self->targetTime = self->a_time * MYPOW(self->a_expand, self->currentCount);
+                self->currentTap[self->voiceCount] = self->currentCount;
+                self->currentAmp[self->voiceCount] = MYPOW(self->a_ampfade, self->currentCount);
+                self->currentDur[self->voiceCount] = self->targetTime;
+                self->buffer_streams[i + self->voiceCount * self->bufsize] = 1.0;
+                self->currentCount++;
+                if (self->currentCount == (self->a_count - 1))
+                    self->end_buffer_streams[i + self->voiceCount * self->bufsize] = 1.0;
+                if (self->currentCount == self->a_count)
+                    self->flag = 0;
+                self->voiceCount++;
+                if (self->voiceCount == self->poly)
+                    self->voiceCount = 0;
+            }
+            self->currentTime += self->sampleToSec;
+        }
+        for (j=0; j<self->poly; j++) {
+            self->tap_buffer_streams[i + j * self->bufsize] = (MYFLT)self->currentTap[j];
+            self->amp_buffer_streams[i + j * self->bufsize] = self->currentAmp[j];
+            self->dur_buffer_streams[i + j * self->bufsize] = self->currentDur[j];
+        }
+    }
+}
+
+MYFLT *
+TrigBurster_getSamplesBuffer(TrigBurster *self)
+{
+    return (MYFLT *)self->buffer_streams;
+}    
+
+MYFLT *
+TrigBurster_getTapBuffer(TrigBurster *self)
+{
+    return (MYFLT *)self->tap_buffer_streams;
+}    
+
+MYFLT *
+TrigBurster_getAmpBuffer(TrigBurster *self)
+{
+    return (MYFLT *)self->amp_buffer_streams;
+}    
+
+MYFLT *
+TrigBurster_getDurBuffer(TrigBurster *self)
+{
+    return (MYFLT *)self->dur_buffer_streams;
+}    
+
+MYFLT *
+TrigBurster_getEndBuffer(TrigBurster *self)
+{
+    return (MYFLT *)self->end_buffer_streams;
+}    
+
+static void
+TrigBurster_setProcMode(TrigBurster *self)
+{
+    self->proc_func_ptr = TrigBurster_generate_i;
+}
+
+static void
+TrigBurster_compute_next_data_frame(TrigBurster *self)
+{
+    (*self->proc_func_ptr)(self);    
+}
+
+static int
+TrigBurster_traverse(TrigBurster *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    return 0;
+}
+
+static int 
+TrigBurster_clear(TrigBurster *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    return 0;
+}
+
+static void
+TrigBurster_dealloc(TrigBurster* self)
+{
+    pyo_DEALLOC
+    free(self->buffer_streams);
+    free(self->tap_buffer_streams);
+    free(self->amp_buffer_streams);
+    free(self->dur_buffer_streams);
+    free(self->end_buffer_streams);
+    free(self->currentTap);
+    free(self->currentAmp);
+    free(self->currentDur);
+    TrigBurster_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurster_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *inputtmp, *input_streamtmp;
+    TrigBurster *self;
+    self = (TrigBurster *)type->tp_alloc(type, 0);
+    
+    
+    self->poly = 1;
+    self->voiceCount = 0;
+    self->time = self->a_time = 0.25;
+    self->count = self->a_count = 10;
+    self->expand = self->a_expand = 1.0;
+    self->ampfade = self->a_ampfade = 1.0;
+    self->currentCount = 0;
+    self->targetTime = 0.0;
+    self->currentTime = -1.0;
+    self->flag = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, TrigBurster_compute_next_data_frame);
+    self->mode_func_ptr = TrigBurster_setProcMode;
+    
+    self->sampleToSec = 1. / self->sr;
+
+    Stream_setStreamActive(self->stream, 1);
+
+    static char *kwlist[] = {"input", "time", "count", "expand", "ampfade", "poly", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_FIFFI, kwlist, &inputtmp, &self->time, &self->count, &self->expand, &self->ampfade, &self->poly))
+        Py_RETURN_NONE;
+    
+    INIT_INPUT_STREAM
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+
+    self->buffer_streams = (MYFLT *)realloc(self->buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+    self->tap_buffer_streams = (MYFLT *)realloc(self->tap_buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+    self->amp_buffer_streams = (MYFLT *)realloc(self->amp_buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+    self->dur_buffer_streams = (MYFLT *)realloc(self->dur_buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+    self->end_buffer_streams = (MYFLT *)realloc(self->end_buffer_streams, self->poly * self->bufsize * sizeof(MYFLT));
+    for (i=0; i<(self->poly*self->bufsize); i++) {
+        self->buffer_streams[i] = self->tap_buffer_streams[i] = self->amp_buffer_streams[i] = self->dur_buffer_streams[i] = self->end_buffer_streams[i] = 0.0;
+    }
+
+    self->currentTap = (int *)realloc(self->currentTap, self->poly * sizeof(int));
+    self->currentAmp = (MYFLT *)realloc(self->currentAmp, self->poly * sizeof(MYFLT));
+    self->currentDur = (MYFLT *)realloc(self->currentDur, self->poly * sizeof(MYFLT));
+    for (i=0; i<(self->poly); i++) {
+        self->currentTap[i] = 0;
+        self->currentAmp[i] = self->currentDur[i] = 0.0;
+    }
+
+    return (PyObject *)self;
+}
+
+static PyObject * TrigBurster_getServer(TrigBurster* self) { GET_SERVER };
+static PyObject * TrigBurster_getStream(TrigBurster* self) { GET_STREAM };
+
+static PyObject * TrigBurster_play(TrigBurster *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurster_stop(TrigBurster *self) { STOP };
+
+static PyObject *
+TrigBurster_setTime(TrigBurster *self, PyObject *arg)
+{    
+	if (PyNumber_Check(arg))
+        self->time = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (self->time <= 0.01) 
+            self->time = 0.01;
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+TrigBurster_setCount(TrigBurster *self, PyObject *arg)
+{    
+	if (PyInt_Check(arg))
+        self->count = PyInt_AS_LONG(arg);
+        if (self->count < 1) 
+            self->count = 1;
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+TrigBurster_setExpand(TrigBurster *self, PyObject *arg)
+{    
+	if (PyNumber_Check(arg))
+        self->expand = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (self->expand <= 0.1) 
+            self->expand = 0.1;
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+TrigBurster_setAmpfade(TrigBurster *self, PyObject *arg)
+{    
+	if (PyNumber_Check(arg))
+        self->ampfade = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (self->ampfade <= 0.1) 
+            self->ampfade = 0.1;
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyMemberDef TrigBurster_members[] = {
+    {"server", T_OBJECT_EX, offsetof(TrigBurster, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(TrigBurster, stream), 0, "Stream object."},
+    {"input", T_OBJECT_EX, offsetof(TrigBurster, input), 0, "Input sound object."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef TrigBurster_methods[] = {
+    {"getServer", (PyCFunction)TrigBurster_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)TrigBurster_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)TrigBurster_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"stop", (PyCFunction)TrigBurster_stop, METH_NOARGS, "Stops computing."},
+    {"setTime", (PyCFunction)TrigBurster_setTime, METH_O, "Sets the base time of the serie."},
+    {"setCount", (PyCFunction)TrigBurster_setCount, METH_O, "Sets the number of trigs in the serie."},
+    {"setExpand", (PyCFunction)TrigBurster_setExpand, METH_O, "Sets the time's expansion factor of the serie."},
+    {"setAmpfade", (PyCFunction)TrigBurster_setAmpfade, METH_O, "Sets the amplitude's expansion factor of the serie."},
+    {NULL}  /* Sentinel */
+};
+
+PyTypeObject TrigBursterType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "_pyo.TrigBurster_base",         /*tp_name*/
+    sizeof(TrigBurster),         /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)TrigBurster_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,             /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+    "TrigBurster objects. Create an algorithmic beat sequence.",           /* tp_doc */
+    (traverseproc)TrigBurster_traverse,   /* tp_traverse */
+    (inquiry)TrigBurster_clear,           /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    TrigBurster_methods,             /* tp_methods */
+    TrigBurster_members,             /* tp_members */
+    0,                      /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,      /* tp_init */
+    0,                         /* tp_alloc */
+    TrigBurster_new,                 /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurst streamer object per channel */
+/************************************************************************************************/
+typedef struct {
+    pyo_audio_HEAD
+    TrigBurster *mainPlayer;
+    int chnl; 
+    int modebuffer[2];
+} TrigBurst;
+
+static void TrigBurst_postprocessing_ii(TrigBurst *self) { POST_PROCESSING_II };
+static void TrigBurst_postprocessing_ai(TrigBurst *self) { POST_PROCESSING_AI };
+static void TrigBurst_postprocessing_ia(TrigBurst *self) { POST_PROCESSING_IA };
+static void TrigBurst_postprocessing_aa(TrigBurst *self) { POST_PROCESSING_AA };
+static void TrigBurst_postprocessing_ireva(TrigBurst *self) { POST_PROCESSING_IREVA };
+static void TrigBurst_postprocessing_areva(TrigBurst *self) { POST_PROCESSING_AREVA };
+static void TrigBurst_postprocessing_revai(TrigBurst *self) { POST_PROCESSING_REVAI };
+static void TrigBurst_postprocessing_revaa(TrigBurst *self) { POST_PROCESSING_REVAA };
+static void TrigBurst_postprocessing_revareva(TrigBurst *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurst_setProcMode(TrigBurst *self) {
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = TrigBurst_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = TrigBurst_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = TrigBurst_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = TrigBurst_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = TrigBurst_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = TrigBurst_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = TrigBurst_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = TrigBurst_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = TrigBurst_postprocessing_revareva;
+            break;
+    }  
+}
+
+static void
+TrigBurst_compute_next_data_frame(TrigBurst *self)
+{
+    int i;
+    MYFLT *tmp;
+    int offset = self->chnl * self->bufsize;
+    tmp = TrigBurster_getSamplesBuffer((TrigBurster *)self->mainPlayer);
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = tmp[i + offset];
+    }    
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurst_traverse(TrigBurst *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->mainPlayer);
+    return 0;
+}
+
+static int 
+TrigBurst_clear(TrigBurst *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->mainPlayer);    
+    return 0;
+}
+
+static void
+TrigBurst_dealloc(TrigBurst* self)
+{
+    pyo_DEALLOC
+    TrigBurst_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurst_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *maintmp=NULL;
+    TrigBurst *self;
+    self = (TrigBurst *)type->tp_alloc(type, 0);
+    
+    self->chnl = 0;
+    self->modebuffer[0] = 0;
+    self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, TrigBurst_compute_next_data_frame);
+    self->mode_func_ptr = TrigBurst_setProcMode;
+
+    static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+        Py_RETURN_NONE;
+    
+    Py_XDECREF(self->mainPlayer);
+    Py_INCREF(maintmp);
+    self->mainPlayer = (TrigBurster *)maintmp;
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * TrigBurst_getServer(TrigBurst* self) { GET_SERVER };
+static PyObject * TrigBurst_getStream(TrigBurst* self) { GET_STREAM };
+static PyObject * TrigBurst_setMul(TrigBurst *self, PyObject *arg) { SET_MUL };	
+static PyObject * TrigBurst_setAdd(TrigBurst *self, PyObject *arg) { SET_ADD };	
+static PyObject * TrigBurst_setSub(TrigBurst *self, PyObject *arg) { SET_SUB };	
+static PyObject * TrigBurst_setDiv(TrigBurst *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * TrigBurst_play(TrigBurst *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurst_out(TrigBurst *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurst_stop(TrigBurst *self) { STOP };
+
+static PyObject * TrigBurst_multiply(TrigBurst *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurst_inplace_multiply(TrigBurst *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurst_add(TrigBurst *self, PyObject *arg) { ADD };
+static PyObject * TrigBurst_inplace_add(TrigBurst *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurst_sub(TrigBurst *self, PyObject *arg) { SUB };
+static PyObject * TrigBurst_inplace_sub(TrigBurst *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurst_div(TrigBurst *self, PyObject *arg) { DIV };
+static PyObject * TrigBurst_inplace_div(TrigBurst *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurst_members[] = {
+    {"server", T_OBJECT_EX, offsetof(TrigBurst, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(TrigBurst, stream), 0, "Stream object."},
+    {"mul", T_OBJECT_EX, offsetof(TrigBurst, mul), 0, "Mul factor."},
+    {"add", T_OBJECT_EX, offsetof(TrigBurst, add), 0, "Add factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef TrigBurst_methods[] = {
+    {"getServer", (PyCFunction)TrigBurst_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)TrigBurst_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)TrigBurst_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"out", (PyCFunction)TrigBurst_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+    {"stop", (PyCFunction)TrigBurst_stop, METH_NOARGS, "Stops computing."},
+    {"setMul", (PyCFunction)TrigBurst_setMul, METH_O, "Sets oscillator mul factor."},
+    {"setAdd", (PyCFunction)TrigBurst_setAdd, METH_O, "Sets oscillator add factor."},
+    {"setSub", (PyCFunction)TrigBurst_setSub, METH_O, "Sets inverse add factor."},
+    {"setDiv", (PyCFunction)TrigBurst_setDiv, METH_O, "Sets inverse mul factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyNumberMethods TrigBurst_as_number = {
+    (binaryfunc)TrigBurst_add,                         /*nb_add*/
+    (binaryfunc)TrigBurst_sub,                         /*nb_subtract*/
+    (binaryfunc)TrigBurst_multiply,                    /*nb_multiply*/
+    (binaryfunc)TrigBurst_div,                                              /*nb_divide*/
+    0,                                              /*nb_remainder*/
+    0,                                              /*nb_divmod*/
+    0,                                              /*nb_power*/
+    0,                                              /*nb_neg*/
+    0,                                              /*nb_pos*/
+    0,                                              /*(unaryfunc)array_abs,*/
+    0,                                              /*nb_nonzero*/
+    0,                                              /*nb_invert*/
+    0,                                              /*nb_lshift*/
+    0,                                              /*nb_rshift*/
+    0,                                              /*nb_and*/
+    0,                                              /*nb_xor*/
+    0,                                              /*nb_or*/
+    0,                                              /*nb_coerce*/
+    0,                                              /*nb_int*/
+    0,                                              /*nb_long*/
+    0,                                              /*nb_float*/
+    0,                                              /*nb_oct*/
+    0,                                              /*nb_hex*/
+    (binaryfunc)TrigBurst_inplace_add,                 /*inplace_add*/
+    (binaryfunc)TrigBurst_inplace_sub,                 /*inplace_subtract*/
+    (binaryfunc)TrigBurst_inplace_multiply,            /*inplace_multiply*/
+    (binaryfunc)TrigBurst_inplace_div,                                              /*inplace_divide*/
+    0,                                              /*inplace_remainder*/
+    0,                                              /*inplace_power*/
+    0,                                              /*inplace_lshift*/
+    0,                                              /*inplace_rshift*/
+    0,                                              /*inplace_and*/
+    0,                                              /*inplace_xor*/
+    0,                                              /*inplace_or*/
+    0,                                              /*nb_floor_divide*/
+    0,                                              /*nb_true_divide*/
+    0,                                              /*nb_inplace_floor_divide*/
+    0,                                              /*nb_inplace_true_divide*/
+    0,                                              /* nb_index */
+};
+
+PyTypeObject TrigBurstType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "_pyo.TrigBurst_base",         /*tp_name*/
+    sizeof(TrigBurst),         /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)TrigBurst_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    &TrigBurst_as_number,             /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,  /*tp_flags*/
+    "TrigBurst objects. Reads a channel from a TrigBurster.",           /* tp_doc */
+    (traverseproc)TrigBurst_traverse,   /* tp_traverse */
+    (inquiry)TrigBurst_clear,           /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    TrigBurst_methods,             /* tp_methods */
+    TrigBurst_members,             /* tp_members */
+    0,                      /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,      /* tp_init */
+    0,                         /* tp_alloc */
+    TrigBurst_new,                 /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurstTapStream object per channel */
+/************************************************************************************************/
+typedef struct {
+    pyo_audio_HEAD
+    TrigBurster *mainPlayer;
+    int chnl; 
+    int modebuffer[2];
+} TrigBurstTapStream;
+
+static void TrigBurstTapStream_postprocessing_ii(TrigBurstTapStream *self) { POST_PROCESSING_II };
+static void TrigBurstTapStream_postprocessing_ai(TrigBurstTapStream *self) { POST_PROCESSING_AI };
+static void TrigBurstTapStream_postprocessing_ia(TrigBurstTapStream *self) { POST_PROCESSING_IA };
+static void TrigBurstTapStream_postprocessing_aa(TrigBurstTapStream *self) { POST_PROCESSING_AA };
+static void TrigBurstTapStream_postprocessing_ireva(TrigBurstTapStream *self) { POST_PROCESSING_IREVA };
+static void TrigBurstTapStream_postprocessing_areva(TrigBurstTapStream *self) { POST_PROCESSING_AREVA };
+static void TrigBurstTapStream_postprocessing_revai(TrigBurstTapStream *self) { POST_PROCESSING_REVAI };
+static void TrigBurstTapStream_postprocessing_revaa(TrigBurstTapStream *self) { POST_PROCESSING_REVAA };
+static void TrigBurstTapStream_postprocessing_revareva(TrigBurstTapStream *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurstTapStream_setProcMode(TrigBurstTapStream *self) {
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = TrigBurstTapStream_postprocessing_revareva;
+            break;
+    }  
+}
+
+static void
+TrigBurstTapStream_compute_next_data_frame(TrigBurstTapStream *self)
+{
+    int i;
+    MYFLT *tmp;
+    int offset = self->chnl * self->bufsize;
+    tmp = TrigBurster_getTapBuffer((TrigBurster *)self->mainPlayer);
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = tmp[i + offset];
+    }    
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurstTapStream_traverse(TrigBurstTapStream *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->mainPlayer);
+    return 0;
+}
+
+static int 
+TrigBurstTapStream_clear(TrigBurstTapStream *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->mainPlayer);    
+    return 0;
+}
+
+static void
+TrigBurstTapStream_dealloc(TrigBurstTapStream* self)
+{
+    pyo_DEALLOC
+    TrigBurstTapStream_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurstTapStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *maintmp=NULL;
+    TrigBurstTapStream *self;
+    self = (TrigBurstTapStream *)type->tp_alloc(type, 0);
+    
+    self->chnl = 0;
+    self->modebuffer[0] = 0;
+    self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, TrigBurstTapStream_compute_next_data_frame);
+    self->mode_func_ptr = TrigBurstTapStream_setProcMode;
+
+    static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+        Py_RETURN_NONE;
+    
+    Py_XDECREF(self->mainPlayer);
+    Py_INCREF(maintmp);
+    self->mainPlayer = (TrigBurster *)maintmp;
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * TrigBurstTapStream_getServer(TrigBurstTapStream* self) { GET_SERVER };
+static PyObject * TrigBurstTapStream_getStream(TrigBurstTapStream* self) { GET_STREAM };
+static PyObject * TrigBurstTapStream_setMul(TrigBurstTapStream *self, PyObject *arg) { SET_MUL };	
+static PyObject * TrigBurstTapStream_setAdd(TrigBurstTapStream *self, PyObject *arg) { SET_ADD };	
+static PyObject * TrigBurstTapStream_setSub(TrigBurstTapStream *self, PyObject *arg) { SET_SUB };	
+static PyObject * TrigBurstTapStream_setDiv(TrigBurstTapStream *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * TrigBurstTapStream_play(TrigBurstTapStream *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurstTapStream_out(TrigBurstTapStream *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurstTapStream_stop(TrigBurstTapStream *self) { STOP };
+
+static PyObject * TrigBurstTapStream_multiply(TrigBurstTapStream *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurstTapStream_inplace_multiply(TrigBurstTapStream *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurstTapStream_add(TrigBurstTapStream *self, PyObject *arg) { ADD };
+static PyObject * TrigBurstTapStream_inplace_add(TrigBurstTapStream *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurstTapStream_sub(TrigBurstTapStream *self, PyObject *arg) { SUB };
+static PyObject * TrigBurstTapStream_inplace_sub(TrigBurstTapStream *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurstTapStream_div(TrigBurstTapStream *self, PyObject *arg) { DIV };
+static PyObject * TrigBurstTapStream_inplace_div(TrigBurstTapStream *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurstTapStream_members[] = {
+    {"server", T_OBJECT_EX, offsetof(TrigBurstTapStream, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(TrigBurstTapStream, stream), 0, "Stream object."},
+    {"mul", T_OBJECT_EX, offsetof(TrigBurstTapStream, mul), 0, "Mul factor."},
+    {"add", T_OBJECT_EX, offsetof(TrigBurstTapStream, add), 0, "Add factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef TrigBurstTapStream_methods[] = {
+    {"getServer", (PyCFunction)TrigBurstTapStream_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)TrigBurstTapStream_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)TrigBurstTapStream_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"out", (PyCFunction)TrigBurstTapStream_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+    {"stop", (PyCFunction)TrigBurstTapStream_stop, METH_NOARGS, "Stops computing."},
+    {"setMul", (PyCFunction)TrigBurstTapStream_setMul, METH_O, "Sets oscillator mul factor."},
+    {"setAdd", (PyCFunction)TrigBurstTapStream_setAdd, METH_O, "Sets oscillator add factor."},
+    {"setSub", (PyCFunction)TrigBurstTapStream_setSub, METH_O, "Sets inverse add factor."},
+    {"setDiv", (PyCFunction)TrigBurstTapStream_setDiv, METH_O, "Sets inverse mul factor."},    
+    {NULL}  /* Sentinel */
+};
+
+static PyNumberMethods TrigBurstTapStream_as_number = {
+    (binaryfunc)TrigBurstTapStream_add,                         /*nb_add*/
+    (binaryfunc)TrigBurstTapStream_sub,                         /*nb_subtract*/
+    (binaryfunc)TrigBurstTapStream_multiply,                    /*nb_multiply*/
+    (binaryfunc)TrigBurstTapStream_div,                                              /*nb_divide*/
+    0,                                              /*nb_remainder*/
+    0,                                              /*nb_divmod*/
+    0,                                              /*nb_power*/
+    0,                                              /*nb_neg*/
+    0,                                              /*nb_pos*/
+    0,                                              /*(unaryfunc)array_abs,*/
+    0,                                              /*nb_nonzero*/
+    0,                                              /*nb_invert*/
+    0,                                              /*nb_lshift*/
+    0,                                              /*nb_rshift*/
+    0,                                              /*nb_and*/
+    0,                                              /*nb_xor*/
+    0,                                              /*nb_or*/
+    0,                                              /*nb_coerce*/
+    0,                                              /*nb_int*/
+    0,                                              /*nb_long*/
+    0,                                              /*nb_float*/
+    0,                                              /*nb_oct*/
+    0,                                              /*nb_hex*/
+    (binaryfunc)TrigBurstTapStream_inplace_add,                 /*inplace_add*/
+    (binaryfunc)TrigBurstTapStream_inplace_sub,                 /*inplace_subtract*/
+    (binaryfunc)TrigBurstTapStream_inplace_multiply,            /*inplace_multiply*/
+    (binaryfunc)TrigBurstTapStream_inplace_div,                                              /*inplace_divide*/
+    0,                                              /*inplace_remainder*/
+    0,                                              /*inplace_power*/
+    0,                                              /*inplace_lshift*/
+    0,                                              /*inplace_rshift*/
+    0,                                              /*inplace_and*/
+    0,                                              /*inplace_xor*/
+    0,                                              /*inplace_or*/
+    0,                                              /*nb_floor_divide*/
+    0,                                              /*nb_true_divide*/
+    0,                                              /*nb_inplace_floor_divide*/
+    0,                                              /*nb_inplace_true_divide*/
+    0,                                              /* nb_index */
+};
+
+PyTypeObject TrigBurstTapStreamType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "_pyo.TrigBurstTapStream_base",         /*tp_name*/
+    sizeof(TrigBurstTapStream),         /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)TrigBurstTapStream_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    &TrigBurstTapStream_as_number,             /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,  /*tp_flags*/
+    "TrigBurstTapStream objects. Reads the current tap from a TrigBurster object.",           /* tp_doc */
+    (traverseproc)TrigBurstTapStream_traverse,   /* tp_traverse */
+    (inquiry)TrigBurstTapStream_clear,           /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    TrigBurstTapStream_methods,             /* tp_methods */
+    TrigBurstTapStream_members,             /* tp_members */
+    0,                      /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,      /* tp_init */
+    0,                         /* tp_alloc */
+    TrigBurstTapStream_new,                 /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurstAmpStream object per channel */
+/************************************************************************************************/
+typedef struct {
+    pyo_audio_HEAD
+    TrigBurster *mainPlayer;
+    int chnl; 
+    int modebuffer[2];
+} TrigBurstAmpStream;
+
+static void TrigBurstAmpStream_postprocessing_ii(TrigBurstAmpStream *self) { POST_PROCESSING_II };
+static void TrigBurstAmpStream_postprocessing_ai(TrigBurstAmpStream *self) { POST_PROCESSING_AI };
+static void TrigBurstAmpStream_postprocessing_ia(TrigBurstAmpStream *self) { POST_PROCESSING_IA };
+static void TrigBurstAmpStream_postprocessing_aa(TrigBurstAmpStream *self) { POST_PROCESSING_AA };
+static void TrigBurstAmpStream_postprocessing_ireva(TrigBurstAmpStream *self) { POST_PROCESSING_IREVA };
+static void TrigBurstAmpStream_postprocessing_areva(TrigBurstAmpStream *self) { POST_PROCESSING_AREVA };
+static void TrigBurstAmpStream_postprocessing_revai(TrigBurstAmpStream *self) { POST_PROCESSING_REVAI };
+static void TrigBurstAmpStream_postprocessing_revaa(TrigBurstAmpStream *self) { POST_PROCESSING_REVAA };
+static void TrigBurstAmpStream_postprocessing_revareva(TrigBurstAmpStream *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurstAmpStream_setProcMode(TrigBurstAmpStream *self) {
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = TrigBurstAmpStream_postprocessing_revareva;
+            break;
+    }  
+}
+
+static void
+TrigBurstAmpStream_compute_next_data_frame(TrigBurstAmpStream *self)
+{
+    int i;
+    MYFLT *tmp;
+    int offset = self->chnl * self->bufsize;
+    tmp = TrigBurster_getAmpBuffer((TrigBurster *)self->mainPlayer);
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = tmp[i + offset];
+    }    
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurstAmpStream_traverse(TrigBurstAmpStream *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->mainPlayer);
+    return 0;
+}
+
+static int 
+TrigBurstAmpStream_clear(TrigBurstAmpStream *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->mainPlayer);    
+    return 0;
+}
+
+static void
+TrigBurstAmpStream_dealloc(TrigBurstAmpStream* self)
+{
+    pyo_DEALLOC
+    TrigBurstAmpStream_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurstAmpStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *maintmp=NULL;
+    TrigBurstAmpStream *self;
+    self = (TrigBurstAmpStream *)type->tp_alloc(type, 0);
+    
+    self->chnl = 0;
+    self->modebuffer[0] = 0;
+    self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, TrigBurstAmpStream_compute_next_data_frame);
+    self->mode_func_ptr = TrigBurstAmpStream_setProcMode;
+
+    static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+        Py_RETURN_NONE;
+    
+    Py_XDECREF(self->mainPlayer);
+    Py_INCREF(maintmp);
+    self->mainPlayer = (TrigBurster *)maintmp;
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * TrigBurstAmpStream_getServer(TrigBurstAmpStream* self) { GET_SERVER };
+static PyObject * TrigBurstAmpStream_getStream(TrigBurstAmpStream* self) { GET_STREAM };
+static PyObject * TrigBurstAmpStream_setMul(TrigBurstAmpStream *self, PyObject *arg) { SET_MUL };	
+static PyObject * TrigBurstAmpStream_setAdd(TrigBurstAmpStream *self, PyObject *arg) { SET_ADD };	
+static PyObject * TrigBurstAmpStream_setSub(TrigBurstAmpStream *self, PyObject *arg) { SET_SUB };	
+static PyObject * TrigBurstAmpStream_setDiv(TrigBurstAmpStream *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * TrigBurstAmpStream_play(TrigBurstAmpStream *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurstAmpStream_out(TrigBurstAmpStream *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurstAmpStream_stop(TrigBurstAmpStream *self) { STOP };
+
+static PyObject * TrigBurstAmpStream_multiply(TrigBurstAmpStream *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurstAmpStream_inplace_multiply(TrigBurstAmpStream *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurstAmpStream_add(TrigBurstAmpStream *self, PyObject *arg) { ADD };
+static PyObject * TrigBurstAmpStream_inplace_add(TrigBurstAmpStream *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurstAmpStream_sub(TrigBurstAmpStream *self, PyObject *arg) { SUB };
+static PyObject * TrigBurstAmpStream_inplace_sub(TrigBurstAmpStream *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurstAmpStream_div(TrigBurstAmpStream *self, PyObject *arg) { DIV };
+static PyObject * TrigBurstAmpStream_inplace_div(TrigBurstAmpStream *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurstAmpStream_members[] = {
+    {"server", T_OBJECT_EX, offsetof(TrigBurstAmpStream, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(TrigBurstAmpStream, stream), 0, "Stream object."},
+    {"mul", T_OBJECT_EX, offsetof(TrigBurstAmpStream, mul), 0, "Mul factor."},
+    {"add", T_OBJECT_EX, offsetof(TrigBurstAmpStream, add), 0, "Add factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef TrigBurstAmpStream_methods[] = {
+    {"getServer", (PyCFunction)TrigBurstAmpStream_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)TrigBurstAmpStream_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)TrigBurstAmpStream_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"out", (PyCFunction)TrigBurstAmpStream_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+    {"stop", (PyCFunction)TrigBurstAmpStream_stop, METH_NOARGS, "Stops computing."},
+    {"setMul", (PyCFunction)TrigBurstAmpStream_setMul, METH_O, "Sets oscillator mul factor."},
+    {"setAdd", (PyCFunction)TrigBurstAmpStream_setAdd, METH_O, "Sets oscillator add factor."},
+    {"setSub", (PyCFunction)TrigBurstAmpStream_setSub, METH_O, "Sets inverse add factor."},
+    {"setDiv", (PyCFunction)TrigBurstAmpStream_setDiv, METH_O, "Sets inverse mul factor."},    
+    {NULL}  /* Sentinel */
+};
+
+static PyNumberMethods TrigBurstAmpStream_as_number = {
+    (binaryfunc)TrigBurstAmpStream_add,                         /*nb_add*/
+    (binaryfunc)TrigBurstAmpStream_sub,                         /*nb_subtract*/
+    (binaryfunc)TrigBurstAmpStream_multiply,                    /*nb_multiply*/
+    (binaryfunc)TrigBurstAmpStream_div,                                              /*nb_divide*/
+    0,                                              /*nb_remainder*/
+    0,                                              /*nb_divmod*/
+    0,                                              /*nb_power*/
+    0,                                              /*nb_neg*/
+    0,                                              /*nb_pos*/
+    0,                                              /*(unaryfunc)array_abs,*/
+    0,                                              /*nb_nonzero*/
+    0,                                              /*nb_invert*/
+    0,                                              /*nb_lshift*/
+    0,                                              /*nb_rshift*/
+    0,                                              /*nb_and*/
+    0,                                              /*nb_xor*/
+    0,                                              /*nb_or*/
+    0,                                              /*nb_coerce*/
+    0,                                              /*nb_int*/
+    0,                                              /*nb_long*/
+    0,                                              /*nb_float*/
+    0,                                              /*nb_oct*/
+    0,                                              /*nb_hex*/
+    (binaryfunc)TrigBurstAmpStream_inplace_add,                 /*inplace_add*/
+    (binaryfunc)TrigBurstAmpStream_inplace_sub,                 /*inplace_subtract*/
+    (binaryfunc)TrigBurstAmpStream_inplace_multiply,            /*inplace_multiply*/
+    (binaryfunc)TrigBurstAmpStream_inplace_div,                                              /*inplace_divide*/
+    0,                                              /*inplace_remainder*/
+    0,                                              /*inplace_power*/
+    0,                                              /*inplace_lshift*/
+    0,                                              /*inplace_rshift*/
+    0,                                              /*inplace_and*/
+    0,                                              /*inplace_xor*/
+    0,                                              /*inplace_or*/
+    0,                                              /*nb_floor_divide*/
+    0,                                              /*nb_true_divide*/
+    0,                                              /*nb_inplace_floor_divide*/
+    0,                                              /*nb_inplace_true_divide*/
+    0,                                              /* nb_index */
+};
+
+PyTypeObject TrigBurstAmpStreamType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "_pyo.TrigBurstAmpStream_base",         /*tp_name*/
+    sizeof(TrigBurstAmpStream),         /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)TrigBurstAmpStream_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    &TrigBurstAmpStream_as_number,             /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,  /*tp_flags*/
+    "TrigBurstAmpStream objects. Reads a amplitude channel from a TrigBurster object.",           /* tp_doc */
+    (traverseproc)TrigBurstAmpStream_traverse,   /* tp_traverse */
+    (inquiry)TrigBurstAmpStream_clear,           /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    TrigBurstAmpStream_methods,             /* tp_methods */
+    TrigBurstAmpStream_members,             /* tp_members */
+    0,                      /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,      /* tp_init */
+    0,                         /* tp_alloc */
+    TrigBurstAmpStream_new,                 /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurstDurStream object per channel */
+/************************************************************************************************/
+typedef struct {
+    pyo_audio_HEAD
+    TrigBurster *mainPlayer;
+    int chnl; 
+    int modebuffer[2];
+} TrigBurstDurStream;
+
+static void TrigBurstDurStream_postprocessing_ii(TrigBurstDurStream *self) { POST_PROCESSING_II };
+static void TrigBurstDurStream_postprocessing_ai(TrigBurstDurStream *self) { POST_PROCESSING_AI };
+static void TrigBurstDurStream_postprocessing_ia(TrigBurstDurStream *self) { POST_PROCESSING_IA };
+static void TrigBurstDurStream_postprocessing_aa(TrigBurstDurStream *self) { POST_PROCESSING_AA };
+static void TrigBurstDurStream_postprocessing_ireva(TrigBurstDurStream *self) { POST_PROCESSING_IREVA };
+static void TrigBurstDurStream_postprocessing_areva(TrigBurstDurStream *self) { POST_PROCESSING_AREVA };
+static void TrigBurstDurStream_postprocessing_revai(TrigBurstDurStream *self) { POST_PROCESSING_REVAI };
+static void TrigBurstDurStream_postprocessing_revaa(TrigBurstDurStream *self) { POST_PROCESSING_REVAA };
+static void TrigBurstDurStream_postprocessing_revareva(TrigBurstDurStream *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurstDurStream_setProcMode(TrigBurstDurStream *self) {
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = TrigBurstDurStream_postprocessing_revareva;
+            break;
+    }  
+}
+
+static void
+TrigBurstDurStream_compute_next_data_frame(TrigBurstDurStream *self)
+{
+    int i;
+    MYFLT *tmp;
+    int offset = self->chnl * self->bufsize;
+    tmp = TrigBurster_getDurBuffer((TrigBurster *)self->mainPlayer);
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = tmp[i + offset];
+    }    
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurstDurStream_traverse(TrigBurstDurStream *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->mainPlayer);
+    return 0;
+}
+
+static int 
+TrigBurstDurStream_clear(TrigBurstDurStream *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->mainPlayer);    
+    return 0;
+}
+
+static void
+TrigBurstDurStream_dealloc(TrigBurstDurStream* self)
+{
+    pyo_DEALLOC
+    TrigBurstDurStream_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurstDurStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *maintmp=NULL;
+    TrigBurstDurStream *self;
+    self = (TrigBurstDurStream *)type->tp_alloc(type, 0);
+    
+    self->chnl = 0;
+    self->modebuffer[0] = 0;
+    self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, TrigBurstDurStream_compute_next_data_frame);
+    self->mode_func_ptr = TrigBurstDurStream_setProcMode;
+
+    static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+        Py_RETURN_NONE;
+    
+    Py_XDECREF(self->mainPlayer);
+    Py_INCREF(maintmp);
+    self->mainPlayer = (TrigBurster *)maintmp;
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * TrigBurstDurStream_getServer(TrigBurstDurStream* self) { GET_SERVER };
+static PyObject * TrigBurstDurStream_getStream(TrigBurstDurStream* self) { GET_STREAM };
+static PyObject * TrigBurstDurStream_setMul(TrigBurstDurStream *self, PyObject *arg) { SET_MUL };	
+static PyObject * TrigBurstDurStream_setAdd(TrigBurstDurStream *self, PyObject *arg) { SET_ADD };	
+static PyObject * TrigBurstDurStream_setSub(TrigBurstDurStream *self, PyObject *arg) { SET_SUB };	
+static PyObject * TrigBurstDurStream_setDiv(TrigBurstDurStream *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * TrigBurstDurStream_play(TrigBurstDurStream *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurstDurStream_out(TrigBurstDurStream *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurstDurStream_stop(TrigBurstDurStream *self) { STOP };
+
+static PyObject * TrigBurstDurStream_multiply(TrigBurstDurStream *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurstDurStream_inplace_multiply(TrigBurstDurStream *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurstDurStream_add(TrigBurstDurStream *self, PyObject *arg) { ADD };
+static PyObject * TrigBurstDurStream_inplace_add(TrigBurstDurStream *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurstDurStream_sub(TrigBurstDurStream *self, PyObject *arg) { SUB };
+static PyObject * TrigBurstDurStream_inplace_sub(TrigBurstDurStream *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurstDurStream_div(TrigBurstDurStream *self, PyObject *arg) { DIV };
+static PyObject * TrigBurstDurStream_inplace_div(TrigBurstDurStream *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurstDurStream_members[] = {
+    {"server", T_OBJECT_EX, offsetof(TrigBurstDurStream, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(TrigBurstDurStream, stream), 0, "Stream object."},
+    {"mul", T_OBJECT_EX, offsetof(TrigBurstDurStream, mul), 0, "Mul factor."},
+    {"add", T_OBJECT_EX, offsetof(TrigBurstDurStream, add), 0, "Add factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef TrigBurstDurStream_methods[] = {
+    {"getServer", (PyCFunction)TrigBurstDurStream_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)TrigBurstDurStream_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)TrigBurstDurStream_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"out", (PyCFunction)TrigBurstDurStream_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+    {"stop", (PyCFunction)TrigBurstDurStream_stop, METH_NOARGS, "Stops computing."},
+    {"setMul", (PyCFunction)TrigBurstDurStream_setMul, METH_O, "Sets oscillator mul factor."},
+    {"setAdd", (PyCFunction)TrigBurstDurStream_setAdd, METH_O, "Sets oscillator add factor."},
+    {"setSub", (PyCFunction)TrigBurstDurStream_setSub, METH_O, "Sets inverse add factor."},
+    {"setDiv", (PyCFunction)TrigBurstDurStream_setDiv, METH_O, "Sets inverse mul factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyNumberMethods TrigBurstDurStream_as_number = {
+    (binaryfunc)TrigBurstDurStream_add,                         /*nb_add*/
+    (binaryfunc)TrigBurstDurStream_sub,                         /*nb_subtract*/
+    (binaryfunc)TrigBurstDurStream_multiply,                    /*nb_multiply*/
+    (binaryfunc)TrigBurstDurStream_div,                                              /*nb_divide*/
+    0,                                              /*nb_remainder*/
+    0,                                              /*nb_divmod*/
+    0,                                              /*nb_power*/
+    0,                                              /*nb_neg*/
+    0,                                              /*nb_pos*/
+    0,                                              /*(unaryfunc)array_abs,*/
+    0,                                              /*nb_nonzero*/
+    0,                                              /*nb_invert*/
+    0,                                              /*nb_lshift*/
+    0,                                              /*nb_rshift*/
+    0,                                              /*nb_and*/
+    0,                                              /*nb_xor*/
+    0,                                              /*nb_or*/
+    0,                                              /*nb_coerce*/
+    0,                                              /*nb_int*/
+    0,                                              /*nb_long*/
+    0,                                              /*nb_float*/
+    0,                                              /*nb_oct*/
+    0,                                              /*nb_hex*/
+    (binaryfunc)TrigBurstDurStream_inplace_add,                 /*inplace_add*/
+    (binaryfunc)TrigBurstDurStream_inplace_sub,                 /*inplace_subtract*/
+    (binaryfunc)TrigBurstDurStream_inplace_multiply,            /*inplace_multiply*/
+    (binaryfunc)TrigBurstDurStream_inplace_div,                                              /*inplace_divide*/
+    0,                                              /*inplace_remainder*/
+    0,                                              /*inplace_power*/
+    0,                                              /*inplace_lshift*/
+    0,                                              /*inplace_rshift*/
+    0,                                              /*inplace_and*/
+    0,                                              /*inplace_xor*/
+    0,                                              /*inplace_or*/
+    0,                                              /*nb_floor_divide*/
+    0,                                              /*nb_true_divide*/
+    0,                                              /*nb_inplace_floor_divide*/
+    0,                                              /*nb_inplace_true_divide*/
+    0,                                              /* nb_index */
+};
+
+PyTypeObject TrigBurstDurStreamType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "_pyo.TrigBurstDurStream_base",         /*tp_name*/
+    sizeof(TrigBurstDurStream),         /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)TrigBurstDurStream_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    &TrigBurstDurStream_as_number,             /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,  /*tp_flags*/
+    "TrigBurstDurStream objects. Reads a duration channel from a TrigBurster object.",           /* tp_doc */
+    (traverseproc)TrigBurstDurStream_traverse,   /* tp_traverse */
+    (inquiry)TrigBurstDurStream_clear,           /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    TrigBurstDurStream_methods,             /* tp_methods */
+    TrigBurstDurStream_members,             /* tp_members */
+    0,                      /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,      /* tp_init */
+    0,                         /* tp_alloc */
+    TrigBurstDurStream_new,                 /* tp_new */
+};
+
+/************************************************************************************************/
+/* TrigBurstEndStream object per channel */
+/************************************************************************************************/
+typedef struct {
+    pyo_audio_HEAD
+    TrigBurster *mainPlayer;
+    int chnl; 
+    int modebuffer[2];
+} TrigBurstEndStream;
+
+static void TrigBurstEndStream_postprocessing_ii(TrigBurstEndStream *self) { POST_PROCESSING_II };
+static void TrigBurstEndStream_postprocessing_ai(TrigBurstEndStream *self) { POST_PROCESSING_AI };
+static void TrigBurstEndStream_postprocessing_ia(TrigBurstEndStream *self) { POST_PROCESSING_IA };
+static void TrigBurstEndStream_postprocessing_aa(TrigBurstEndStream *self) { POST_PROCESSING_AA };
+static void TrigBurstEndStream_postprocessing_ireva(TrigBurstEndStream *self) { POST_PROCESSING_IREVA };
+static void TrigBurstEndStream_postprocessing_areva(TrigBurstEndStream *self) { POST_PROCESSING_AREVA };
+static void TrigBurstEndStream_postprocessing_revai(TrigBurstEndStream *self) { POST_PROCESSING_REVAI };
+static void TrigBurstEndStream_postprocessing_revaa(TrigBurstEndStream *self) { POST_PROCESSING_REVAA };
+static void TrigBurstEndStream_postprocessing_revareva(TrigBurstEndStream *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrigBurstEndStream_setProcMode(TrigBurstEndStream *self) {
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = TrigBurstEndStream_postprocessing_revareva;
+            break;
+    }  
+}
+
+static void
+TrigBurstEndStream_compute_next_data_frame(TrigBurstEndStream *self)
+{
+    int i;
+    MYFLT *tmp;
+    int offset = self->chnl * self->bufsize;
+    tmp = TrigBurster_getEndBuffer((TrigBurster *)self->mainPlayer);
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = tmp[i + offset];
+    }    
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrigBurstEndStream_traverse(TrigBurstEndStream *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->mainPlayer);
+    return 0;
+}
+
+static int 
+TrigBurstEndStream_clear(TrigBurstEndStream *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->mainPlayer);    
+    return 0;
+}
+
+static void
+TrigBurstEndStream_dealloc(TrigBurstEndStream* self)
+{
+    pyo_DEALLOC
+    TrigBurstEndStream_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrigBurstEndStream_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *maintmp=NULL;
+    TrigBurstEndStream *self;
+    self = (TrigBurstEndStream *)type->tp_alloc(type, 0);
+    
+    self->chnl = 0;
+    self->modebuffer[0] = 0;
+    self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, TrigBurstEndStream_compute_next_data_frame);
+    self->mode_func_ptr = TrigBurstEndStream_setProcMode;
+
+    static char *kwlist[] = {"mainPlayer", "chnl", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist, &maintmp, &self->chnl))
+        Py_RETURN_NONE;
+    
+    Py_XDECREF(self->mainPlayer);
+    Py_INCREF(maintmp);
+    self->mainPlayer = (TrigBurster *)maintmp;
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * TrigBurstEndStream_getServer(TrigBurstEndStream* self) { GET_SERVER };
+static PyObject * TrigBurstEndStream_getStream(TrigBurstEndStream* self) { GET_STREAM };
+static PyObject * TrigBurstEndStream_setMul(TrigBurstEndStream *self, PyObject *arg) { SET_MUL };	
+static PyObject * TrigBurstEndStream_setAdd(TrigBurstEndStream *self, PyObject *arg) { SET_ADD };	
+static PyObject * TrigBurstEndStream_setSub(TrigBurstEndStream *self, PyObject *arg) { SET_SUB };	
+static PyObject * TrigBurstEndStream_setDiv(TrigBurstEndStream *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * TrigBurstEndStream_play(TrigBurstEndStream *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrigBurstEndStream_out(TrigBurstEndStream *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrigBurstEndStream_stop(TrigBurstEndStream *self) { STOP };
+
+static PyObject * TrigBurstEndStream_multiply(TrigBurstEndStream *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrigBurstEndStream_inplace_multiply(TrigBurstEndStream *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrigBurstEndStream_add(TrigBurstEndStream *self, PyObject *arg) { ADD };
+static PyObject * TrigBurstEndStream_inplace_add(TrigBurstEndStream *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrigBurstEndStream_sub(TrigBurstEndStream *self, PyObject *arg) { SUB };
+static PyObject * TrigBurstEndStream_inplace_sub(TrigBurstEndStream *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrigBurstEndStream_div(TrigBurstEndStream *self, PyObject *arg) { DIV };
+static PyObject * TrigBurstEndStream_inplace_div(TrigBurstEndStream *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef TrigBurstEndStream_members[] = {
+    {"server", T_OBJECT_EX, offsetof(TrigBurstEndStream, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(TrigBurstEndStream, stream), 0, "Stream object."},
+    {"mul", T_OBJECT_EX, offsetof(TrigBurstEndStream, mul), 0, "Mul factor."},
+    {"add", T_OBJECT_EX, offsetof(TrigBurstEndStream, add), 0, "Add factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef TrigBurstEndStream_methods[] = {
+    {"getServer", (PyCFunction)TrigBurstEndStream_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)TrigBurstEndStream_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)TrigBurstEndStream_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"out", (PyCFunction)TrigBurstEndStream_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+    {"stop", (PyCFunction)TrigBurstEndStream_stop, METH_NOARGS, "Stops computing."},
+    {"setMul", (PyCFunction)TrigBurstEndStream_setMul, METH_O, "Sets oscillator mul factor."},
+    {"setAdd", (PyCFunction)TrigBurstEndStream_setAdd, METH_O, "Sets oscillator add factor."},
+    {"setSub", (PyCFunction)TrigBurstEndStream_setSub, METH_O, "Sets inverse add factor."},
+    {"setDiv", (PyCFunction)TrigBurstEndStream_setDiv, METH_O, "Sets inverse mul factor."},    
+    {NULL}  /* Sentinel */
+};
+
+static PyNumberMethods TrigBurstEndStream_as_number = {
+    (binaryfunc)TrigBurstEndStream_add,                         /*nb_add*/
+    (binaryfunc)TrigBurstEndStream_sub,                         /*nb_subtract*/
+    (binaryfunc)TrigBurstEndStream_multiply,                    /*nb_multiply*/
+    (binaryfunc)TrigBurstEndStream_div,                                              /*nb_divide*/
+    0,                                              /*nb_remainder*/
+    0,                                              /*nb_divmod*/
+    0,                                              /*nb_power*/
+    0,                                              /*nb_neg*/
+    0,                                              /*nb_pos*/
+    0,                                              /*(unaryfunc)array_abs,*/
+    0,                                              /*nb_nonzero*/
+    0,                                              /*nb_invert*/
+    0,                                              /*nb_lshift*/
+    0,                                              /*nb_rshift*/
+    0,                                              /*nb_and*/
+    0,                                              /*nb_xor*/
+    0,                                              /*nb_or*/
+    0,                                              /*nb_coerce*/
+    0,                                              /*nb_int*/
+    0,                                              /*nb_long*/
+    0,                                              /*nb_float*/
+    0,                                              /*nb_oct*/
+    0,                                              /*nb_hex*/
+    (binaryfunc)TrigBurstEndStream_inplace_add,                 /*inplace_add*/
+    (binaryfunc)TrigBurstEndStream_inplace_sub,                 /*inplace_subtract*/
+    (binaryfunc)TrigBurstEndStream_inplace_multiply,            /*inplace_multiply*/
+    (binaryfunc)TrigBurstEndStream_inplace_div,                                              /*inplace_divide*/
+    0,                                              /*inplace_remainder*/
+    0,                                              /*inplace_power*/
+    0,                                              /*inplace_lshift*/
+    0,                                              /*inplace_rshift*/
+    0,                                              /*inplace_and*/
+    0,                                              /*inplace_xor*/
+    0,                                              /*inplace_or*/
+    0,                                              /*nb_floor_divide*/
+    0,                                              /*nb_true_divide*/
+    0,                                              /*nb_inplace_floor_divide*/
+    0,                                              /*nb_inplace_true_divide*/
+    0,                                              /* nb_index */
+};
+
+PyTypeObject TrigBurstEndStreamType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "_pyo.TrigBurstEndStream_base",         /*tp_name*/
+    sizeof(TrigBurstEndStream),         /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)TrigBurstEndStream_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    &TrigBurstEndStream_as_number,             /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,  /*tp_flags*/
+    "TrigBurstEndStream objects. Reads a duration channel from a TrigBurster object.",           /* tp_doc */
+    (traverseproc)TrigBurstEndStream_traverse,   /* tp_traverse */
+    (inquiry)TrigBurstEndStream_clear,           /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    TrigBurstEndStream_methods,             /* tp_methods */
+    TrigBurstEndStream_members,             /* tp_members */
+    0,                      /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    0,      /* tp_init */
+    0,                         /* tp_alloc */
+    TrigBurstEndStream_new,                 /* tp_new */
+};
diff --git a/src/objects/midimodule.c b/src/objects/midimodule.c
index cc35226..f9be648 100644
--- a/src/objects/midimodule.c
+++ b/src/objects/midimodule.c
@@ -126,6 +126,14 @@ static PyObject * CtlScan_getStream(CtlScan* self) { GET_STREAM };
 static PyObject * CtlScan_play(CtlScan *self, PyObject *args, PyObject *kwds) { PLAY };
 static PyObject * CtlScan_stop(CtlScan *self) { STOP };
 
+static PyObject * 
+CtlScan_reset(CtlScan *self) 
+{ 
+    self->ctlnumber = -1;
+	Py_INCREF(Py_None);
+	return Py_None;
+};
+
 static PyObject *
 CtlScan_setFunction(CtlScan *self, PyObject *arg)
 {
@@ -168,6 +176,7 @@ static PyMethodDef CtlScan_methods[] = {
     {"_getStream", (PyCFunction)CtlScan_getStream, METH_NOARGS, "Returns stream object."},
     {"play", (PyCFunction)CtlScan_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
     {"stop", (PyCFunction)CtlScan_stop, METH_NOARGS, "Stops computing."},
+    {"reset", (PyCFunction)CtlScan_reset, METH_NOARGS, "Resets the scanned number."},
     {"setFunction", (PyCFunction)CtlScan_setFunction, METH_O, "Sets the function to be called."},
     {"setToprint", (PyCFunction)CtlScan_setToprint, METH_O, "If True, print values to the console."},
     {NULL}  /* Sentinel */
@@ -318,6 +327,14 @@ static PyObject * CtlScan2_getStream(CtlScan2* self) { GET_STREAM };
 static PyObject * CtlScan2_play(CtlScan2 *self, PyObject *args, PyObject *kwds) { PLAY };
 static PyObject * CtlScan2_stop(CtlScan2 *self) { STOP };
 
+static PyObject * 
+CtlScan2_reset(CtlScan2 *self) 
+{ 
+    self->ctlnumber = self->midichnl = -1;
+	Py_INCREF(Py_None);
+	return Py_None;
+};
+
 static PyObject *
 CtlScan2_setFunction(CtlScan2 *self, PyObject *arg)
 {
@@ -360,6 +377,7 @@ static PyMethodDef CtlScan2_methods[] = {
     {"_getStream", (PyCFunction)CtlScan2_getStream, METH_NOARGS, "Returns stream object."},
     {"play", (PyCFunction)CtlScan2_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
     {"stop", (PyCFunction)CtlScan2_stop, METH_NOARGS, "Stops computing."},
+    {"reset", (PyCFunction)CtlScan2_reset, METH_NOARGS, "Reset scanned numbers."},
     {"setFunction", (PyCFunction)CtlScan2_setFunction, METH_O, "Sets the function to be called."},
     {"setToprint", (PyCFunction)CtlScan2_setToprint, METH_O, "If True, print values to the console."},
     {NULL}  /* Sentinel */
@@ -1905,6 +1923,7 @@ typedef struct {
     int centralkey;
     int channel;
     int stealing;
+    MYFLT *trigger_streams;
 } MidiNote;
 
 static void
@@ -2000,12 +2019,14 @@ void grabMidiNotes(MidiNote *self, PmEvent *buffer, int count)
                         self->vcount = voice;
                         self->notebuf[voice*2] = pitch;
                         self->notebuf[voice*2+1] = velocity;
+                        self->trigger_streams[self->bufsize*(self->vcount*2)] = 1.0;
                     }
                 }
                 else {
                     self->vcount = (self->vcount + 1) % self->voices;
                     self->notebuf[self->vcount*2] = pitch;
                     self->notebuf[self->vcount*2+1] = velocity;
+                    self->trigger_streams[self->bufsize*(self->vcount*2)] = 1.0;
                 }
             }    
             else if (pitchIsIn(self->notebuf, pitch, self->voices) == 1 && kind == 0 && pitch >= self->first && pitch <= self->last) {
@@ -2013,6 +2034,7 @@ void grabMidiNotes(MidiNote *self, PmEvent *buffer, int count)
                 voice = whichVoice(self->notebuf, pitch, self->voices);
                 self->notebuf[voice*2] = -1;
                 self->notebuf[voice*2+1] = 0.;
+                self->trigger_streams[self->bufsize*(voice*2+1)] = 1.0;
             }
         }
     }    
@@ -2022,7 +2044,11 @@ static void
 MidiNote_compute_next_data_frame(MidiNote *self)
 {   
     PmEvent *tmp;
-    int count;
+    int i, count;
+
+    for (i=0; i<self->bufsize*self->voices*2; i++) {
+        self->trigger_streams[i] = 0.0;
+    }
     
     tmp = Server_getMidiEventBuffer((Server *)self->server);
     count = Server_getMidiEventCount((Server *)self->server);
@@ -2049,10 +2075,17 @@ MidiNote_dealloc(MidiNote* self)
 {
     pyo_DEALLOC
     free(self->notebuf);
+    free(self->trigger_streams);
     MidiNote_clear(self);
     self->ob_type->tp_free((PyObject*)self);
 }
 
+static MYFLT *
+MidiNote_get_trigger_buffer(MidiNote *self)
+{
+    return self->trigger_streams;
+}
+
 static PyObject *
 MidiNote_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
@@ -2081,6 +2114,11 @@ MidiNote_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
 
     self->notebuf = (int *)realloc(self->notebuf, self->voices * 2 * sizeof(int));
+    self->trigger_streams = (MYFLT *)realloc(self->trigger_streams, self->bufsize * self->voices * 2 * sizeof(MYFLT));
+
+    for (i=0; i<self->bufsize*self->voices*2; i++) {
+        self->trigger_streams[i] = 0.0;
+    }
 
     for (i=0; i<self->voices; i++) {
         self->notebuf[i*2] = -1;
@@ -2503,6 +2541,262 @@ Notein_members,             /* tp_members */
 Notein_new,                 /* tp_new */
 };
 
+/* NoteinTrig trig streamer */
+typedef struct {
+    pyo_audio_HEAD
+    MidiNote *handler;
+    int modebuffer[2];
+    int voice;
+    int mode; /* 0 = noteon, 1 = noteoff */
+} NoteinTrig;
+
+static void NoteinTrig_postprocessing_ii(NoteinTrig *self) { POST_PROCESSING_II };
+static void NoteinTrig_postprocessing_ai(NoteinTrig *self) { POST_PROCESSING_AI };
+static void NoteinTrig_postprocessing_ia(NoteinTrig *self) { POST_PROCESSING_IA };
+static void NoteinTrig_postprocessing_aa(NoteinTrig *self) { POST_PROCESSING_AA };
+static void NoteinTrig_postprocessing_ireva(NoteinTrig *self) { POST_PROCESSING_IREVA };
+static void NoteinTrig_postprocessing_areva(NoteinTrig *self) { POST_PROCESSING_AREVA };
+static void NoteinTrig_postprocessing_revai(NoteinTrig *self) { POST_PROCESSING_REVAI };
+static void NoteinTrig_postprocessing_revaa(NoteinTrig *self) { POST_PROCESSING_REVAA };
+static void NoteinTrig_postprocessing_revareva(NoteinTrig *self) { POST_PROCESSING_REVAREVA };
+
+static void
+NoteinTrig_setProcMode(NoteinTrig *self)
+{
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = NoteinTrig_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = NoteinTrig_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = NoteinTrig_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = NoteinTrig_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = NoteinTrig_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = NoteinTrig_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = NoteinTrig_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = NoteinTrig_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = NoteinTrig_postprocessing_revareva;
+            break;
+    }
+}
+
+static void
+NoteinTrig_compute_next_data_frame(NoteinTrig *self)
+{
+    int i;
+    MYFLT *tmp = MidiNote_get_trigger_buffer(self->handler);
+    
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = tmp[self->bufsize*(self->voice*2+self->mode)+i];
+    }    
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+NoteinTrig_traverse(NoteinTrig *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->handler);
+    return 0;
+}
+
+static int 
+NoteinTrig_clear(NoteinTrig *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->handler);    
+    return 0;
+}
+
+static void
+NoteinTrig_dealloc(NoteinTrig* self)
+{
+    pyo_DEALLOC
+    NoteinTrig_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+NoteinTrig_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *handlertmp=NULL, *multmp=NULL, *addtmp=NULL;
+    NoteinTrig *self;
+    self = (NoteinTrig *)type->tp_alloc(type, 0);
+    
+    self->voice = 0;
+    self->mode = 0;
+    self->modebuffer[0] = 0;
+    self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, NoteinTrig_compute_next_data_frame);
+    self->mode_func_ptr = NoteinTrig_setProcMode;
+
+    static char *kwlist[] = {"handler", "voice", "mode", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|iiOO", kwlist, &handlertmp, &self->voice, &self->mode, &multmp, &addtmp))
+        Py_RETURN_NONE;
+    
+    Py_XDECREF(self->handler);
+    Py_INCREF(handlertmp);
+    self->handler = (MidiNote *)handlertmp;
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+    
+    return (PyObject *)self;
+}
+
+static PyObject * NoteinTrig_getServer(NoteinTrig* self) { GET_SERVER };
+static PyObject * NoteinTrig_getStream(NoteinTrig* self) { GET_STREAM };
+static PyObject * NoteinTrig_setMul(NoteinTrig *self, PyObject *arg) { SET_MUL };	
+static PyObject * NoteinTrig_setAdd(NoteinTrig *self, PyObject *arg) { SET_ADD };	
+static PyObject * NoteinTrig_setSub(NoteinTrig *self, PyObject *arg) { SET_SUB };	
+static PyObject * NoteinTrig_setDiv(NoteinTrig *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * NoteinTrig_play(NoteinTrig *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * NoteinTrig_stop(NoteinTrig *self) { STOP };
+
+static PyObject * NoteinTrig_multiply(NoteinTrig *self, PyObject *arg) { MULTIPLY };
+static PyObject * NoteinTrig_inplace_multiply(NoteinTrig *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * NoteinTrig_add(NoteinTrig *self, PyObject *arg) { ADD };
+static PyObject * NoteinTrig_inplace_add(NoteinTrig *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * NoteinTrig_sub(NoteinTrig *self, PyObject *arg) { SUB };
+static PyObject * NoteinTrig_inplace_sub(NoteinTrig *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * NoteinTrig_div(NoteinTrig *self, PyObject *arg) { DIV };
+static PyObject * NoteinTrig_inplace_div(NoteinTrig *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef NoteinTrig_members[] = {
+{"server", T_OBJECT_EX, offsetof(NoteinTrig, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(NoteinTrig, stream), 0, "Stream object."},
+{"mul", T_OBJECT_EX, offsetof(NoteinTrig, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(NoteinTrig, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef NoteinTrig_methods[] = {
+{"getServer", (PyCFunction)NoteinTrig_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)NoteinTrig_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)NoteinTrig_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)NoteinTrig_stop, METH_NOARGS, "Stops computing."},
+{"setMul", (PyCFunction)NoteinTrig_setMul, METH_O, "Sets NoteinTrig mul factor."},
+{"setAdd", (PyCFunction)NoteinTrig_setAdd, METH_O, "Sets NoteinTrig add factor."},
+{"setSub", (PyCFunction)NoteinTrig_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)NoteinTrig_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods NoteinTrig_as_number = {
+(binaryfunc)NoteinTrig_add,                      /*nb_add*/
+(binaryfunc)NoteinTrig_sub,                 /*nb_subtract*/
+(binaryfunc)NoteinTrig_multiply,                 /*nb_multiply*/
+(binaryfunc)NoteinTrig_div,                   /*nb_divide*/
+0,                /*nb_remainder*/
+0,                   /*nb_divmod*/
+0,                   /*nb_power*/
+0,                  /*nb_neg*/
+0,                /*nb_pos*/
+0,                  /*(unaryfunc)array_abs,*/
+0,                    /*nb_nonzero*/
+0,                    /*nb_invert*/
+0,               /*nb_lshift*/
+0,              /*nb_rshift*/
+0,              /*nb_and*/
+0,              /*nb_xor*/
+0,               /*nb_or*/
+0,                                          /*nb_coerce*/
+0,                       /*nb_int*/
+0,                      /*nb_long*/
+0,                     /*nb_float*/
+0,                       /*nb_oct*/
+0,                       /*nb_hex*/
+(binaryfunc)NoteinTrig_inplace_add,              /*inplace_add*/
+(binaryfunc)NoteinTrig_inplace_sub,         /*inplace_subtract*/
+(binaryfunc)NoteinTrig_inplace_multiply,         /*inplace_multiply*/
+(binaryfunc)NoteinTrig_inplace_div,           /*inplace_divide*/
+0,        /*inplace_remainder*/
+0,           /*inplace_power*/
+0,       /*inplace_lshift*/
+0,      /*inplace_rshift*/
+0,      /*inplace_and*/
+0,      /*inplace_xor*/
+0,       /*inplace_or*/
+0,             /*nb_floor_divide*/
+0,              /*nb_true_divide*/
+0,     /*nb_inplace_floor_divide*/
+0,      /*nb_inplace_true_divide*/
+0,                     /* nb_index */
+};
+
+PyTypeObject NoteinTrigType = {
+PyObject_HEAD_INIT(NULL)
+0,                         /*ob_size*/
+"_pyo.NoteinTrig_base",         /*tp_name*/
+sizeof(NoteinTrig),         /*tp_basicsize*/
+0,                         /*tp_itemsize*/
+(destructor)NoteinTrig_dealloc, /*tp_dealloc*/
+0,                         /*tp_print*/
+0,                         /*tp_getattr*/
+0,                         /*tp_setattr*/
+0,                         /*tp_compare*/
+0,                         /*tp_repr*/
+&NoteinTrig_as_number,             /*tp_as_number*/
+0,                         /*tp_as_sequence*/
+0,                         /*tp_as_mapping*/
+0,                         /*tp_hash */
+0,                         /*tp_call*/
+0,                         /*tp_str*/
+0,                         /*tp_getattro*/
+0,                         /*tp_setattro*/
+0,                         /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,  /*tp_flags*/
+"NoteinTrig objects. Stream noteon or noteoff trigger from a Notein voice.",           /* tp_doc */
+(traverseproc)NoteinTrig_traverse,   /* tp_traverse */
+(inquiry)NoteinTrig_clear,           /* tp_clear */
+0,		               /* tp_richcompare */
+0,		               /* tp_weaklistoffset */
+0,		               /* tp_iter */
+0,		               /* tp_iternext */
+NoteinTrig_methods,             /* tp_methods */
+NoteinTrig_members,             /* tp_members */
+0,                      /* tp_getset */
+0,                         /* tp_base */
+0,                         /* tp_dict */
+0,                         /* tp_descr_get */
+0,                         /* tp_descr_set */
+0,                         /* tp_dictoffset */
+0,      /* tp_init */
+0,                         /* tp_alloc */
+NoteinTrig_new,                 /* tp_new */
+};
+
 typedef struct {
     pyo_audio_HEAD
     PyObject *input;
diff --git a/src/objects/oscbankmodule.c b/src/objects/oscbankmodule.c
index b8b4cd3..9f98380 100644
--- a/src/objects/oscbankmodule.c
+++ b/src/objects/oscbankmodule.c
@@ -452,11 +452,8 @@ OscBank_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of OscBank must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of OscBank must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
diff --git a/src/objects/oscilmodule.c b/src/objects/oscilmodule.c
index 5c7f1e0..722521e 100644
--- a/src/objects/oscilmodule.c
+++ b/src/objects/oscilmodule.c
@@ -1207,11 +1207,8 @@ Osc_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of Osc must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Osc must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -1742,11 +1739,8 @@ OscLoop_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of OscLoop must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of OscLoop must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -2268,11 +2262,8 @@ OscTrig_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of OscTrig must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of OscTrig must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -3084,13 +3075,12 @@ Pointer_readframes_a(Pointer *self) {
     int size = TableStream_getSize(self->table);
     
     MYFLT *pha = Stream_getData((Stream *)self->index_stream);
-    
+
     for (i=0; i<self->bufsize; i++) {
-        ph = Osc_clip(pha[i] * size, size);
-   
+        ph = Osc_clip(pha[i] * size, size);       
         ipart = (int)ph;
         fpart = ph - ipart;
-        self->data[i] = tablelist[ipart] * (1.0 - fpart) + tablelist[ipart+1] * fpart;
+        self->data[i] = tablelist[ipart] + (tablelist[ipart+1] - tablelist[ipart]) * fpart;
     }
 }
 
@@ -3199,11 +3189,8 @@ Pointer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of Pointer must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pointer must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -3221,7 +3208,7 @@ Pointer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
     
     (*self->mode_func_ptr)(self);
-    
+  
     return (PyObject *)self;
 }
 
@@ -3280,16 +3267,12 @@ Pointer_setIndex(Pointer *self, PyObject *arg)
 		return Py_None;
 	}
     
-	int isNumber = PyNumber_Check(arg);
-	if (isNumber == 1) {
-		PySys_WriteStderr("TypeError: \"index\" attribute of Pointer must be a PyoObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+	tmp = arg;
+	if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+        PyErr_SetString(PyExc_TypeError, "\"index\" argument of Pointer must be a PyoObject.\n");
+        Py_RETURN_NONE;
 	}
 	
-	tmp = arg;
 	Py_INCREF(tmp);
 	Py_XDECREF(self->index);
 
@@ -3414,6 +3397,421 @@ Pointer_new,                 /* tp_new */
 };
 
 /**************/
+/* Pointer2 object */
+/**************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *table;
+    PyObject *index;
+    Stream *index_stream;
+    int modebuffer[2];
+    int interp; /* 0 = default to 2, 1 = nointerp, 2 = linear, 3 = cos, 4 = cubic */
+    int autosmooth; /* 0 = off, > 0 = on */
+    MYFLT y1;
+    MYFLT y2;
+    MYFLT c;
+    MYFLT lastPh;
+    MYFLT (*interp_func_ptr)(MYFLT *, int, MYFLT, int);
+} Pointer2;
+
+static void
+Pointer2_readframes_a(Pointer2 *self) {
+    MYFLT fpart, phdiff, b, fr;
+    double ph;
+    int i, ipart;
+    MYFLT *tablelist = TableStream_getData(self->table);
+    int size = TableStream_getSize(self->table);
+    double tableSr = TableStream_getSamplingRate(self->table);
+    
+    MYFLT *pha = Stream_getData((Stream *)self->index_stream);
+
+    if (!self->autosmooth) {
+        for (i=0; i<self->bufsize; i++) {
+            ph = Osc_clip(pha[i] * size, size);       
+            ipart = (int)ph;
+            fpart = ph - ipart;
+            self->y1 = self->y2 = self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
+        }
+    }
+    else {
+        for (i=0; i<self->bufsize; i++) {
+            ph = Osc_clip(pha[i] * size, size);
+            ipart = (int)ph;
+            fpart = ph - ipart;
+            self->data[i] = (*self->interp_func_ptr)(tablelist, ipart, fpart, size);
+            phdiff = MYFABS(ph - self->lastPh);
+            self->lastPh = ph;
+            if (phdiff < 1) {
+                fr = phdiff * tableSr * 0.45;
+                b = 2.0 - MYCOS(TWOPI * fr / self->sr);
+                self->c = (b - MYSQRT(b * b - 1.0));
+                self->y1 = self->data[i] + (self->y1 - self->data[i]) * self->c;
+                self->data[i] = self->y2 = self->y1 + (self->y2 - self->y1) * self->c;
+            }
+            else
+                self->y1 = self->y2 = self->data[i];
+        }
+    }
+}
+
+static void Pointer2_postprocessing_ii(Pointer2 *self) { POST_PROCESSING_II };
+static void Pointer2_postprocessing_ai(Pointer2 *self) { POST_PROCESSING_AI };
+static void Pointer2_postprocessing_ia(Pointer2 *self) { POST_PROCESSING_IA };
+static void Pointer2_postprocessing_aa(Pointer2 *self) { POST_PROCESSING_AA };
+static void Pointer2_postprocessing_ireva(Pointer2 *self) { POST_PROCESSING_IREVA };
+static void Pointer2_postprocessing_areva(Pointer2 *self) { POST_PROCESSING_AREVA };
+static void Pointer2_postprocessing_revai(Pointer2 *self) { POST_PROCESSING_REVAI };
+static void Pointer2_postprocessing_revaa(Pointer2 *self) { POST_PROCESSING_REVAA };
+static void Pointer2_postprocessing_revareva(Pointer2 *self) { POST_PROCESSING_REVAREVA };
+
+static void
+Pointer2_setProcMode(Pointer2 *self)
+{
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+
+    self->proc_func_ptr = Pointer2_readframes_a;
+
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = Pointer2_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = Pointer2_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = Pointer2_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = Pointer2_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = Pointer2_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = Pointer2_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = Pointer2_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = Pointer2_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = Pointer2_postprocessing_revareva;
+            break;
+    } 
+}
+
+static void
+Pointer2_compute_next_data_frame(Pointer2 *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+Pointer2_traverse(Pointer2 *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->table);
+    Py_VISIT(self->index);    
+    Py_VISIT(self->index_stream);    
+    return 0;
+}
+
+static int 
+Pointer2_clear(Pointer2 *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->table);
+    Py_CLEAR(self->index);    
+    Py_CLEAR(self->index_stream);    
+    return 0;
+}
+
+static void
+Pointer2_dealloc(Pointer2* self)
+{
+    pyo_DEALLOC
+    Pointer2_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+Pointer2_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *tabletmp, *indextmp, *multmp=NULL, *addtmp=NULL;
+    Pointer2 *self;
+    self = (Pointer2 *)type->tp_alloc(type, 0);
+    
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+    self->interp = 4;
+    self->autosmooth = 1;
+    self->y1 = self->y2 = self->c = self->lastPh = 0.0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, Pointer2_compute_next_data_frame);
+    self->mode_func_ptr = Pointer2_setProcMode;
+
+    static char *kwlist[] = {"table", "index", "interp", "autosmooth", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|iiOO", kwlist, &tabletmp, &indextmp, &self->interp, &self->autosmooth, &multmp, &addtmp))
+        Py_RETURN_NONE;
+    
+    if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pointer2 must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
+    }
+    Py_XDECREF(self->table);
+    self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
+    
+    if (indextmp) {
+        PyObject_CallMethod((PyObject *)self, "setIndex", "O", indextmp);
+    }
+
+    PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+  
+    SET_INTERP_POINTER
+  
+    return (PyObject *)self;
+}
+
+static PyObject * Pointer2_getServer(Pointer2* self) { GET_SERVER };
+static PyObject * Pointer2_getStream(Pointer2* self) { GET_STREAM };
+static PyObject * Pointer2_setMul(Pointer2 *self, PyObject *arg) { SET_MUL };	
+static PyObject * Pointer2_setAdd(Pointer2 *self, PyObject *arg) { SET_ADD };	
+static PyObject * Pointer2_setSub(Pointer2 *self, PyObject *arg) { SET_SUB };	
+static PyObject * Pointer2_setDiv(Pointer2 *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * Pointer2_play(Pointer2 *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * Pointer2_out(Pointer2 *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * Pointer2_stop(Pointer2 *self) { STOP };
+
+static PyObject * Pointer2_multiply(Pointer2 *self, PyObject *arg) { MULTIPLY };
+static PyObject * Pointer2_inplace_multiply(Pointer2 *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * Pointer2_add(Pointer2 *self, PyObject *arg) { ADD };
+static PyObject * Pointer2_inplace_add(Pointer2 *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * Pointer2_sub(Pointer2 *self, PyObject *arg) { SUB };
+static PyObject * Pointer2_inplace_sub(Pointer2 *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * Pointer2_div(Pointer2 *self, PyObject *arg) { DIV };
+static PyObject * Pointer2_inplace_div(Pointer2 *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+Pointer2_getTable(Pointer2* self)
+{
+    Py_INCREF(self->table);
+    return self->table;
+};
+
+static PyObject *
+Pointer2_setTable(Pointer2 *self, PyObject *arg)
+{
+	PyObject *tmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	tmp = arg;
+	Py_DECREF(self->table);
+    self->table = PyObject_CallMethod((PyObject *)tmp, "getTableStream", "");
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+Pointer2_setIndex(Pointer2 *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	tmp = arg;
+	if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+        PyErr_SetString(PyExc_TypeError, "\"index\" argument of Pointer2 must be a PyoObject.\n");
+        Py_RETURN_NONE;
+	}
+	
+	Py_INCREF(tmp);
+	Py_XDECREF(self->index);
+
+    self->index = tmp;
+    streamtmp = PyObject_CallMethod((PyObject *)self->index, "_getStream", NULL);
+    Py_INCREF(streamtmp);
+    Py_XDECREF(self->index_stream);
+    self->index_stream = (Stream *)streamtmp;
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+Pointer2_setInterp(Pointer2 *self, PyObject *arg)
+{
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+    int isNumber = PyNumber_Check(arg);
+    
+	if (isNumber == 1) {
+		self->interp = PyInt_AsLong(PyNumber_Int(arg));
+    }  
+    
+    SET_INTERP_POINTER
+    
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
+Pointer2_setAutoSmooth(Pointer2 *self, PyObject *arg)
+{
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+    int isNumber = PyNumber_Check(arg);
+    
+	if (isNumber == 1) {
+		self->autosmooth = PyInt_AsLong(PyNumber_Int(arg));
+    }  
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyMemberDef Pointer2_members[] = {
+{"server", T_OBJECT_EX, offsetof(Pointer2, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(Pointer2, stream), 0, "Stream object."},
+{"table", T_OBJECT_EX, offsetof(Pointer2, table), 0, "Waveform table."},
+{"index", T_OBJECT_EX, offsetof(Pointer2, index), 0, "Reader index."},
+{"mul", T_OBJECT_EX, offsetof(Pointer2, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(Pointer2, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef Pointer2_methods[] = {
+{"getTable", (PyCFunction)Pointer2_getTable, METH_NOARGS, "Returns waveform table object."},
+{"getServer", (PyCFunction)Pointer2_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)Pointer2_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)Pointer2_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)Pointer2_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)Pointer2_stop, METH_NOARGS, "Stops computing."},
+{"setTable", (PyCFunction)Pointer2_setTable, METH_O, "Sets oscillator table."},
+{"setIndex", (PyCFunction)Pointer2_setIndex, METH_O, "Sets reader index."},
+{"setInterp", (PyCFunction)Pointer2_setInterp, METH_O, "Sets oscillator interpolation mode."},
+{"setAutoSmooth", (PyCFunction)Pointer2_setAutoSmooth, METH_O, "Activates auto smoother filter."},
+{"setMul", (PyCFunction)Pointer2_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)Pointer2_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)Pointer2_setSub, METH_O, "Sets oscillator inverse add factor."},
+{"setDiv", (PyCFunction)Pointer2_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods Pointer2_as_number = {
+(binaryfunc)Pointer2_add,                      /*nb_add*/
+(binaryfunc)Pointer2_sub,                 /*nb_subtract*/
+(binaryfunc)Pointer2_multiply,                 /*nb_multiply*/
+(binaryfunc)Pointer2_div,                   /*nb_divide*/
+0,                /*nb_remainder*/
+0,                   /*nb_divmod*/
+0,                   /*nb_power*/
+0,                  /*nb_neg*/
+0,                /*nb_pos*/
+0,                  /*(unaryfunc)array_abs,*/
+0,                    /*nb_nonzero*/
+0,                    /*nb_invert*/
+0,               /*nb_lshift*/
+0,              /*nb_rshift*/
+0,              /*nb_and*/
+0,              /*nb_xor*/
+0,               /*nb_or*/
+0,                                          /*nb_coerce*/
+0,                       /*nb_int*/
+0,                      /*nb_long*/
+0,                     /*nb_float*/
+0,                       /*nb_oct*/
+0,                       /*nb_hex*/
+(binaryfunc)Pointer2_inplace_add,              /*inplace_add*/
+(binaryfunc)Pointer2_inplace_sub,         /*inplace_subtract*/
+(binaryfunc)Pointer2_inplace_multiply,         /*inplace_multiply*/
+(binaryfunc)Pointer2_inplace_div,           /*inplace_divide*/
+0,        /*inplace_remainder*/
+0,           /*inplace_power*/
+0,       /*inplace_lshift*/
+0,      /*inplace_rshift*/
+0,      /*inplace_and*/
+0,      /*inplace_xor*/
+0,       /*inplace_or*/
+0,             /*nb_floor_divide*/
+0,              /*nb_true_divide*/
+0,     /*nb_inplace_floor_divide*/
+0,      /*nb_inplace_true_divide*/
+0,                     /* nb_index */
+};
+
+PyTypeObject Pointer2Type = {
+PyObject_HEAD_INIT(NULL)
+0,                         /*ob_size*/
+"_pyo.Pointer2_base",         /*tp_name*/
+sizeof(Pointer2),         /*tp_basicsize*/
+0,                         /*tp_itemsize*/
+(destructor)Pointer2_dealloc, /*tp_dealloc*/
+0,                         /*tp_print*/
+0,                         /*tp_getattr*/
+0,                         /*tp_setattr*/
+0,                         /*tp_compare*/
+0,                         /*tp_repr*/
+&Pointer2_as_number,             /*tp_as_number*/
+0,                         /*tp_as_sequence*/
+0,                         /*tp_as_mapping*/
+0,                         /*tp_hash */
+0,                         /*tp_call*/
+0,                         /*tp_str*/
+0,                         /*tp_getattro*/
+0,                         /*tp_setattro*/
+0,                         /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"Pointer2 objects. High quality table reader with a pointer index.",           /* tp_doc */
+(traverseproc)Pointer2_traverse,   /* tp_traverse */
+(inquiry)Pointer2_clear,           /* tp_clear */
+0,		               /* tp_richcompare */
+0,		               /* tp_weaklistoffset */
+0,		               /* tp_iter */
+0,		               /* tp_iternext */
+Pointer2_methods,             /* tp_methods */
+Pointer2_members,             /* tp_members */
+0,                      /* tp_getset */
+0,                         /* tp_base */
+0,                         /* tp_dict */
+0,                         /* tp_descr_get */
+0,                         /* tp_descr_set */
+0,                         /* tp_dictoffset */
+0,      /* tp_init */
+0,                         /* tp_alloc */
+Pointer2_new,                 /* tp_new */
+};
+
+/**************/
 /* TableIndex object */
 /**************/
 typedef struct {
@@ -3548,11 +3946,8 @@ TableIndex_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of TableIndex must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableIndex must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -3629,16 +4024,12 @@ TableIndex_setIndex(TableIndex *self, PyObject *arg)
 		return Py_None;
 	}
     
-	int isNumber = PyNumber_Check(arg);
-	if (isNumber == 1) {
-		PySys_WriteStderr("TypeError: \"index\" attribute of TableIndex must be a PyoObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+	tmp = arg;
+	if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+        PyErr_SetString(PyExc_TypeError, "\"index\" argument of TableIndex must be a PyoObject.\n");
+        Py_RETURN_NONE;
 	}
 	
-	tmp = arg;
 	Py_INCREF(tmp);
 	Py_XDECREF(self->index);
     
@@ -3905,11 +4296,8 @@ Lookup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of Lookup must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Lookup must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -3986,16 +4374,12 @@ Lookup_setIndex(Lookup *self, PyObject *arg)
 		return Py_None;
 	}
     
-	int isNumber = PyNumber_Check(arg);
-	if (isNumber == 1) {
-		PySys_WriteStderr("TypeError: \"index\" attribute of Lookup must be a PyoObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
-	}
-	
 	tmp = arg;
+	if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+        PyErr_SetString(PyExc_TypeError, "\"index\" argument of Lookup must be a PyoObject.\n");
+        Py_RETURN_NONE;
+	}
+
 	Py_INCREF(tmp);
 	Py_XDECREF(self->index);
     
@@ -4634,21 +5018,15 @@ Pulsar_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of Pulsar must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of Pulsar must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
 
     if ( PyObject_HasAttrString((PyObject *)envtmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"env\" argument of Pulsar must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"env\" argument of Pulsar must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->env);
     self->env = PyObject_CallMethod((PyObject *)envtmp, "getTableStream", "");
@@ -5216,11 +5594,8 @@ TableRead_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of TableRead must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableRead must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
@@ -10976,21 +11351,15 @@ TableScale_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of TableScale must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableScale must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
     
     if ( PyObject_HasAttrString((PyObject *)outtabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"outtable\" argument of TableScale must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"outtable\" argument of TableScale must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->outtable);
     self->outtable = PyObject_CallMethod((PyObject *)outtabletmp, "getTableStream", "");
diff --git a/src/objects/oscmodule.c b/src/objects/oscmodule.c
index a8e8f05..65cd201 100644
--- a/src/objects/oscmodule.c
+++ b/src/objects/oscmodule.c
@@ -937,7 +937,7 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
                         void *data, void *user_data)
 {
     OscDataReceive *self = user_data;
-    PyObject *tup, *result;
+    PyObject *tup, *result=NULL;
     tup = PyTuple_New(argc+1);
     int i, ok = 0;
     
@@ -976,6 +976,8 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
         if (result == NULL)
             PyErr_Print();
     }
+    Py_XDECREF(tup);
+    Py_XDECREF(result);
     return 0;
 }
 
@@ -1054,6 +1056,8 @@ OscDataReceive_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
 static PyObject * OscDataReceive_getServer(OscDataReceive* self) { GET_SERVER };
 static PyObject * OscDataReceive_getStream(OscDataReceive* self) { GET_STREAM };
+static PyObject * OscDataReceive_play(OscDataReceive *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * OscDataReceive_stop(OscDataReceive *self) { STOP };
 
 static PyObject *
 OscDataReceive_addAddress(OscDataReceive *self, PyObject *arg) {
@@ -1094,6 +1098,8 @@ static PyMemberDef OscDataReceive_members[] = {
 static PyMethodDef OscDataReceive_methods[] = {
     {"getServer", (PyCFunction)OscDataReceive_getServer, METH_NOARGS, "Returns server object."},
     {"_getStream", (PyCFunction)OscDataReceive_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)OscDataReceive_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"stop", (PyCFunction)OscDataReceive_stop, METH_NOARGS, "Stops computing."},
     {"addAddress", (PyCFunction)OscDataReceive_addAddress, METH_O, "Add new paths to the object."},
     {"delAddress", (PyCFunction)OscDataReceive_delAddress, METH_O, "Remove path from the object."},
     {NULL}  /* Sentinel */
diff --git a/src/objects/phasevocmodule.c b/src/objects/phasevocmodule.c
index af5d3dc..5ed4bb0 100644
--- a/src/objects/phasevocmodule.c
+++ b/src/objects/phasevocmodule.c
@@ -612,11 +612,8 @@ PVSynth_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVSynth \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVSynth must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -653,9 +650,8 @@ PVSynth_setInput(PVSynth *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVSynth \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVSynth must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -1087,11 +1083,8 @@ PVAddSynth_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVAddSynth \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVAddSynth must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -1137,9 +1130,8 @@ PVAddSynth_setInput(PVAddSynth *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVAddSynth \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVAddSynth must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -1573,11 +1565,8 @@ PVTranspose_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVTranspose \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVTranspose must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -1621,9 +1610,8 @@ PVTranspose_setInput(PVTranspose *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVTranspose \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVTranspose must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -1752,6 +1740,7 @@ typedef struct {
     int hopsize;
     int overcount;
     MYFLT *l_magn;
+    MYFLT *l_freq;
     MYFLT **magn;
     MYFLT **freq;
     int *count;
@@ -1766,8 +1755,9 @@ PVVerb_realloc_memories(PVVerb *self) {
     inputLatency = self->size - self->hopsize;
     self->overcount = 0;
     self->l_magn = (MYFLT *)realloc(self->l_magn, self->hsize * sizeof(MYFLT)); 
+    self->l_freq = (MYFLT *)realloc(self->l_freq, self->hsize * sizeof(MYFLT)); 
     for (i=0; i<self->hsize; i++)
-        self->l_magn[i] = 0.0;
+        self->l_magn[i] = self->l_freq[i] = 0.0;
     self->magn = (MYFLT **)realloc(self->magn, self->olaps * sizeof(MYFLT *));
     self->freq = (MYFLT **)realloc(self->freq, self->olaps * sizeof(MYFLT *));
     for (i=0; i<self->olaps; i++) {
@@ -1788,7 +1778,7 @@ PVVerb_realloc_memories(PVVerb *self) {
 static void
 PVVerb_process_ii(PVVerb *self) {
     int i, k;
-    MYFLT revtime, damp, mag, amp;
+    MYFLT revtime, damp, mag, amp, fre;
     MYFLT **magn = PVStream_getMagn((PVStream *)self->input_stream);
     MYFLT **freq = PVStream_getFreq((PVStream *)self->input_stream);
     int *count = PVStream_getCount((PVStream *)self->input_stream);
@@ -1819,11 +1809,15 @@ PVVerb_process_ii(PVVerb *self) {
             amp = 1.0;
             for (k=0; k<self->hsize; k++) {
                 mag = magn[self->overcount][k];
-                if (mag > self->l_magn[k])
+                fre = freq[self->overcount][k];
+                if (mag > self->l_magn[k]) {
                     self->magn[self->overcount][k] = self->l_magn[k] = mag;
-                else
+                    self->freq[self->overcount][k] = self->l_freq[k] = fre;
+                }
+                else {
                     self->magn[self->overcount][k] = self->l_magn[k] = mag + (self->l_magn[k] - mag) * revtime * amp;
-                self->freq[self->overcount][k] = freq[self->overcount][k];
+                    self->freq[self->overcount][k] = self->l_freq[k] = fre + (self->l_freq[k] - fre) * revtime * amp;
+                }
                 amp *= damp;
             }
             self->overcount++;
@@ -1836,7 +1830,7 @@ PVVerb_process_ii(PVVerb *self) {
 static void
 PVVerb_process_ai(PVVerb *self) {
     int i, k;
-    MYFLT revtime, damp, mag, amp;
+    MYFLT revtime, damp, mag, amp, fre;
     MYFLT **magn = PVStream_getMagn((PVStream *)self->input_stream);
     MYFLT **freq = PVStream_getFreq((PVStream *)self->input_stream);
     int *count = PVStream_getCount((PVStream *)self->input_stream);
@@ -1868,11 +1862,15 @@ PVVerb_process_ai(PVVerb *self) {
             amp = 1.0;
             for (k=0; k<self->hsize; k++) {
                 mag = magn[self->overcount][k];
-                if (mag > self->l_magn[k])
+                fre = freq[self->overcount][k];
+                if (mag > self->l_magn[k]) {
                     self->magn[self->overcount][k] = self->l_magn[k] = mag;
-                else
+                    self->freq[self->overcount][k] = self->l_freq[k] = fre;
+                }
+                else {
                     self->magn[self->overcount][k] = self->l_magn[k] = mag + (self->l_magn[k] - mag) * revtime * amp;
-                self->freq[self->overcount][k] = freq[self->overcount][k];
+                    self->freq[self->overcount][k] = self->l_freq[k] = fre + (self->l_freq[k] - fre) * revtime * amp;
+                }
                 amp *= damp;
             }
             self->overcount++;
@@ -1885,7 +1883,7 @@ PVVerb_process_ai(PVVerb *self) {
 static void
 PVVerb_process_ia(PVVerb *self) {
     int i, k;
-    MYFLT revtime, damp, mag, amp;
+    MYFLT revtime, damp, mag, amp, fre;
     MYFLT **magn = PVStream_getMagn((PVStream *)self->input_stream);
     MYFLT **freq = PVStream_getFreq((PVStream *)self->input_stream);
     int *count = PVStream_getCount((PVStream *)self->input_stream);
@@ -1917,11 +1915,15 @@ PVVerb_process_ia(PVVerb *self) {
             amp = 1.0;
             for (k=0; k<self->hsize; k++) {
                 mag = magn[self->overcount][k];
-                if (mag > self->l_magn[k])
+                fre = freq[self->overcount][k];
+                if (mag > self->l_magn[k]) {
                     self->magn[self->overcount][k] = self->l_magn[k] = mag;
-                else
+                    self->freq[self->overcount][k] = self->l_freq[k] = fre;
+                }
+                else {
                     self->magn[self->overcount][k] = self->l_magn[k] = mag + (self->l_magn[k] - mag) * revtime * amp;
-                self->freq[self->overcount][k] = freq[self->overcount][k];
+                    self->freq[self->overcount][k] = self->l_freq[k] = fre + (self->l_freq[k] - fre) * revtime * amp;
+                }
                 amp *= damp;
             }
             self->overcount++;
@@ -1934,7 +1936,7 @@ PVVerb_process_ia(PVVerb *self) {
 static void
 PVVerb_process_aa(PVVerb *self) {
     int i, k;
-    MYFLT revtime, damp, mag, amp;
+    MYFLT revtime, damp, mag, amp, fre;
     MYFLT **magn = PVStream_getMagn((PVStream *)self->input_stream);
     MYFLT **freq = PVStream_getFreq((PVStream *)self->input_stream);
     int *count = PVStream_getCount((PVStream *)self->input_stream);
@@ -1967,11 +1969,15 @@ PVVerb_process_aa(PVVerb *self) {
             amp = 1.0;
             for (k=0; k<self->hsize; k++) {
                 mag = magn[self->overcount][k];
-                if (mag > self->l_magn[k])
+                fre = freq[self->overcount][k];
+                if (mag > self->l_magn[k]) {
                     self->magn[self->overcount][k] = self->l_magn[k] = mag;
-                else
+                    self->freq[self->overcount][k] = self->l_freq[k] = fre;
+                }
+                else {
                     self->magn[self->overcount][k] = self->l_magn[k] = mag + (self->l_magn[k] - mag) * revtime * amp;
-                self->freq[self->overcount][k] = freq[self->overcount][k];
+                    self->freq[self->overcount][k] = self->l_freq[k] = fre + (self->l_freq[k] - fre) * revtime * amp;
+                }
                 amp *= damp;
             }
             self->overcount++;
@@ -2049,6 +2055,7 @@ PVVerb_dealloc(PVVerb* self)
     free(self->magn);
     free(self->freq);
     free(self->l_magn);
+    free(self->l_freq);
     free(self->count);
     PVVerb_clear(self);
     self->ob_type->tp_free((PyObject*)self);
@@ -2076,11 +2083,8 @@ PVVerb_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVVerb \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVVerb must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -2128,9 +2132,8 @@ PVVerb_setInput(PVVerb *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVVerb \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVVerb must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -2570,11 +2573,8 @@ PVGate_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVGate \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVGate must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -2622,9 +2622,8 @@ PVGate_setInput(PVGate *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVGate \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVGate must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -2970,11 +2969,8 @@ PVCross_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVCross \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVCross must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -2985,11 +2981,8 @@ PVCross_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->input_stream = (PVStream *)input_streamtmp;
 
     if ( PyObject_HasAttrString((PyObject *)input2tmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVCross \"input2\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVCross must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(input2tmp);
     Py_XDECREF(self->input2);
@@ -3033,9 +3026,8 @@ PVCross_setInput(PVCross *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVCross \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVCross must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -3057,9 +3049,8 @@ PVCross_setInput2(PVCross *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVCross \"input2\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVCross must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -3318,11 +3309,8 @@ PVMult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMult \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMult must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -3333,11 +3321,8 @@ PVMult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->input_stream = (PVStream *)input_streamtmp;
 
     if ( PyObject_HasAttrString((PyObject *)input2tmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMult \"input2\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMult must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(input2tmp);
     Py_XDECREF(self->input2);
@@ -3377,9 +3362,8 @@ PVMult_setInput(PVMult *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMult \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMult must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -3401,9 +3385,8 @@ PVMult_setInput2(PVMult *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMult \"input2\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMult must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -3689,11 +3672,8 @@ PVMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMorph \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMorph must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -3704,11 +3684,8 @@ PVMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->input_stream = (PVStream *)input_streamtmp;
 
     if ( PyObject_HasAttrString((PyObject *)input2tmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMorph \"input2\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMorph must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(input2tmp);
     Py_XDECREF(self->input2);
@@ -3752,9 +3729,8 @@ PVMorph_setInput(PVMorph *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMorph \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMorph must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -3776,9 +3752,8 @@ PVMorph_setInput2(PVMorph *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMorph \"input2\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMorph must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -4138,11 +4113,8 @@ PVFilter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVFilter \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVFilter must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -4189,9 +4161,8 @@ PVFilter_setInput(PVFilter *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVFilter \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVFilter must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -4624,11 +4595,8 @@ PVDelay_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVDelay \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVDelay must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -4675,9 +4643,8 @@ PVDelay_setInput(PVDelay *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVDelay \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVDelay must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -5088,11 +5055,8 @@ PVBuffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVBuffer \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBuffer must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -5144,9 +5108,8 @@ PVBuffer_setInput(PVBuffer *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVBuffer \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBuffer must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -5171,16 +5134,12 @@ PVBuffer_setIndex(PVBuffer *self, PyObject *arg)
 		return Py_None;
 	}
     
-	int isNumber = PyNumber_Check(arg);
-	if (isNumber == 1) {
-		PySys_WriteStderr("TypeError: \"index\" attribute of PVBuffer must be a PyoObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+	tmp = arg;
+	if (PyObject_HasAttrString((PyObject *)tmp, "server") == 0) {
+        PyErr_SetString(PyExc_TypeError, "\"index\" argument of PVBuffer must be a PyoObject.\n");
+        Py_RETURN_NONE;
 	}
 	
-	tmp = arg;
 	Py_INCREF(tmp);
 	Py_XDECREF(self->index);
 
@@ -5501,11 +5460,8 @@ PVShift_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVShift \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVShift must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -5549,9 +5505,8 @@ PVShift_setInput(PVShift *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVShift \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVShift must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -5980,11 +5935,8 @@ PVAmpMod_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVAmpMod \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVAmpMod must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -6037,9 +5989,8 @@ PVAmpMod_setInput(PVAmpMod *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVAmpMod \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVAmpMod must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -6589,11 +6540,8 @@ PVFreqMod_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVFreqMod \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVFreqMod must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -6650,9 +6598,8 @@ PVFreqMod_setInput(PVFreqMod *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVFreqMod \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVFreqMod must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -7137,11 +7084,8 @@ PVBufLoops_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVBufLoops \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBufLoops must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -7196,9 +7140,8 @@ PVBufLoops_setInput(PVBufLoops *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVBufLoops \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBufLoops must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -7570,11 +7513,8 @@ PVBufTabLoops_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVBufTabLoops \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBufTabLoops must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -7624,9 +7564,8 @@ PVBufTabLoops_setInput(PVBufTabLoops *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVBufTabLoops \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVBufTabLoops must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -7884,11 +7823,8 @@ PVMix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         Py_RETURN_NONE;
 
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMix \"input\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMix must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(inputtmp);
     Py_XDECREF(self->input);
@@ -7899,11 +7835,8 @@ PVMix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->input_stream = (PVStream *)input_streamtmp;
 
     if ( PyObject_HasAttrString((PyObject *)input2tmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMix \"input2\" argument must be a PyoPVObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMix must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
     Py_INCREF(input2tmp);
     Py_XDECREF(self->input2);
@@ -7943,9 +7876,8 @@ PVMix_setInput(PVMix *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMix \"input\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input\" argument of PVMix must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
@@ -7967,9 +7899,8 @@ PVMix_setInput2(PVMix *self, PyObject *arg)
 
     inputtmp = arg;
     if ( PyObject_HasAttrString((PyObject *)inputtmp, "pv_stream") == 0 ) {
-        PySys_WriteStderr("TypeError: PVMix \"input2\" argument must be a PyoPVObject.\n");
-        Py_INCREF(Py_None);
-        return Py_None;
+        PyErr_SetString(PyExc_TypeError, "\"input2\" argument of PVMix must be a PyoPVObject.\n");
+        Py_RETURN_NONE;
     }
 
     Py_INCREF(inputtmp);
diff --git a/src/objects/sigmodule.c b/src/objects/sigmodule.c
index 93e295e..7cd4cf0 100644
--- a/src/objects/sigmodule.c
+++ b/src/objects/sigmodule.c
@@ -333,9 +333,9 @@ typedef struct {
     pyo_audio_HEAD
     PyObject *value;
     Stream *value_stream;
-    MYFLT time;
     MYFLT lastValue;
     MYFLT currentValue;
+    MYFLT time;
     long timeStep;
     MYFLT stepVal;
     long timeCount;
@@ -346,20 +346,19 @@ static void
 SigTo_generates_i(SigTo *self) {
     int i;
     MYFLT value;
-    
     if (self->modebuffer[2] == 0) {
         value = PyFloat_AS_DOUBLE(self->value);
+        if (value != self->lastValue) {
+            self->timeCount = 0;
+            self->timeStep = (long)(self->time * self->sr);
+            self->stepVal = (value - self->currentValue) / self->timeStep;
+            self->lastValue = value;
+        }
         if (self->timeStep <= 0) {
             for (i=0; i<self->bufsize; i++)
                 self->data[i] = self->currentValue = self->lastValue = value;
         }
-        else {
-            if (value != self->lastValue) {
-                self->timeCount = 0;
-                self->stepVal = (value - self->currentValue) / self->timeStep;
-                self->lastValue = value;
-            }    
-        
+        else {        
             for (i=0; i<self->bufsize; i++) {
                 if (self->timeCount == (self->timeStep - 1)) {
                     self->currentValue = value;
@@ -386,6 +385,7 @@ SigTo_generates_i(SigTo *self) {
                 value = vals[i];
                 if (value != self->lastValue) {
                     self->timeCount = 0;
+                    self->timeStep = (long)(self->time * self->sr);
                     self->stepVal = (value - self->currentValue) / self->timeStep;
                     self->lastValue = value;
                 }    
@@ -497,7 +497,6 @@ SigTo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
     self->value = PyFloat_FromDouble(0.0);
     self->time = 0.025;
-    self->timeStep = (long)(self->time * self->sr);
     self->timeCount = 0;
     self->stepVal = 0.0;
 	self->modebuffer[0] = 0;
@@ -532,6 +531,7 @@ SigTo_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
     
     self->lastValue = self->currentValue = inittmp;
+    self->timeStep = (long)(self->time * self->sr);
     
     (*self->mode_func_ptr)(self);
 
@@ -590,7 +590,6 @@ SigTo_setTime(SigTo *self, PyObject *arg)
 	Py_INCREF(tmp);
 	if (isNumber == 1) {
 		self->time = PyFloat_AS_DOUBLE(PyNumber_Float(tmp));
-        self->timeStep = (long)(self->time * self->sr);
 	}
     
 	Py_INCREF(Py_None);
@@ -992,6 +991,26 @@ VarPort_setTime(VarPort *self, PyObject *arg)
 	return Py_None;
 }	
 
+static PyObject *
+VarPort_setFunction(VarPort *self, PyObject *arg)
+{
+	PyObject *tmp;
+	
+	if (! PyCallable_Check(arg)) {
+        PyErr_SetString(PyExc_TypeError, "The function attribute must be callable.");
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+    tmp = arg;
+    Py_XDECREF(self->callable);
+    Py_INCREF(tmp);
+    self->callable = tmp;
+  
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
 static PyObject * VarPort_getServer(VarPort* self) { GET_SERVER };
 static PyObject * VarPort_getStream(VarPort* self) { GET_STREAM };
 static PyObject * VarPort_setMul(VarPort *self, PyObject *arg) { SET_MUL };	
@@ -1026,6 +1045,7 @@ static PyMethodDef VarPort_methods[] = {
     {"stop", (PyCFunction)VarPort_stop, METH_NOARGS, "Stops computing."},
     {"setValue", (PyCFunction)VarPort_setValue, METH_O, "Sets VarPort value."},
     {"setTime", (PyCFunction)VarPort_setTime, METH_O, "Sets ramp time in seconds."},
+    {"setFunction", (PyCFunction)VarPort_setFunction, METH_O, "Sets function to be called."},
     {"setMul", (PyCFunction)VarPort_setMul, METH_O, "Sets VarPort mul factor."},
     {"setAdd", (PyCFunction)VarPort_setAdd, METH_O, "Sets VarPort add factor."},
     {"setSub", (PyCFunction)VarPort_setSub, METH_O, "Sets inverse add factor."},
diff --git a/src/objects/tablemodule.c b/src/objects/tablemodule.c
index 0be9ea5..3852057 100644
--- a/src/objects/tablemodule.c
+++ b/src/objects/tablemodule.c
@@ -231,10 +231,17 @@ static PyObject * HarmTable_reset(HarmTable *self) { TABLE_RESET };
 static PyObject * HarmTable_normalize(HarmTable *self) { NORMALIZE };
 static PyObject * HarmTable_removeDC(HarmTable *self) { REMOVE_DC };
 static PyObject * HarmTable_reverse(HarmTable *self) { REVERSE };
+static PyObject * HarmTable_invert(HarmTable *self) { INVERT };
+static PyObject * HarmTable_rectify(HarmTable *self) { RECTIFY };
+static PyObject * HarmTable_bipolarGain(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * HarmTable_lowpass(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * HarmTable_fadein(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * HarmTable_fadeout(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * HarmTable_pow(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * HarmTable_copy(HarmTable *self, PyObject *arg) { COPY };
 static PyObject * HarmTable_setTable(HarmTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * HarmTable_getTable(HarmTable *self) { GET_TABLE };
-static PyObject * HarmTable_getViewTable(HarmTable *self) { GET_VIEW_TABLE };
+static PyObject * HarmTable_getViewTable(HarmTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * HarmTable_put(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * HarmTable_get(HarmTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -302,12 +309,19 @@ static PyMethodDef HarmTable_methods[] = {
 {"getServer", (PyCFunction)HarmTable_getServer, METH_NOARGS, "Returns server object."},
 {"setTable", (PyCFunction)HarmTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
 {"getTable", (PyCFunction)HarmTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)HarmTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)HarmTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
 {"getTableStream", (PyCFunction)HarmTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
 {"normalize", (PyCFunction)HarmTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
 {"reset", (PyCFunction)HarmTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)HarmTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
-{"reverse", (PyCFunction)HarmTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"reverse", (PyCFunction)HarmTable_reverse, METH_NOARGS, "Reverse the table's data in time."},
+{"invert", (PyCFunction)HarmTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)HarmTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)HarmTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)HarmTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)HarmTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)HarmTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)HarmTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {"copy", (PyCFunction)HarmTable_copy, METH_O, "Copy data from table given in argument."},
 {"setData", (PyCFunction)HarmTable_setData, METH_O, "Sets the table from samples in a text file."},
 {"setSize", (PyCFunction)HarmTable_setSize, METH_O, "Sets the size of the table in samples"},
@@ -505,10 +519,17 @@ static PyObject * ChebyTable_normalize(ChebyTable *self) { NORMALIZE };
 static PyObject * ChebyTable_reset(ChebyTable *self) { TABLE_RESET };
 static PyObject * ChebyTable_removeDC(ChebyTable *self) { REMOVE_DC };
 static PyObject * ChebyTable_reverse(ChebyTable *self) { REVERSE };
+static PyObject * ChebyTable_invert(ChebyTable *self) { INVERT };
+static PyObject * ChebyTable_rectify(ChebyTable *self) { RECTIFY };
+static PyObject * ChebyTable_bipolarGain(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * ChebyTable_lowpass(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * ChebyTable_fadein(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * ChebyTable_fadeout(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * ChebyTable_pow(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * ChebyTable_copy(ChebyTable *self, PyObject *arg) { COPY };
 static PyObject * ChebyTable_setTable(ChebyTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * ChebyTable_getTable(ChebyTable *self) { GET_TABLE };
-static PyObject * ChebyTable_getViewTable(ChebyTable *self) { GET_VIEW_TABLE };
+static PyObject * ChebyTable_getViewTable(ChebyTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * ChebyTable_put(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * ChebyTable_get(ChebyTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -650,13 +671,20 @@ static PyMethodDef ChebyTable_methods[] = {
 {"copy", (PyCFunction)ChebyTable_copy, METH_O, "Copy data from table given in argument."},
 {"setTable", (PyCFunction)ChebyTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
 {"getTable", (PyCFunction)ChebyTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)ChebyTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)ChebyTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
 {"getTableStream", (PyCFunction)ChebyTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
 {"setData", (PyCFunction)ChebyTable_setData, METH_O, "Sets the table from samples in a text file."},
 {"normalize", (PyCFunction)ChebyTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
 {"reset", (PyCFunction)ChebyTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)ChebyTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)ChebyTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)ChebyTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)ChebyTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)ChebyTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)ChebyTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)ChebyTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)ChebyTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)ChebyTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {"setSize", (PyCFunction)ChebyTable_setSize, METH_O, "Sets the size of the table in samples"},
 {"getSize", (PyCFunction)ChebyTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
 {"put", (PyCFunction)ChebyTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -787,10 +815,17 @@ static PyObject * HannTable_normalize(HannTable *self) { NORMALIZE };
 static PyObject * HannTable_reset(HannTable *self) { TABLE_RESET };
 static PyObject * HannTable_removeDC(HannTable *self) { REMOVE_DC };
 static PyObject * HannTable_reverse(HannTable *self) { REVERSE };
+static PyObject * HannTable_invert(HannTable *self) { INVERT };
+static PyObject * HannTable_rectify(HannTable *self) { RECTIFY };
+static PyObject * HannTable_bipolarGain(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * HannTable_lowpass(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * HannTable_fadein(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * HannTable_fadeout(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * HannTable_pow(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * HannTable_copy(HannTable *self, PyObject *arg) { COPY };
 static PyObject * HannTable_setTable(HannTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * HannTable_getTable(HannTable *self) { GET_TABLE };
-static PyObject * HannTable_getViewTable(HannTable *self) { GET_VIEW_TABLE };
+static PyObject * HannTable_getViewTable(HannTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * HannTable_put(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * HannTable_get(HannTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -835,13 +870,20 @@ static PyMethodDef HannTable_methods[] = {
 {"copy", (PyCFunction)HannTable_copy, METH_O, "Copy data from table given in argument."},
 {"setTable", (PyCFunction)HannTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
 {"getTable", (PyCFunction)HannTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)HannTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)HannTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
 {"getTableStream", (PyCFunction)HannTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
 {"setData", (PyCFunction)HannTable_setData, METH_O, "Sets the table from samples in a text file."},
 {"normalize", (PyCFunction)HannTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
 {"reset", (PyCFunction)HannTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)HannTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)HannTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)HannTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)HannTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)HannTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)HannTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)HannTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)HannTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)HannTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {"setSize", (PyCFunction)HannTable_setSize, METH_O, "Sets the size of the table in samples"},
 {"getSize", (PyCFunction)HannTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
 {"put", (PyCFunction)HannTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -991,10 +1033,17 @@ static PyObject * SincTable_normalize(SincTable *self) { NORMALIZE };
 static PyObject * SincTable_reset(SincTable *self) { TABLE_RESET };
 static PyObject * SincTable_removeDC(SincTable *self) { REMOVE_DC };
 static PyObject * SincTable_reverse(SincTable *self) { REVERSE };
+static PyObject * SincTable_invert(SincTable *self) { INVERT };
+static PyObject * SincTable_rectify(SincTable *self) { RECTIFY };
+static PyObject * SincTable_bipolarGain(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * SincTable_lowpass(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * SincTable_fadein(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * SincTable_fadeout(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * SincTable_pow(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * SincTable_copy(SincTable *self, PyObject *arg) { COPY };
 static PyObject * SincTable_setTable(SincTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * SincTable_getTable(SincTable *self) { GET_TABLE };
-static PyObject * SincTable_getViewTable(SincTable *self) { GET_VIEW_TABLE };
+static PyObject * SincTable_getViewTable(SincTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * SincTable_put(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * SincTable_get(SincTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -1073,13 +1122,20 @@ static PyMethodDef SincTable_methods[] = {
     {"copy", (PyCFunction)SincTable_copy, METH_O, "Copy data from table given in argument."},
     {"setTable", (PyCFunction)SincTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
     {"getTable", (PyCFunction)SincTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-    {"getViewTable", (PyCFunction)SincTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+    {"getViewTable", (PyCFunction)SincTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
     {"getTableStream", (PyCFunction)SincTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
     {"setData", (PyCFunction)SincTable_setData, METH_O, "Sets the table from samples in a text file."},
     {"normalize", (PyCFunction)SincTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
     {"reset", (PyCFunction)SincTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
     {"removeDC", (PyCFunction)SincTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
     {"reverse", (PyCFunction)SincTable_reverse, METH_NOARGS, "Reverse the table's data."},
+    {"invert", (PyCFunction)SincTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+    {"rectify", (PyCFunction)SincTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+    {"bipolarGain", (PyCFunction)SincTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+    {"lowpass", (PyCFunction)SincTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+    {"fadein", (PyCFunction)SincTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+    {"fadeout", (PyCFunction)SincTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+    {"pow", (PyCFunction)SincTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
     {"setSize", (PyCFunction)SincTable_setSize, METH_O, "Sets the size of the table in samples"},
     {"getSize", (PyCFunction)SincTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
     {"setFreq", (PyCFunction)SincTable_setFreq, METH_O, "Sets the frequency, in radians, of the sinc function."},
@@ -1203,10 +1259,17 @@ static PyObject * WinTable_normalize(WinTable *self) { NORMALIZE };
 static PyObject * WinTable_reset(WinTable *self) { TABLE_RESET };
 static PyObject * WinTable_removeDC(WinTable *self) { REMOVE_DC };
 static PyObject * WinTable_reverse(WinTable *self) { REVERSE };
+static PyObject * WinTable_invert(WinTable *self) { INVERT };
+static PyObject * WinTable_rectify(WinTable *self) { RECTIFY };
+static PyObject * WinTable_bipolarGain(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * WinTable_lowpass(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * WinTable_fadein(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * WinTable_fadeout(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * WinTable_pow(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * WinTable_copy(WinTable *self, PyObject *arg) { COPY };
 static PyObject * WinTable_setTable(WinTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * WinTable_getTable(WinTable *self) { GET_TABLE };
-static PyObject * WinTable_getViewTable(WinTable *self) { GET_VIEW_TABLE };
+static PyObject * WinTable_getViewTable(WinTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * WinTable_put(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * WinTable_get(WinTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -1272,13 +1335,20 @@ static PyMethodDef WinTable_methods[] = {
 {"copy", (PyCFunction)WinTable_copy, METH_O, "Copy data from table given in argument."},
 {"setTable", (PyCFunction)WinTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
 {"getTable", (PyCFunction)WinTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)WinTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)WinTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
 {"getTableStream", (PyCFunction)WinTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
 {"setData", (PyCFunction)WinTable_setData, METH_O, "Sets the table from samples in a text file."},
 {"normalize", (PyCFunction)WinTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
 {"reset", (PyCFunction)WinTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)WinTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)WinTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)WinTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)WinTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)WinTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)WinTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)WinTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)WinTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)WinTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {"setSize", (PyCFunction)WinTable_setSize, METH_O, "Sets the size of the table in samples"},
 {"getSize", (PyCFunction)WinTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
 {"setType", (PyCFunction)WinTable_setType, METH_O, "Sets the type of the table."},
@@ -1415,10 +1485,17 @@ static PyObject * ParaTable_normalize(ParaTable *self) { NORMALIZE };
 static PyObject * ParaTable_reset(ParaTable *self) { TABLE_RESET };
 static PyObject * ParaTable_removeDC(ParaTable *self) { REMOVE_DC };
 static PyObject * ParaTable_reverse(ParaTable *self) { REVERSE };
+static PyObject * ParaTable_invert(ParaTable *self) { INVERT };
+static PyObject * ParaTable_rectify(ParaTable *self) { RECTIFY };
+static PyObject * ParaTable_bipolarGain(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * ParaTable_lowpass(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * ParaTable_fadein(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * ParaTable_fadeout(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * ParaTable_pow(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * ParaTable_copy(ParaTable *self, PyObject *arg) { COPY };
 static PyObject * ParaTable_setTable(ParaTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * ParaTable_getTable(ParaTable *self) { GET_TABLE };
-static PyObject * ParaTable_getViewTable(ParaTable *self) { GET_VIEW_TABLE };
+static PyObject * ParaTable_getViewTable(ParaTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * ParaTable_put(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * ParaTable_get(ParaTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -1463,13 +1540,20 @@ static PyMethodDef ParaTable_methods[] = {
     {"copy", (PyCFunction)ParaTable_copy, METH_O, "Copy data from table given in argument."},
     {"setTable", (PyCFunction)ParaTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
     {"getTable", (PyCFunction)ParaTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-    {"getViewTable", (PyCFunction)ParaTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+    {"getViewTable", (PyCFunction)ParaTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
     {"getTableStream", (PyCFunction)ParaTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
     {"setData", (PyCFunction)ParaTable_setData, METH_O, "Sets the table from samples in a text file."},
     {"normalize", (PyCFunction)ParaTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
     {"reset", (PyCFunction)ParaTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
     {"removeDC", (PyCFunction)ParaTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
     {"reverse", (PyCFunction)ParaTable_reverse, METH_NOARGS, "Reverse the table's data."},
+    {"invert", (PyCFunction)ParaTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+    {"rectify", (PyCFunction)ParaTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+    {"bipolarGain", (PyCFunction)ParaTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+    {"lowpass", (PyCFunction)ParaTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+    {"fadein", (PyCFunction)ParaTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+    {"fadeout", (PyCFunction)ParaTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+    {"pow", (PyCFunction)ParaTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
     {"setSize", (PyCFunction)ParaTable_setSize, METH_O, "Sets the size of the table in samples"},
     {"getSize", (PyCFunction)ParaTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
     {"put", (PyCFunction)ParaTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -1639,10 +1723,17 @@ static PyObject * LinTable_normalize(LinTable *self) { NORMALIZE };
 static PyObject * LinTable_reset(LinTable *self) { TABLE_RESET };
 static PyObject * LinTable_removeDC(LinTable *self) { REMOVE_DC };
 static PyObject * LinTable_reverse(LinTable *self) { REVERSE };
+static PyObject * LinTable_invert(LinTable *self) { INVERT };
+static PyObject * LinTable_rectify(LinTable *self) { RECTIFY };
+static PyObject * LinTable_bipolarGain(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * LinTable_lowpass(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * LinTable_fadein(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * LinTable_fadeout(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * LinTable_pow(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * LinTable_copy(LinTable *self, PyObject *arg) { COPY };
 static PyObject * LinTable_setTable(LinTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * LinTable_getTable(LinTable *self) { GET_TABLE };
-static PyObject * LinTable_getViewTable(LinTable *self) { GET_VIEW_TABLE };
+static PyObject * LinTable_getViewTable(LinTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * LinTable_put(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * LinTable_get(LinTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -1741,13 +1832,20 @@ static PyMethodDef LinTable_methods[] = {
 {"copy", (PyCFunction)LinTable_copy, METH_O, "Copy data from table given in argument."},
 {"setTable", (PyCFunction)LinTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
 {"getTable", (PyCFunction)LinTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)LinTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)LinTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
 {"getTableStream", (PyCFunction)LinTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
 {"setData", (PyCFunction)LinTable_setData, METH_O, "Sets the table from samples in a text file."},
 {"normalize", (PyCFunction)LinTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
 {"reset", (PyCFunction)LinTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)LinTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)LinTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)LinTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)LinTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)LinTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)LinTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)LinTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)LinTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)LinTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {"setSize", (PyCFunction)LinTable_setSize, METH_O, "Sets the size of the table in samples"},
 {"getSize", (PyCFunction)LinTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
 {"put", (PyCFunction)LinTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -1943,10 +2041,17 @@ static PyObject * LogTable_normalize(LogTable *self) { NORMALIZE };
 static PyObject * LogTable_reset(LogTable *self) { TABLE_RESET };
 static PyObject * LogTable_removeDC(LogTable *self) { REMOVE_DC };
 static PyObject * LogTable_reverse(LogTable *self) { REVERSE };
+static PyObject * LogTable_invert(LogTable *self) { INVERT };
+static PyObject * LogTable_rectify(LogTable *self) { RECTIFY };
+static PyObject * LogTable_bipolarGain(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * LogTable_lowpass(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * LogTable_fadein(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * LogTable_fadeout(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * LogTable_pow(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * LogTable_copy(LogTable *self, PyObject *arg) { COPY };
 static PyObject * LogTable_setTable(LogTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * LogTable_getTable(LogTable *self) { GET_TABLE };
-static PyObject * LogTable_getViewTable(LogTable *self) { GET_VIEW_TABLE };
+static PyObject * LogTable_getViewTable(LogTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * LogTable_put(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * LogTable_get(LogTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -2045,13 +2150,20 @@ static PyMethodDef LogTable_methods[] = {
     {"copy", (PyCFunction)LogTable_copy, METH_O, "Copy data from table given in argument."},
     {"setTable", (PyCFunction)LogTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
     {"getTable", (PyCFunction)LogTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-    {"getViewTable", (PyCFunction)LogTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+    {"getViewTable", (PyCFunction)LogTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
     {"getTableStream", (PyCFunction)LogTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
     {"setData", (PyCFunction)LogTable_setData, METH_O, "Sets the table from samples in a text file."},
     {"normalize", (PyCFunction)LogTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
     {"reset", (PyCFunction)LogTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
     {"removeDC", (PyCFunction)LogTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
     {"reverse", (PyCFunction)LogTable_reverse, METH_NOARGS, "Reverse the table's data."},
+    {"invert", (PyCFunction)LogTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+    {"rectify", (PyCFunction)LogTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+    {"bipolarGain", (PyCFunction)LogTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+    {"lowpass", (PyCFunction)LogTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+    {"fadein", (PyCFunction)LogTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+    {"fadeout", (PyCFunction)LogTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+    {"pow", (PyCFunction)LogTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
     {"setSize", (PyCFunction)LogTable_setSize, METH_O, "Sets the size of the table in samples"},
     {"getSize", (PyCFunction)LogTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
     {"put", (PyCFunction)LogTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -2225,10 +2337,17 @@ static PyObject * CosTable_normalize(CosTable *self) { NORMALIZE };
 static PyObject * CosTable_reset(CosTable *self) { TABLE_RESET };
 static PyObject * CosTable_removeDC(CosTable *self) { REMOVE_DC };
 static PyObject * CosTable_reverse(CosTable *self) { REVERSE };
+static PyObject * CosTable_invert(CosTable *self) { INVERT };
+static PyObject * CosTable_rectify(CosTable *self) { RECTIFY };
+static PyObject * CosTable_bipolarGain(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * CosTable_lowpass(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * CosTable_fadein(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * CosTable_fadeout(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * CosTable_pow(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * CosTable_copy(CosTable *self, PyObject *arg) { COPY };
 static PyObject * CosTable_setTable(CosTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * CosTable_getTable(CosTable *self) { GET_TABLE };
-static PyObject * CosTable_getViewTable(CosTable *self) { GET_VIEW_TABLE };
+static PyObject * CosTable_getViewTable(CosTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * CosTable_put(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * CosTable_get(CosTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -2327,13 +2446,20 @@ static PyMethodDef CosTable_methods[] = {
 {"copy", (PyCFunction)CosTable_copy, METH_O, "Copy data from table given in argument."},
 {"setTable", (PyCFunction)CosTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
 {"getTable", (PyCFunction)CosTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)CosTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)CosTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
 {"getTableStream", (PyCFunction)CosTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
 {"setData", (PyCFunction)CosTable_setData, METH_O, "Sets the table from samples in a text file."},
 {"normalize", (PyCFunction)CosTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
 {"reset", (PyCFunction)CosTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)CosTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)CosTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)CosTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)CosTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)CosTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)CosTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)CosTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)CosTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)CosTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {"setSize", (PyCFunction)CosTable_setSize, METH_O, "Sets the size of the table in samples"},
 {"getSize", (PyCFunction)CosTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
 {"put", (PyCFunction)CosTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -2531,10 +2657,17 @@ static PyObject * CosLogTable_normalize(CosLogTable *self) { NORMALIZE };
 static PyObject * CosLogTable_reset(CosLogTable *self) { TABLE_RESET };
 static PyObject * CosLogTable_removeDC(CosLogTable *self) { REMOVE_DC };
 static PyObject * CosLogTable_reverse(CosLogTable *self) { REVERSE };
+static PyObject * CosLogTable_invert(CosLogTable *self) { INVERT };
+static PyObject * CosLogTable_rectify(CosLogTable *self) { RECTIFY };
+static PyObject * CosLogTable_bipolarGain(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * CosLogTable_lowpass(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * CosLogTable_fadein(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * CosLogTable_fadeout(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * CosLogTable_pow(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * CosLogTable_copy(CosLogTable *self, PyObject *arg) { COPY };
 static PyObject * CosLogTable_setTable(CosLogTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * CosLogTable_getTable(CosLogTable *self) { GET_TABLE };
-static PyObject * CosLogTable_getViewTable(CosLogTable *self) { GET_VIEW_TABLE };
+static PyObject * CosLogTable_getViewTable(CosLogTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * CosLogTable_put(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * CosLogTable_get(CosLogTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -2633,13 +2766,20 @@ static PyMethodDef CosLogTable_methods[] = {
     {"copy", (PyCFunction)CosLogTable_copy, METH_O, "Copy data from table given in argument."},
     {"setTable", (PyCFunction)CosLogTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
     {"getTable", (PyCFunction)CosLogTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-    {"getViewTable", (PyCFunction)CosLogTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+    {"getViewTable", (PyCFunction)CosLogTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
     {"getTableStream", (PyCFunction)CosLogTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
     {"setData", (PyCFunction)CosLogTable_setData, METH_O, "Sets the table from samples in a text file."},
     {"normalize", (PyCFunction)CosLogTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
     {"reset", (PyCFunction)CosLogTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
     {"removeDC", (PyCFunction)CosLogTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
     {"reverse", (PyCFunction)CosLogTable_reverse, METH_NOARGS, "Reverse the table's data."},
+    {"invert", (PyCFunction)CosLogTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+    {"rectify", (PyCFunction)CosLogTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+    {"bipolarGain", (PyCFunction)CosLogTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+    {"lowpass", (PyCFunction)CosLogTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+    {"fadein", (PyCFunction)CosLogTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+    {"fadeout", (PyCFunction)CosLogTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+    {"pow", (PyCFunction)CosLogTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
     {"setSize", (PyCFunction)CosLogTable_setSize, METH_O, "Sets the size of the table in samples"},
     {"getSize", (PyCFunction)CosLogTable_getSize, METH_NOARGS, "Return the size of the table in samples"},
     {"put", (PyCFunction)CosLogTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
@@ -2840,10 +2980,17 @@ static PyObject * CurveTable_normalize(CurveTable * self) { NORMALIZE };
 static PyObject * CurveTable_reset(CurveTable * self) { TABLE_RESET };
 static PyObject * CurveTable_removeDC(CurveTable *self) { REMOVE_DC };
 static PyObject * CurveTable_reverse(CurveTable *self) { REVERSE };
+static PyObject * CurveTable_invert(CurveTable *self) { INVERT };
+static PyObject * CurveTable_rectify(CurveTable *self) { RECTIFY };
+static PyObject * CurveTable_bipolarGain(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * CurveTable_lowpass(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * CurveTable_fadein(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * CurveTable_fadeout(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * CurveTable_pow(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * CurveTable_copy(CurveTable *self, PyObject *arg) { COPY };
 static PyObject * CurveTable_setTable(CurveTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * CurveTable_getTable(CurveTable *self) { GET_TABLE };
-static PyObject * CurveTable_getViewTable(CurveTable *self) { GET_VIEW_TABLE };
+static PyObject * CurveTable_getViewTable(CurveTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * CurveTable_put(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * CurveTable_get(CurveTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -2984,7 +3131,7 @@ static PyMethodDef CurveTable_methods[] = {
 {"copy", (PyCFunction)CurveTable_copy, METH_O, "Copy data from table given in argument."},
 {"setTable", (PyCFunction)CurveTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
 {"getTable", (PyCFunction)CurveTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)CurveTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)CurveTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
 {"getTableStream", (PyCFunction)CurveTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
 {"setData", (PyCFunction)CurveTable_setData, METH_O, "Sets the table from samples in a text file."},
 {"setSize", (PyCFunction)CurveTable_setSize, METH_O, "Sets the size of the table in samples"},
@@ -2999,6 +3146,13 @@ static PyMethodDef CurveTable_methods[] = {
 {"reset", (PyCFunction)CurveTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)CurveTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)CurveTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)CurveTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)CurveTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)CurveTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)CurveTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)CurveTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)CurveTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)CurveTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {NULL}  /* Sentinel */
 };
 
@@ -3190,10 +3344,17 @@ static PyObject * ExpTable_normalize(ExpTable * self) { NORMALIZE };
 static PyObject * ExpTable_reset(ExpTable * self) { TABLE_RESET };
 static PyObject * ExpTable_removeDC(ExpTable *self) { REMOVE_DC };
 static PyObject * ExpTable_reverse(ExpTable *self) { REVERSE };
+static PyObject * ExpTable_invert(ExpTable *self) { INVERT };
+static PyObject * ExpTable_rectify(ExpTable *self) { RECTIFY };
+static PyObject * ExpTable_bipolarGain(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * ExpTable_lowpass(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * ExpTable_fadein(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * ExpTable_fadeout(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * ExpTable_pow(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * ExpTable_copy(ExpTable *self, PyObject *arg) { COPY };
 static PyObject * ExpTable_setTable(ExpTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * ExpTable_getTable(ExpTable *self) { GET_TABLE };
-static PyObject * ExpTable_getViewTable(ExpTable *self) { GET_VIEW_TABLE };
+static PyObject * ExpTable_getViewTable(ExpTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * ExpTable_put(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * ExpTable_get(ExpTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -3333,7 +3494,7 @@ static PyMethodDef ExpTable_methods[] = {
 {"copy", (PyCFunction)ExpTable_copy, METH_O, "Copy data from table given in argument."},
 {"setTable", (PyCFunction)ExpTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
 {"getTable", (PyCFunction)ExpTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-{"getViewTable", (PyCFunction)ExpTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+{"getViewTable", (PyCFunction)ExpTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
 {"getTableStream", (PyCFunction)ExpTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
 {"setData", (PyCFunction)ExpTable_setData, METH_O, "Sets the table from samples in a text file."},
 {"setSize", (PyCFunction)ExpTable_setSize, METH_O, "Sets the size of the table in samples"},
@@ -3348,6 +3509,13 @@ static PyMethodDef ExpTable_methods[] = {
 {"reset", (PyCFunction)ExpTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)ExpTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)ExpTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)ExpTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)ExpTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)ExpTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)ExpTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)ExpTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)ExpTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)ExpTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {NULL}  /* Sentinel */
 };
 
@@ -3856,6 +4024,13 @@ static PyObject * SndTable_normalize(SndTable *self) { NORMALIZE };
 static PyObject * SndTable_reset(SndTable *self) { TABLE_RESET };
 static PyObject * SndTable_removeDC(SndTable *self) { REMOVE_DC };
 static PyObject * SndTable_reverse(SndTable *self) { REVERSE };
+static PyObject * SndTable_invert(SndTable *self) { INVERT };
+static PyObject * SndTable_rectify(SndTable *self) { RECTIFY };
+static PyObject * SndTable_bipolarGain(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * SndTable_lowpass(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * SndTable_fadein(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * SndTable_fadeout(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * SndTable_pow(SndTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * SndTable_copy(SndTable *self, PyObject *arg) { COPY };
 static PyObject * SndTable_setTable(SndTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * SndTable_getTable(SndTable *self) { GET_TABLE };
@@ -3864,17 +4039,37 @@ static PyObject * SndTable_get(SndTable *self, PyObject *args, PyObject *kwds) {
 
 static PyObject * 
 SndTable_getViewTable(SndTable *self, PyObject *args, PyObject *kwds) { 
-    int i, j, y, w, h, h2, step;
+    int i, j, y, w, h, h2, step, size;
     int count = 0;
-    MYFLT absin;
-    PyObject *samples;
+    int yOffset = 0;
+    MYFLT absin, fstep;
+    MYFLT begin = 0.0;
+    MYFLT end = -1.0;
+    PyObject *samples, *tuple;
     PyObject *sizetmp = NULL;
 
-    static char *kwlist[] = {"size", NULL};
+    static char *kwlist[] = {"size", "begin", "end", "yOffset", NULL};
     
-    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &sizetmp))
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE__OFFI, kwlist, &sizetmp, &begin, &end, &yOffset))
         return PyInt_FromLong(-1); 
     
+    if (end <= 0.0)
+        end = self->size;
+    else {
+        end = end * self->sr;
+        if (end > self->size)
+            end = self->size;
+    }
+
+    if (begin < 0.0)
+        begin = 0;
+    else {
+        begin = begin * self->sr;
+        if (begin >= end)
+            begin = 0;
+    }
+    size = (int)(end - begin);
+
     if (sizetmp) {
         if (PyTuple_Check(sizetmp)) {
             w = PyInt_AsLong(PyTuple_GET_ITEM(sizetmp, 0));
@@ -3894,20 +4089,52 @@ SndTable_getViewTable(SndTable *self, PyObject *args, PyObject *kwds) {
         h = 200;
     }
     h2 = h/2;
-    step = (int)(self->size / (MYFLT)(w));
-    
-    samples = PyList_New(w*4);
-    for(i=0; i<w; i++) {
-        absin = 0.0;
-        for (j=0; j<step; j++) {
-            if (MYFABS(self->data[count++]) > absin)
-                absin = self->data[count];
+    step = (int)(size / (MYFLT)(w));
+    fstep = (MYFLT)(w) / (size-1);
+    
+    if (step == 0) {
+        samples = PyList_New(size);
+        for (i=0; i<size; i++) {
+            tuple = PyTuple_New(2);
+            PyTuple_SetItem(tuple, 0, PyInt_FromLong((int)(i*fstep)));
+            PyTuple_SetItem(tuple, 1, PyInt_FromLong(-self->data[i+(int)(begin)]*h2+h2+yOffset));
+            PyList_SetItem(samples, i, tuple);
+        }
+    }
+    else if (step < 32) {
+        samples = PyList_New(w);
+        for(i=0; i<w; i++) {
+            absin = 0.0;
+            for (j=0; j<step; j++) {
+                absin += -self->data[(int)(begin)+count];
+                count++;
+            }
+            y = (int)(absin / step * h2);
+            tuple = PyTuple_New(2);
+            PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+            PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2+y+yOffset));
+            PyList_SetItem(samples, i, tuple);
+        }
+    }
+    else {
+        samples = PyList_New(w*2);
+        for(i=0; i<w; i++) {
+            absin = 0.0;
+            for (j=0; j<step; j++) {
+                if (MYFABS(self->data[(int)(begin)+count]) > absin)
+                    absin = -self->data[(int)(begin)+count];
+                count++;
+            }
+            y = (int)(absin * h2);
+            tuple = PyTuple_New(2);
+            PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+            PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2-y+yOffset));
+            PyList_SetItem(samples, i*2, tuple);
+            tuple = PyTuple_New(2);
+            PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+            PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2+y+yOffset));
+            PyList_SetItem(samples, i*2+1, tuple);
         }
-        y = (int)(absin * h2);
-        PyList_SetItem(samples, i*4, PyInt_FromLong(i));
-        PyList_SetItem(samples, i*4+1, PyInt_FromLong(h2-y));
-        PyList_SetItem(samples, i*4+2, PyInt_FromLong(i));
-        PyList_SetItem(samples, i*4+3, PyInt_FromLong(h2+y));
     }
     return samples;
 };
@@ -4080,6 +4307,13 @@ static PyMethodDef SndTable_methods[] = {
 {"reset", (PyCFunction)SndTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)SndTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)SndTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)SndTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)SndTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)SndTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)SndTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)SndTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)SndTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)SndTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {"put", (PyCFunction)SndTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
 {"get", (PyCFunction)SndTable_get, METH_VARARGS|METH_KEYWORDS, "Gets the value at specified position in the table."},
 {"setSound", (PyCFunction)SndTable_setSound, METH_VARARGS|METH_KEYWORDS, "Load a new sound in the table."},
@@ -4148,6 +4382,7 @@ typedef struct {
     pyo_table_HEAD
     MYFLT length;
     MYFLT feedback;
+    MYFLT sr;
     int pointer;
 } NewTable;
 
@@ -4222,8 +4457,8 @@ NewTable_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_F_OF, kwlist, &self->length, &inittmp, &self->feedback))
         Py_RETURN_NONE; 
 
-    double sr = PyFloat_AsDouble(PyObject_CallMethod(self->server, "getSamplingRate", NULL));
-    self->size = (int)(self->length * sr + 0.5);
+    self->sr = (MYFLT)PyFloat_AsDouble(PyObject_CallMethod(self->server, "getSamplingRate", NULL));
+    self->size = (int)(self->length * self->sr + 0.5);
     self->data = (MYFLT *)realloc(self->data, (self->size + 1) * sizeof(MYFLT));
 
     for (i=0; i<(self->size+1); i++) {
@@ -4237,7 +4472,7 @@ NewTable_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     }
     
     TableStream_setData(self->tablestream, self->data);
-    TableStream_setSamplingRate(self->tablestream, sr);
+    TableStream_setSamplingRate(self->tablestream, self->sr);
     
     return (PyObject *)self;
 }
@@ -4249,6 +4484,13 @@ static PyObject * NewTable_normalize(NewTable *self) { NORMALIZE };
 static PyObject * NewTable_reset(NewTable *self) { TABLE_RESET };
 static PyObject * NewTable_removeDC(NewTable *self) { REMOVE_DC };
 static PyObject * NewTable_reverse(NewTable *self) { REVERSE };
+static PyObject * NewTable_invert(NewTable *self) { INVERT };
+static PyObject * NewTable_rectify(NewTable *self) { RECTIFY };
+static PyObject * NewTable_bipolarGain(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * NewTable_lowpass(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * NewTable_fadein(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * NewTable_fadeout(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * NewTable_pow(NewTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * NewTable_copy(NewTable *self, PyObject *arg) { COPY };
 static PyObject * NewTable_setTable(NewTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * NewTable_getTable(NewTable *self) { GET_TABLE };
@@ -4257,17 +4499,37 @@ static PyObject * NewTable_get(NewTable *self, PyObject *args, PyObject *kwds) {
 
 static PyObject * 
 NewTable_getViewTable(NewTable *self, PyObject *args, PyObject *kwds) { 
-    int i, j, y, w, h, h2, step;
+    int i, j, y, w, h, h2, step, size;
     int count = 0;
-    MYFLT absin;
-    PyObject *samples;
+    int yOffset = 0;
+    MYFLT absin, fstep;
+    MYFLT begin = 0.0;
+    MYFLT end = -1.0;
+    PyObject *samples, *tuple;
     PyObject *sizetmp = NULL;
+
+    static char *kwlist[] = {"size", "begin", "end", "yOffset", NULL};
     
-    static char *kwlist[] = {"size", NULL};
-    
-    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &sizetmp))
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE__OFFI, kwlist, &sizetmp, &begin, &end, &yOffset))
         return PyInt_FromLong(-1); 
     
+    if (end <= 0.0)
+        end = self->size;
+    else {
+        end = end * self->sr;
+        if (end > self->size)
+            end = self->size;
+    }
+
+    if (begin < 0.0)
+        begin = 0;
+    else {
+        begin = begin * self->sr;
+        if (begin >= end)
+            begin = 0;
+    }
+    size = (int)(end - begin);
+
     if (sizetmp) {
         if (PyTuple_Check(sizetmp)) {
             w = PyInt_AsLong(PyTuple_GET_ITEM(sizetmp, 0));
@@ -4287,20 +4549,52 @@ NewTable_getViewTable(NewTable *self, PyObject *args, PyObject *kwds) {
         h = 200;
     }
     h2 = h/2;
-    step = (int)(self->size / (MYFLT)(w));
-    
-    samples = PyList_New(w*4);
-    for(i=0; i<w; i++) {
-        absin = 0.0;
-        for (j=0; j<step; j++) {
-            if (MYFABS(self->data[count++]) > absin)
-                absin = self->data[count];
+    step = (int)(size / (MYFLT)(w));
+    fstep = (MYFLT)(w) / (size-1);
+    
+    if (step == 0) {
+        samples = PyList_New(size);
+        for (i=0; i<size; i++) {
+            tuple = PyTuple_New(2);
+            PyTuple_SetItem(tuple, 0, PyInt_FromLong((int)(i*fstep)));
+            PyTuple_SetItem(tuple, 1, PyInt_FromLong(-self->data[i+(int)(begin)]*h2+h2+yOffset));
+            PyList_SetItem(samples, i, tuple);
+        }
+    }
+    else if (step < 32) {
+        samples = PyList_New(w);
+        for(i=0; i<w; i++) {
+            absin = 0.0;
+            for (j=0; j<step; j++) {
+                absin += -self->data[(int)(begin)+count];
+                count++;
+            }
+            y = (int)(absin / step * h2);
+            tuple = PyTuple_New(2);
+            PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+            PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2+y+yOffset));
+            PyList_SetItem(samples, i, tuple);
+        }
+    }
+    else {
+        samples = PyList_New(w*2);
+        for(i=0; i<w; i++) {
+            absin = 0.0;
+            for (j=0; j<step; j++) {
+                if (MYFABS(self->data[(int)(begin)+count]) > absin)
+                    absin = -self->data[(int)(begin)+count];
+                count++;
+            }
+            y = (int)(absin * h2);
+            tuple = PyTuple_New(2);
+            PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+            PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2-y+yOffset));
+            PyList_SetItem(samples, i*2, tuple);
+            tuple = PyTuple_New(2);
+            PyTuple_SetItem(tuple, 0, PyInt_FromLong(i));
+            PyTuple_SetItem(tuple, 1, PyInt_FromLong(h2+y+yOffset));
+            PyList_SetItem(samples, i*2+1, tuple);
         }
-        y = (int)(absin * h2);
-        PyList_SetItem(samples, i*4, PyInt_FromLong(i));
-        PyList_SetItem(samples, i*4+1, PyInt_FromLong(h2-y));
-        PyList_SetItem(samples, i*4+2, PyInt_FromLong(i));
-        PyList_SetItem(samples, i*4+3, PyInt_FromLong(h2+y));
     }
     return samples;
 };
@@ -4360,6 +4654,13 @@ static PyMethodDef NewTable_methods[] = {
 {"reset", (PyCFunction)NewTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
 {"removeDC", (PyCFunction)NewTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
 {"reverse", (PyCFunction)NewTable_reverse, METH_NOARGS, "Reverse the table's data."},
+{"invert", (PyCFunction)NewTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+{"rectify", (PyCFunction)NewTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+{"bipolarGain", (PyCFunction)NewTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+{"lowpass", (PyCFunction)NewTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+{"fadein", (PyCFunction)NewTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+{"fadeout", (PyCFunction)NewTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+{"pow", (PyCFunction)NewTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
 {"put", (PyCFunction)NewTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
 {"get", (PyCFunction)NewTable_get, METH_VARARGS|METH_KEYWORDS, "Gets the value at specified position in the table."},
 {"getSize", (PyCFunction)NewTable_getSize, METH_NOARGS, "Return the size of the table in samples."},
@@ -4492,10 +4793,17 @@ static PyObject * DataTable_normalize(DataTable *self) { NORMALIZE };
 static PyObject * DataTable_reset(DataTable *self) { TABLE_RESET };
 static PyObject * DataTable_removeDC(DataTable *self) { REMOVE_DC };
 static PyObject * DataTable_reverse(DataTable *self) { REVERSE };
+static PyObject * DataTable_invert(DataTable *self) { INVERT };
+static PyObject * DataTable_rectify(DataTable *self) { RECTIFY };
+static PyObject * DataTable_bipolarGain(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_BIPOLAR_GAIN };
+static PyObject * DataTable_lowpass(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_LOWPASS };
+static PyObject * DataTable_fadein(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEIN };
+static PyObject * DataTable_fadeout(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_FADEOUT };
+static PyObject * DataTable_pow(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_POWER };
 static PyObject * DataTable_copy(DataTable *self, PyObject *arg) { COPY };
 static PyObject * DataTable_setTable(DataTable *self, PyObject *arg) { SET_TABLE };
 static PyObject * DataTable_getTable(DataTable *self) { GET_TABLE };
-static PyObject * DataTable_getViewTable(DataTable *self) { GET_VIEW_TABLE };
+static PyObject * DataTable_getViewTable(DataTable *self, PyObject *args, PyObject *kwds) { GET_VIEW_TABLE };
 static PyObject * DataTable_put(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_PUT };
 static PyObject * DataTable_get(DataTable *self, PyObject *args, PyObject *kwds) { TABLE_GET };
 
@@ -4523,13 +4831,20 @@ static PyMethodDef DataTable_methods[] = {
     {"copy", (PyCFunction)DataTable_copy, METH_O, "Copy data from table given in argument."},
     {"setTable", (PyCFunction)DataTable_setTable, METH_O, "Sets the table content from a list of floats (must be the same size as the object size)."},
     {"getTable", (PyCFunction)DataTable_getTable, METH_NOARGS, "Returns a list of table samples."},
-    {"getViewTable", (PyCFunction)DataTable_getViewTable, METH_NOARGS, "Returns a list of pixel coordinates for drawing the table."},
+    {"getViewTable", (PyCFunction)DataTable_getViewTable, METH_VARARGS|METH_KEYWORDS, "Returns a list of pixel coordinates for drawing the table."},
     {"getTableStream", (PyCFunction)DataTable_getTableStream, METH_NOARGS, "Returns table stream object created by this table."},
     {"setData", (PyCFunction)DataTable_setData, METH_O, "Sets the table from samples in a text file."},
     {"normalize", (PyCFunction)DataTable_normalize, METH_NOARGS, "Normalize table samples between -1 and 1"},
     {"reset", (PyCFunction)DataTable_reset, METH_NOARGS, "Resets table samples to 0.0"},
     {"removeDC", (PyCFunction)DataTable_removeDC, METH_NOARGS, "Filter out DC offset from the table's data."},
     {"reverse", (PyCFunction)DataTable_reverse, METH_NOARGS, "Reverse the table's data."},
+    {"invert", (PyCFunction)DataTable_invert, METH_NOARGS, "Reverse the table's data in amplitude."},
+    {"rectify", (PyCFunction)DataTable_rectify, METH_NOARGS, "Positive rectification of the table's data."},
+    {"bipolarGain", (PyCFunction)DataTable_bipolarGain, METH_VARARGS|METH_KEYWORDS, "Apply different amp values to positive and negative samples."},
+    {"lowpass", (PyCFunction)DataTable_lowpass, METH_VARARGS|METH_KEYWORDS, "Apply a one-pole lowpass filter on table's samples."},
+    {"fadein", (PyCFunction)DataTable_fadein, METH_VARARGS|METH_KEYWORDS, "Apply a gradual increase in the level of the table's samples."},
+    {"fadeout", (PyCFunction)DataTable_fadeout, METH_VARARGS|METH_KEYWORDS, "Apply a gradual decrease in the level of the table's samples."},
+    {"pow", (PyCFunction)DataTable_pow, METH_VARARGS|METH_KEYWORDS, "Apply a power function on each sample in the table."},
     {"put", (PyCFunction)DataTable_put, METH_VARARGS|METH_KEYWORDS, "Puts a value at specified position in the table."},
     {"get", (PyCFunction)DataTable_get, METH_VARARGS|METH_KEYWORDS, "Gets the value at specified position in the table."},
     {"getSize", (PyCFunction)DataTable_getSize, METH_NOARGS, "Return the size of the table in samples."},
@@ -4720,13 +5035,11 @@ TableRec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of TableRec must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableRec must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
+    Py_INCREF(tabletmp);
     self->table = (NewTable *)tabletmp;
     
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
@@ -5210,16 +5523,15 @@ TableMorph_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of TableMorph must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TableMorph must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
+    Py_INCREF(tabletmp);
     self->table = (PyObject *)tabletmp;
     
     Py_XDECREF(self->sources);
+    Py_INCREF(sourcestmp);
     self->sources = (PyObject *)sourcestmp;
     
     TableMorph_alloc_memories(self);
@@ -5521,6 +5833,7 @@ TrigTableRec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
 
     Py_XDECREF(self->trigger);
+    Py_INCREF(trigtmp);
     self->trigger = trigtmp;
     trig_streamtmp = PyObject_CallMethod((PyObject *)self->trigger, "_getStream", NULL);
     Py_INCREF(trig_streamtmp);
@@ -5528,13 +5841,11 @@ TrigTableRec_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->trigger_stream = (Stream *)trig_streamtmp;
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of TrigTableRec must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TrigTableRec must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
+    Py_INCREF(tabletmp);
     self->table = (NewTable *)tabletmp;
     
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
@@ -5989,13 +6300,11 @@ TablePut_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of TablePut must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TablePut must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
+    Py_INCREF(tabletmp);
     self->table = (DataTable *)tabletmp;
     
     PyObject_CallMethod(self->server, "addStream", "O", self->stream);
diff --git a/src/objects/trigmodule.c b/src/objects/trigmodule.c
index cdbcf85..be86e0c 100644
--- a/src/objects/trigmodule.c
+++ b/src/objects/trigmodule.c
@@ -1394,7 +1394,7 @@ TrigFunc_setArg(TrigFunc *self, PyObject *arg)
 	PyObject *tmp;
 
     tmp = arg;
-    Py_DECREF(self->arg);
+    Py_XDECREF(self->arg);
     Py_INCREF(tmp);
     self->arg = tmp;
     
@@ -1692,11 +1692,8 @@ TrigEnv_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_INPUT_STREAM
     
     if ( PyObject_HasAttrString((PyObject *)tabletmp, "getTableStream") == 0 ) {
-        PySys_WriteStderr("TypeError: \"table\" argument of TrigEnv must be a PyoTableObject.\n");
-        if (PyInt_AsLong(PyObject_CallMethod(self->server, "getIsBooted", NULL))) {
-            PyObject_CallMethod(self->server, "shutdown", NULL);
-        }
-        Py_Exit(1);
+        PyErr_SetString(PyExc_TypeError, "\"table\" argument of TrigEnv must be a PyoTableObject.\n");
+        Py_RETURN_NONE;
     }
     Py_XDECREF(self->table);
     self->table = PyObject_CallMethod((PyObject *)tabletmp, "getTableStream", "");
diff --git a/src/objects/utilsmodule.c b/src/objects/utilsmodule.c
index a82cec9..e4e5653 100644
--- a/src/objects/utilsmodule.c
+++ b/src/objects/utilsmodule.c
@@ -1203,11 +1203,11 @@ SampHold_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     
     INIT_INPUT_STREAM
     
-    Py_XDECREF(self->controlsig); \
-    self->controlsig = controlsigtmp; \
-    controlsig_streamtmp = PyObject_CallMethod((PyObject *)self->controlsig, "_getStream", NULL); \
-    Py_INCREF(controlsig_streamtmp); \
-    Py_XDECREF(self->controlsig_stream); \
+    Py_XDECREF(self->controlsig);
+    self->controlsig = controlsigtmp;
+    controlsig_streamtmp = PyObject_CallMethod((PyObject *)self->controlsig, "_getStream", NULL);
+    Py_INCREF(controlsig_streamtmp);
+    Py_XDECREF(self->controlsig_stream);
     self->controlsig_stream = (Stream *)controlsig_streamtmp;
     
     if (valuetmp) {
@@ -1393,6 +1393,383 @@ SampHold_new,                                     /* tp_new */
 };
 
 /************/
+/* TrackHold */
+/************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    PyObject *controlsig;
+    Stream *controlsig_stream;
+    PyObject *value;
+    Stream *value_stream;
+    MYFLT currentValue;
+    int flag;
+    int modebuffer[3]; // need at least 2 slots for mul & add 
+} TrackHold;
+
+static void
+TrackHold_filters_i(TrackHold *self) {
+    MYFLT ctrl;
+    int i;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT *ctrlsig = Stream_getData((Stream *)self->controlsig_stream);
+    MYFLT val = PyFloat_AS_DOUBLE(self->value);
+
+    for (i=0; i<self->bufsize; i++) {
+        ctrl = ctrlsig[i];
+        if (ctrl > (val - 0.0001) && ctrl < (val + 0.0001)) {
+            if (self->flag == 1) {
+                self->currentValue = in[i];
+                self->flag = 0;
+            }    
+        }
+        else {
+            self->currentValue = in[i];
+            self->flag = 1;
+        }
+        self->data[i] = self->currentValue;
+    }
+}
+
+static void
+TrackHold_filters_a(TrackHold *self) {
+    MYFLT ctrl, val;
+    int i;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT *ctrlsig = Stream_getData((Stream *)self->controlsig_stream);
+    MYFLT *valsig = Stream_getData((Stream *)self->value_stream);
+    
+    for (i=0; i<self->bufsize; i++) {
+        ctrl = ctrlsig[i];
+        val = valsig[i];
+        if (ctrl > (val - 0.0001) && ctrl < (val + 0.0001)) {
+            if (self->flag == 1) {
+                self->currentValue = in[i];
+                self->flag = 0;
+            }    
+        }
+        else {
+            self->currentValue = in[i];
+            self->flag = 1;
+        }
+        self->data[i] = self->currentValue;
+    }
+}
+
+static void TrackHold_postprocessing_ii(TrackHold *self) { POST_PROCESSING_II };
+static void TrackHold_postprocessing_ai(TrackHold *self) { POST_PROCESSING_AI };
+static void TrackHold_postprocessing_ia(TrackHold *self) { POST_PROCESSING_IA };
+static void TrackHold_postprocessing_aa(TrackHold *self) { POST_PROCESSING_AA };
+static void TrackHold_postprocessing_ireva(TrackHold *self) { POST_PROCESSING_IREVA };
+static void TrackHold_postprocessing_areva(TrackHold *self) { POST_PROCESSING_AREVA };
+static void TrackHold_postprocessing_revai(TrackHold *self) { POST_PROCESSING_REVAI };
+static void TrackHold_postprocessing_revaa(TrackHold *self) { POST_PROCESSING_REVAA };
+static void TrackHold_postprocessing_revareva(TrackHold *self) { POST_PROCESSING_REVAREVA };
+
+static void
+TrackHold_setProcMode(TrackHold *self)
+{
+    int procmode, muladdmode;
+    procmode = self->modebuffer[2];
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+	switch (procmode) {
+        case 0:    
+            self->proc_func_ptr = TrackHold_filters_i;
+            break;
+        case 1:    
+            self->proc_func_ptr = TrackHold_filters_a;
+            break;
+    } 
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = TrackHold_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = TrackHold_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = TrackHold_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = TrackHold_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = TrackHold_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = TrackHold_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = TrackHold_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = TrackHold_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = TrackHold_postprocessing_revareva;
+            break;
+    }   
+}
+
+static void
+TrackHold_compute_next_data_frame(TrackHold *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+TrackHold_traverse(TrackHold *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    Py_VISIT(self->controlsig);
+    Py_VISIT(self->controlsig_stream);
+    Py_VISIT(self->value);    
+    Py_VISIT(self->value_stream);    
+    return 0;
+}
+
+static int 
+TrackHold_clear(TrackHold *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    Py_CLEAR(self->controlsig);
+    Py_CLEAR(self->controlsig_stream);
+    Py_CLEAR(self->value);    
+    Py_CLEAR(self->value_stream);    
+    return 0;
+}
+
+static void
+TrackHold_dealloc(TrackHold* self)
+{
+    pyo_DEALLOC
+    TrackHold_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+TrackHold_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *inputtmp, *input_streamtmp, *controlsigtmp, *controlsig_streamtmp, *valuetmp=NULL, *multmp=NULL, *addtmp=NULL;
+    TrackHold *self;
+    self = (TrackHold *)type->tp_alloc(type, 0);
+    
+    self->value = PyFloat_FromDouble(0.0);
+    self->currentValue = 0.0;
+    self->flag = 1;
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+	self->modebuffer[2] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, TrackHold_compute_next_data_frame);
+    self->mode_func_ptr = TrackHold_setProcMode;
+
+    static char *kwlist[] = {"input", "controlsig", "value", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOO", kwlist, &inputtmp, &controlsigtmp, &valuetmp, &multmp, &addtmp))
+        Py_RETURN_NONE;
+    
+    INIT_INPUT_STREAM
+    
+    Py_XDECREF(self->controlsig);
+    self->controlsig = controlsigtmp;
+    controlsig_streamtmp = PyObject_CallMethod((PyObject *)self->controlsig, "_getStream", NULL);
+    Py_INCREF(controlsig_streamtmp);
+    Py_XDECREF(self->controlsig_stream);
+    self->controlsig_stream = (Stream *)controlsig_streamtmp;
+    
+    if (valuetmp) {
+        PyObject_CallMethod((PyObject *)self, "setValue", "O", valuetmp);
+    }
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * TrackHold_getServer(TrackHold* self) { GET_SERVER };
+static PyObject * TrackHold_getStream(TrackHold* self) { GET_STREAM };
+static PyObject * TrackHold_setMul(TrackHold *self, PyObject *arg) { SET_MUL };	
+static PyObject * TrackHold_setAdd(TrackHold *self, PyObject *arg) { SET_ADD };	
+static PyObject * TrackHold_setSub(TrackHold *self, PyObject *arg) { SET_SUB };	
+static PyObject * TrackHold_setDiv(TrackHold *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * TrackHold_play(TrackHold *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * TrackHold_out(TrackHold *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * TrackHold_stop(TrackHold *self) { STOP };
+
+static PyObject * TrackHold_multiply(TrackHold *self, PyObject *arg) { MULTIPLY };
+static PyObject * TrackHold_inplace_multiply(TrackHold *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * TrackHold_add(TrackHold *self, PyObject *arg) { ADD };
+static PyObject * TrackHold_inplace_add(TrackHold *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * TrackHold_sub(TrackHold *self, PyObject *arg) { SUB };
+static PyObject * TrackHold_inplace_sub(TrackHold *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * TrackHold_div(TrackHold *self, PyObject *arg) { DIV };
+static PyObject * TrackHold_inplace_div(TrackHold *self, PyObject *arg) { INPLACE_DIV };
+
+static PyObject *
+TrackHold_setValue(TrackHold *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+	
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->value);
+	if (isNumber == 1) {
+		self->value = PyNumber_Float(tmp);
+        self->modebuffer[2] = 0;
+	}
+	else {
+		self->value = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->value, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->value_stream);
+        self->value_stream = (Stream *)streamtmp;
+		self->modebuffer[2] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMemberDef TrackHold_members[] = {
+{"server", T_OBJECT_EX, offsetof(TrackHold, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(TrackHold, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(TrackHold, input), 0, "Input sound object."},
+{"controlsig", T_OBJECT_EX, offsetof(TrackHold, controlsig), 0, "Control input object."},
+{"value", T_OBJECT_EX, offsetof(TrackHold, value), 0, "Trigger value."},
+{"mul", T_OBJECT_EX, offsetof(TrackHold, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(TrackHold, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef TrackHold_methods[] = {
+{"getServer", (PyCFunction)TrackHold_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)TrackHold_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)TrackHold_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)TrackHold_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)TrackHold_stop, METH_NOARGS, "Stops computing."},
+{"setValue", (PyCFunction)TrackHold_setValue, METH_O, "Sets trigger value."},
+{"setMul", (PyCFunction)TrackHold_setMul, METH_O, "Sets oscillator mul factor."},
+{"setAdd", (PyCFunction)TrackHold_setAdd, METH_O, "Sets oscillator add factor."},
+{"setSub", (PyCFunction)TrackHold_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)TrackHold_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods TrackHold_as_number = {
+(binaryfunc)TrackHold_add,                         /*nb_add*/
+(binaryfunc)TrackHold_sub,                         /*nb_subtract*/
+(binaryfunc)TrackHold_multiply,                    /*nb_multiply*/
+(binaryfunc)TrackHold_div,                                              /*nb_divide*/
+0,                                              /*nb_remainder*/
+0,                                              /*nb_divmod*/
+0,                                              /*nb_power*/
+0,                                              /*nb_neg*/
+0,                                              /*nb_pos*/
+0,                                              /*(unaryfunc)array_abs,*/
+0,                                              /*nb_nonzero*/
+0,                                              /*nb_invert*/
+0,                                              /*nb_lshift*/
+0,                                              /*nb_rshift*/
+0,                                              /*nb_and*/
+0,                                              /*nb_xor*/
+0,                                              /*nb_or*/
+0,                                              /*nb_coerce*/
+0,                                              /*nb_int*/
+0,                                              /*nb_long*/
+0,                                              /*nb_float*/
+0,                                              /*nb_oct*/
+0,                                              /*nb_hex*/
+(binaryfunc)TrackHold_inplace_add,                 /*inplace_add*/
+(binaryfunc)TrackHold_inplace_sub,                 /*inplace_subtract*/
+(binaryfunc)TrackHold_inplace_multiply,            /*inplace_multiply*/
+(binaryfunc)TrackHold_inplace_div,                                              /*inplace_divide*/
+0,                                              /*inplace_remainder*/
+0,                                              /*inplace_power*/
+0,                                              /*inplace_lshift*/
+0,                                              /*inplace_rshift*/
+0,                                              /*inplace_and*/
+0,                                              /*inplace_xor*/
+0,                                              /*inplace_or*/
+0,                                              /*nb_floor_divide*/
+0,                                              /*nb_true_divide*/
+0,                                              /*nb_inplace_floor_divide*/
+0,                                              /*nb_inplace_true_divide*/
+0,                                              /* nb_index */
+};
+
+PyTypeObject TrackHoldType = {
+PyObject_HEAD_INIT(NULL)
+0,                                              /*ob_size*/
+"_pyo.TrackHold_base",                                   /*tp_name*/
+sizeof(TrackHold),                                 /*tp_basicsize*/
+0,                                              /*tp_itemsize*/
+(destructor)TrackHold_dealloc,                     /*tp_dealloc*/
+0,                                              /*tp_print*/
+0,                                              /*tp_getattr*/
+0,                                              /*tp_setattr*/
+0,                                              /*tp_compare*/
+0,                                              /*tp_repr*/
+&TrackHold_as_number,                              /*tp_as_number*/
+0,                                              /*tp_as_sequence*/
+0,                                              /*tp_as_mapping*/
+0,                                              /*tp_hash */
+0,                                              /*tp_call*/
+0,                                              /*tp_str*/
+0,                                              /*tp_getattro*/
+0,                                              /*tp_setattro*/
+0,                                              /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"TrackHold objects. Let pass and freeze an audio stream.",           /* tp_doc */
+(traverseproc)TrackHold_traverse,                  /* tp_traverse */
+(inquiry)TrackHold_clear,                          /* tp_clear */
+0,                                              /* tp_richcompare */
+0,                                              /* tp_weaklistoffset */
+0,                                              /* tp_iter */
+0,                                              /* tp_iternext */
+TrackHold_methods,                                 /* tp_methods */
+TrackHold_members,                                 /* tp_members */
+0,                                              /* tp_getset */
+0,                                              /* tp_base */
+0,                                              /* tp_dict */
+0,                                              /* tp_descr_get */
+0,                                              /* tp_descr_set */
+0,                                              /* tp_dictoffset */
+0,                          /* tp_init */
+0,                                              /* tp_alloc */
+TrackHold_new,                                     /* tp_new */
+};
+
+/************/
 /* Compare */
 /************/
 typedef struct {
@@ -4250,7 +4627,7 @@ MToF_process(MToF *self) {
     for (i=0; i<self->bufsize; i++) {
         midi = in[i];
         if (midi != self->lastmidi) {
-            self->data[i] = self->curfreq = 8.1757989156437 * MYPOW(1.0594630943593, midi);
+            self->data[i] = self->curfreq = 440.0 * MYPOW(2.0, (midi - 69) / 12.0);
             self->lastmidi = midi;
         }
         else
@@ -4506,6 +4883,284 @@ PyTypeObject MToFType = {
 };
 
 /************/
+/* FToM */
+/************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    MYFLT lastfreq;
+    MYFLT curmidi;
+    int modebuffer[2]; // need at least 2 slots for mul & add
+} FToM;
+
+static void
+FToM_process(FToM *self) {
+    int i;
+    MYFLT freq;
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    
+    for (i=0; i<self->bufsize; i++) {
+        freq = in[i];
+        if (freq != self->lastfreq) {
+            if (freq < 8.1758)
+                freq = 8.1578;
+            self->curmidi = 12.0 * MYLOG2(freq / 440.0) + 69;
+            self->lastfreq = freq;
+        }
+        else
+            self->data[i] = self->curmidi;
+    }
+}
+
+static void FToM_postprocessing_ii(FToM *self) { POST_PROCESSING_II };
+static void FToM_postprocessing_ai(FToM *self) { POST_PROCESSING_AI };
+static void FToM_postprocessing_ia(FToM *self) { POST_PROCESSING_IA };
+static void FToM_postprocessing_aa(FToM *self) { POST_PROCESSING_AA };
+static void FToM_postprocessing_ireva(FToM *self) { POST_PROCESSING_IREVA };
+static void FToM_postprocessing_areva(FToM *self) { POST_PROCESSING_AREVA };
+static void FToM_postprocessing_revai(FToM *self) { POST_PROCESSING_REVAI };
+static void FToM_postprocessing_revaa(FToM *self) { POST_PROCESSING_REVAA };
+static void FToM_postprocessing_revareva(FToM *self) { POST_PROCESSING_REVAREVA };
+
+static void
+FToM_setProcMode(FToM *self)
+{
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+    self->proc_func_ptr = FToM_process;
+    
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = FToM_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = FToM_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = FToM_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = FToM_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = FToM_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = FToM_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = FToM_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = FToM_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = FToM_postprocessing_revareva;
+            break;
+    }   
+}
+
+static void
+FToM_compute_next_data_frame(FToM *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+FToM_traverse(FToM *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);
+    return 0;
+}
+
+static int 
+FToM_clear(FToM *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);
+    return 0;
+}
+
+static void
+FToM_dealloc(FToM* self)
+{
+    pyo_DEALLOC
+    FToM_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+FToM_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *inputtmp, *input_streamtmp, *multmp=NULL, *addtmp=NULL;
+    FToM *self;
+    self = (FToM *)type->tp_alloc(type, 0);
+    
+    self->lastfreq = 8.1758;
+    self->curmidi = 0.0;
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, FToM_compute_next_data_frame);
+    self->mode_func_ptr = FToM_setProcMode;
+
+    static char *kwlist[] = {"input", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist, &inputtmp, &multmp, &addtmp))
+        Py_RETURN_NONE;
+    
+    INIT_INPUT_STREAM
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * FToM_getServer(FToM* self) { GET_SERVER };
+static PyObject * FToM_getStream(FToM* self) { GET_STREAM };
+static PyObject * FToM_setMul(FToM *self, PyObject *arg) { SET_MUL };	
+static PyObject * FToM_setAdd(FToM *self, PyObject *arg) { SET_ADD };	
+static PyObject * FToM_setSub(FToM *self, PyObject *arg) { SET_SUB };	
+static PyObject * FToM_setDiv(FToM *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * FToM_play(FToM *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * FToM_out(FToM *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * FToM_stop(FToM *self) { STOP };
+
+static PyObject * FToM_multiply(FToM *self, PyObject *arg) { MULTIPLY };
+static PyObject * FToM_inplace_multiply(FToM *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * FToM_add(FToM *self, PyObject *arg) { ADD };
+static PyObject * FToM_inplace_add(FToM *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * FToM_sub(FToM *self, PyObject *arg) { SUB };
+static PyObject * FToM_inplace_sub(FToM *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * FToM_div(FToM *self, PyObject *arg) { DIV };
+static PyObject * FToM_inplace_div(FToM *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef FToM_members[] = {
+    {"server", T_OBJECT_EX, offsetof(FToM, server), 0, "Pyo server."},
+    {"stream", T_OBJECT_EX, offsetof(FToM, stream), 0, "Stream object."},
+    {"input", T_OBJECT_EX, offsetof(FToM, input), 0, "Input sound object."},
+    {"mul", T_OBJECT_EX, offsetof(FToM, mul), 0, "Mul factor."},
+    {"add", T_OBJECT_EX, offsetof(FToM, add), 0, "Add factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyMethodDef FToM_methods[] = {
+    {"getServer", (PyCFunction)FToM_getServer, METH_NOARGS, "Returns server object."},
+    {"_getStream", (PyCFunction)FToM_getStream, METH_NOARGS, "Returns stream object."},
+    {"play", (PyCFunction)FToM_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+    {"stop", (PyCFunction)FToM_stop, METH_NOARGS, "Stops computing."},
+    {"out", (PyCFunction)FToM_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+    {"setMul", (PyCFunction)FToM_setMul, METH_O, "Sets oscillator mul factor."},
+    {"setAdd", (PyCFunction)FToM_setAdd, METH_O, "Sets oscillator add factor."},
+    {"setSub", (PyCFunction)FToM_setSub, METH_O, "Sets inverse add factor."},
+    {"setDiv", (PyCFunction)FToM_setDiv, METH_O, "Sets inverse mul factor."},
+    {NULL}  /* Sentinel */
+};
+
+static PyNumberMethods FToM_as_number = {
+    (binaryfunc)FToM_add,                         /*nb_add*/
+    (binaryfunc)FToM_sub,                         /*nb_subtract*/
+    (binaryfunc)FToM_multiply,                    /*nb_multiply*/
+    (binaryfunc)FToM_div,                                              /*nb_divide*/
+    0,                                              /*nb_remainder*/
+    0,                                              /*nb_divmod*/
+    0,                                              /*nb_power*/
+    0,                                              /*nb_neg*/
+    0,                                              /*nb_pos*/
+    0,                                              /*(unaryfunc)array_abs,*/
+    0,                                              /*nb_nonzero*/
+    0,                                              /*nb_invert*/
+    0,                                              /*nb_lshift*/
+    0,                                              /*nb_rshift*/
+    0,                                              /*nb_and*/
+    0,                                              /*nb_xor*/
+    0,                                              /*nb_or*/
+    0,                                              /*nb_coerce*/
+    0,                                              /*nb_int*/
+    0,                                              /*nb_long*/
+    0,                                              /*nb_float*/
+    0,                                              /*nb_oct*/
+    0,                                              /*nb_hex*/
+    (binaryfunc)FToM_inplace_add,                 /*inplace_add*/
+    (binaryfunc)FToM_inplace_sub,                 /*inplace_subtract*/
+    (binaryfunc)FToM_inplace_multiply,            /*inplace_multiply*/
+    (binaryfunc)FToM_inplace_div,                                              /*inplace_divide*/
+    0,                                              /*inplace_remainder*/
+    0,                                              /*inplace_power*/
+    0,                                              /*inplace_lshift*/
+    0,                                              /*inplace_rshift*/
+    0,                                              /*inplace_and*/
+    0,                                              /*inplace_xor*/
+    0,                                              /*inplace_or*/
+    0,                                              /*nb_floor_divide*/
+    0,                                              /*nb_true_divide*/
+    0,                                              /*nb_inplace_floor_divide*/
+    0,                                              /*nb_inplace_true_divide*/
+    0,                                              /* nb_index */
+};
+
+PyTypeObject FToMType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                                              /*ob_size*/
+    "_pyo.FToM_base",                                   /*tp_name*/
+    sizeof(FToM),                                 /*tp_basicsize*/
+    0,                                              /*tp_itemsize*/
+    (destructor)FToM_dealloc,                     /*tp_dealloc*/
+    0,                                              /*tp_print*/
+    0,                                              /*tp_getattr*/
+    0,                                              /*tp_setattr*/
+    0,                                              /*tp_compare*/
+    0,                                              /*tp_repr*/
+    &FToM_as_number,                              /*tp_as_number*/
+    0,                                              /*tp_as_sequence*/
+    0,                                              /*tp_as_mapping*/
+    0,                                              /*tp_hash */
+    0,                                              /*tp_call*/
+    0,                                              /*tp_str*/
+    0,                                              /*tp_getattro*/
+    0,                                              /*tp_setattro*/
+    0,                                              /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+    "FToM objects. Converts frequency to midi note.",           /* tp_doc */
+    (traverseproc)FToM_traverse,                  /* tp_traverse */
+    (inquiry)FToM_clear,                          /* tp_clear */
+    0,                                              /* tp_richcompare */
+    0,                                              /* tp_weaklistoffset */
+    0,                                              /* tp_iter */
+    0,                                              /* tp_iternext */
+    FToM_methods,                                 /* tp_methods */
+    FToM_members,                                 /* tp_members */
+    0,                                              /* tp_getset */
+    0,                                              /* tp_base */
+    0,                                              /* tp_dict */
+    0,                                              /* tp_descr_get */
+    0,                                              /* tp_descr_set */
+    0,                                              /* tp_dictoffset */
+    0,                          /* tp_init */
+    0,                                              /* tp_alloc */
+    FToM_new,                                     /* tp_new */
+};
+
+/************/
 /* MToT */
 /************/
 typedef struct {
diff --git a/src/objects/wgverbmodule.c b/src/objects/wgverbmodule.c
index 79970ce..1fa6d06 100644
--- a/src/objects/wgverbmodule.c
+++ b/src/objects/wgverbmodule.c
@@ -26,18 +26,20 @@
 #include "servermodule.h"
 #include "dummymodule.h"
 
+#define NUM_REFS  13
 
 static const MYFLT randomScaling = 0.5;
-static const MYFLT reverbParams[8][3] = {
-{ 2473.0, 0.0010, 3.100 },
-{ 2767.0, 0.0011, 3.500 },
-{ 3217.0, 0.0017, 1.110 },
-{ 3557.0, 0.0006, 3.973 },
-{ 3907.0, 0.0010, 2.341 },
-{ 4127.0, 0.0011, 1.897 },
-{ 2143.0, 0.0017, 0.891 },
-{ 1933.0, 0.0006, 3.221 }
-};
+static const MYFLT reverbParams[8][4] = {
+{ 2473.0, 0.0010, 3.100, 2503.0 },
+{ 2767.0, 0.0011, 3.500, 2749.0 },
+{ 3217.0, 0.0017, 1.110, 3187.0 },
+{ 3557.0, 0.0006, 3.973, 3583.0 },
+{ 3907.0, 0.0010, 2.341, 3929.0 },
+{ 4127.0, 0.0011, 1.897, 4093.0 },
+{ 2143.0, 0.0017, 0.891, 2131.0 },
+{ 1933.0, 0.0006, 3.221, 1951.0 }};
+
+static const MYFLT first_ref_delays[NUM_REFS] = {283, 467, 587, 677, 757, 911, 1117, 1223, 1307, 1429, 1553, 1613, 1783};
 
 typedef struct {
     pyo_audio_HEAD
@@ -486,12 +488,6 @@ WGVerb_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     self->mix = PyFloat_FromDouble(0.5);
     self->lastFreq = self->damp = 0.0;
     
-    for (i=0; i<8; i++) {
-        self->in_count[i] = 0;
-        self->lastSamples[i] = 0.0;
-        self->rnd_value[i] = self->rnd_oldValue[i] = self->rnd_diff[i] = 0.0;
-        self->rnd_time[i] = 1.0;
-    }    
     self->total_signal = 0.0;
 	self->modebuffer[0] = 0;
 	self->modebuffer[1] = 0;
@@ -770,7 +766,7 @@ sizeof(WGVerb),         /*tp_basicsize*/
 0,                         /*tp_setattro*/
 0,                         /*tp_as_buffer*/
 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
-"WGVerb objects. WGVerb signal by x samples.",           /* tp_doc */
+"WGVerb objects. Waveguide-based reverberation network.",           /* tp_doc */
 (traverseproc)WGVerb_traverse,   /* tp_traverse */
 (inquiry)WGVerb_clear,           /* tp_clear */
 0,		               /* tp_richcompare */
@@ -789,3 +785,1327 @@ WGVerb_members,             /* tp_members */
 0,                         /* tp_alloc */
 WGVerb_new,                 /* tp_new */
 };
+
+/***************/
+/**** STRev ****/
+/***************/
+typedef struct {
+    pyo_audio_HEAD
+    PyObject *input;
+    Stream *input_stream;
+    PyObject *inpos;
+    Stream *inpos_stream;
+    PyObject *revtime;
+    Stream *revtime_stream;
+    PyObject *cutoff;
+    Stream *cutoff_stream;
+    PyObject *mix;
+    Stream *mix_stream;
+    void (*mix_func_ptr)();
+    int modebuffer[4];
+    MYFLT firstRefGain;
+    MYFLT total_signal[2];
+    MYFLT delays[2][8];
+    long size[2][8];
+    int in_count[2][8];
+    MYFLT *buffer[2][8];
+    MYFLT *ref_buffer[NUM_REFS];
+    int ref_size[NUM_REFS];
+    int ref_in_count[NUM_REFS];
+    MYFLT avg_time;
+    MYFLT srfac;
+    // lowpass
+    MYFLT damp[2];
+    MYFLT lastFreq;
+    MYFLT nyquist;
+    MYFLT lastInpos;
+    // sample memories
+    MYFLT lastSamples[2][8];
+    // jitters
+    MYFLT rnd[2][8];
+    MYFLT rnd_value[2][8];
+    MYFLT rnd_oldValue[2][8];
+    MYFLT rnd_diff[2][8];
+    MYFLT rnd_time[2][8];
+    MYFLT rnd_timeInc[2][8];
+    MYFLT rnd_range[2][8];
+    MYFLT rnd_halfRange[2][8];
+    MYFLT *buffer_streams;
+    MYFLT *input_buffer[2];
+} STReverb;
+
+static void
+STReverb_process_ii(STReverb *self) {
+    int i, j, k, k2, ind, half;
+    MYFLT val, x, x1, xind, frac, junction, inval, filt, amp1, amp2, b, f, sum_ref, feed, step, invp;
+    MYFLT ref_amp_l[NUM_REFS];
+    MYFLT ref_amp_r[NUM_REFS];
+    MYFLT ref_buf[2];
+    
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT inpos = PyFloat_AS_DOUBLE(self->inpos);
+    if (self->modebuffer[1] == 0)
+        feed = PyFloat_AS_DOUBLE(self->revtime);
+    else
+        feed = Stream_getData((Stream *)self->revtime_stream)[0];
+    MYFLT freq = PyFloat_AS_DOUBLE(self->cutoff);
+        
+    if (inpos < 0.0)
+        inpos = 0.0;
+    else if (inpos > 1.0)
+        inpos = 1.0;
+       
+    if (feed < 0.01)
+        feed = 0.01;
+    feed = MYPOW(100.0, -self->avg_time/feed);
+
+    if (freq < 20.0)
+        freq = 20.0;
+    else if (freq > self->nyquist)
+        freq = self->nyquist;
+
+    if (freq != self->lastFreq || inpos != self->lastInpos) {
+        self->lastFreq = freq;
+        self->lastInpos = inpos;
+        f = ((1.0 - inpos) * 0.3 + 0.7) * freq;
+        b = 2.0 - MYCOS(TWOPI * f / self->sr);
+        self->damp[0] = (b - MYSQRT(b * b - 1.0));
+        f = (inpos * 0.3 + 0.7) * freq;
+        b = 2.0 - MYCOS(TWOPI * f / self->sr);
+        self->damp[1] = (b - MYSQRT(b * b - 1.0));
+    }
+
+    /* position of the source and first reflexions */
+    amp1 = 1.0 - inpos;
+    amp2 = inpos;
+    half = (NUM_REFS - 1) / 2;
+    if (inpos <= 0.5) {
+        step = (0.5 - inpos) / half;
+        ref_amp_l[half] = ref_amp_r[half] = 0.5;
+        for (k=0; k<half; k++) {
+            k2 = NUM_REFS - 1 - k;
+            ref_amp_r[k] = ref_amp_l[k2] = inpos + step * k;
+            ref_amp_l[k] = ref_amp_r[k2] = 1.0 - ref_amp_r[k];
+            ref_amp_r[k2] *= inpos + 0.5;
+        }
+    }
+    else {
+        invp = 1.0 - inpos;
+        step = (0.5 - invp) / half;
+        ref_amp_l[half] = ref_amp_r[half] = 0.5;
+        for (k=0; k<half; k++) {
+            k2 = NUM_REFS - 1 - k;
+            ref_amp_l[k] = ref_amp_r[k2] = invp + step * k;
+            ref_amp_r[k] = ref_amp_l[k2] = 1.0 - ref_amp_l[k];
+            ref_amp_l[k2] *= invp + 0.5;
+        }
+    }
+
+    for (i=0; i<self->bufsize; i++) {
+        self->input_buffer[0][i] = in[i] * amp1;
+        self->input_buffer[1][i] = in[i] * amp2;
+        ref_buf[0] = ref_buf[1] = 0.0;
+        for (k=0; k<NUM_REFS; k++) {
+            sum_ref = self->ref_buffer[k][self->ref_in_count[k]];
+            self->ref_buffer[k][self->ref_in_count[k]] = in[i];
+            self->ref_in_count[k]++;
+            if (self->ref_in_count[k] == self->ref_size[k])
+                self->ref_in_count[k] = 0;
+            ref_buf[0] += sum_ref * ref_amp_l[k];
+            ref_buf[1] += sum_ref * ref_amp_r[k];
+        }
+        for (k=0; k<2; k++) {
+            inval = self->input_buffer[k][i] * 0.8 + self->input_buffer[1-k][i] * 0.2 + ref_buf[k] * 0.1;
+            junction = self->total_signal[k] * .25;
+            self->total_signal[k] = ref_buf[k] * self->firstRefGain;
+            for (j=0; j<8; j++) {
+                self->rnd_time[k][j] += self->rnd_timeInc[k][j];
+                if (self->rnd_time[k][j] < 0.0)
+                    self->rnd_time[k][j] += 1.0;
+                else if (self->rnd_time[k][j] >= 1.0) {
+                    self->rnd_time[k][j] -= 1.0;
+                    self->rnd_oldValue[k][j] = self->rnd_value[k][j];
+                    self->rnd_value[k][j] = self->rnd_range[k][j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[k][j];
+                    self->rnd_diff[k][j] = self->rnd_value[k][j] - self->rnd_oldValue[k][j];
+                }
+                self->rnd[k][j] = self->rnd_oldValue[k][j] + self->rnd_diff[k][j] * self->rnd_time[k][j];
+                
+                xind = self->in_count[k][j] - (self->delays[k][j] + self->rnd[k][j]);
+                if (xind < 0)
+                    xind += self->size[k][j];
+                ind = (int)xind;
+                frac = xind - ind;
+                x = self->buffer[k][j][ind];
+                x1 = self->buffer[k][j][ind+1];
+                val = x + (x1 - x) * frac;
+                val *= feed;
+                filt = val + (self->lastSamples[k][j] - val) * self->damp[k];
+                self->total_signal[k] += filt;
+            
+                self->buffer[k][j][self->in_count[k][j]] = inval + junction - self->lastSamples[k][j];
+                self->lastSamples[k][j] = filt;
+                if(self->in_count[k][j] == 0)
+                    self->buffer[k][j][self->size[k][j]] = self->buffer[k][j][0];
+                self->in_count[k][j]++;
+                if (self->in_count[k][j] >= self->size[k][j])
+                    self->in_count[k][j] = 0;
+            } 
+            self->buffer_streams[i+k*self->bufsize] = self->total_signal[k] * 0.25;
+        }
+    }
+}
+
+static void
+STReverb_process_ai(STReverb *self) {
+    MYFLT val, x, x1, xind, frac, junction, inval, filt, amp1, amp2, b, f, sum_ref, inpos, feed, step, invp;
+    MYFLT ref_amp_l[NUM_REFS];
+    MYFLT ref_amp_r[NUM_REFS];
+    MYFLT ref_buf[2];
+    int i, j, k, k2, ind, half;
+    
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT *pos = Stream_getData((Stream *)self->inpos_stream);
+    if (self->modebuffer[1] == 0)
+        feed = PyFloat_AS_DOUBLE(self->revtime);
+    else
+        feed = Stream_getData((Stream *)self->revtime_stream)[0];
+    MYFLT freq = PyFloat_AS_DOUBLE(self->cutoff);
+
+    if (feed < 0.01)
+        feed = 0.01;
+    feed = MYPOW(100.0, -self->avg_time/feed);
+
+    if (freq < 20.0)
+        freq = 20.0;
+    else if (freq > self->nyquist)
+        freq = self->nyquist;
+
+    for (i=0; i<self->bufsize; i++) {
+        inpos = pos[i];
+        if (inpos < 0.0)
+            inpos = 0.0;
+        else if (inpos > 1.0)
+            inpos = 1.0;
+        if (freq != self->lastFreq || inpos != self->lastInpos) {
+            self->lastFreq = freq;
+            self->lastInpos = inpos;
+            f = ((1.0 - inpos) * 0.3 + 0.7) * freq;
+            b = 2.0 - MYCOS(TWOPI * f / self->sr);
+            self->damp[0] = (b - MYSQRT(b * b - 1.0));
+            f = (inpos * 0.3 + 0.7) * freq;
+            b = 2.0 - MYCOS(TWOPI * f / self->sr);
+            self->damp[1] = (b - MYSQRT(b * b - 1.0));
+        }
+
+        /* position of the source and first reflexions */
+        amp1 = 1.0 - inpos;
+        amp2 = inpos;
+        half = (NUM_REFS - 1) / 2;
+        if (inpos <= 0.5) {
+            step = (0.5 - inpos) / half;
+            ref_amp_l[half] = ref_amp_r[half] = 0.5;
+            for (k=0; k<half; k++) {
+                k2 = NUM_REFS - 1 - k;
+                ref_amp_r[k] = ref_amp_l[k2] = inpos + step * k;
+                ref_amp_l[k] = ref_amp_r[k2] = 1.0 - ref_amp_r[k];
+                ref_amp_r[k2] *= inpos + 0.5;
+            }
+        }
+        else {
+            invp = 1.0 - inpos;
+            step = (0.5 - invp) / half;
+            ref_amp_l[half] = ref_amp_r[half] = 0.5;
+            for (k=0; k<half; k++) {
+                k2 = NUM_REFS - 1 - k;
+                ref_amp_l[k] = ref_amp_r[k2] = invp + step * k;
+                ref_amp_r[k] = ref_amp_l[k2] = 1.0 - ref_amp_l[k];
+                ref_amp_l[k2] *= invp + 0.5;
+            }
+        }
+
+        self->input_buffer[0][i] = in[i] * amp1;
+        self->input_buffer[1][i] = in[i] * amp2;
+        ref_buf[0] = ref_buf[1] = 0.0;
+        for (k=0; k<NUM_REFS; k++) {
+            sum_ref = self->ref_buffer[k][self->ref_in_count[k]];
+            self->ref_buffer[k][self->ref_in_count[k]] = in[i];
+            self->ref_in_count[k]++;
+            if (self->ref_in_count[k] == self->ref_size[k])
+                self->ref_in_count[k] = 0;
+            ref_buf[0] += sum_ref * ref_amp_l[k];
+            ref_buf[1] += sum_ref * ref_amp_r[k];
+        }
+        for (k=0; k<2; k++) {
+            inval = self->input_buffer[k][i] * 0.8 + self->input_buffer[1-k][i] * 0.2 + ref_buf[k] * 0.1;
+            junction = self->total_signal[k] * .25;
+            self->total_signal[k] = ref_buf[k] * self->firstRefGain;
+            for (j=0; j<8; j++) {
+                self->rnd_time[k][j] += self->rnd_timeInc[k][j];
+                if (self->rnd_time[k][j] < 0.0)
+                    self->rnd_time[k][j] += 1.0;
+                else if (self->rnd_time[k][j] >= 1.0) {
+                    self->rnd_time[k][j] -= 1.0;
+                    self->rnd_oldValue[k][j] = self->rnd_value[k][j];
+                    self->rnd_value[k][j] = self->rnd_range[k][j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[k][j];
+                    self->rnd_diff[k][j] = self->rnd_value[k][j] - self->rnd_oldValue[k][j];
+                }
+                self->rnd[k][j] = self->rnd_oldValue[k][j] + self->rnd_diff[k][j] * self->rnd_time[k][j];
+                
+                xind = self->in_count[k][j] - (self->delays[k][j] + self->rnd[k][j]);
+                if (xind < 0)
+                    xind += self->size[k][j];
+                ind = (int)xind;
+                frac = xind - ind;
+                x = self->buffer[k][j][ind];
+                x1 = self->buffer[k][j][ind+1];
+                val = x + (x1 - x) * frac;
+                val *= feed;
+                filt = val + (self->lastSamples[k][j] - val) * self->damp[k];
+                self->total_signal[k] += filt;
+            
+                self->buffer[k][j][self->in_count[k][j]] = inval + junction - self->lastSamples[k][j];
+                self->lastSamples[k][j] = filt;
+                if(self->in_count[k][j] == 0)
+                    self->buffer[k][j][self->size[k][j]] = self->buffer[k][j][0];
+                self->in_count[k][j]++;
+                if (self->in_count[k][j] >= self->size[k][j])
+                    self->in_count[k][j] = 0;
+            } 
+            self->buffer_streams[i+k*self->bufsize] = self->total_signal[k] * 0.25;
+        }
+    }
+}
+
+static void
+STReverb_process_ia(STReverb *self) {
+    MYFLT val, x, x1, xind, frac, junction, inval, filt, amp1, amp2, b, f, sum_ref, feed, freq, step, invp;
+    MYFLT ref_amp_l[NUM_REFS];
+    MYFLT ref_amp_r[NUM_REFS];
+    MYFLT ref_buf[2];
+    int i, j, k, k2, ind, half;
+    
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT inpos = PyFloat_AS_DOUBLE(self->inpos);
+    if (self->modebuffer[1] == 0)
+        feed = PyFloat_AS_DOUBLE(self->revtime);
+    else
+        feed = Stream_getData((Stream *)self->revtime_stream)[0];
+    MYFLT *fr = Stream_getData((Stream *)self->cutoff_stream);
+        
+    if (inpos < 0.0)
+        inpos = 0.0;
+    else if (inpos > 1.0)
+        inpos = 1.0;
+       
+    if (feed < 0.01)
+        feed = 0.01;
+    feed = MYPOW(100.0, -self->avg_time/feed);
+
+    /* position of the source and first reflexions */
+    amp1 = 1.0 - inpos;
+    amp2 = inpos;
+    half = (NUM_REFS - 1) / 2;
+    if (inpos <= 0.5) {
+        step = (0.5 - inpos) / half;
+        ref_amp_l[half] = ref_amp_r[half] = 0.5;
+        for (k=0; k<half; k++) {
+            k2 = NUM_REFS - 1 - k;
+            ref_amp_r[k] = ref_amp_l[k2] = inpos + step * k;
+            ref_amp_l[k] = ref_amp_r[k2] = 1.0 - ref_amp_r[k];
+            ref_amp_r[k2] *= inpos + 0.5;
+        }
+    }
+    else {
+        invp = 1.0 - inpos;
+        step = (0.5 - invp) / half;
+        ref_amp_l[half] = ref_amp_r[half] = 0.5;
+        for (k=0; k<half; k++) {
+            k2 = NUM_REFS - 1 - k;
+            ref_amp_l[k] = ref_amp_r[k2] = invp + step * k;
+            ref_amp_r[k] = ref_amp_l[k2] = 1.0 - ref_amp_l[k];
+            ref_amp_l[k2] *= invp + 0.5;
+        }
+    }
+
+    for (i=0; i<self->bufsize; i++) {
+        freq = fr[i];
+        if (freq < 20.0)
+            freq = 20.0;
+        else if (freq > self->nyquist)
+            freq = self->nyquist;
+
+        if (freq != self->lastFreq || inpos != self->lastInpos) {
+            self->lastFreq = freq;
+            self->lastInpos = inpos;
+            f = ((1.0 - inpos) * 0.3 + 0.7) * freq;
+            b = 2.0 - MYCOS(TWOPI * f / self->sr);
+            self->damp[0] = (b - MYSQRT(b * b - 1.0));
+            f = (inpos * 0.3 + 0.7) * freq;
+            b = 2.0 - MYCOS(TWOPI * f / self->sr);
+            self->damp[1] = (b - MYSQRT(b * b - 1.0));
+        }
+
+        self->input_buffer[0][i] = in[i] * amp1;
+        self->input_buffer[1][i] = in[i] * amp2;
+        ref_buf[0] = ref_buf[1] = 0.0;
+        for (k=0; k<NUM_REFS; k++) {
+            sum_ref = self->ref_buffer[k][self->ref_in_count[k]];
+            self->ref_buffer[k][self->ref_in_count[k]] = in[i];
+            self->ref_in_count[k]++;
+            if (self->ref_in_count[k] == self->ref_size[k])
+                self->ref_in_count[k] = 0;
+            ref_buf[0] += sum_ref * ref_amp_l[k];
+            ref_buf[1] += sum_ref * ref_amp_r[k];
+        }
+        for (k=0; k<2; k++) {
+            inval = self->input_buffer[k][i] * 0.8 + self->input_buffer[1-k][i] * 0.2 + ref_buf[k] * 0.1;
+            junction = self->total_signal[k] * .25;
+            self->total_signal[k] = ref_buf[k] * self->firstRefGain;
+            for (j=0; j<8; j++) {
+                self->rnd_time[k][j] += self->rnd_timeInc[k][j];
+                if (self->rnd_time[k][j] < 0.0)
+                    self->rnd_time[k][j] += 1.0;
+                else if (self->rnd_time[k][j] >= 1.0) {
+                    self->rnd_time[k][j] -= 1.0;
+                    self->rnd_oldValue[k][j] = self->rnd_value[k][j];
+                    self->rnd_value[k][j] = self->rnd_range[k][j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[k][j];
+                    self->rnd_diff[k][j] = self->rnd_value[k][j] - self->rnd_oldValue[k][j];
+                }
+                self->rnd[k][j] = self->rnd_oldValue[k][j] + self->rnd_diff[k][j] * self->rnd_time[k][j];
+                
+                xind = self->in_count[k][j] - (self->delays[k][j] + self->rnd[k][j]);
+                if (xind < 0)
+                    xind += self->size[k][j];
+                ind = (int)xind;
+                frac = xind - ind;
+                x = self->buffer[k][j][ind];
+                x1 = self->buffer[k][j][ind+1];
+                val = x + (x1 - x) * frac;
+                val *= feed;
+                filt = val + (self->lastSamples[k][j] - val) * self->damp[k];
+                self->total_signal[k] += filt;
+            
+                self->buffer[k][j][self->in_count[k][j]] = inval + junction - self->lastSamples[k][j];
+                self->lastSamples[k][j] = filt;
+                if(self->in_count[k][j] == 0)
+                    self->buffer[k][j][self->size[k][j]] = self->buffer[k][j][0];
+                self->in_count[k][j]++;
+                if (self->in_count[k][j] >= self->size[k][j])
+                    self->in_count[k][j] = 0;
+            } 
+            self->buffer_streams[i+k*self->bufsize] = self->total_signal[k] * 0.25;
+        }
+    }
+}
+
+static void
+STReverb_process_aa(STReverb *self) {
+    MYFLT val, x, x1, xind, frac, junction, inval, filt, amp1, amp2, b, f, sum_ref, inpos, feed, freq, step, invp;
+    MYFLT ref_amp_l[NUM_REFS];
+    MYFLT ref_amp_r[NUM_REFS];
+    MYFLT ref_buf[2];
+    int i, j, k, k2, ind, half;
+    
+    MYFLT *in = Stream_getData((Stream *)self->input_stream);
+    MYFLT *pos = Stream_getData((Stream *)self->inpos_stream);
+    if (self->modebuffer[1] == 0)
+        feed = PyFloat_AS_DOUBLE(self->revtime);
+    else
+        feed = Stream_getData((Stream *)self->revtime_stream)[0];
+    MYFLT *fr = Stream_getData((Stream *)self->cutoff_stream);
+
+    if (feed < 0.01)
+        feed = 0.01;
+    feed = MYPOW(100.0, -self->avg_time/feed);
+
+    for (i=0; i<self->bufsize; i++) {
+        inpos = pos[i];
+        freq = fr[i];
+        if (inpos < 0.0)
+            inpos = 0.0;
+        else if (inpos > 1.0)
+            inpos = 1.0;
+        if (freq < 20.0)
+            freq = 20.0;
+        else if (freq > self->nyquist)
+            freq = self->nyquist;
+
+        if (freq != self->lastFreq || inpos != self->lastInpos) {
+            self->lastFreq = freq;
+            self->lastInpos = inpos;
+            f = ((1.0 - inpos) * 0.3 + 0.7) * freq;
+            b = 2.0 - MYCOS(TWOPI * f / self->sr);
+            self->damp[0] = (b - MYSQRT(b * b - 1.0));
+            f = (inpos * 0.3 + 0.7) * freq;
+            b = 2.0 - MYCOS(TWOPI * f / self->sr);
+            self->damp[1] = (b - MYSQRT(b * b - 1.0));
+        }
+
+        /* position of the source and first reflexions */
+        amp1 = 1.0 - inpos;
+        amp2 = inpos;
+        half = (NUM_REFS - 1) / 2;
+        if (inpos <= 0.5) {
+            step = (0.5 - inpos) / half;
+            ref_amp_l[half] = ref_amp_r[half] = 0.5;
+            for (k=0; k<half; k++) {
+                k2 = NUM_REFS - 1 - k;
+                ref_amp_r[k] = ref_amp_l[k2] = inpos + step * k;
+                ref_amp_l[k] = ref_amp_r[k2] = 1.0 - ref_amp_r[k];
+                ref_amp_r[k2] *= inpos + 0.5;
+            }
+        }
+        else {
+            invp = 1.0 - inpos;
+            step = (0.5 - invp) / half;
+            ref_amp_l[half] = ref_amp_r[half] = 0.5;
+            for (k=0; k<half; k++) {
+                k2 = NUM_REFS - 1 - k;
+                ref_amp_l[k] = ref_amp_r[k2] = invp + step * k;
+                ref_amp_r[k] = ref_amp_l[k2] = 1.0 - ref_amp_l[k];
+                ref_amp_l[k2] *= invp + 0.5;
+            }
+        }
+
+        self->input_buffer[0][i] = in[i] * amp1;
+        self->input_buffer[1][i] = in[i] * amp2;
+        ref_buf[0] = ref_buf[1] = 0.0;
+        for (k=0; k<NUM_REFS; k++) {
+            sum_ref = self->ref_buffer[k][self->ref_in_count[k]];
+            self->ref_buffer[k][self->ref_in_count[k]] = in[i];
+            self->ref_in_count[k]++;
+            if (self->ref_in_count[k] == self->ref_size[k])
+                self->ref_in_count[k] = 0;
+            ref_buf[0] += sum_ref * ref_amp_l[k];
+            ref_buf[1] += sum_ref * ref_amp_r[k];
+        }
+        for (k=0; k<2; k++) {
+            inval = self->input_buffer[k][i] * 0.8 + self->input_buffer[1-k][i] * 0.2 + ref_buf[k] * 0.1;
+            junction = self->total_signal[k] * .25;
+            self->total_signal[k] = ref_buf[k] * self->firstRefGain;
+            for (j=0; j<8; j++) {
+                self->rnd_time[k][j] += self->rnd_timeInc[k][j];
+                if (self->rnd_time[k][j] < 0.0)
+                    self->rnd_time[k][j] += 1.0;
+                else if (self->rnd_time[k][j] >= 1.0) {
+                    self->rnd_time[k][j] -= 1.0;
+                    self->rnd_oldValue[k][j] = self->rnd_value[k][j];
+                    self->rnd_value[k][j] = self->rnd_range[k][j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[k][j];
+                    self->rnd_diff[k][j] = self->rnd_value[k][j] - self->rnd_oldValue[k][j];
+                }
+                self->rnd[k][j] = self->rnd_oldValue[k][j] + self->rnd_diff[k][j] * self->rnd_time[k][j];
+                
+                xind = self->in_count[k][j] - (self->delays[k][j] + self->rnd[k][j]);
+                if (xind < 0)
+                    xind += self->size[k][j];
+                ind = (int)xind;
+                frac = xind - ind;
+                x = self->buffer[k][j][ind];
+                x1 = self->buffer[k][j][ind+1];
+                val = x + (x1 - x) * frac;
+                val *= feed;
+                filt = val + (self->lastSamples[k][j] - val) * self->damp[k];
+                self->total_signal[k] += filt;
+            
+                self->buffer[k][j][self->in_count[k][j]] = inval + junction - self->lastSamples[k][j];
+                self->lastSamples[k][j] = filt;
+                if(self->in_count[k][j] == 0)
+                    self->buffer[k][j][self->size[k][j]] = self->buffer[k][j][0];
+                self->in_count[k][j]++;
+                if (self->in_count[k][j] >= self->size[k][j])
+                    self->in_count[k][j] = 0;
+            } 
+            self->buffer_streams[i+k*self->bufsize] = self->total_signal[k] * 0.25;
+        }
+    }
+}
+
+static void
+STReverb_mix_i(STReverb *self) {
+    int i, k;
+    MYFLT val;
+    
+    MYFLT mix = PyFloat_AS_DOUBLE(self->mix);
+    
+    if (mix < 0.0)
+        mix = 0.0;
+    else if (mix > 1.0)
+        mix = 1.0;
+    
+    for (i=0; i<self->bufsize; i++) {
+        for (k=0; k<2; k++) {
+            val = self->input_buffer[k][i] + (self->buffer_streams[i+k*self->bufsize] - self->input_buffer[k][i]) * mix;
+            self->buffer_streams[i+k*self->bufsize] = val;
+        }
+    }
+}
+
+static void
+STReverb_mix_a(STReverb *self) {
+    int i, k;
+    MYFLT mix, val;
+    
+    MYFLT *mi = Stream_getData((Stream *)self->mix_stream);
+    
+    for (i=0; i<self->bufsize; i++) {
+        mix = mi[i];
+        if (mix < 0.0)
+            mix = 0.0;
+        else if (mix > 1.0)
+            mix = 1.0;
+        
+        for (k=0; k<2; k++) {
+            val = self->input_buffer[k][i] + (self->buffer_streams[i+k*self->bufsize] - self->input_buffer[k][i]) * mix;
+            self->buffer_streams[i+k*self->bufsize] = val;
+        }
+    }
+}
+
+static void
+STReverb_setProcMode(STReverb *self)
+{
+    int procmode, mixmode;
+    procmode = self->modebuffer[0] + self->modebuffer[2] * 10;
+    mixmode = self->modebuffer[3];
+    
+	switch (procmode) {
+        case 0:    
+            self->proc_func_ptr = STReverb_process_ii;
+            break;
+        case 1:    
+            self->proc_func_ptr = STReverb_process_ai;
+            break;
+        case 10:    
+            self->proc_func_ptr = STReverb_process_ia;
+            break;
+        case 11:    
+            self->proc_func_ptr = STReverb_process_aa;
+            break;
+    } 
+    switch (mixmode) {
+        case 0:    
+            self->mix_func_ptr = STReverb_mix_i;
+            break;
+        case 1:    
+            self->mix_func_ptr = STReverb_mix_a;
+            break;
+    }
+}
+
+MYFLT *
+STReverb_getSamplesBuffer(STReverb *self)
+{
+    return (MYFLT *)self->buffer_streams;
+}    
+
+static void
+STReverb_compute_next_data_frame(STReverb *self)
+{
+    (*self->proc_func_ptr)(self); 
+    (*self->mix_func_ptr)(self); 
+}
+
+static int
+STReverb_traverse(STReverb *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->input);
+    Py_VISIT(self->input_stream);    
+    Py_VISIT(self->inpos);    
+    Py_VISIT(self->inpos_stream);    
+    Py_VISIT(self->revtime);    
+    Py_VISIT(self->revtime_stream);    
+    Py_VISIT(self->cutoff);    
+    Py_VISIT(self->cutoff_stream);    
+    Py_VISIT(self->mix);    
+    Py_VISIT(self->mix_stream);    
+    return 0;
+}
+
+static int 
+STReverb_clear(STReverb *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->input);
+    Py_CLEAR(self->input_stream);    
+    Py_CLEAR(self->inpos);    
+    Py_CLEAR(self->inpos_stream);    
+    Py_CLEAR(self->revtime);    
+    Py_CLEAR(self->revtime_stream);    
+    Py_CLEAR(self->cutoff);    
+    Py_CLEAR(self->cutoff_stream);    
+    Py_CLEAR(self->mix);    
+    Py_CLEAR(self->mix_stream);    
+    return 0;
+}
+
+static void
+STReverb_dealloc(STReverb* self)
+{
+    int i, k;
+    pyo_DEALLOC
+    for (k=0; k<2; k++) {
+            free(self->input_buffer[k]);
+        for (i=0; i<8; i++) {
+            free(self->buffer[k][i]);
+        }
+    }
+    for (i=0; i<NUM_REFS; i++) {
+        free(self->ref_buffer[i]);
+    }
+    free(self->buffer_streams);
+    STReverb_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+STReverb_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i, j, k, din;
+    long maxsize;
+    MYFLT roomSize = 1.0;
+    MYFLT firstRefTmp = -3.0;
+    PyObject *inputtmp, *input_streamtmp, *inpostmp=NULL, *revtimetmp=NULL, *cutofftmp=NULL, *mixtmp=NULL;
+    STReverb *self;
+    self = (STReverb *)type->tp_alloc(type, 0);
+    
+    self->inpos = PyFloat_FromDouble(0.5);
+    self->revtime = PyFloat_FromDouble(0.5);
+    self->cutoff = PyFloat_FromDouble(5000.0);
+    self->mix = PyFloat_FromDouble(0.5);
+    self->total_signal[0] = self->total_signal[1] = self->lastFreq = self->damp[0] = self->damp[1] = 0.0;
+    self->lastInpos = -1.0;
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+	self->modebuffer[2] = 0;
+    
+    INIT_OBJECT_COMMON
+    
+    self->nyquist = self->sr * 0.49;
+    self->srfac = self->sr / 44100.0;
+
+    Stream_setFunctionPtr(self->stream, STReverb_compute_next_data_frame);
+    self->mode_func_ptr = STReverb_setProcMode;
+
+    static char *kwlist[] = {"input", "inpos", "revtime", "cutoff", "mix", "roomSize", "firstRefGain", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, TYPE_O_OOOOFF, kwlist, &inputtmp, &inpostmp, &revtimetmp, &cutofftmp, &mixtmp, &roomSize, &firstRefTmp))
+        Py_RETURN_NONE;
+    
+    INIT_INPUT_STREAM
+
+    if (inpostmp) {
+        PyObject_CallMethod((PyObject *)self, "setInpos", "O", inpostmp);
+    }
+       
+    if (revtimetmp) {
+        PyObject_CallMethod((PyObject *)self, "setRevtime", "O", revtimetmp);
+    }
+
+    if (cutofftmp) {
+        PyObject_CallMethod((PyObject *)self, "setCutoff", "O", cutofftmp);
+    }
+
+    if (mixtmp) {
+        PyObject_CallMethod((PyObject *)self, "setMix", "O", mixtmp);
+    }
+
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+
+    self->firstRefGain = MYPOW(10.0, firstRefTmp * 0.05);
+    if (roomSize < 0.25)
+        roomSize = 0.25;
+    else if (roomSize > 4.0)
+        roomSize = 4.0;
+
+    self->avg_time = 0.0;
+    for (k=0; k<2; k++) {
+        din = k * 3;
+        for (i=0; i<8; i++) {
+            self->in_count[k][i] = 0;
+            self->lastSamples[k][i] = 0.0;
+            self->rnd[k][i] = self->rnd_value[k][i] = self->rnd_oldValue[k][i] = self->rnd_diff[k][i] = 0.0;
+            self->rnd_time[k][i] = 1.0;
+            self->rnd_timeInc[k][i] = reverbParams[i][2] * randomScaling / self->sr;
+            self->rnd_range[k][i] = reverbParams[i][1] * randomScaling * self->sr;
+            self->rnd_halfRange[k][i] = self->rnd_range[k][i] * 0.5;
+            self->delays[k][i] = reverbParams[i][din] * self->srfac * roomSize;
+            self->avg_time += self->delays[k][i] / self->sr;
+            self->size[k][i] = reverbParams[i][din] * self->srfac * roomSize + (int)(reverbParams[i][1] * self->sr + 0.5);
+            maxsize = reverbParams[i][din] * self->srfac * 4.0 + (int)(reverbParams[i][1] * self->sr + 0.5);
+            self->buffer[k][i] = (MYFLT *)realloc(self->buffer[k][i], (maxsize+1) * sizeof(MYFLT));
+            for (j=0; j<(maxsize+1); j++) {
+                self->buffer[k][i][j] = 0.;
+            }
+        }    
+    }
+    self->avg_time /= 16.0;
+
+    for (k=0; k<NUM_REFS; k++) {
+        self->ref_in_count[k] = 0;
+        self->ref_size[k] = (int)(first_ref_delays[k] * self->srfac * roomSize + 0.5);
+        maxsize = (int)(first_ref_delays[k] * self->srfac * 4.0 + 0.5);
+        self->ref_buffer[k] = (MYFLT *)realloc(self->ref_buffer[k], (maxsize+1) * sizeof(MYFLT));
+        for (i=0; i<(maxsize+1); i++) {
+            self->ref_buffer[k][i] = 0.0;
+        }
+    }
+
+    for (k=0; k<2; k++) {
+        self->input_buffer[k] = (MYFLT *)realloc(self->input_buffer[k], self->bufsize * sizeof(MYFLT));
+        for (i=0; i<self->bufsize; i++) {
+            self->input_buffer[k][i] = 0.0;
+        }
+    }
+
+    self->buffer_streams = (MYFLT *)realloc(self->buffer_streams, 2 * self->bufsize * sizeof(MYFLT));
+    for (i=0; i<(2 * self->bufsize); i++) {
+        self->buffer_streams[i] = 0.0;
+    }
+
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * STReverb_getServer(STReverb* self) { GET_SERVER };
+static PyObject * STReverb_getStream(STReverb* self) { GET_STREAM };
+
+static PyObject * STReverb_play(STReverb *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * STReverb_stop(STReverb *self) { STOP };
+
+static PyObject *
+STReverb_setInpos(STReverb *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+    
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->inpos);
+	if (isNumber == 1) {
+		self->inpos = PyNumber_Float(tmp);
+        self->modebuffer[0] = 0;
+	}
+	else {
+		self->inpos = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->inpos, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->inpos_stream);
+        self->inpos_stream = (Stream *)streamtmp;
+		self->modebuffer[0] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+STReverb_setRevtime(STReverb *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+    
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->revtime);
+	if (isNumber == 1) {
+		self->revtime = PyNumber_Float(tmp);
+        self->modebuffer[1] = 0;
+	}
+	else {
+		self->revtime = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->revtime, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->revtime_stream);
+        self->revtime_stream = (Stream *)streamtmp;
+		self->modebuffer[1] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+STReverb_setCutoff(STReverb *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+    
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->cutoff);
+	if (isNumber == 1) {
+		self->cutoff = PyNumber_Float(tmp);
+        self->modebuffer[2] = 0;
+	}
+	else {
+		self->cutoff = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->cutoff, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->cutoff_stream);
+        self->cutoff_stream = (Stream *)streamtmp;
+		self->modebuffer[2] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+STReverb_setMix(STReverb *self, PyObject *arg)
+{
+	PyObject *tmp, *streamtmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+    
+	tmp = arg;
+	Py_INCREF(tmp);
+	Py_DECREF(self->mix);
+	if (isNumber == 1) {
+		self->mix = PyNumber_Float(tmp);
+        self->modebuffer[3] = 0;
+	}
+	else {
+		self->mix = tmp;
+        streamtmp = PyObject_CallMethod((PyObject *)self->mix, "_getStream", NULL);
+        Py_INCREF(streamtmp);
+        Py_XDECREF(self->mix_stream);
+        self->mix_stream = (Stream *)streamtmp;
+		self->modebuffer[3] = 1;
+	}
+    
+    (*self->mode_func_ptr)(self);
+    
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyObject *
+STReverb_setRoomSize(STReverb *self, PyObject *arg)
+{
+    int i, j, k, din;
+    long maxsize;
+	MYFLT roomSize;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+    
+	if (isNumber == 1) {
+        roomSize = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        if (roomSize < 0.25)
+            roomSize = 0.25;
+        else if (roomSize > 4.0)
+            roomSize = 4.0;
+
+        self->avg_time = 0.0;
+        for (k=0; k<2; k++) {
+            din = k * 3;
+            for (i=0; i<8; i++) {
+                self->in_count[k][i] = 0;
+                self->lastSamples[k][i] = 0.0;
+                self->rnd[k][i] = self->rnd_value[k][i] = self->rnd_oldValue[k][i] = self->rnd_diff[k][i] = 0.0;
+                self->rnd_time[k][i] = 1.0;
+                self->delays[k][i] = reverbParams[i][din] * self->srfac * roomSize;
+                self->avg_time += self->delays[k][i] / self->sr;
+                self->size[k][i] = reverbParams[i][din] * self->srfac * roomSize + (int)(reverbParams[i][1] * self->sr + 0.5);
+                maxsize = reverbParams[i][din] * self->srfac * 2 + (int)(reverbParams[i][1] * self->sr + 0.5);
+                for (j=0; j<(maxsize+1); j++) {
+                    self->buffer[k][i][j] = 0.;
+                }
+            }    
+        }
+        self->avg_time /= 16.0;
+
+        for (k=0; k<NUM_REFS; k++) {
+            self->ref_in_count[k] = 0;
+            self->ref_size[k] = (int)(first_ref_delays[k] * self->srfac * roomSize + 0.5);
+            maxsize = (int)(first_ref_delays[k] * self->srfac * 2 + 0.5);
+            for (i=0; i<(maxsize+1); i++) {
+                self->ref_buffer[k][i] = 0.0;
+            }
+        }
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+STReverb_setFirstRefGain(STReverb *self, PyObject *arg)
+{
+	MYFLT tmp;
+	
+	if (arg == NULL) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+    
+	int isNumber = PyNumber_Check(arg);
+    
+	if (isNumber == 1) {
+        tmp = PyFloat_AS_DOUBLE(PyNumber_Float(arg));
+        self->firstRefGain = MYPOW(10.0, tmp * 0.05);
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}	
+
+static PyMemberDef STReverb_members[] = {
+{"server", T_OBJECT_EX, offsetof(STReverb, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(STReverb, stream), 0, "Stream object."},
+{"input", T_OBJECT_EX, offsetof(STReverb, input), 0, "Input sound object."},
+{"inpos", T_OBJECT_EX, offsetof(STReverb, inpos), 0, "Position left-right of the source."},
+{"revtime", T_OBJECT_EX, offsetof(STReverb, revtime), 0, "Reverb duration value."},
+{"cutoff", T_OBJECT_EX, offsetof(STReverb, cutoff), 0, "STReverb lowpass filter cutoff."},
+{"mix", T_OBJECT_EX, offsetof(STReverb, mix), 0, "Balance between dry and wet signals."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef STReverb_methods[] = {
+{"getServer", (PyCFunction)STReverb_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)STReverb_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)STReverb_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"stop", (PyCFunction)STReverb_stop, METH_NOARGS, "Stops computing."},
+{"setInpos", (PyCFunction)STReverb_setInpos, METH_O, "Sets position of the source between 0 -> 1."},
+{"setRevtime", (PyCFunction)STReverb_setRevtime, METH_O, "Sets reverb duration in seconds."},
+{"setCutoff", (PyCFunction)STReverb_setCutoff, METH_O, "Sets lowpass filter cutoff."},
+{"setMix", (PyCFunction)STReverb_setMix, METH_O, "Sets balance between dry and wet signals."},
+{"setFirstRefGain", (PyCFunction)STReverb_setFirstRefGain, METH_O, "Sets gain of the first reflexions."},
+{"setRoomSize", (PyCFunction)STReverb_setRoomSize, METH_O, "Sets room size scaler."},
+{NULL}  /* Sentinel */
+};
+
+PyTypeObject STReverbType = {
+PyObject_HEAD_INIT(NULL)
+0,                         /*ob_size*/
+"_pyo.STReverb_base",         /*tp_name*/
+sizeof(STReverb),         /*tp_basicsize*/
+0,                         /*tp_itemsize*/
+(destructor)STReverb_dealloc, /*tp_dealloc*/
+0,                         /*tp_print*/
+0,                         /*tp_getattr*/
+0,                         /*tp_setattr*/
+0,                         /*tp_compare*/
+0,                         /*tp_repr*/
+0,             /*tp_as_number*/
+0,                         /*tp_as_sequence*/
+0,                         /*tp_as_mapping*/
+0,                         /*tp_hash */
+0,                         /*tp_call*/
+0,                         /*tp_str*/
+0,                         /*tp_getattro*/
+0,                         /*tp_setattro*/
+0,                         /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES, /*tp_flags*/
+"STReverb objects. Waveguide-based reverberation network.",           /* tp_doc */
+(traverseproc)STReverb_traverse,   /* tp_traverse */
+(inquiry)STReverb_clear,           /* tp_clear */
+0,		               /* tp_richcompare */
+0,		               /* tp_weaklistoffset */
+0,		               /* tp_iter */
+0,		               /* tp_iternext */
+STReverb_methods,             /* tp_methods */
+STReverb_members,             /* tp_members */
+0,                      /* tp_getset */
+0,                         /* tp_base */
+0,                         /* tp_dict */
+0,                         /* tp_descr_get */
+0,                         /* tp_descr_set */
+0,                         /* tp_dictoffset */
+0,      /* tp_init */
+0,                         /* tp_alloc */
+STReverb_new,                 /* tp_new */
+};
+
+/************************************************************************************************/
+/* STReverb streamer object */
+/************************************************************************************************/
+typedef struct {
+    pyo_audio_HEAD
+    STReverb *mainSplitter;
+    int modebuffer[2];
+    int chnl; // STRev order
+} STRev;
+
+static void STRev_postprocessing_ii(STRev *self) { POST_PROCESSING_II };
+static void STRev_postprocessing_ai(STRev *self) { POST_PROCESSING_AI };
+static void STRev_postprocessing_ia(STRev *self) { POST_PROCESSING_IA };
+static void STRev_postprocessing_aa(STRev *self) { POST_PROCESSING_AA };
+static void STRev_postprocessing_ireva(STRev *self) { POST_PROCESSING_IREVA };
+static void STRev_postprocessing_areva(STRev *self) { POST_PROCESSING_AREVA };
+static void STRev_postprocessing_revai(STRev *self) { POST_PROCESSING_REVAI };
+static void STRev_postprocessing_revaa(STRev *self) { POST_PROCESSING_REVAA };
+static void STRev_postprocessing_revareva(STRev *self) { POST_PROCESSING_REVAREVA };
+
+static void
+STRev_setProcMode(STRev *self)
+{
+    int muladdmode;
+    muladdmode = self->modebuffer[0] + self->modebuffer[1] * 10;
+    
+	switch (muladdmode) {
+        case 0:        
+            self->muladd_func_ptr = STRev_postprocessing_ii;
+            break;
+        case 1:    
+            self->muladd_func_ptr = STRev_postprocessing_ai;
+            break;
+        case 2:    
+            self->muladd_func_ptr = STRev_postprocessing_revai;
+            break;
+        case 10:        
+            self->muladd_func_ptr = STRev_postprocessing_ia;
+            break;
+        case 11:    
+            self->muladd_func_ptr = STRev_postprocessing_aa;
+            break;
+        case 12:    
+            self->muladd_func_ptr = STRev_postprocessing_revaa;
+            break;
+        case 20:        
+            self->muladd_func_ptr = STRev_postprocessing_ireva;
+            break;
+        case 21:    
+            self->muladd_func_ptr = STRev_postprocessing_areva;
+            break;
+        case 22:    
+            self->muladd_func_ptr = STRev_postprocessing_revareva;
+            break;
+    }
+}
+
+static void
+STRev_compute_next_data_frame(STRev *self)
+{
+    int i;
+    MYFLT *tmp;
+    int offset = self->chnl * self->bufsize;
+    tmp = STReverb_getSamplesBuffer((STReverb *)self->mainSplitter);
+    for (i=0; i<self->bufsize; i++) {
+        self->data[i] = tmp[i + offset];
+    }    
+    (*self->muladd_func_ptr)(self);
+}
+
+static int
+STRev_traverse(STRev *self, visitproc visit, void *arg)
+{
+    pyo_VISIT
+    Py_VISIT(self->mainSplitter);
+    return 0;
+}
+
+static int 
+STRev_clear(STRev *self)
+{
+    pyo_CLEAR
+    Py_CLEAR(self->mainSplitter);    
+    return 0;
+}
+
+static void
+STRev_dealloc(STRev* self)
+{
+    pyo_DEALLOC
+    STRev_clear(self);
+    self->ob_type->tp_free((PyObject*)self);
+}
+
+static PyObject *
+STRev_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    int i;
+    PyObject *maintmp=NULL, *multmp=NULL, *addtmp=NULL;
+    STRev *self;
+    self = (STRev *)type->tp_alloc(type, 0);
+    
+	self->modebuffer[0] = 0;
+	self->modebuffer[1] = 0;
+    
+    INIT_OBJECT_COMMON
+    Stream_setFunctionPtr(self->stream, STRev_compute_next_data_frame);
+    self->mode_func_ptr = STRev_setProcMode;
+
+    static char *kwlist[] = {"mainSplitter", "chnl", "mul", "add", NULL};
+    
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi|OO", kwlist, &maintmp, &self->chnl, &multmp, &addtmp))
+        Py_RETURN_NONE;
+
+    Py_XDECREF(self->mainSplitter);
+    Py_INCREF(maintmp);
+    self->mainSplitter = (STReverb *)maintmp;
+    
+    if (multmp) {
+        PyObject_CallMethod((PyObject *)self, "setMul", "O", multmp);
+    }
+    
+    if (addtmp) {
+        PyObject_CallMethod((PyObject *)self, "setAdd", "O", addtmp);
+    }
+    
+    PyObject_CallMethod(self->server, "addStream", "O", self->stream);
+    
+    (*self->mode_func_ptr)(self);
+
+    return (PyObject *)self;
+}
+
+static PyObject * STRev_getServer(STRev* self) { GET_SERVER };
+static PyObject * STRev_getStream(STRev* self) { GET_STREAM };
+static PyObject * STRev_setMul(STRev *self, PyObject *arg) { SET_MUL };	
+static PyObject * STRev_setAdd(STRev *self, PyObject *arg) { SET_ADD };	
+static PyObject * STRev_setSub(STRev *self, PyObject *arg) { SET_SUB };	
+static PyObject * STRev_setDiv(STRev *self, PyObject *arg) { SET_DIV };	
+
+static PyObject * STRev_play(STRev *self, PyObject *args, PyObject *kwds) { PLAY };
+static PyObject * STRev_out(STRev *self, PyObject *args, PyObject *kwds) { OUT };
+static PyObject * STRev_stop(STRev *self) { STOP };
+
+static PyObject * STRev_multiply(STRev *self, PyObject *arg) { MULTIPLY };
+static PyObject * STRev_inplace_multiply(STRev *self, PyObject *arg) { INPLACE_MULTIPLY };
+static PyObject * STRev_add(STRev *self, PyObject *arg) { ADD };
+static PyObject * STRev_inplace_add(STRev *self, PyObject *arg) { INPLACE_ADD };
+static PyObject * STRev_sub(STRev *self, PyObject *arg) { SUB };
+static PyObject * STRev_inplace_sub(STRev *self, PyObject *arg) { INPLACE_SUB };
+static PyObject * STRev_div(STRev *self, PyObject *arg) { DIV };
+static PyObject * STRev_inplace_div(STRev *self, PyObject *arg) { INPLACE_DIV };
+
+static PyMemberDef STRev_members[] = {
+{"server", T_OBJECT_EX, offsetof(STRev, server), 0, "Pyo server."},
+{"stream", T_OBJECT_EX, offsetof(STRev, stream), 0, "Stream object."},
+{"mul", T_OBJECT_EX, offsetof(STRev, mul), 0, "Mul factor."},
+{"add", T_OBJECT_EX, offsetof(STRev, add), 0, "Add factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyMethodDef STRev_methods[] = {
+{"getServer", (PyCFunction)STRev_getServer, METH_NOARGS, "Returns server object."},
+{"_getStream", (PyCFunction)STRev_getStream, METH_NOARGS, "Returns stream object."},
+{"play", (PyCFunction)STRev_play, METH_VARARGS|METH_KEYWORDS, "Starts computing without sending sound to soundcard."},
+{"out", (PyCFunction)STRev_out, METH_VARARGS|METH_KEYWORDS, "Starts computing and sends sound to soundcard channel speficied by argument."},
+{"stop", (PyCFunction)STRev_stop, METH_NOARGS, "Stops computing."},
+{"setMul", (PyCFunction)STRev_setMul, METH_O, "Sets STRev mul factor."},
+{"setAdd", (PyCFunction)STRev_setAdd, METH_O, "Sets STRev add factor."},
+{"setSub", (PyCFunction)STRev_setSub, METH_O, "Sets inverse add factor."},
+{"setDiv", (PyCFunction)STRev_setDiv, METH_O, "Sets inverse mul factor."},
+{NULL}  /* Sentinel */
+};
+
+static PyNumberMethods STRev_as_number = {
+(binaryfunc)STRev_add,                      /*nb_add*/
+(binaryfunc)STRev_sub,                 /*nb_subtract*/
+(binaryfunc)STRev_multiply,                 /*nb_multiply*/
+(binaryfunc)STRev_div,                   /*nb_divide*/
+0,                /*nb_remainder*/
+0,                   /*nb_divmod*/
+0,                   /*nb_power*/
+0,                  /*nb_neg*/
+0,                /*nb_pos*/
+0,                  /*(unaryfunc)array_abs,*/
+0,                    /*nb_nonzero*/
+0,                    /*nb_invert*/
+0,               /*nb_lshift*/
+0,              /*nb_rshift*/
+0,              /*nb_and*/
+0,              /*nb_xor*/
+0,               /*nb_or*/
+0,                                          /*nb_coerce*/
+0,                       /*nb_int*/
+0,                      /*nb_long*/
+0,                     /*nb_float*/
+0,                       /*nb_oct*/
+0,                       /*nb_hex*/
+(binaryfunc)STRev_inplace_add,              /*inplace_add*/
+(binaryfunc)STRev_inplace_sub,         /*inplace_subtract*/
+(binaryfunc)STRev_inplace_multiply,         /*inplace_multiply*/
+(binaryfunc)STRev_inplace_div,           /*inplace_divide*/
+0,        /*inplace_remainder*/
+0,           /*inplace_power*/
+0,       /*inplace_lshift*/
+0,      /*inplace_rshift*/
+0,      /*inplace_and*/
+0,      /*inplace_xor*/
+0,       /*inplace_or*/
+0,             /*nb_floor_divide*/
+0,              /*nb_true_divide*/
+0,     /*nb_inplace_floor_divide*/
+0,      /*nb_inplace_true_divide*/
+0,                     /* nb_index */
+};
+
+PyTypeObject STRevType = {
+PyObject_HEAD_INIT(NULL)
+0,                         /*ob_size*/
+"_pyo.STRev_base",         /*tp_name*/
+sizeof(STRev),         /*tp_basicsize*/
+0,                         /*tp_itemsize*/
+(destructor)STRev_dealloc, /*tp_dealloc*/
+0,                         /*tp_print*/
+0,                         /*tp_getattr*/
+0,                         /*tp_setattr*/
+0,                         /*tp_compare*/
+0,                         /*tp_repr*/
+&STRev_as_number,             /*tp_as_number*/
+0,                         /*tp_as_sequence*/
+0,                         /*tp_as_mapping*/
+0,                         /*tp_hash */
+0,                         /*tp_call*/
+0,                         /*tp_str*/
+0,                         /*tp_getattro*/
+0,                         /*tp_setattro*/
+0,                         /*tp_as_buffer*/
+Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,  /*tp_flags*/
+"STRev objects. Reads one channel from a STReverb object.",           /* tp_doc */
+(traverseproc)STRev_traverse,   /* tp_traverse */
+(inquiry)STRev_clear,           /* tp_clear */
+0,		               /* tp_richcompare */
+0,		               /* tp_weaklistoffset */
+0,		               /* tp_iter */
+0,		               /* tp_iternext */
+STRev_methods,             /* tp_methods */
+STRev_members,             /* tp_members */
+0,                      /* tp_getset */
+0,                         /* tp_base */
+0,                         /* tp_dict */
+0,                         /* tp_descr_get */
+0,                         /* tp_descr_set */
+0,                         /* tp_dictoffset */
+0,      /* tp_init */
+0,                         /* tp_alloc */
+STRev_new,                 /* tp_new */
+};
diff --git a/utils/E-Pyo.py b/utils/E-Pyo.py
index e0b42f5..dfb2ae7 100755
--- a/utils/E-Pyo.py
+++ b/utils/E-Pyo.py
@@ -3,13 +3,28 @@
 """
 E-Pyo is a simple text editor especially configured to edit pyo audio programs.
 
-You can do absolutely everything you want to with this piece of software.
+You can do absolutely everything you want with this piece of software.
 
 Olivier Belanger - 2012
 
+TODO:
+    - Fix printing to pdf
+    - Output panel close button on OSX (display only) 
 """
 from __future__ import with_statement
-import sys, os, string, inspect, keyword, wx, codecs, subprocess, unicodedata, contextlib, StringIO, shutil, copy, pprint, random, time, threading
+import sys
+import __builtin__
+__builtin__.EPYO_APP_OPENED = True
+        
+if sys.platform == "linux2":
+    import wxversion
+    if wxversion.checkInstalled("3.0"):
+        wxversion.select("3.0")
+    elif wxversion.checkInstalled("2.8"):
+        wxversion.select("2.8")
+
+import os, string, inspect, keyword, wx, codecs, subprocess, unicodedata
+import contextlib, StringIO, shutil, copy, pprint, random, time, threading
 from types import UnicodeType, MethodType, ListType
 from wx.lib.wordwrap import wordwrap
 from wx.lib.embeddedimage import PyEmbeddedImage
@@ -17,8 +32,8 @@ import wx.lib.colourselect as csel
 import wx.lib.scrolledpanel as scrolled
 import wx.lib.dialogs
 import wx.combo
-import wx.stc  as  stc
-import FlatNotebook as FNB
+import wx.stc  as stc
+import wx.lib.agw.flatnotebook as FNB
 from pyo import *
 from PyoDoc import ManualFrame
 
@@ -40,6 +55,70 @@ APP_VERSION = PYO_VERSION
 OSX_APP_BUNDLED = False
 WIN_APP_BUNDLED = False
 
+################## Utility Functions ##################
+ at contextlib.contextmanager
+def stdoutIO(stdout=None):
+    old = sys.stdout
+    if stdout is None:
+        stdout = StringIO.StringIO()
+    sys.stdout = stdout
+    yield stdout
+    sys.stdout = old
+
+def convert_line_endings(temp, mode):
+    #modes:  0 - Unix, 1 - Mac, 2 - DOS
+    if mode == 0:
+        temp = string.replace(temp, '\r\n', '\n')
+        temp = string.replace(temp, '\r', '\n')
+    elif mode == 1:
+        temp = string.replace(temp, '\r\n', '\r')
+        temp = string.replace(temp, '\n', '\r')
+    elif mode == 2:
+        import re
+        temp = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", temp)
+    return temp
+
+def ensureNFD(unistr):
+    if PLATFORM in ['linux2', 'win32']:
+        encodings = [DEFAULT_ENCODING, ENCODING,
+                     'cp1252', 'iso-8859-1', 'utf-16']
+        format = 'NFC'
+    else:
+        encodings = [DEFAULT_ENCODING, ENCODING,
+                     'macroman', 'iso-8859-1', 'utf-16']
+        format = 'NFC'
+    decstr = unistr
+    if type(decstr) != UnicodeType:
+        for encoding in encodings:
+            try:
+                decstr = decstr.decode(encoding)
+                break
+            except UnicodeDecodeError:
+                continue
+            except:
+                decstr = "UnableToDecodeString"
+                print "Unicode encoding not in a recognized format..."
+                break
+    if decstr == "UnableToDecodeString":
+        return unistr
+    else:
+        return unicodedata.normalize(format, decstr)
+
+def toSysEncoding(unistr):
+    try:
+        if PLATFORM == "win32":
+            unistr = unistr.encode(ENCODING)
+        else:
+            unistr = unicode(unistr)
+    except:
+        pass
+    return unistr
+
+def hex_to_rgb(value):
+    value = value.lstrip('#')
+    lv = len(value)
+    return tuple(int(value[i:i+lv/3], 16) for i in range(0, lv, lv/3))
+
 TEMP_PATH = os.path.join(os.path.expanduser('~'), '.epyo')
 if not os.path.isdir(TEMP_PATH):
     os.mkdir(TEMP_PATH)
@@ -49,6 +128,7 @@ if not os.path.isfile(PREFERENCES_PATH):
     with open(PREFERENCES_PATH, "w") as f:
         f.write("epyo_prefs = {}")
 
+epyo_prefs = {}
 with open(PREFERENCES_PATH, "r") as f:
     text = f.read()
 exec text in locals()
@@ -201,7 +281,7 @@ DEFAULT_STYLE = os.path.join(STYLES_PATH, "Default")
 if not os.path.isfile(os.path.join(STYLES_PATH, "Default")):
     shutil.copy(os.path.join(os.getcwd(), "styles", "Default"), DEFAULT_STYLE)
 if PREFERENCES.has_key("pref_style"):
-    PREF_STYLE = os.path.join(STYLES_PATH, PREFERENCES["pref_style"])
+    PREF_STYLE = os.path.join(ensureNFD(STYLES_PATH), PREFERENCES["pref_style"])
 else:
     PREF_STYLE = DEFAULT_STYLE
 
@@ -216,70 +296,6 @@ if not os.path.isfile(MARKERS_FILE):
 BACKGROUND_SERVER_DEFAULT_ARGS = 'sr=44100, nchnls=2, buffersize=256, duplex=1, audio="portaudio", jackname="pyo"'
 BACKGROUND_SERVER_ARGS = PREFERENCES.get("background_server_args", BACKGROUND_SERVER_DEFAULT_ARGS)
 
-################## Utility Functions ##################
- at contextlib.contextmanager
-def stdoutIO(stdout=None):
-    old = sys.stdout
-    if stdout is None:
-        stdout = StringIO.StringIO()
-    sys.stdout = stdout
-    yield stdout
-    sys.stdout = old
-
-def convert_line_endings(temp, mode):
-    #modes:  0 - Unix, 1 - Mac, 2 - DOS
-    if mode == 0:
-        temp = string.replace(temp, '\r\n', '\n')
-        temp = string.replace(temp, '\r', '\n')
-    elif mode == 1:
-        temp = string.replace(temp, '\r\n', '\r')
-        temp = string.replace(temp, '\n', '\r')
-    elif mode == 2:
-        import re
-        temp = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", temp)
-    return temp
-
-def ensureNFD(unistr):
-    if PLATFORM in ['linux2', 'win32']:
-        encodings = [DEFAULT_ENCODING, ENCODING,
-                     'cp1252', 'latin_1', 'utf-16']
-        format = 'NFC'
-    else:
-        encodings = [DEFAULT_ENCODING, ENCODING,
-                     'macroman', 'latin_1', 'utf-16']
-        format = 'NFC'
-    decstr = unistr
-    if type(decstr) != UnicodeType:
-        for encoding in encodings:
-            try:
-                decstr = decstr.decode(encoding)
-                break
-            except UnicodeDecodeError:
-                continue
-            except:
-                decstr = "UnableToDecodeString"
-                print "Unicode encoding not in a recognized format..."
-                break
-    if decstr == "UnableToDecodeString":
-        return unistr
-    else:
-        return unicodedata.normalize(format, decstr)
-
-def toSysEncoding(unistr):
-    try:
-        if PLATFORM == "win32":
-            unistr = unistr.encode(ENCODING)
-        else:
-            unistr = unicode(unistr)
-    except:
-        pass
-    return unistr
-
-def hex_to_rgb(value):
-    value = value.lstrip('#')
-    lv = len(value)
-    return tuple(int(value[i:i+lv/3], 16) for i in range(0, lv, lv/3))
-
 ################## TEMPLATES ##################
 HEADER_TEMPLATE = """#!/usr/bin/env python
 # encoding: utf-8
@@ -378,7 +394,7 @@ class MyFrame(wx.Frame):
         self.frTxt.SetLabel("Freq: %.2f" % x)
         self.freqPort.value = x
         
-app = wx.PySimpleApp()
+app = wx.App(False)
 mainFrame = MyFrame(None, title='Simple App', pos=(100,100), size=(500,300))
 mainFrame.Show()
 app.MainLoop()
@@ -396,14 +412,90 @@ class MyFrame(wx.Frame):
 
 
 if __name__ == "__main__":
-    app = wx.PySimpleApp()
+    app = wx.App(False)
     mainFrame = MyFrame(None, title='Simple App', pos=(100,100), size=(500,300))
     mainFrame.Show()
     app.MainLoop()
 '''
-TEMPLATE_NAMES = {93: "Header", 94: "Pyo", 95: "WxPython", 96: "Cecilia5", 97: "Zyne", 98: "Audio Interface"}
-TEMPLATE_DICT = {93: HEADER_TEMPLATE, 94: PYO_TEMPLATE, 95: WXPYTHON_TEMPLATE, 96: CECILIA5_TEMPLATE, 
-                97: ZYNE_TEMPLATE, 98: AUDIO_INTERFACE_TEMPLATE}
+
+RADIOPYO_TEMPLATE = '''#!/usr/bin/env python
+# encoding: utf-8
+"""
+Template for a RadioPyo song (version 1.0).
+
+A RadioPyo song is a musical python script using the python-pyo 
+module to create the audio processing chain. You can connect to
+the radio here : http://radiopyo.acaia.ca/ 
+
+There is only a few rules:
+    1 - It must be a one-page script.
+    2 - No soundfile, only synthesis.
+    3 - The script must be finite in time, with fade-in and fade-out 
+        to avoid clicks between pieces. Use the DURATION variable.
+
+belangeo - 2014
+
+"""
+from pyo import *
+
+################### USER-DEFINED VARIABLES ###################
+### READY is used to manage the server behaviour depending ###
+### of the context. Set this variable to True when the     ###
+### music is ready for the radio. TITLE and ARTIST are the ###
+### infos shown by the radio player. DURATION set the      ###
+### duration of the audio file generated for the streaming.###
+##############################################################
+READY = False           # Set to True when ready for the radio
+TITLE = "Song Title"    # The title of the music
+ARTIST = "Artist Name"  # Your artist name
+DURATION = 300          # The duration of the music in seconds
+##################### These are optional #####################
+GENRE = "Electronic"    # Kind of your music, if there is any
+DATE = 2014             # Year of creation
+
+####################### SERVER CREATION ######################
+if READY:
+    s = Server(duplex=0, audio="offline").boot()
+    s.recordOptions(dur=DURATION, filename="radiopyo.ogg", fileformat=7)
+else:
+    s = Server(duplex=0).boot()
+
+
+##################### PROCESSING SECTION #####################
+# global volume (should be used to control the overall sound)
+fade = Fader(fadein=0.001, fadeout=10, dur=DURATION).play()
+
+
+###
+### Insert your algorithms here...
+###
+
+
+#################### START THE PROCESSING ###################
+s.start()
+if not READY:
+    s.gui(locals())
+'''
+
+TEMPLATE_NAMES = {98: "Header", 97: "Pyo", 96: "WxPython", 95: "Cecilia5", 94: "Zyne", 93: "Audio Interface", 92: "RadioPyo"}
+TEMPLATE_DICT = {98: HEADER_TEMPLATE, 97: PYO_TEMPLATE, 96: WXPYTHON_TEMPLATE, 95: CECILIA5_TEMPLATE, 
+                94: ZYNE_TEMPLATE, 93: AUDIO_INTERFACE_TEMPLATE, 92: RADIOPYO_TEMPLATE}
+
+TEMPLATE_PATH = os.path.join(RESOURCES_PATH, "templates")
+if not os.path.isdir(TEMPLATE_PATH):
+    os.mkdir(TEMPLATE_PATH)
+
+templateid = 91
+template_files = sorted([f for f in os.listdir(TEMPLATE_PATH) if f.endswith(".py")])   
+for f in template_files:
+    try:
+        with open(os.path.join(TEMPLATE_PATH, f)) as ftemp:
+            ftext = ftemp.read()
+        TEMPLATE_NAMES[templateid] = f.replace(".py", "")
+        TEMPLATE_DICT[templateid] = ftext
+        templateid -= 1
+    except:
+        pass
 
 ################## BUILTIN KEYWORDS COMPLETION ##################
 FROM_COMP = ''' `module` import `*`
@@ -639,17 +731,21 @@ KEY_COMMANDS = {
 "23. Alt + Shift + BACK": "Delete the word to the right of the caret",
 "24. Ctrl/Cmd + BACK": "Delete back from the current position to the start of the line",
 "25. Ctrl/Cmd + Shift + BACK": "Delete forwards from the current position to the end of the line",
-"26. TAB": "If selection is empty or all on one line replace the selection with a tab character. If more than one line selected, indent the lines. In the middle of a word, trig the AutoCompletion of pyo keywords. Just after a complete pyo keyword, insert its default arguments. Just after a complete python builtin keyword, insert a default structure snippet. Just after a variable name, representing a pyo object, followed by a dot, trig the AutoCompletion of the object's attributes.",
+"26. TAB": "If selection is empty or all on one line replace the selection with a tab character. If more than one line selected, indent the lines. In the middle of a word, trig the AutoCompletion of pyo keywords. Just after an open brace following a pyo keyword, insert its default arguments. Just after a complete python builtin keyword, insert a default structure snippet. Just after a variable name, representing a pyo object, followed by a dot, trig the AutoCompletion of the object's attributes.",
 "27. Shift + TAB": "Dedent the selected lines",
 "28. Alt + 'C'": "Line Copy",
 "29. Alt + 'D'": "Line Duplicate",
 "30. Alt + 'X'": "Line Cut",
 "31. Alt + 'V'": "Line Paste",
-"32. Alt + CLICK + DRAG": "Rectangular selection"
+"32. Alt + CLICK + DRAG": "Rectangular selection",
+"33. Shit + Return": "Show the init line of a pyo object in a tooltip",
+"34. Ctrl/Cmd + Return": "Show the __doc__ string of a python object, module or function",
+"35. CLICK in the most left margin": "Add a marker to the corresponding line",
+"36. Shift + CLICK on a marker": "Delete the marker"
 }
 
 ############## Allowed Extensions ##############
-ALLOWED_EXT = PREFERENCES.get("allowed_ext", ["py", "c5", "txt", "", "c", "h", "cpp", "hpp", "sh", "rst", "iss"])
+ALLOWED_EXT = PREFERENCES.get("allowed_ext", ["py", "c5", "txt", "", "c", "h", "cpp", "hpp", "sh", "rst", "iss", "sg"])
 
 ############## Pyo keywords ##############
 tree = OBJECTS_TREE
@@ -685,7 +781,7 @@ elif wx.Platform == '__WXMAC__':
 else:
     FONT_SIZE = 8
     FONT_SIZE2 = 7
-    DEFAULT_FONT_FACE = 'Courier New'
+    DEFAULT_FONT_FACE = 'Monospace'
 
 
 STYLES_GENERALS = ['default', 'background', 'selback', 'caret']
@@ -702,7 +798,31 @@ STYLES_LABELS = {'default': 'Foreground', 'background': 'Background', 'selback':
 with open(PREF_STYLE) as f:
     text = f.read()
 exec text in locals()
-STYLES = copy.deepcopy(style)
+try:
+    STYLES = copy.deepcopy(style)
+except:
+    STYLES = {'background': {'colour': '#FFFFFF'},
+ 'bracebad': {'colour': '#DD0000'},
+ 'bracelight': {'colour': '#AABBDD'},
+ 'caret': {'colour': '#000000'},
+ 'class': {'bold': 1, 'colour': '#000097', 'italic': 0, 'underline': 0},
+ 'comment': {'bold': 0, 'colour': '#0066FF', 'italic': 1, 'underline': 0},
+ 'commentblock': {'bold': 0, 'colour': u'#468EFF', 'italic': 1, 'underline': 0},
+ 'default': {'bold': 0, 'colour': '#000000', 'italic': 0, 'underline': 0},
+ 'foldmarginback': {'colour': '#D0D0D0'},
+ 'function': {'bold': 1, 'colour': '#0000A2', 'italic': 0, 'underline': 0},
+ 'keyword': {'bold': 1, 'colour': '#0000FF', 'italic': 0, 'underline': 0},
+ 'lineedge': {'colour': '#DDDDDD'},
+ 'linenumber': {'bold': 0, 'colour': '#000000', 'italic': 0, 'underline': 0},
+ 'marginback': {'colour': '#B0B0B0'},
+ 'markerbg': {'colour': '#000000'},
+ 'markerfg': {'colour': '#CCCCCC'},
+ 'number': {'bold': 1, 'colour': '#0000CD', 'italic': 0, 'underline': 0},
+ 'operator': {'bold': 1, 'colour': '#000000', 'italic': 0, 'underline': 0},
+ 'pyokeyword': {'bold': 1, 'colour': '#5555FF', 'italic': 0, 'underline': 0},
+ 'selback': {'colour': '#C0DFFF'},
+ 'string': {'bold': 0, 'colour': '#036A07', 'italic': 0, 'underline': 0},
+ 'triple': {'bold': 0, 'colour': '#03BA07', 'italic': 0, 'underline': 0}}
 if not STYLES.has_key('face'):
     STYLES['face'] = DEFAULT_FONT_FACE
 if not STYLES.has_key('size'):
@@ -739,7 +859,6 @@ class DataEvent(wx.PyEvent):
     def Clone (self): 
         self.__class__ (self.GetId())
 
-
 class RunningThread(threading.Thread):
     def __init__(self, path, cwd, event_receiver):
         threading.Thread.__init__(self)
@@ -772,30 +891,38 @@ class RunningThread(threading.Thread):
             vars_to_remove = "PYTHONHOME PYTHONPATH EXECUTABLEPATH RESOURCEPATH ARGVZERO PYTHONOPTIMIZE"
             prelude = "export -n %s;export PATH=/usr/local/bin:/usr/local/lib:$PATH;" % vars_to_remove
             if CALLER_NEED_TO_INVOKE_32_BIT:
-                self.proc = subprocess.Popen(['%s%s%s "%s"' % (prelude, SET_32_BIT_ARCH, WHICH_PYTHON, self.path)], 
+                self.proc = subprocess.Popen(['%s%s%s -u "%s"' % (prelude, SET_32_BIT_ARCH, WHICH_PYTHON, self.path)], 
                                 shell=True, cwd=self.cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
             else:
-                self.proc = subprocess.Popen(['%s%s "%s"' % (prelude, WHICH_PYTHON, self.path)], cwd=self.cwd, 
+                self.proc = subprocess.Popen(['%s%s -u "%s"' % (prelude, WHICH_PYTHON, self.path)], cwd=self.cwd, 
                                     shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         elif PLATFORM == "darwin":
             if CALLER_NEED_TO_INVOKE_32_BIT:
-                self.proc = subprocess.Popen(['%s%s "%s"' % (SET_32_BIT_ARCH, WHICH_PYTHON, self.path)], 
+                self.proc = subprocess.Popen(['%s%s -u "%s"' % (SET_32_BIT_ARCH, WHICH_PYTHON, self.path)], 
                                 shell=True, cwd=self.cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
             else:
-                self.proc = subprocess.Popen(['%s "%s"' % (WHICH_PYTHON, self.path)], cwd=self.cwd, 
+                self.proc = subprocess.Popen(['%s -u "%s"' % (WHICH_PYTHON, self.path)], cwd=self.cwd, 
                                 shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         elif PLATFORM == "win32":
-            self.proc = subprocess.Popen([WHICH_PYTHON, self.path], cwd=self.cwd, shell=False, 
+            self.proc = subprocess.Popen([WHICH_PYTHON, "-u", self.path], cwd=self.cwd, shell=False, 
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         else:
-            self.proc = subprocess.Popen([WHICH_PYTHON, self.path], cwd=self.cwd, 
+            self.proc = subprocess.Popen([WHICH_PYTHON, "-u", self.path], cwd=self.cwd, 
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
 
+        header = '=== Output log of process "%s", launched: %s ===\n' % (self.filename, time.strftime('"%d %b %Y %H:%M:%S"', time.localtime()))
+        data_event = DataEvent({"log": header, "pid": self.pid, "filename": self.filename, "active": True})
+        wx.PostEvent(self.event_receiver, data_event)
         while self.proc.poll() == None and not self.terminated:
-            time.sleep(.25)
+            log = ""
+            for line in self.proc.stdout.readline():
+                log = log + line
+            data_event = DataEvent({"log": log, "pid": self.pid, "filename": self.filename, "active": True})
+            wx.PostEvent(self.event_receiver, data_event)            
+            sys.stdout.flush()
+            time.sleep(.025)
         stdout, stderr = self.proc.communicate()
-        header = '=== Output log of process "%s", launched: %s ===\n' % (self.filename, time.strftime('"%d %b %Y %H:%M:%S"', time.localtime()))
-        output = header + stdout + stderr
+        output = stdout + stderr
         if "StartNotification name = default" in output:
             output = output.replace("StartNotification name = default", "")
         if "epyo_tempfile.py" in output:
@@ -817,12 +944,12 @@ class RunningThread(threading.Thread):
                     pos += 1
                 elinepos = pos
                 linenum = int(output[slinepos:elinepos].strip())
-                output = output[:slinepos] + str(linenum-2) + output[elinepos:]
+                output = output[:slinepos] + str(linenum-3) + output[elinepos:]
             except:
                 pass
         if self.terminated:
             output = output + "\n=== Process killed. ==="
-        data_event = DataEvent({"log": output, "pid": self.pid, "filename": self.filename})
+        data_event = DataEvent({"log": output, "pid": self.pid, "filename": self.filename, "active": False})
         wx.PostEvent(self.event_receiver, data_event)
 
 class KeyCommandsFrame(wx.Frame):
@@ -961,6 +1088,9 @@ class EditorPreview(stc.StyledTextCtrl):
         self.SetFoldMarginHiColour(True, STYLES['foldmarginback']['colour'])
         self.SetEdgeColumn(60)
 
+        # WxPython 3 needs the lexer to be set before folding property
+        self.SetProperty("fold", "1")
+
 class ComponentPanel(scrolled.ScrolledPanel):
     def __init__(self, parent, size):
         scrolled.ScrolledPanel.__init__(self, parent, wx.ID_ANY, pos=(0,0), size=size, style=wx.SUNKEN_BORDER)
@@ -974,17 +1104,17 @@ class ComponentPanel(scrolled.ScrolledPanel):
             box = wx.BoxSizer(wx.HORIZONTAL)
             label = wx.StaticText(self, wx.ID_ANY, label=STYLES_LABELS[component])
             box.Add(label, 1, wx.EXPAND|wx.TOP|wx.LEFT, 3)
-            btog = wx.ToggleButton(self, wx.ID_ANY, label="B", size=(20,20))
+            btog = wx.ToggleButton(self, wx.ID_ANY, label="B", size=(24,20))
             btog.SetValue(STYLES[component]['bold'])
             box.Add(btog, 0, wx.TOP|wx.ALIGN_RIGHT, 1)
             btog.Bind(wx.EVT_TOGGLEBUTTON, self.OnBToggleButton)
             self.bTogRefs[btog] = component          
-            itog = wx.ToggleButton(self, wx.ID_ANY, label="I", size=(20,20))
+            itog = wx.ToggleButton(self, wx.ID_ANY, label="I", size=(24,20))
             itog.SetValue(STYLES[component]['italic'])
             box.Add(itog, 0, wx.TOP|wx.ALIGN_RIGHT, 1)            
             itog.Bind(wx.EVT_TOGGLEBUTTON, self.OnIToggleButton)
             self.iTogRefs[itog] = component          
-            utog = wx.ToggleButton(self, wx.ID_ANY, label="U", size=(20,20))
+            utog = wx.ToggleButton(self, wx.ID_ANY, label="U", size=(24,20))
             utog.SetValue(STYLES[component]['underline'])
             box.Add(utog, 0, wx.TOP|wx.ALIGN_RIGHT, 1)  
             utog.Bind(wx.EVT_TOGGLEBUTTON, self.OnUToggleButton)
@@ -1068,7 +1198,12 @@ class ColourEditor(wx.Frame):
 
         self.cur_style = ""
 
-        toolbar = self.CreateToolBar()
+        self.panel = wx.Panel(self)
+        self.panel.SetAutoLayout(True)
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+        self.panel.SetSizer(mainSizer)
+
+        toolbar = wx.ToolBar(self.panel, -1)
         saveButton = wx.Button(toolbar, wx.ID_ANY, label="Save Style")
         saveButton.Bind(wx.EVT_BUTTON, self.OnSave)
         toolbar.AddControl(saveButton)
@@ -1085,25 +1220,22 @@ class ColourEditor(wx.Frame):
         toolbar.AddControl(deleteButton)
         toolbar.Realize()
 
-        self.panel = wx.Panel(self)
-        self.panel.SetAutoLayout(True)
-        mainSizer = wx.BoxSizer(wx.VERTICAL)
-        self.panel.SetSizer(mainSizer)
+        mainSizer.Add(toolbar, 0, wx.EXPAND)
 
         enum = wx.FontEnumerator()
         enum.EnumerateFacenames(fixedWidthOnly=True)
         facelist = enum.GetFacenames()
         facelist.sort()
 
-        buttonData = [  (STYLES_GENERALS[0], STYLES['default']['colour'], (50, 20), STYLES_LABELS['default']),
-                        (STYLES_GENERALS[1], STYLES['background']['colour'], (50, 20), STYLES_LABELS['background']),
-                        (STYLES_GENERALS[2], STYLES['selback']['colour'], (50, 20), STYLES_LABELS['selback']),
-                        (STYLES_GENERALS[3], STYLES['caret']['colour'], (50, 20), STYLES_LABELS['caret']) ]
+        buttonData = [  (STYLES_GENERALS[0], STYLES['default']['colour'], (50, 24), STYLES_LABELS['default']),
+                        (STYLES_GENERALS[1], STYLES['background']['colour'], (50, 24), STYLES_LABELS['background']),
+                        (STYLES_GENERALS[2], STYLES['selback']['colour'], (50, 24), STYLES_LABELS['selback']),
+                        (STYLES_GENERALS[3], STYLES['caret']['colour'], (50, 24), STYLES_LABELS['caret']) ]
 
         self.buttonRefs = {}
 
         section1Sizer = wx.BoxSizer(wx.HORIZONTAL)
-        buttonSizer1 = wx.FlexGridSizer(1, 2, 25, 5)
+        buttonSizer1 = wx.FlexGridSizer(0, 2, 25, 5)
         for name, color, size, label in buttonData[:2]:
             b = csel.ColourSelect(self.panel, -1, "", hex_to_rgb(color), size=size)
             b.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour)
@@ -1112,7 +1244,7 @@ class ColourEditor(wx.Frame):
                                 (b, 0, wx.LEFT|wx.RIGHT, 5)])
         section1Sizer.Add(buttonSizer1, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP|wx.ALIGN_LEFT, 10)
         section1Sizer.AddSpacer(110)
-        buttonSizer2 = wx.FlexGridSizer(1, 2, 25, 5)
+        buttonSizer2 = wx.FlexGridSizer(0, 2, 25, 5)
         for name, color, size, label in buttonData[2:4]:
             b = csel.ColourSelect(self.panel, -1, "", hex_to_rgb(color), size=size)
             b.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour)
@@ -1189,7 +1321,7 @@ class ColourEditor(wx.Frame):
         global STYLES
         stl = event.GetString()
         self.cur_style = stl
-        with open(os.path.join(STYLES_PATH, stl)) as f:
+        with open(os.path.join(ensureNFD(STYLES_PATH), stl)) as f:
             text = f.read()
         exec text in locals()
         STYLES = copy.deepcopy(style)
@@ -1294,7 +1426,7 @@ class SnippetTree(wx.Panel):
         self.sizer = wx.BoxSizer(wx.VERTICAL)
 
         toolbarbox = wx.BoxSizer(wx.HORIZONTAL)
-        self.toolbar = wx.ToolBar(self, -1, size=(-1,36))
+        self.toolbar = wx.ToolBar(self, -1)
         self.toolbar.SetToolBitmapSize(tsize)
         self.toolbar.AddLabelTool(SNIPPET_ADD_FOLDER_ID, "Add Category", folder_add_bmp, shortHelp="Add a New Category")
         self.toolbar.AddLabelTool(SNIPPET_DEL_FILE_ID, "Delete", file_add_bmp, shortHelp="Delete Snippet or Category")
@@ -1412,7 +1544,7 @@ class SnippetTree(wx.Panel):
             name = self.tree.GetItemText(item)
             ritem = self.tree.GetItemParent(item)
             category = self.tree.GetItemText(ritem)
-        self.GetParent().GetParent().onLoad(name, category)
+            self.GetParent().GetParent().onLoad(name, category)
 
     def select(self, item):
         self.tree.SelectItem(item)
@@ -1507,13 +1639,12 @@ class SnippetFrame(wx.Frame):
         saveButton = wx.Button(self.toolbar, wx.ID_ANY, label="Save Snippet")
         self.toolbar.AddControl(saveButton)
         self.Bind(wx.EVT_BUTTON, self.onSave, id=saveButton.GetId())
-
+        self.toolbar.Realize()
+		
         toolbarBox.Add(self.toolbar, 1, wx.ALIGN_LEFT|wx.EXPAND|wx.LEFT, 5)
 
         toolbar2 = wx.ToolBar(self.panel, -1)
         self.tagButton = wx.Button(toolbar2, wx.ID_ANY, label="Tag Selection")
-        X = self.tagButton.GetSize()[0]
-        toolbar2.SetSize((X+8, 40))
         toolbar2.AddControl(self.tagButton)
         self.Bind(wx.EVT_BUTTON, self.onTagSelection, id=self.tagButton.GetId())
         toolbar2.Realize()
@@ -1550,10 +1681,10 @@ class SnippetFrame(wx.Frame):
             self.entry.InsertText(select[0], "`")
 
     def onLoad(self, name, category):
-        if os.path.isfile(os.path.join(SNIPPETS_PATH, category, name)):
+        if os.path.isfile(os.path.join(ensureNFD(SNIPPETS_PATH), category, name)):
             self.snippet_name = name
             self.category_name = category
-            with codecs.open(os.path.join(SNIPPETS_PATH, self.category_name, self.snippet_name), "r", encoding="utf-8") as f:
+            with codecs.open(os.path.join(ensureNFD(SNIPPETS_PATH), self.category_name, self.snippet_name), "r", encoding="utf-8") as f:
                 text = f.read()
             exec text in locals()
             try:
@@ -1570,6 +1701,7 @@ class SnippetFrame(wx.Frame):
     def onSave(self, evt):
         dlg = wx.SingleChoiceDialog(self, 'Choose the Snippet Category', 
                                     'Snippet Category', SNIPPETS_CATEGORIES, wx.OK)
+        dlg.SetSize((250,300))
         dlg.CenterOnParent()
         if dlg.ShowModal() == wx.ID_OK:
             category = dlg.GetStringSelection()
@@ -1765,6 +1897,14 @@ class MainFrame(wx.Frame):
 
         EVT_DATA_EVENT(self, self.format_outputLog)
 
+        if sys.platform == "darwin":
+            accel_ctrl = wx.ACCEL_CMD
+        else:
+            accel_ctrl = wx.ACCEL_CTRL
+        # To set up an accelerator key
+        #aEntry = wx.AcceleratorEntry(accel_ctrl|wx.ACCEL_SHIFT, wx.WXK_UP, 602)
+        # "\t%s" % aEntry.ToString()
+
         self.snippet_frame = SnippetFrame(self, title='Snippet Editor', pos=(25,25), size=(700,450))
         self.style_frame = ColourEditor(self, title='Style Editor', pos=(100,100), size=(500,550))
         self.style_frame.setCurrentStyle(PREF_STYLE)
@@ -1789,7 +1929,7 @@ class MainFrame(wx.Frame):
         menu1.Append(wx.ID_NEW, "New\tCtrl+N")
         self.Bind(wx.EVT_MENU, self.new, id=wx.ID_NEW)
         self.submenu1 = wx.Menu()
-        for key, name in sorted(TEMPLATE_NAMES.items()):
+        for key, name in sorted(TEMPLATE_NAMES.items(), reverse=True):
             self.submenu1.Append(key, "%s Template" % name)
         menu1.AppendMenu(99, "New From Template", self.submenu1)
         self.Bind(wx.EVT_MENU, self.newFromTemplate, id=min(TEMPLATE_NAMES.keys()), id2=max(TEMPLATE_NAMES.keys()))
@@ -1825,11 +1965,14 @@ class MainFrame(wx.Frame):
         self.Bind(wx.EVT_MENU, self.save, id=wx.ID_SAVE)
         menu1.Append(wx.ID_SAVEAS, "Save As...\tShift+Ctrl+S")
         self.Bind(wx.EVT_MENU, self.saveas, id=wx.ID_SAVEAS)
-        menu1.AppendSeparator()
-        menu1.Append(wx.ID_PREVIEW, "Print Preview")
-        self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
-        menu1.Append(wx.ID_PRINT, "Print\tCtrl+P")
-        self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
+        menu1.Append(100, "Save As Template...")
+        self.Bind(wx.EVT_MENU, self.saveasTemplate, id=100)
+        # TODO : printing not working well enough
+        #menu1.AppendSeparator()
+        #menu1.Append(wx.ID_PREVIEW, "Print Preview")
+        #self.Bind(wx.EVT_MENU, self.OnPrintPreview, id=wx.ID_PREVIEW)
+        #menu1.Append(wx.ID_PRINT, "Print\tCtrl+P")
+        #self.Bind(wx.EVT_MENU, self.OnPrint, id=wx.ID_PRINT)
         if sys.platform != "darwin":
             menu1.AppendSeparator()
         prefItem = menu1.Append(wx.ID_PREFERENCES, "Preferences...\tCtrl+;")
@@ -1868,20 +2011,28 @@ class MainFrame(wx.Frame):
         menu2.Append(107, "Remove Trailing White Space")
         self.Bind(wx.EVT_MENU, self.removeTrailingWhiteSpace, id=107)
         menu2.AppendSeparator()
-        menu2.Append(103, "Collapse/Expand\tCtrl+I")
+        menu2.Append(103, "Fold All\tCtrl+I")
         self.Bind(wx.EVT_MENU, self.fold, id=103)
+        menu2.Append(104, "Expand All\tShift+Ctrl+I")
+        self.Bind(wx.EVT_MENU, self.fold, id=104)
+        menu2.Append(105, "Fold/Expand Current Scope\tCtrl+8")
+        self.Bind(wx.EVT_MENU, self.foldExpandScope, id=105)
         menu2.Append(108, "Un/Comment Selection\tCtrl+J")
         self.Bind(wx.EVT_MENU, self.OnComment, id=108)
-        menu2.Append(114, "Show AutoCompletion\tCtrl+K")
-        self.Bind(wx.EVT_MENU, self.autoComp, id=114)
         menu2.Append(121, "Insert File Path...\tShift+Ctrl+P")
         self.Bind(wx.EVT_MENU, self.insertPath, id=121)
         menu2.AppendSeparator()
-        menu2.Append(170, "Convert Selection to Uppercase\tCtrl+U")
-        menu2.Append(171, "Convert Selection to Lowercase\tShift+Ctrl+U")
+        menu2.Append(114, "Auto Complete container syntax", kind=wx.ITEM_CHECK)
+        self.Bind(wx.EVT_MENU, self.autoCompContainer, id=114)
+        menu2.Check(114, PREFERENCES.get("auto_comp_container", 0))
+        menu2.AppendSeparator()
+        submenu2 = wx.Menu()
+        submenu2.Append(170, "Convert Selection to Uppercase\tCtrl+U")
+        submenu2.Append(171, "Convert Selection to Lowercase\tShift+Ctrl+U")
         self.Bind(wx.EVT_MENU, self.upperLower, id=170, id2=171)
-        menu2.Append(172, "Convert Tabs to Spaces")
+        submenu2.Append(172, "Convert Tabs to Spaces")
         self.Bind(wx.EVT_MENU, self.tabsToSpaces, id=172)
+        menu2.AppendMenu(-1, "Text Converters", submenu2)
         menu2.AppendSeparator()
         menu2.Append(140, "Goto line...\tCtrl+L")
         self.Bind(wx.EVT_MENU, self.gotoLine, id=140)
@@ -1941,6 +2092,10 @@ class MainFrame(wx.Frame):
         self.Bind(wx.EVT_MENU, self.showDocFrame, id=190)
         menu4.Append(180, "Open Documentation for Pyo Object Under Caret\tCtrl+D")
         self.Bind(wx.EVT_MENU, self.showDoc, id=180)
+        menu4.Append(181, "Show args for Pyo Object Under Caret\tShift+Return")
+        self.Bind(wx.EVT_MENU, self.showArgs, id=181)
+        menu4.Append(182, "Show __doc__ String for Word Under Caret\tCtrl+Return")
+        self.Bind(wx.EVT_MENU, self.showDocString, id=182)
         menu4.AppendSeparator()
         menu4.Append(185, "Rebuild Documentation")
         self.Bind(wx.EVT_MENU, self.rebuildDoc, id=185)
@@ -1963,11 +2118,6 @@ class MainFrame(wx.Frame):
         self.makeSnippetMenu()
         self.menuBar.Append(self.menu7, "Snippets")
 
-        if sys.platform == "darwin":
-            accel_ctrl = wx.ACCEL_CMD
-        else:
-            accel_ctrl = wx.ACCEL_CTRL
-
         menu8 = wx.Menu()
         menu8.Append(600, "Add Marker to Current Line\tShift+Ctrl+M")
         self.Bind(wx.EVT_MENU, self.addMarker, id=600)
@@ -1976,10 +2126,8 @@ class MainFrame(wx.Frame):
         menu8.Append(604, "Delete All Markers")
         self.Bind(wx.EVT_MENU, self.deleteAllMarkers, id=604)
         menu8.AppendSeparator()
-        aEntry = wx.AcceleratorEntry(accel_ctrl|wx.ACCEL_SHIFT, wx.WXK_UP, 602)
-        menu8.Append(602, 'Navigate Markers Upward\t%s' % aEntry.ToString())
-        aEntry = wx.AcceleratorEntry(accel_ctrl|wx.ACCEL_SHIFT, wx.WXK_DOWN, 603)
-        menu8.Append(603, 'Navigate Markers Downward\t%s' % aEntry.ToString())
+        menu8.Append(602, 'Navigate Markers Upward\tCtrl+9')
+        menu8.Append(603, 'Navigate Markers Downward\tCtrl+0')
         self.Bind(wx.EVT_MENU, self.navigateMarkers, id=602, id2=603)
         self.menuBar.Append(menu8, "Markers")
 
@@ -2028,22 +2176,23 @@ class MainFrame(wx.Frame):
 
         self.SetMenuBar(self.menuBar)
 
+        self.status = self.CreateStatusBar()
+        self.status.Bind(wx.EVT_SIZE, self.StatusOnSize)
+        self.status.SetFieldsCount(3)
+        
         if PLATFORM == "darwin":
             ststyle = wx.TE_PROCESS_ENTER|wx.NO_BORDER
-            sth = 17
+            sth = self.status.GetSize()[1] #16
             cch = -1
         elif PLATFORM == "linux2":
             ststyle = wx.TE_PROCESS_ENTER|wx.SIMPLE_BORDER
-            sth = 20
-            cch = 21
+            sth = self.status.GetSize()[1]+1 #20
+            cch = self.status.GetSize()[1] #21
         elif PLATFORM == "win32":
             ststyle = wx.TE_PROCESS_ENTER|wx.SIMPLE_BORDER
             sth = 20
             cch = 20
 
-        self.status = self.CreateStatusBar()
-        self.status.Bind(wx.EVT_SIZE, self.StatusOnSize)
-        self.status.SetFieldsCount(3)
         self.field1X, field1Y = self.status.GetTextExtent("Quick Search:")
         self.status.SetStatusWidths([self.field1X+9,-1,-2])
         self.status.SetStatusText("Quick Search:", 0)
@@ -2080,11 +2229,11 @@ class MainFrame(wx.Frame):
             yoff1 = -1
             yoff2 = -5
         elif PLATFORM == "linux2":
-            yoff1 = 1
-            yoff2 = 0
-        elif PLATFORM == "win32":
             yoff1 = -2
-            yoff2 = -2
+            yoff2 = -1
+        elif PLATFORM == "win32":
+            yoff1 = 0
+            yoff2 = -1
 
         self.status.SetStatusText("Quick Search:", 0)
         rect = self.status.GetFieldRect(1)
@@ -2118,6 +2267,7 @@ class MainFrame(wx.Frame):
 
     def makeSnippetMenu(self):
         itemId = 30000
+        accel_entries = []
         for cat in SNIPPETS_CATEGORIES:
             submenu = wx.Menu(title=cat)
             files = [f for f in os.listdir(os.path.join(SNIPPETS_PATH, cat))]
@@ -2147,6 +2297,7 @@ class MainFrame(wx.Frame):
                 short = short.replace("-", "")
                 if short != "":
                     accel_tuple = wx.AcceleratorEntry(accel, ord(short), itemId)
+                    accel_entries.append(accel_tuple)
                     short = accel_tuple.ToString()
                     submenu.Append(itemId, "%s\t%s" % (file, short))
                 else:
@@ -2155,6 +2306,10 @@ class MainFrame(wx.Frame):
                 itemId += 1
             self.menu7.AppendMenu(itemId, cat, submenu)
             itemId += 1
+        if accel_entries != []:            
+            accel_table  = wx.AcceleratorTable(accel_entries)
+            self.SetAcceleratorTable(accel_table)
+        
         self.menu7.AppendSeparator()
         self.menu7.Append(51, "Open Snippet Editor")
         self.Bind(wx.EVT_MENU, self.showSnippetEditor, id=51)
@@ -2294,7 +2449,6 @@ class MainFrame(wx.Frame):
     def addMarker(self, evt):
         line = self.panel.editor.GetCurrentLine()
         self.panel.editor.addMarker(line)
-        self.panel.editor.addMarkerComment(line)
 
     def deleteMarker(self, evt):
         line = self.panel.editor.GetCurrentLine()
@@ -2317,25 +2471,37 @@ class MainFrame(wx.Frame):
                 val = int(dlg.GetValue())
             except:
                 val = -1
-            dlg.Destroy()
+        dlg.Destroy()
         if val != -1:
-            pos = self.panel.editor.FindColumn(val-1, 0)
-            self.panel.editor.SetCurrentPos(pos)
-            self.panel.editor.EnsureVisible(val)
-            self.panel.editor.EnsureCaretVisible()
+            val -= 1
+            pos = self.panel.editor.FindColumn(val, 0)
+            self.panel.editor.GotoLine(val)
+            first = self.panel.editor.GetFirstVisibleLine()
+            if val == first:
+                self.panel.editor.LineScroll(0, -self.panel.editor.LinesOnScreen()/2)
+            else:
+                self.panel.editor.LineScroll(0, self.panel.editor.LinesOnScreen()/2)
+            #self.panel.editor.SetCurrentPos(pos)
+            #self.panel.editor.EnsureVisible(val)
+            #self.panel.editor.EnsureCaretVisible()
             wx.CallAfter(self.panel.editor.SetAnchor, pos)
 
     def OnComment(self, evt):
         self.panel.editor.OnComment()
 
     def fold(self, event):
-        self.panel.editor.FoldAll()
+        if event.GetId() == 103:
+            self.panel.editor.FoldAll()
+        else:
+            self.panel.editor.ExpandAll()
 
-    def autoComp(self, evt):
-        try:
-            self.panel.editor.showAutoComp()
-        except AttributeError:
-            pass
+    def foldExpandScope(self, evt):
+        self.panel.editor.foldExpandCurrentScope()
+
+    def autoCompContainer(self, evt):
+        state = evt.GetInt()
+        PREFERENCES["auto_comp_container"] = state
+        self.panel.editor.showAutoCompContainer(state)
 
     def showFind(self, evt):
         self.panel.editor.OnShowFindReplace()
@@ -2444,20 +2610,24 @@ class MainFrame(wx.Frame):
             paths = dlg.GetPaths()
             if len(paths) == 1:
                 text = ensureNFD(paths[0])
+                if PLATFORM == "win32":
+                    text = text.replace("\\", "/")
                 self.panel.editor.ReplaceSelection("'" + text + "'")
             else:
                 text = ", ".join(["'"+ensureNFD(path)+"'" for path in paths])
+                if PLATFORM == "win32":
+                    text = text.replace("\\", "/")
                 self.panel.editor.ReplaceSelection("[" + text + "]")
             PREFERENCES["insert_path"] = os.path.split(paths[0])[0]
         dlg.Destroy()
 
     def insertSnippet(self, evt):
         id = evt.GetId()
-        menu = self.menu7 #event.GetEventObject()
+        menu = self.menu7
         item = menu.FindItemById(id)
         name = item.GetLabel()
         category = item.GetMenu().GetTitle()
-        with codecs.open(os.path.join(SNIPPETS_PATH, category, name), "r", encoding="utf-8") as f:
+        with codecs.open(os.path.join(ensureNFD(SNIPPETS_PATH), category, name), "r", encoding="utf-8") as f:
             text = f.read()
         exec text in locals()
         self.panel.editor.insertSnippet(snippet["value"])
@@ -2474,7 +2644,7 @@ class MainFrame(wx.Frame):
         
     def setStyle(self, st, fromMenu=False):
         global STYLES
-        with open(os.path.join(STYLES_PATH, st)) as f:
+        with open(os.path.join(ensureNFD(STYLES_PATH), st)) as f:
             text = f.read()
         exec text in locals()
         STYLES = copy.deepcopy(style)
@@ -2654,7 +2824,7 @@ class MainFrame(wx.Frame):
         item = menu.FindItemById(id)
         filename = item.GetLabel()
         folder = item.GetMenu().GetTitle()
-        path = os.path.join(EXAMPLE_PATH, folder, filename)
+        path = os.path.join(ensureNFD(EXAMPLE_PATH), folder, filename)
         self.panel.addPage(ensureNFD(path))
 
     def openTutorial(self, event):
@@ -2707,12 +2877,28 @@ class MainFrame(wx.Frame):
             PREFERENCES["save_file_path"] = os.path.split(path)[0]
         dlg.Destroy()
 
+    def saveasTemplate(self, event):
+        dlg = wx.TextEntryDialog(self, 'Give a name to your template:', 'Save file as template...')
+        if dlg.ShowModal() == wx.ID_OK:
+            fname = dlg.GetValue()
+            if not fname.endswith(".py"):
+                fname = fname + ".py"
+            try:
+                text = self.panel.editor.GetTextUTF8()
+            except:
+                text = self.panel.editor.GetText()
+            with open(os.path.join(TEMPLATE_PATH, fname), "w") as f:
+                f.write(text)
+        dlg.Destroy()
+
     def close(self, event):
         action = self.panel.editor.close()
         if action == 'delete':
+            self.panel.close_from_menu = True
             self.panel.deletePage()
         else:
             pass
+        self.panel.close_from_menu = False
 
     def closeAll(self, event):
         count = self.panel.notebook.GetPageCount()
@@ -2745,8 +2931,9 @@ class MainFrame(wx.Frame):
 
     def format_outputLog(self, evt):
         data = evt.data
-        self.panel.outputlog.setLog(data["log"])
-        self.panel.outputlog.removeProcess(data["pid"], data["filename"])
+        self.panel.outputlog.appendToLog(data["log"])
+        if not data["active"]:
+            self.panel.outputlog.removeProcess(data["pid"], data["filename"])
 
     def run(self, path):
         cwd = self.getCurrentWorkingDirectory()
@@ -2810,6 +2997,7 @@ class MainFrame(wx.Frame):
         self.panel.editor.addText(s.getvalue())
 
     def startStopBackgroundServer(self, evt):
+        # TODO: need to add midi output driver
         if not self.back_server_started:
             outDriverIndex = -1
             preferedDriver = PREFERENCES.get("background_server_out_device", "")
@@ -2866,15 +3054,25 @@ class MainFrame(wx.Frame):
             self.sendToServerItem.Enable(False)
 
     def sendSelectionToBackgroundServer(self, evt):
+        end = None
         text = self.panel.editor.GetSelectedTextUTF8()
         if text == "":
             pos = self.panel.editor.GetCurrentPos()
             line = self.panel.editor.LineFromPosition(pos)
             text = self.panel.editor.GetLineUTF8(line)
+        else:
+            end = self.panel.editor.GetSelectionEnd()
         if self.server_pipe != None:
             for line in text.splitlines():
                 self.server_pipe.write(line + "\n")
             self.server_pipe.write("\n")
+        if end != None:
+            self.panel.editor.SetCurrentPos(end)
+        self.panel.editor.LineDown()
+        line = self.panel.editor.GetCurrentLine()
+        pos = self.panel.editor.PositionFromLine(line)
+        self.panel.editor.SetCurrentPos(pos)
+        self.panel.editor.SetSelectionEnd(pos)
 
     def buildDoc(self):
         self.doc_frame = ManualFrame(osx_app_bundled=OSX_APP_BUNDLED, which_python=WHICH_PYTHON,
@@ -2899,6 +3097,12 @@ class MainFrame(wx.Frame):
         except:
             pass
         self.buildDoc()
+
+    def showArgs(self, evt):
+        self.panel.editor.onShowTip()
+
+    def showDocString(self, evt):
+        self.panel.editor.onShowDocString()
         
     def onShowEditorKeyCommands(self, evt):
         if not self.keyCommandsFrame.IsShown():
@@ -2980,6 +3184,7 @@ class MainPanel(wx.Panel):
         wx.Panel.__init__(self, parent, size=size, style=wx.SUNKEN_BORDER)
 
         self.new_inc = 0
+        self.close_from_menu = False
         self.mainFrame = parent
         mainBox = wx.BoxSizer(wx.HORIZONTAL)
 
@@ -2988,13 +3193,12 @@ class MainPanel(wx.Panel):
 
         self.left_splitter = wx.SplitterWindow(self.splitter, -1, style=wx.SP_LIVE_UPDATE|wx.SP_3DSASH)
         self.right_splitter = wx.SplitterWindow(self.splitter, -1, style=wx.SP_LIVE_UPDATE|wx.SP_3DSASH)
-        #self.right_splitter.SetMinimumPaneSize(150)
 
         self.project = ProjectTree(self.left_splitter, self, (-1, -1))
         self.markers = MarkersPanel(self.left_splitter, self, (-1, -1))
 
-        self.notebook = FNB.FlatNotebook(self.right_splitter, size=(-1,-1), 
-                        style=FNB.FNB_FF2|FNB.FNB_X_ON_TAB|FNB.FNB_NO_X_BUTTON|FNB.FNB_DROPDOWN_TABS_LIST|FNB.FNB_HIDE_ON_SINGLE_TAB)
+        self.notebook = FNB.FlatNotebook(self.right_splitter, size=(-1,-1))
+        self.notebook.SetAGWWindowStyleFlag(FNB.FNB_FF2|FNB.FNB_X_ON_TAB|FNB.FNB_NO_X_BUTTON|FNB.FNB_DROPDOWN_TABS_LIST|FNB.FNB_HIDE_ON_SINGLE_TAB)
         self.addNewPage()
         self.outputlog = OutputLogPanel(self.right_splitter, self, size=(-1,150))
 
@@ -3006,8 +3210,8 @@ class MainPanel(wx.Panel):
         mainBox.Add(self.splitter, 1, wx.EXPAND)
         self.SetSizer(mainBox)
 
-        self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.onPageChange)
-        self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.onClosingPage)
+        self.notebook.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.onPageChange)
+        self.notebook.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.onClosingPage)
 
     def addNewPage(self):
         title = "Untitled-%i.py" % self.new_inc
@@ -3035,6 +3239,11 @@ class MainPanel(wx.Panel):
                 except:
                     continue
         editor.setText(ensureNFD(text))
+
+        # Scan the entire document (needed for FoldAll to fold everything)
+        editor.GotoLine(editor.GetLineCount())
+        wx.CallAfter(editor.GotoLine, 0)
+
         editor.path = file
         editor.saveMark = True
         editor.EmptyUndoBuffer()
@@ -3057,7 +3266,10 @@ class MainPanel(wx.Panel):
             self.editor.setMarkers(copy.deepcopy(markers))
 
     def onClosingPage(self, evt):
-        action = self.editor.closeNoCancel()
+        if not self.close_from_menu:
+            action = self.editor.close()
+            if action == "keep":
+                evt.Veto()
 
     def deletePage(self):
         select = self.notebook.GetSelection()
@@ -3097,6 +3309,22 @@ class MainPanel(wx.Panel):
             ed = self.notebook.GetPage(i)
             ed.Close()
 
+#######################################################
+### The idea of EditorPanel is to allow multiple views
+### at the same time in a single notebook page. 
+### Also: A tree view of classes and functions of the file
+### Not yet implemented... ( TODO )
+#######################################################
+class EditorPanel(wx.Panel):
+    def __init__(self, parent):
+        wx.Panel.__init__(self, parent, -1)
+        self.editor = Editor(parent, -1, size=(0, -1))
+        self.editor2 = Editor(parent, -1, size=(0, -1))
+        box = wx.BoxSizer(wx.HORIZONTAL)
+        box.Add(self.editor, 1, wx.ALL|wx.EXPAND, 5)
+        box.Add(self.editor2, 1, wx.ALL|wx.EXPAND, 5)
+        self.SetSizerAndFit(box)
+
 class Editor(stc.StyledTextCtrl):
     def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style= wx.NO_BORDER | wx.WANTS_CHARS,
                  setTitle=None, getTitle=None):
@@ -3122,6 +3350,8 @@ class Editor(stc.StyledTextCtrl):
         self.markers_dict = {}
         self.current_marker = -1
         self.objs_attr_dict = {}
+        self.auto_comp_container = PREFERENCES.get("auto_comp_container", 0)
+
 
         self.alphaStr = string.lowercase + string.uppercase + '0123456789'
 
@@ -3168,22 +3398,16 @@ class Editor(stc.StyledTextCtrl):
         self.SetMarginSensitive(2, True)
 
         self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+        self.Bind(wx.EVT_CHAR, self.OnChar)
         self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
         self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
         self.Bind(wx.EVT_CLOSE, self.OnClose)
-        self.Bind(wx.EVT_FIND, self.OnFind)
-        self.Bind(wx.EVT_FIND_NEXT, self.OnFind)
-        self.Bind(wx.EVT_FIND_REPLACE, self.OnFind)
-        self.Bind(wx.EVT_FIND_REPLACE_ALL, self.OnFind)
-        self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
 
         self.EmptyUndoBuffer()
         self.SetFocus()
         self.setStyle()
 
         # Remove unwanted KeyCommands
-        self.CmdKeyClear(stc.STC_KEY_UP, stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(stc.STC_KEY_DOWN, stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(stc.STC_KEY_RIGHT, stc.STC_SCMOD_ALT)
         self.CmdKeyClear(stc.STC_KEY_LEFT, stc.STC_SCMOD_ALT)
         self.CmdKeyClear(stc.STC_KEY_RIGHT, stc.STC_SCMOD_SHIFT | stc.STC_SCMOD_ALT)
@@ -3192,20 +3416,10 @@ class Editor(stc.StyledTextCtrl):
         self.CmdKeyClear(stc.STC_KEY_LEFT, stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(stc.STC_KEY_RIGHT, stc.STC_SCMOD_SHIFT | stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(stc.STC_KEY_LEFT, stc.STC_SCMOD_SHIFT | stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(stc.STC_KEY_HOME, 0)
-        self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_ALT)
-        self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_SHIFT)
-        self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT)
-        self.CmdKeyClear(stc.STC_KEY_HOME, stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT)
-        self.CmdKeyClear(stc.STC_KEY_END, 0)
-        self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_ALT)
-        self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_SHIFT)
-        self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_ALT | stc.STC_SCMOD_SHIFT)
-        self.CmdKeyClear(stc.STC_KEY_END, stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT)
         self.CmdKeyClear(stc.STC_KEY_DELETE, 0)
         self.CmdKeyClear(stc.STC_KEY_DELETE, stc.STC_SCMOD_SHIFT)
+        self.CmdKeyClear(stc.STC_KEY_DELETE, stc.STC_SCMOD_CTRL)
+        self.CmdKeyClear(stc.STC_KEY_DELETE, stc.STC_SCMOD_SHIFT | stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(stc.STC_KEY_BACK, stc.STC_SCMOD_ALT)
         self.CmdKeyClear(stc.STC_KEY_BACK, stc.STC_SCMOD_SHIFT)
         self.CmdKeyClear(stc.STC_KEY_BACK, stc.STC_SCMOD_CTRL)
@@ -3213,22 +3427,19 @@ class Editor(stc.StyledTextCtrl):
         self.CmdKeyClear(stc.STC_KEY_INSERT, 0)
         self.CmdKeyClear(stc.STC_KEY_INSERT, stc.STC_SCMOD_SHIFT)
         self.CmdKeyClear(stc.STC_KEY_INSERT, stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(ord('Z'), stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(ord('Y'), stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(ord('X'), stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(ord('C'), stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(ord('V'), stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
+        self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
-        self.CmdKeyClear(ord('U'), stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT)
-        self.CmdKeyClear(ord('U'), stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT)
         self.CmdKeyClear(stc.STC_KEY_RETURN, stc.STC_SCMOD_SHIFT)
         self.CmdKeyClear(stc.STC_KEY_ADD, stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(stc.STC_KEY_SUBTRACT, stc.STC_SCMOD_CTRL)
         self.CmdKeyClear(stc.STC_KEY_DIVIDE, stc.STC_SCMOD_CTRL)
 
+        self.CmdKeyAssign(ord('U'), stc.STC_SCMOD_CTRL, stc.STC_CMD_UPPERCASE)
+        self.CmdKeyAssign(ord('U'), stc.STC_SCMOD_CTRL | stc.STC_SCMOD_SHIFT, stc.STC_CMD_LOWERCASE)
+
         wx.CallAfter(self.SetAnchor, 0)
         self.Refresh()
 
@@ -3248,6 +3459,7 @@ class Editor(stc.StyledTextCtrl):
                 if STYLES[forekey]['underline']:
                     st += ",underline"
             return st
+
         self.StyleSetSpec(stc.STC_STYLE_DEFAULT, buildStyle('default', 'background'))
         self.StyleClearAll()  # Reset all to be like the default
 
@@ -3266,8 +3478,23 @@ class Editor(stc.StyledTextCtrl):
         self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, buildStyle('default', 'bracebad') + ",bold")
 
         ext = os.path.splitext(self.path)[1].strip(".")
+        if ext == "":
+            try:
+                with open(self.path, "r") as f:
+                    fline = f.readline()
+                    if fline.startswith("#!"):
+                        fline = fline.replace("/", " ")
+                        last = fline.split()[-1]
+                        ext = {"python": "py", "bash": "sh", "sh": "sh"}.get(last, "")
+                    else:
+                        text = f.read()
+                        if "desc:" in text:
+                            ext = "jsfx"
+            except:
+                pass
         if ext in ["py", "pyw", "c5"]:
             self.SetLexer(stc.STC_LEX_PYTHON)
+            self.SetStyleBits(self.GetStyleBitsNeeded())
             self.SetKeyWords(0, " ".join(keyword.kwlist) + " None True False ")
             self.SetKeyWords(1, " ".join(PYO_WORDLIST))
             self.StyleSetSpec(stc.STC_P_DEFAULT, buildStyle('default'))
@@ -3286,6 +3513,11 @@ class Editor(stc.StyledTextCtrl):
             self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, buildStyle('commentblock'))
         elif ext in ["c", "cc", "cpp", "cxx", "cs", "h", "hh", "hpp", "hxx"]:
             self.SetLexer(stc.STC_LEX_CPP)
+            self.SetStyleBits(self.GetStyleBitsNeeded())
+            self.SetProperty('fold.comment', '1')
+            self.SetProperty('fold.preprocessor', '1')
+            self.SetProperty('fold.compact', '1')
+            self.SetProperty('styling.within.preprocessor', '0')
             self.SetKeyWords(0, "auto break case char const continue default do double else enum extern float for goto if int long \
             register return short signed sizeof static struct switch typedef union unsigned void volatile while ")
             self.StyleSetSpec(stc.STC_C_DEFAULT, buildStyle('default'))
@@ -3302,6 +3534,7 @@ class Editor(stc.StyledTextCtrl):
             self.StyleSetSpec(stc.STC_C_PREPROCESSOR, buildStyle('commentblock'))
         elif ext == "sh":
             self.SetLexer(stc.STC_LEX_BASH)
+            self.SetStyleBits(self.GetStyleBitsNeeded())
             self.SetKeyWords(0, "! [[ ]] case do done elif else esac fi for function if in select then time until while { } \
             alias bg bind break builtin caller cd command compgen complete compopt continue declare dirs disown echo enable \
             eval exec exit export fc fg getopts hash help history jobs kill let local logout mapfile popd printf pushd pwd \
@@ -3316,12 +3549,53 @@ class Editor(stc.StyledTextCtrl):
             self.StyleSetSpec(stc.STC_SH_IDENTIFIER, buildStyle('default'))
             self.StyleSetSpec(stc.STC_SH_PARAM, buildStyle('default'))
             self.StyleSetSpec(stc.STC_SH_SCALAR, buildStyle('function'))
+        elif ext in ["jsfx", "jsfx-inc"]:
+            self.SetLexer(stc.STC_LEX_CPP)
+            self.SetStyleBits(self.GetStyleBitsNeeded())
+            self.SetProperty('fold.comment', '1')
+            self.SetProperty('fold.preprocessor', '1')
+            self.SetProperty('fold.compact', '1')
+            self.SetProperty('styling.within.preprocessor', '0')
+            self.SetKeyWords(1, "abs acos asin atan atan2 atexit ceil convolve_c cos defer eval exp fclose feof fflush \
+                                 fft fft_ipermute fft_permute fgetc floor fopen fprintf fread freembuf fseek ftell fwrite \
+                                 gfx_aaaaa gfx_arc gfx_blit gfx_blit gfx_blitext gfx_blurto gfx_circle gfx_deltablit \
+                                 gfx_drawchar gfx_drawnumber gfx_drawstr gfx_getchar gfx_getfont gfx_getimgdim gfx_getpixel \
+                                 gfx_gradrect gfx_init gfx_line gfx_lineto gfx_loadimg gfx_measurestr gfx_muladdrect gfx_printf \
+                                 gfx_quit gfx_rect gfx_rectto gfx_roundrect gfx_setfont gfx_setimgdim gfx_setpixel gfx_transformblit \
+                                 gfx_update ifft invsqrt log log10 match matchi max memcpy memset min pow printf rand sign sin sleep \
+                                 sprintf sqr sqrt stack_exch stack_peek stack_pop stack_push str_delsub str_getchar str_insert \
+                                 str_setchar str_setlen strcat strcmp strcpy strcpy_from strcpy_substr stricmp strlen strncat strncmp \
+                                 strncpy strnicmp tan tcp_close tcp_connect tcp_listen tcp_listen_end tcp_recv tcp_send tcp_set_block \
+                                 time time_precise")
+            self.SetKeyWords(0, "loop while function local static instance this global globals _global gfx_r gfx_g gfx_b gfx_a gfx_w \
+                                 gfx_h gfx_x gfx_y gfx_mode gfx_clear gfx_dest gfx_texth mouse_x mouse_y mouse_cap mouse_wheel mouse_hwheel \
+                                 @init @slider @sample @block @serialize @gfx import desc slider1 slider2 slider3 slider4 slider5 \
+                                 slider6 slider7 slider8 slider9 slider10 slider11 slider12 slider13 slider14 slider15 slider16 in_pin \
+                                 out_pin filename ")
+            self.StyleSetSpec(stc.STC_C_DEFAULT, buildStyle('default'))
+            self.StyleSetSpec(stc.STC_C_COMMENT, buildStyle('comment'))
+            self.StyleSetSpec(stc.STC_C_COMMENTDOC, buildStyle('comment'))
+            self.StyleSetSpec(stc.STC_C_COMMENTLINE, buildStyle('comment'))
+            self.StyleSetSpec(stc.STC_C_COMMENTLINEDOC, buildStyle('comment'))
+            self.StyleSetSpec(stc.STC_C_NUMBER, buildStyle('number'))
+            self.StyleSetSpec(stc.STC_C_STRING, buildStyle('string'))
+            self.StyleSetSpec(stc.STC_C_CHARACTER, buildStyle('string'))
+            self.StyleSetSpec(stc.STC_C_WORD, buildStyle('keyword'))
+            self.StyleSetSpec(stc.STC_C_WORD2, buildStyle('pyokeyword'))
+            self.StyleSetSpec(stc.STC_C_OPERATOR, buildStyle('operator'))
+            self.StyleSetSpec(stc.STC_C_IDENTIFIER, buildStyle('default'))
+            self.StyleSetSpec(stc.STC_C_PREPROCESSOR, buildStyle('commentblock'))
 
         self.SetEdgeColour(STYLES["lineedge"]['colour'])
         self.SetCaretForeground(STYLES['caret']['colour'])
         self.SetSelBackground(1, STYLES['selback']['colour'])
         self.SetFoldMarginColour(True, STYLES['foldmarginback']['colour'])
         self.SetFoldMarginHiColour(True, STYLES['foldmarginback']['colour'])
+        self.CallTipSetForeground(STYLES['default']['colour'])
+        self.CallTipSetBackground(STYLES['background']['colour'])
+
+        # WxPython 3 needs the lexer to be set before folding property
+        self.SetProperty("fold", "1")
 
     def OnQuickSearch(self, str, next=True):
         if self.GetSelection() != (0,0):
@@ -3348,10 +3622,14 @@ class Editor(stc.StyledTextCtrl):
         self.ScrollToLine(line - halfNumLinesOnScreen)
 
     def OnShowFindReplace(self):
-        data = wx.FindReplaceData()
-        self.findReplace = wx.FindReplaceDialog(self, data, "Find & Replace", wx.FR_REPLACEDIALOG | wx.FR_NOUPDOWN)
-        self.findReplace.data = data  # save a reference to it...
-        self.findReplace.Show(True)
+        self.data = wx.FindReplaceData()
+        dlg = wx.FindReplaceDialog(self, self.data, "Find & Replace", wx.FR_REPLACEDIALOG | wx.FR_NOUPDOWN)
+        dlg.Bind(wx.EVT_FIND, self.OnFind)
+        dlg.Bind(wx.EVT_FIND_NEXT, self.OnFind)
+        dlg.Bind(wx.EVT_FIND_REPLACE, self.OnFind)
+        dlg.Bind(wx.EVT_FIND_REPLACE_ALL, self.OnFind)
+        dlg.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
+        dlg.Show(True)
 
     def OnFind(self, evt):
         map = { wx.wxEVT_COMMAND_FIND : "FIND",
@@ -3359,41 +3637,50 @@ class Editor(stc.StyledTextCtrl):
                 wx.wxEVT_COMMAND_FIND_REPLACE : "REPLACE",
                 wx.wxEVT_COMMAND_FIND_REPLACE_ALL : "REPLACE_ALL" }
 
-        et = evt.GetEventType()
+        evtType = evt.GetEventType()
         findTxt = evt.GetFindString()
+        newTxt = evt.GetReplaceString()
+        findStrLen = len(findTxt)
+        newStrLen = len(newTxt)
+        diffLen = newStrLen - findStrLen
 
         selection = self.GetSelection()
         if selection[0] == selection[1]:
             selection = (0, self.GetLength())
 
-        if map[et] == 'FIND':
+        if map[evtType] == 'FIND':
             startpos = self.FindText(selection[0], selection[1], findTxt, evt.GetFlags())
             endpos = startpos+len(findTxt)
             self.anchor1 = endpos
             self.anchor2 = selection[1]
             self.SetSelection(startpos, endpos)
-        elif map[et] == 'FIND_NEXT':
+        elif map[evtType] == 'FIND_NEXT':
             startpos = self.FindText(self.anchor1, self.anchor2, findTxt, evt.GetFlags())
             endpos = startpos+len(findTxt)
             self.anchor1 = endpos
             self.SetSelection(startpos, endpos)
-        elif map[et] == 'REPLACE':
-            startpos = self.FindText(selection[0], selection[1], findTxt)
-            endpos = startpos+len(findTxt)
+        elif map[evtType] == 'REPLACE':
+            startpos = self.FindText(selection[0], selection[1], findTxt, evt.GetFlags())
             if startpos != -1:
+                endpos = startpos+len(findTxt)
                 self.SetSelection(startpos, endpos)
-                self.ReplaceSelection(evt.GetReplaceString())
-        elif map[et] == 'REPLACE_ALL':
-            self.anchor1 = selection[0]
+                self.ReplaceSelection(newTxt)
+                self.anchor1 = startpos + newStrLen + 1
+                self.anchor2 += diffLen
+        elif map[evtType] == 'REPLACE_ALL':
+            self.anchor1 = startpos = selection[0]
             self.anchor2 = selection[1]
-            startpos = selection[0]
             while startpos != -1:
-                startpos = self.FindText(self.anchor1, self.anchor2, findTxt)
-                endpos = startpos+len(findTxt)
-                self.anchor1 = endpos
+                startpos = self.FindText(self.anchor1, self.anchor2, findTxt, evt.GetFlags())
                 if startpos != -1:
+                    endpos = startpos+len(findTxt)
                     self.SetSelection(startpos, endpos)
-                    self.ReplaceSelection(evt.GetReplaceString())
+                    self.ReplaceSelection(newTxt)
+                    self.anchor1 = startpos + newStrLen + 1
+                    self.anchor2 += diffLen
+        line = self.GetCurrentLine()
+        halfNumLinesOnScreen = self.LinesOnScreen() / 2
+        self.ScrollToLine(line - halfNumLinesOnScreen)
 
     def OnFindClose(self, evt):
         evt.GetDialog().Destroy()
@@ -3452,30 +3739,6 @@ class Editor(stc.StyledTextCtrl):
             for line in lines:
                 f.write("%s=%s\n" % (line[0], line[1]))
 
-    def closeNoCancel(self):
-        if self.GetModify():
-            if not self.path: f = "Untitled"
-            else: f = self.path
-            dlg = wx.MessageDialog(None, 'file ' + f + ' has been modified. Do you want to save?', 
-                                   'Warning!', wx.YES | wx.NO)
-            but = dlg.ShowModal()
-            if but == wx.ID_YES:
-                dlg.Destroy()
-                if not self.path or "Untitled-" in self.path:
-                    dlg2 = wx.FileDialog(None, message="Save file as ... (the file will be closed even if you pressed Cancel!)", defaultDir=os.getcwd(), 
-                                         defaultFile="", style=wx.SAVE|wx.FD_OVERWRITE_PROMPT)
-                    dlg2.SetFilterIndex(0)
-                    if dlg2.ShowModal() == wx.ID_OK:
-                        path = dlg2.GetPath()
-                        self.SaveFile(path)
-                        dlg2.Destroy()
-                    else:
-                        dlg2.Destroy()
-                else:
-                    self.SaveFile(self.path)
-            elif but == wx.ID_NO:
-                dlg.Destroy()
-
     def close(self):
         if self.GetModify():
             if not self.path: f = "Untitled"
@@ -3595,6 +3858,9 @@ class Editor(stc.StyledTextCtrl):
         currentword = self.GetTextRangeUTF8(startpos, endpos)
         return currentword
 
+    def showAutoCompContainer(self, state):
+        self.auto_comp_container = state
+        
     def showAutoComp(self):
         propagate = True
         charBefore = " "
@@ -3612,15 +3878,27 @@ class Editor(stc.StyledTextCtrl):
                 propagate = False
         return propagate
 
-    def insertDefArgs(self, currentword):
+    def insertDefArgs(self, currentword, charat):
         propagate = True
+        braceend = True
+        currentword = ""
+        if charat == ord("("):
+            pos = self.GetCurrentPos()
+            if chr(self.GetCharAt(pos)) == ')':
+                braceend = False
+            startpos = self.WordStartPosition(pos-2, True)
+            endpos = self.WordEndPosition(pos-2, True)
+            currentword = self.GetTextRangeUTF8(startpos, endpos)
         for word in PYO_WORDLIST:
             if word == currentword:
                 text = class_args(eval(word)).replace(word, "")
                 self.args_buffer = text.replace("(", "").replace(")", "").split(",")
                 self.args_buffer = [arg.strip() for arg in self.args_buffer]
                 self.args_line_number = [self.GetCurrentLine(), self.GetCurrentLine()+1]
-                self.insertText(self.GetCurrentPos(), text, False)
+                if braceend:
+                    self.insertText(self.GetCurrentPos(), text[1:], False)
+                else:
+                    self.insertText(self.GetCurrentPos(), text[1:-1], False)
                 self.selection = self.GetSelectedText()
                 wx.CallAfter(self.navigateArgs)
                 propagate = False
@@ -3760,7 +4038,7 @@ class Editor(stc.StyledTextCtrl):
     def processTab(self, currentword, autoCompActive, charat, pos):
         propagate = self.showAutoComp()
         if propagate:
-            propagate = self.insertDefArgs(currentword)
+            propagate = self.insertDefArgs(currentword, charat)
             if propagate:
                 propagate = self.checkForBuiltinComp()
                 if propagate:
@@ -3775,30 +4053,64 @@ class Editor(stc.StyledTextCtrl):
         except:
             pass
 
-    def navigateMarkers(self, down=True):
-        if self.markers_dict != {}:
-            llen = len(self.markers_dict)
-            keys = sorted(self.markers_dict.keys())
-            if down:
-                self.current_marker += 1
-            else:
-                self.current_marker -= 1
-            if self.current_marker < 0:
-                self.current_marker = llen - 1
-            elif self.current_marker >= llen:
-                self.current_marker = 0
-            line = keys[self.current_marker]
-            self.GotoLine(line)
-            halfNumLinesOnScreen = self.LinesOnScreen() / 2
-            self.ScrollToLine(line - halfNumLinesOnScreen)
-            self.GetParent().GetParent().GetParent().GetParent().markers.setSelected(self.current_marker)
+    def onShowDocString(self):
+        if self.GetSelectedText() != "":
+            currentword = self.GetSelectedText()
+        else:
+            currentword = self.getWordUnderCaret()
+            firstCaretPos = self.GetCurrentPos()
+            caretPos = self.GetCurrentPos()
+            startpos = self.WordStartPosition(caretPos, True)
+            while chr(self.GetCharAt(startpos-1)) == ".":
+                self.GotoPos(startpos-2)
+                parent = self.getWordUnderCaret()
+                currentword = parent + "." + currentword
+                caretPos = self.GetCurrentPos()
+                startpos = self.WordStartPosition(caretPos, True)
+            self.GotoPos(firstCaretPos)
+        lineCount = self.GetLineCount()
+        text = ""
+        for i in range(lineCount):
+            line = self.GetLine(i)
+            if "import " in line:
+                text = text + line
+        try:
+            exec text in locals()
+            docstr = eval(currentword).__doc__
+            dlg = wx.lib.dialogs.ScrolledMessageDialog(self, docstr, "__doc__ string for %s" % currentword, size=(700,500))
+            dlg.CenterOnParent()
+            dlg.ShowModal()
+        except:
+            pass
 
+    def OnChar(self, evt):
+        propagate = True
+
+        if chr(evt.GetKeyCode()) in ['[', '{', '(', '"', '`'] and self.auto_comp_container:
+            if chr(evt.GetKeyCode()) == '[':
+                self.AddText('[]')
+            elif chr(evt.GetKeyCode()) == '{':
+                self.AddText('{}')
+            elif chr(evt.GetKeyCode()) == '(':
+                self.AddText('()')
+            elif chr(evt.GetKeyCode()) == '"':
+                self.AddText('""')
+            elif chr(evt.GetKeyCode()) == '`':
+                self.AddText('``')
+            self.CharLeft()
+            propagate = False
+
+        if propagate:
+            evt.Skip()
+        else:
+            evt.StopPropagation()
+        
     def OnKeyDown(self, evt):
         if PLATFORM == "darwin":
             ControlDown = evt.CmdDown
         else:
             ControlDown = evt.ControlDown
-
+        
         propagate = True
         # Stop propagation on markers navigation --- Shift+Ctrl+Arrows up/down
         if evt.GetKeyCode() in [wx.WXK_DOWN,wx.WXK_UP] and evt.ShiftDown() and ControlDown():
@@ -3807,6 +4119,10 @@ class Editor(stc.StyledTextCtrl):
         elif evt.GetKeyCode() == wx.WXK_RETURN and evt.ShiftDown():
             self.onShowTip()
             propagate = False
+        # Stop propagation on Tip Show of __doc__ string --- Ctrl+Return
+        elif evt.GetKeyCode() == wx.WXK_RETURN and ControlDown():
+            self.onShowDocString()
+            propagate = False
 
         # Move and/or Select one word left or right --- (Shift+)Alt+Arrows left/right
         elif evt.GetKeyCode() == wx.WXK_LEFT and evt.AltDown() and evt.ShiftDown():
@@ -3832,6 +4148,11 @@ class Editor(stc.StyledTextCtrl):
             self.CmdKeyExecute(stc.STC_CMD_LINEEND)
             propagate = False
 
+        # Delete forward DELETE
+        elif evt.GetKeyCode() == wx.WXK_DELETE:
+            self.CmdKeyExecute(stc.STC_CMD_CHARRIGHT)
+            self.CmdKeyExecute(stc.STC_CMD_DELETEBACK)
+            propagate = False
         # Delete the word to the right of the caret --- Shift+Alt+BACK
         elif evt.GetKeyCode() == wx.WXK_BACK and evt.AltDown() and evt.ShiftDown():
             self.DelWordRight()
@@ -3863,6 +4184,19 @@ class Editor(stc.StyledTextCtrl):
                 self.Paste()
             propagate = False
 
+        # Show documentation for pyo object under the caret
+        elif evt.GetKeyCode() == ord('D') and ControlDown():
+            self.GetParent().GetParent().GetParent().GetParent().GetParent().showDoc(None)
+            propagate = False
+        # Goto line
+        elif evt.GetKeyCode() == ord('L') and ControlDown():
+            self.GetParent().GetParent().GetParent().GetParent().GetParent().gotoLine(None)
+            propagate = False
+        # Send line/selection to pyo background server
+        elif evt.GetKeyCode() == ord('T') and ControlDown():
+            self.GetParent().GetParent().GetParent().GetParent().GetParent().sendSelectionToBackgroundServer(None)
+            propagate = False
+
         # Process Return key --- automatic indentation
         elif evt.GetKeyCode() == wx.WXK_RETURN:
             wx.CallAfter(self.processReturn)
@@ -3943,6 +4277,7 @@ class Editor(stc.StyledTextCtrl):
         #         pos = self.GetLineEndPosition(i)
         #         if self.GetCharAt(pos-1) != 172:
         #             self.InsertTextUTF8(pos, "¬")
+        self.moveMarkers()
         self.checkScrollbar()
         self.OnModified()
         evt.Skip()
@@ -3970,96 +4305,129 @@ class Editor(stc.StyledTextCtrl):
                 self.GotoPos(pos+1)
                 self.DelWordLeft()
 
+    def navigateMarkers(self, down=True):
+        if self.markers_dict != {}:
+            llen = len(self.markers_dict)
+            swap = [(x[1], x[0]) for x in self.markers_dict.items()]
+            handles = [x[1] for x in sorted(swap)]
+            if down:
+                self.current_marker += 1
+            else:
+                self.current_marker -= 1
+            if self.current_marker < 0:
+                self.current_marker = llen - 1
+            elif self.current_marker >= llen:
+                self.current_marker = 0
+            handle = handles[self.current_marker]
+            line = self.markers_dict[handle][0]
+            self.GotoLine(line)
+            halfNumLinesOnScreen = self.LinesOnScreen() / 2
+            self.ScrollToLine(line - halfNumLinesOnScreen)
+            self.GetParent().GetParent().GetParent().GetParent().markers.setSelected(handle)
+
     def setMarkers(self, dic):
+        try:
+            key = dic.keys()[0]
+        except:
+            return
+        if type(dic[key]) != ListType:
+            return
         self.markers_dict = dic
-        for line in self.markers_dict.keys():
+        for handle in self.markers_dict.keys():
+            line = self.markers_dict[handle][0]
             self.MarkerAdd(line, 0)
         self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
 
-    def addMarker(self, line):
-        if line not in self.markers_dict.keys():
-            self.MarkerAdd(line, 0)
-            self.markers_dict[line] = ""
+    def moveMarkers(self):
+        dict = {}
+        for handle in self.markers_dict.keys():
+            line = self.MarkerLineFromHandle(handle)
+            comment = self.markers_dict[handle][1]
+            dict[handle] = [line, comment]
+        if dict != self.markers_dict:
+            self.markers_dict = dict
             self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
-            return True
+            
+    def addMarker(self, line):
+        if not self.MarkerGet(line):
+            handle = self.MarkerAdd(line, 0)
+            self.markers_dict[handle] = [line, ""]            
+        comment = ""
+        dlg = wx.TextEntryDialog(self, 'Enter a comment for that marker:', 'Marker Comment')
+        if dlg.ShowModal() == wx.ID_OK:
+            comment = dlg.GetValue()
+            dlg.Destroy()
         else:
-            return False
+            dlg.Destroy()
+            return
+        self.markers_dict[handle][1] = comment
+        self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
 
     def deleteMarker(self, line):
-        if line in self.markers_dict.keys():
-            del self.markers_dict[line]
-            self.MarkerDelete(line, 0)
-            self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
+        for handle in self.markers_dict.keys():
+            if line == self.markers_dict[handle][0]:
+                del self.markers_dict[handle]
+                self.MarkerDeleteHandle(handle)
+                self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
 
     def deleteAllMarkers(self):
         self.markers_dict = {}
         self.MarkerDeleteAll(0)
         self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
 
-    def addMarkerComment(self, line):
-        if line in self.markers_dict.keys():
-            comment = ""
-            dlg = wx.TextEntryDialog(self, 'Enter a comment for that marker:', 'Marker Comment')
-            if dlg.ShowModal() == wx.ID_OK:
-                comment = dlg.GetValue()
-                dlg.Destroy()
-            else:
-                dlg.Destroy()
-                return
-            self.markers_dict[line] = comment
-            self.GetParent().GetParent().GetParent().GetParent().markers.setDict(self.markers_dict)
-
     def OnMarginClick(self, evt):
         if evt.GetMargin() == 0:
-            if PLATFORM == "darwin":
-                modif = evt.GetAlt
-            else:
-                modif = evt.GetControl
             lineClicked = self.LineFromPosition(evt.GetPosition())
-            if modif():
+            if evt.GetShift():
                 self.deleteMarker(lineClicked)
-            elif evt.GetShift():
-                self.addMarkerComment(lineClicked)
             else:
-                ok = self.addMarker(lineClicked)
-                if ok:
-                    self.addMarkerComment(lineClicked)
+                self.addMarker(lineClicked)
         elif evt.GetMargin() == 2:
             if evt.GetShift() and evt.GetControl():
-                self.FoldAll()
+                self.ToggleFoldAll()
             else:
                 lineClicked = self.LineFromPosition(evt.GetPosition())
-
                 if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
-                    if evt.GetShift():
-                        self.SetFoldExpanded(lineClicked, True)
-                        self.Expand(lineClicked, True, True, 1)
-                    elif evt.GetControl():
-                        if self.GetFoldExpanded(lineClicked):
-                            self.SetFoldExpanded(lineClicked, False)
-                            self.Expand(lineClicked, False, True, 0)
-                        else:
-                            self.SetFoldExpanded(lineClicked, True)
-                            self.Expand(lineClicked, True, True, 100)
-                    else:
-                        self.ToggleFold(lineClicked)
+                    self.ToggleFold(lineClicked)
 
     def FoldAll(self):
         lineCount = self.GetLineCount()
-        expanding = True
+        lineNum = 0
+        while lineNum < lineCount:
+            level = self.GetFoldLevel(lineNum)
+            if level & stc.STC_FOLDLEVELHEADERFLAG and \
+               (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+                lastChild = self.GetLastChild(lineNum, -1)
+                self.SetFoldExpanded(lineNum, False)
+                if lastChild > lineNum:
+                    self.HideLines(lineNum+1, lastChild)
+            lineNum = lineNum + 1
+
+    def ExpandAll(self):
+        lineCount = self.GetLineCount()
+        lineNum = 0
+        while lineNum < lineCount:
+            level = self.GetFoldLevel(lineNum)
+            if level & stc.STC_FOLDLEVELHEADERFLAG and \
+               (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+                self.SetFoldExpanded(lineNum, True)
+                lineNum = self.Expand(lineNum, True)
+                lineNum = lineNum - 1
+            lineNum = lineNum + 1
 
+    def ToggleFoldAll(self):
+        lineCount = self.GetLineCount()
+        expanding = True
         # find out if we are folding or unfolding
         for lineNum in range(lineCount):
             if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
                 expanding = not self.GetFoldExpanded(lineNum)
                 break
-
         lineNum = 0
         while lineNum < lineCount:
             level = self.GetFoldLevel(lineNum)
             if level & stc.STC_FOLDLEVELHEADERFLAG and \
                (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
-
                 if expanding:
                     self.SetFoldExpanded(lineNum, True)
                     lineNum = self.Expand(lineNum, True)
@@ -4071,6 +4439,16 @@ class Editor(stc.StyledTextCtrl):
                         self.HideLines(lineNum+1, lastChild)
             lineNum = lineNum + 1
 
+    def foldExpandCurrentScope(self):
+        line = self.GetCurrentLine()
+        while (line >= 0):
+            level = self.GetFoldLevel(line)
+            if level & stc.STC_FOLDLEVELHEADERFLAG and (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
+                self.ToggleFold(line)
+                self.GotoLine(line)
+                break
+            line -= 1
+
     def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
         lastChild = self.GetLastChild(line, level)
         line = line + 1
@@ -4167,6 +4545,12 @@ class OutputLogEditor(SimpleEditor):
     def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style= wx.NO_BORDER):
         SimpleEditor.__init__(self, parent=parent, ID=ID, pos=pos, size=size, style=style)
 
+    def appendToLog(self, text):
+        self.SetReadOnly(False)
+        self.AppendText(text)
+        self.GotoLine(self.GetLineCount())
+        self.SetReadOnly(True)
+
     def setLog(self, text):
         self.SetReadOnly(False)
         self.SetText(text)
@@ -4184,7 +4568,7 @@ class OutputLogPanel(wx.Panel):
         self.sizer = wx.BoxSizer(wx.VERTICAL)
 
         toolbarbox = wx.BoxSizer(wx.HORIZONTAL)
-        self.toolbar = wx.ToolBar(self, -1, size=(-1,36))
+        self.toolbar = wx.ToolBar(self, -1)
         self.toolbar.SetMargins((5, 0))
         font, psize = self.toolbar.GetFont(), self.toolbar.GetFont().GetPointSize()
         if PLATFORM == "darwin":
@@ -4193,7 +4577,7 @@ class OutputLogPanel(wx.Panel):
         
         if PLATFORM == "win32":
             self.toolbar.AddSeparator()
-        title = wx.StaticText(self.toolbar, -1, "Output panel")
+        title = wx.StaticText(self.toolbar, -1, " Output panel")
         title.SetFont(font)
         self.toolbar.AddControl(title)
         self.toolbar.AddSeparator()
@@ -4204,17 +4588,17 @@ class OutputLogPanel(wx.Panel):
         self.toolbar.AddControl(self.processPopup)
         if PLATFORM == "win32":
             self.toolbar.AddSeparator()
-        self.processKill = wx.Button(self.toolbar, -1, label="Kill", size=(40,-1))
+        self.processKill = wx.Button(self.toolbar, -1, label="Kill", size=(40,self.processPopup.GetSize()[1]))
         self.processKill.SetFont(font)        
         self.toolbar.AddControl(self.processKill)
         self.processKill.Bind(wx.EVT_BUTTON, self.killProcess)
         if PLATFORM == "win32":
             self.toolbar.AddSeparator()
-        self.runningLabel = wx.StaticText(self.toolbar, -1, "Running: 0")
+        self.runningLabel = wx.StaticText(self.toolbar, -1, " Running: 0")
         self.runningLabel.SetFont(font)
         self.toolbar.AddControl(self.runningLabel)
         self.toolbar.AddSeparator()
-        self.copyLog = wx.Button(self.toolbar, -1, label="Copy log", size=(70,-1))
+        self.copyLog = wx.Button(self.toolbar, -1, label="Copy log", size=(70,self.processPopup.GetSize()[1]))
         self.copyLog.SetFont(font)
         self.toolbar.AddControl(self.copyLog)
         self.copyLog.Bind(wx.EVT_BUTTON, self.onCopy)
@@ -4231,8 +4615,10 @@ class OutputLogPanel(wx.Panel):
         self.toolbar.Realize()
         toolbarbox.Add(self.toolbar, 1, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 0)
 
-        tb2 = wx.ToolBar(self, -1, size=(-1,36))
-        tb2.SetToolBitmapSize(tsize)
+        tb2 = wx.ToolBar(self, -1, size=(-1,32))
+        if PLATFORM == "darwin":
+            tb2.SetToolBitmapSize(tsize)
+        tb2.AddSeparator()
         tb2.AddLabelTool(17, "Close Panel", close_panel_bmp, shortHelp="Close Panel")
         tb2.Realize()
         toolbarbox.Add(tb2, 0, wx.ALIGN_RIGHT, 0)
@@ -4259,6 +4645,7 @@ class OutputLogPanel(wx.Panel):
         self.processPopup.SetStringSelection("%d :: %s" % (procID, filename))
         self.running += 1
         self.runningLabel.SetLabel("Running: %d" % self.running)
+        self.editor.setLog("")
 
     def removeProcess(self, procID, filename):
         str = "%d :: %s" % (procID, filename)
@@ -4274,6 +4661,9 @@ class OutputLogPanel(wx.Panel):
             thread = self.mainPanel.mainFrame.processes[procID][0]
             thread.kill()
 
+    def appendToLog(self, text):
+        self.editor.appendToLog(text)
+
     def setLog(self, text):
         self.editor.setLog(text)
 
@@ -4577,11 +4967,11 @@ class ProjectTree(wx.Panel):
                 filename = os.path.join(parent, filename)
             dirPath = os.path.split(self.projectDict[parent])[0]
             path = os.path.join(dirPath, filename)
-#            for root, dirs, files in os.walk(dirPath):
-#                if files:
-#                    for file in files:
-#                        if file == self.tree.GetItemText(item):
-#                            path = os.path.join(root, file)
+            #for root, dirs, files in os.walk(dirPath):
+            #    if files:
+            #        for file in files:
+            #            if file == self.tree.GetItemText(item):
+            #                path = os.path.join(root, file)
             self.mainPanel.addPage(path)
 
     def select(self, item):
@@ -4623,16 +5013,18 @@ class MarkersListScroll(scrolled.ScrolledPanel):
     def setDict(self, dic):
         self.row_dict = dic
         self.box.Clear(True)
-        for i, key in enumerate(sorted(self.row_dict.keys())):
+        swap = [(x[1], x[0]) for x in self.row_dict.items()]
+        handles = [x[1] for x in sorted(swap)]
+        for i in handles:
             label = wx.StaticBitmap(self, wx.ID_ANY)
             label.SetBitmap(self.arrow_bit)
-            self.box.Add(label, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 2, userData=(i,key))
-            line = wx.StaticText(self, wx.ID_ANY, label=str(key+1))
+            self.box.Add(label, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 2, userData=(i,self.row_dict[i][0]))
+            line = wx.StaticText(self, wx.ID_ANY, label=str(self.row_dict[i][0]+1))
             line.SetFont(self.font)
-            self.box.Add(line, 0, wx.ALIGN_LEFT|wx.TOP, 3, userData=(i,key))
-            comment = wx.StaticText(self, wx.ID_ANY, label=self.row_dict[key])
+            self.box.Add(line, 0, wx.ALIGN_LEFT|wx.TOP, 3, userData=(i,self.row_dict[i][0]))
+            comment = wx.StaticText(self, wx.ID_ANY, label=self.row_dict[i][1])
             comment.SetFont(self.font)
-            self.box.Add(comment, 1, wx.EXPAND|wx.ALIGN_LEFT|wx.TOP, 3, userData=(i,key))
+            self.box.Add(comment, 1, wx.EXPAND|wx.ALIGN_LEFT|wx.TOP, 3, userData=(i,self.row_dict[i][0]))
             self.box.Layout()
             label.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
             line.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
@@ -4655,13 +5047,14 @@ class MarkersListScroll(scrolled.ScrolledPanel):
                     halfNumLinesOnScreen = editor.LinesOnScreen() / 2
                     editor.ScrollToLine(line - halfNumLinesOnScreen)
                 else:
-                    line = sorted(self.row_dict.keys())[self.selected]
+                    line = self.row_dict[self.selected][0]
                     self.selected2 = item.GetUserData()[0]
                     line2 = item.GetUserData()[1]
-                    editor.GotoLine(line)
+                    l1, l2 = min(line, line2), max(line, line2)
+                    editor.GotoLine(l1)
                     halfNumLinesOnScreen = editor.LinesOnScreen() / 2
-                    editor.ScrollToLine(line - halfNumLinesOnScreen)
-                    editor.SetSelection(editor.PositionFromLine(line), editor.PositionFromLine(line2+1))
+                    editor.ScrollToLine(l1 - halfNumLinesOnScreen)
+                    editor.SetSelection(editor.PositionFromLine(l1), editor.PositionFromLine(l2+1))
                 break
         self.setColour()
 
@@ -4741,7 +5134,7 @@ class PreferencesDialog(wx.Dialog):
         
         font.SetWeight(wx.BOLD)
         if PLATFORM == "linux2":
-            entryfont.SetPointSize(pointsize-1)
+            entryfont.SetPointSize(pointsize)
         elif PLATFORM == "win32":
             entryfont.SetPointSize(pointsize)
         else:
@@ -4901,7 +5294,7 @@ class PreferencesDialog(wx.Dialog):
 
         res_folder = self.entry_res.GetValue()
         if os.path.isdir(res_folder):
-            if res_folder != RESOURCES_PATH:
+            if res_folder != ensureNFD(RESOURCES_PATH):
                 RESOURCES_PATH = PREFERENCES["resources_path"] = res_folder
                 # snippets
                 old_snippets_path = SNIPPETS_PATH
@@ -4959,9 +5352,10 @@ class STCPrintout(wx.Printout):
     a wrapped line, so it may be a difficult task to ever implement printing
     with line wrapping using the wx.StyledTextCtrl.FormatRange method.
     """
-    debuglevel = 0
+    debuglevel = 1
 
-    def __init__(self, stc, page_setup_data=None, print_mode=None, title=None, border=False, lines_per_page=None, output_point_size=None):
+    def __init__(self, stc, page_setup_data=None, print_mode=None, title=None, 
+                 border=False, lines_per_page=None, output_point_size=None):
         """Constructor.
 
         @param stc: wx.StyledTextCtrl to print
@@ -5022,6 +5416,7 @@ class STCPrintout(wx.Printout):
         except (TypeError, ValueError):
             self.user_lines_per_page = None
 
+        self.page_count = 2
         self.border_around_text = border
 
         self.setHeaderFont()
@@ -5368,6 +5763,36 @@ class MyFileDropTarget(wx.FileDropTarget):
             else:
                 pass
 
+class EPyoApp(wx.App):
+    def __init__(self, *args, **kwargs):
+        wx.App.__init__(self, *args, **kwargs)
+
+    def OnInit(self):
+        X,Y = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X), wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
+        if X < 850: X -= 50
+        else: X = 850
+        if Y < 750: Y -= 50
+        else: Y = 750
+        self.frame = MainFrame(None, -1, title='E-Pyo Editor', pos=(10,25), size=(X, Y))
+        self.frame.Show()
+        return True
+
+    def MacOpenFiles(self, filenames):
+        if type(filenames) != ListType:
+            filenames = [filenames]
+        for filename in filenames:
+            if os.path.isdir(filename):
+                self.frame.panel.project.loadFolder(filename)
+                sys.path.append(filename)
+            elif os.path.isfile(filename):
+                self.frame.panel.addPage(filename)
+
+    def MacReopenApp(self):
+        try:
+            self.frame.Raise()
+        except:
+            pass
+
 if __name__ == '__main__':
     filesToOpen = []
     foldersToOpen = []
@@ -5381,12 +5806,5 @@ if __name__ == '__main__':
             else:
                 pass
 
-    app = wx.PySimpleApp()
-    X,Y = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X), wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
-    if X < 850: X -= 50
-    else: X = 850
-    if Y < 750: Y -= 50
-    else: Y = 750
-    frame = MainFrame(None, -1, title='E-Pyo Editor', pos=(10,25), size=(X, Y))
-    frame.Show()
+    app = EPyoApp(redirect=False)
     app.MainLoop()
diff --git a/utils/E-PyoIcon.png b/utils/E-PyoIcon.png
new file mode 100644
index 0000000..f971f13
Binary files /dev/null and b/utils/E-PyoIcon.png differ
diff --git a/utils/FlatNotebook.py b/utils/FlatNotebook.py
deleted file mode 100755
index f4c7d34..0000000
--- a/utils/FlatNotebook.py
+++ /dev/null
@@ -1,4940 +0,0 @@
-# --------------------------------------------------------------------------- #
-# FLATNOTEBOOK Widget wxPython IMPLEMENTATION
-#
-# Original C++ Code From Eran. You Can Find It At:
-#
-# http://wxforum.shadonet.com/viewtopic.php?t=5761&start=0
-#
-# License: wxWidgets license
-#
-#
-# Python Code By:
-#
-# Andrea Gavana, @ 02 Oct 2006
-# Latest Revision: 30 May 2008, 23.00 GMT
-#
-#
-# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
-# Write To Me At:
-#
-# andrea.gavana at gmail.com
-# gavana at kpo.kz
-#
-# Or, Obviously, To The wxPython Mailing List!!!
-#
-#
-# End Of Comments
-# --------------------------------------------------------------------------- #
-
-"""
-The FlatNotebook is a full implementation of the wx.Notebook, and designed to be
-a drop-in replacement for wx.Notebook. The API functions are similar so one can
-expect the function to behave in the same way. 
-
-Some features:
-
-  - The buttons are highlighted a la Firefox style
-  - The scrolling is done for bulks of tabs (so, the scrolling is faster and better)
-  - The buttons area is never overdrawn by tabs (unlike many other implementations I saw)
-  - It is a generic control
-  - Currently there are 5 differnt styles - VC8, VC 71, Standard, Fancy and Firefox 2;
-  - Mouse middle click can be used to close tabs
-  - A function to add right click menu for tabs (simple as SetRightClickMenu)
-  - All styles has bottom style as well (they can be drawn in the bottom of screen)
-  - An option to hide 'X' button or navigation buttons (separately)
-  - Gradient coloring of the selected tabs and border
-  - Support for drag 'n' drop of tabs, both in the same notebook or to another notebook
-  - Possibility to have closing button on the active tab directly
-  - Support for disabled tabs
-  - Colours for active/inactive tabs, and captions
-  - Background of tab area can be painted in gradient (VC8 style only)
-  - Colourful tabs - a random gentle colour is generated for each new tab (very cool, VC8 style only)
-
-
-And much more.
-
-
-License And Version:
-
-FlatNotebook Is Freeware And Distributed Under The wxPython License. 
-
-Latest Revision: Andrea Gavana @ 30 May 2008, 23.00 GMT
-
-Version 2.5.
-
- at undocumented: FNB_HEIGHT_SPACER, VERTICAL_BORDER_PADDING, VC8_SHAPE_LEN,
-    wxEVT*, left_arrow_*, right_arrow*, x_button*, down_arrow*,
-    FNBDragInfo, FNBDropTarget, GetMondrian*
-"""
-
-__docformat__ = "epytext"
-
-
-#----------------------------------------------------------------------
-# Beginning Of FLATNOTEBOOK wxPython Code
-#----------------------------------------------------------------------
-
-import wx
-import random
-import math
-import weakref
-import cPickle
-
-if wx.Platform == '__WXMAC__':
-    import Carbon.Appearance
-
-# Check for the new method in 2.7 (not present in 2.6.3.3)
-if wx.VERSION_STRING < "2.7":
-    wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point)
-
-FNB_HEIGHT_SPACER = 10
-
-# Use Visual Studio 2003 (VC7.1) style for tabs
-FNB_VC71 = 1
-"""Use Visual Studio 2003 (VC7.1) style for tabs"""
-
-# Use fancy style - square tabs filled with gradient coloring
-FNB_FANCY_TABS = 2
-"""Use fancy style - square tabs filled with gradient coloring"""
-
-# Draw thin border around the page
-FNB_TABS_BORDER_SIMPLE = 4
-"""Draw thin border around the page"""
-
-# Do not display the 'X' button
-FNB_NO_X_BUTTON = 8
-"""Do not display the 'X' button"""
-
-# Do not display the Right / Left arrows
-FNB_NO_NAV_BUTTONS = 16
-"""Do not display the right/left arrows"""
-
-# Use the mouse middle button for cloing tabs
-FNB_MOUSE_MIDDLE_CLOSES_TABS = 32
-"""Use the mouse middle button for cloing tabs"""
-
-# Place tabs at bottom - the default is to place them
-# at top
-FNB_BOTTOM = 64
-"""Place tabs at bottom - the default is to place them at top"""
-
-# Disable dragging of tabs
-FNB_NODRAG = 128
-"""Disable dragging of tabs"""
-
-# Use Visual Studio 2005 (VC8) style for tabs
-FNB_VC8 = 256
-"""Use Visual Studio 2005 (VC8) style for tabs"""
-
-# Firefox 2 tabs style
-FNB_FF2 = 131072
-"""Use Firefox 2 style for tabs"""
-
-# Place 'X' on a tab
-FNB_X_ON_TAB = 512
-"""Place 'X' close button on the active tab"""
-
-FNB_BACKGROUND_GRADIENT = 1024
-"""Use gradients to paint the tabs background"""
-
-FNB_COLORFUL_TABS = 2048
-"""Use colourful tabs (VC8 style only)"""
-
-# Style to close tab using double click - styles 1024, 2048 are reserved
-FNB_DCLICK_CLOSES_TABS = 4096
-"""Style to close tab using double click"""
-
-FNB_SMART_TABS = 8192
-"""Use Smart Tabbing, like Alt+Tab on Windows"""
-
-FNB_DROPDOWN_TABS_LIST = 16384
-"""Use a dropdown menu on the left in place of the arrows"""
-
-FNB_ALLOW_FOREIGN_DND = 32768
-"""Allows drag 'n' drop operations between different L{FlatNotebook}s"""
-
-FNB_HIDE_ON_SINGLE_TAB = 65536
-"""Hides the Page Container when there is one or fewer tabs"""
-
-VERTICAL_BORDER_PADDING = 4
-
-# Button size is a 16x16 xpm bitmap
-BUTTON_SPACE = 16
-"""Button size is a 16x16 xpm bitmap"""
-
-VC8_SHAPE_LEN = 16
-
-MASK_COLOR  = wx.Colour(0, 128, 128)
-"""Mask colour for the arrow bitmaps"""
-
-# Button status
-FNB_BTN_PRESSED = 2
-"""Navigation button is pressed"""
-FNB_BTN_HOVER = 1
-"""Navigation button is hovered"""
-FNB_BTN_NONE = 0
-"""No navigation"""
-
-# Hit Test results
-FNB_TAB = 1             # On a tab
-"""Indicates mouse coordinates inside a tab"""
-FNB_X = 2               # On the X button
-"""Indicates mouse coordinates inside the I{X} region"""
-FNB_TAB_X = 3           # On the 'X' button (tab's X button)
-"""Indicates mouse coordinates inside the I{X} region in a tab"""
-FNB_LEFT_ARROW = 4      # On the rotate left arrow button
-"""Indicates mouse coordinates inside the left arrow region"""
-FNB_RIGHT_ARROW = 5     # On the rotate right arrow button
-"""Indicates mouse coordinates inside the right arrow region"""
-FNB_DROP_DOWN_ARROW = 6 # On the drop down arrow button
-"""Indicates mouse coordinates inside the drop down arrow region"""
-FNB_NOWHERE = 0         # Anywhere else
-"""Indicates mouse coordinates not on any tab of the notebook"""
-
-FNB_DEFAULT_STYLE = FNB_MOUSE_MIDDLE_CLOSES_TABS | FNB_HIDE_ON_SINGLE_TAB
-"""L{FlatNotebook} default style"""
-
-# FlatNotebook Events:
-# wxEVT_FLATNOTEBOOK_PAGE_CHANGED: Event Fired When You Switch Page;
-# wxEVT_FLATNOTEBOOK_PAGE_CHANGING: Event Fired When You Are About To Switch
-# Pages, But You Can Still "Veto" The Page Changing By Avoiding To Call
-# event.Skip() In Your Event Handler;
-# wxEVT_FLATNOTEBOOK_PAGE_CLOSING: Event Fired When A Page Is Closing, But
-# You Can Still "Veto" The Page Changing By Avoiding To Call event.Skip()
-# In Your Event Handler;
-# wxEVT_FLATNOTEBOOK_PAGE_CLOSED: Event Fired When A Page Is Closed.
-# wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU: Event Fired When A Menu Pops-up In A Tab.
-
-wxEVT_FLATNOTEBOOK_PAGE_CHANGED = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
-wxEVT_FLATNOTEBOOK_PAGE_CHANGING = wx.wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING
-wxEVT_FLATNOTEBOOK_PAGE_CLOSING = wx.NewEventType()
-wxEVT_FLATNOTEBOOK_PAGE_CLOSED = wx.NewEventType()
-wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.NewEventType()
-
-#-----------------------------------#
-#        FlatNotebookEvent
-#-----------------------------------#
-
-EVT_FLATNOTEBOOK_PAGE_CHANGED = wx.EVT_NOTEBOOK_PAGE_CHANGED
-"""Notify client objects when the active page in L{FlatNotebook} 
-has changed."""
-EVT_FLATNOTEBOOK_PAGE_CHANGING = wx.EVT_NOTEBOOK_PAGE_CHANGING
-"""Notify client objects when the active page in L{FlatNotebook} 
-is about to change."""
-EVT_FLATNOTEBOOK_PAGE_CLOSING = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, 1)
-"""Notify client objects when a page in L{FlatNotebook} is closing."""
-EVT_FLATNOTEBOOK_PAGE_CLOSED = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, 1)
-"""Notify client objects when a page in L{FlatNotebook} has been closed."""
-EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU = wx.PyEventBinder(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, 1)
-"""Notify client objects when a pop-up menu should appear next to a tab."""
-
-
-# Some icons in XPM format
-
-left_arrow_disabled_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #555555",
-    "# c #000000",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````.```````",
-    "```````..```````",
-    "``````.`.```````",
-    "`````.``.```````",
-    "````.```.```````",
-    "`````.``.```````",
-    "``````.`.```````",
-    "```````..```````",
-    "````````.```````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````"
-    ]
-
-x_button_pressed_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #4766e0",
-    "# c #9e9ede",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "`..............`",
-    "`.############.`",
-    "`.############.`",
-    "`.############.`",
-    "`.###aa####aa#.`",
-    "`.####aa##aa##.`",
-    "`.#####aaaa###.`",
-    "`.######aa####.`",
-    "`.#####aaaa###.`",
-    "`.####aa##aa##.`",
-    "`.###aa####aa#.`",
-    "`.############.`",
-    "`..............`",
-    "````````````````",
-    "````````````````"
-    ]
-
-
-left_arrow_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #555555",
-    "# c #000000",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````.```````",
-    "```````..```````",
-    "``````...```````",
-    "`````....```````",
-    "````.....```````",
-    "`````....```````",
-    "``````...```````",
-    "```````..```````",
-    "````````.```````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````"
-    ]
-
-x_button_hilite_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #4766e0",
-    "# c #c9dafb",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "`..............`",
-    "`.############.`",
-    "`.############.`",
-    "`.##aa####aa##.`",
-    "`.###aa##aa###.`",
-    "`.####aaaa####.`",
-    "`.#####aa#####.`",
-    "`.####aaaa####.`",
-    "`.###aa##aa###.`",
-    "`.##aa####aa##.`",
-    "`.############.`",
-    "`.############.`",
-    "`..............`",
-    "````````````````",
-    "````````````````"
-    ]
-
-x_button_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #555555",
-    "# c #000000",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````..````..````",
-    "`````..``..`````",
-    "``````....``````",
-    "```````..```````",
-    "``````....``````",
-    "`````..``..`````",
-    "````..````..````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````"
-    ]
-
-left_arrow_pressed_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #4766e0",
-    "# c #9e9ede",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "`..............`",
-    "`.############.`",
-    "`.############.`",
-    "`.#######a####.`",
-    "`.######aa####.`",
-    "`.#####aaa####.`",
-    "`.####aaaa####.`",
-    "`.###aaaaa####.`",
-    "`.####aaaa####.`",
-    "`.#####aaa####.`",
-    "`.######aa####.`",
-    "`.#######a####.`",
-    "`..............`",
-    "````````````````",
-    "````````````````"
-    ]
-
-left_arrow_hilite_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #4766e0",
-    "# c #c9dafb",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "`..............`",
-    "`.############.`",
-    "`.######a#####.`",
-    "`.#####aa#####.`",
-    "`.####aaa#####.`",
-    "`.###aaaa#####.`",
-    "`.##aaaaa#####.`",
-    "`.###aaaa#####.`",
-    "`.####aaa#####.`",
-    "`.#####aa#####.`",
-    "`.######a#####.`",
-    "`.############.`",
-    "`..............`",
-    "````````````````",
-    "````````````````"
-    ]
-
-right_arrow_disabled_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #555555",
-    "# c #000000",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "```````.````````",
-    "```````..```````",
-    "```````.`.``````",
-    "```````.``.`````",
-    "```````.```.````",
-    "```````.``.`````",
-    "```````.`.``````",
-    "```````..```````",
-    "```````.````````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````"
-    ]
-
-right_arrow_hilite_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #4766e0",
-    "# c #c9dafb",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "`..............`",
-    "`.############.`",
-    "`.####a#######.`",
-    "`.####aa######.`",
-    "`.####aaa#####.`",
-    "`.####aaaa####.`",
-    "`.####aaaaa###.`",
-    "`.####aaaa####.`",
-    "`.####aaa#####.`",
-    "`.####aa######.`",
-    "`.####a#######.`",
-    "`.############.`",
-    "`..............`",
-    "````````````````",
-    "````````````````"
-    ]
-
-right_arrow_pressed_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #4766e0",
-    "# c #9e9ede",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "`..............`",
-    "`.############.`",
-    "`.############.`",
-    "`.#####a######.`",
-    "`.#####aa#####.`",
-    "`.#####aaa####.`",
-    "`.#####aaaa###.`",
-    "`.#####aaaaa##.`",
-    "`.#####aaaa###.`",
-    "`.#####aaa####.`",
-    "`.#####aa#####.`",
-    "`.#####a######.`",
-    "`..............`",
-    "````````````````",
-    "````````````````"
-    ]
-
-
-right_arrow_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #555555",
-    "# c #000000",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "```````.````````",
-    "```````..```````",
-    "```````...``````",
-    "```````....`````",
-    "```````.....````",
-    "```````....`````",
-    "```````...``````",
-    "```````..```````",
-    "```````.````````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````"
-    ]
-
-down_arrow_hilite_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #4766e0",
-    "# c #c9dafb",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "``.............`",
-    "``.###########.`",
-    "``.###########.`",
-    "``.###########.`",
-    "``.#aaaaaaaaa#.`",
-    "``.##aaaaaaa##.`",
-    "``.###aaaaa###.`",
-    "``.####aaa####.`",
-    "``.#####a#####.`",
-    "``.###########.`",
-    "``.###########.`",
-    "``.###########.`",
-    "``.............`",
-    "````````````````",
-    "````````````````"
-    ]
-
-down_arrow_pressed_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #4766e0",
-    "# c #9e9ede",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "``.............`",
-    "``.###########.`",
-    "``.###########.`",
-    "``.###########.`",
-    "``.###########.`",
-    "``.###########.`",
-    "``.#aaaaaaaaa#.`",
-    "``.##aaaaaaa##.`",
-    "``.###aaaaa###.`",
-    "``.####aaa####.`",
-    "``.#####a#####.`",
-    "``.###########.`",
-    "``.............`",
-    "````````````````",
-    "````````````````"
-    ]
-
-
-down_arrow_xpm = [
-    "    16    16        8            1",
-    "` c #008080",
-    ". c #000000",
-    "# c #000000",
-    "a c #000000",
-    "b c #000000",
-    "c c #000000",
-    "d c #000000",
-    "e c #000000",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````.........```",
-    "`````.......````",
-    "``````.....`````",
-    "```````...``````",
-    "````````.```````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````",
-    "````````````````"
-    ]
-
-
-#----------------------------------------------------------------------
-def GetMondrianData():
-    return \
-'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
-\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\
-ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\
-o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\
-\xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\
-\x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\
-\x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82' 
-
-
-def GetMondrianBitmap():
-    return wx.BitmapFromImage(GetMondrianImage().Scale(16, 16))
-
-
-def GetMondrianImage():
-    import cStringIO
-    stream = cStringIO.StringIO(GetMondrianData())
-    return wx.ImageFromStream(stream)
-
-
-def GetMondrianIcon():
-    icon = wx.EmptyIcon()
-    icon.CopyFromBitmap(GetMondrianBitmap())
-    return icon
-#----------------------------------------------------------------------
-
-
-def LightColour(color, percent):
-    """ Brighten input colour by percent. """
-    
-    end_color = wx.WHITE
-    
-    rd = end_color.Red() - color.Red()
-    gd = end_color.Green() - color.Green()
-    bd = end_color.Blue() - color.Blue()
-
-    high = 100
-
-    # We take the percent way of the color from color -. white
-    i = percent
-    r = color.Red() + ((i*rd*100)/high)/100
-    g = color.Green() + ((i*gd*100)/high)/100
-    b = color.Blue() + ((i*bd*100)/high)/100
-    return wx.Colour(r, g, b)
-
-
-def RandomColour(): 
-    """ Creates a random colour. """
-    
-    r = random.randint(0, 255) # Random value betweem 0-255
-    g = random.randint(0, 255) # Random value betweem 0-255
-    b = random.randint(0, 255) # Random value betweem 0-255
-
-    return wx.Colour(r, g, b)
-
-
-def PaintStraightGradientBox(dc, rect, startColor, endColor, vertical=True):
-    """ Draws a gradient colored box from startColor to endColor. """
-
-    rd = endColor.Red() - startColor.Red()
-    gd = endColor.Green() - startColor.Green()
-    bd = endColor.Blue() - startColor.Blue()
-
-    # Save the current pen and brush
-    savedPen = dc.GetPen()
-    savedBrush = dc.GetBrush()
-
-    if vertical:
-        high = rect.GetHeight()-1
-    else:
-        high = rect.GetWidth()-1
-
-    if high < 1:
-        return
-
-    for i in xrange(high+1):
-    
-        r = startColor.Red() + ((i*rd*100)/high)/100
-        g = startColor.Green() + ((i*gd*100)/high)/100
-        b = startColor.Blue() + ((i*bd*100)/high)/100
-
-        p = wx.Pen(wx.Colour(r, g, b))
-        dc.SetPen(p)
-
-        if vertical:
-            dc.DrawLine(rect.x, rect.y+i, rect.x+rect.width, rect.y+i)
-        else:
-            dc.DrawLine(rect.x+i, rect.y, rect.x+i, rect.y+rect.height)
-    
-    # Restore the pen and brush
-    dc.SetPen(savedPen)
-    dc.SetBrush(savedBrush)
-
-
-
-# -----------------------------------------------------------------------------
-# Util functions
-# -----------------------------------------------------------------------------
-
-def DrawButton(dc, rect, focus, upperTabs):
-
-    # Define the rounded rectangle base on the given rect
-    # we need an array of 9 points for it
-    regPts = [wx.Point() for indx in xrange(9)]
-
-    if focus:
-        if upperTabs:
-            leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*8)
-            rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*8)
-        else:
-            leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*5)
-            rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*5)
-    else:
-        leftPt = wx.Point(rect.x, rect.y + (rect.height / 2))
-        rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 2))
-
-    # Define the top region
-    top = wx.RectPP(rect.GetTopLeft(), rightPt)
-    bottom = wx.RectPP(leftPt, rect.GetBottomRight())
-
-    topStartColor = wx.WHITE
-
-    if not focus:
-        topStartColor = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 50)
-
-    topEndColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
-    bottomStartColor = topEndColor
-    bottomEndColor = topEndColor
-
-    # Incase we use bottom tabs, switch the colors
-    if upperTabs:
-        if focus:
-            PaintStraightGradientBox(dc, top, topStartColor, topEndColor)
-            PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor)
-        else:
-            PaintStraightGradientBox(dc, top, topEndColor , topStartColor)
-            PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor)
-
-    else:
-        if focus:
-            PaintStraightGradientBox(dc, bottom, topEndColor, bottomEndColor)
-            PaintStraightGradientBox(dc, top,topStartColor,  topStartColor)
-        else:
-            PaintStraightGradientBox(dc, bottom, bottomStartColor, bottomEndColor)
-            PaintStraightGradientBox(dc, top, topEndColor, topStartColor)
-    
-    dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBDropSource
-# Gives Some Custom UI Feedback during the DnD Operations
-# ---------------------------------------------------------------------------- #
-
-class FNBDropSource(wx.DropSource):
-    """
-    Give some custom UI feedback during the drag and drop operation in this
-    function. It is called on each mouse move, so your implementation must
-    not be too slow.
-    """
-    
-    def __init__(self, win):
-        """ Default class constructor. Used internally. """
-        
-        wx.DropSource.__init__(self, win)
-        self._win = win
-
-
-    def GiveFeedback(self, effect):
-        """ Provides user with a nice feedback when tab is being dragged. """
-
-        self._win.DrawDragHint()
-        return False
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBDragInfo
-# Stores All The Information To Allow Drag And Drop Between Different
-# FlatNotebooks.
-# ---------------------------------------------------------------------------- #
-
-class FNBDragInfo:
-
-    _map = weakref.WeakValueDictionary()
-
-    def __init__(self, container, pageindex):
-        """ Default class constructor. """
-        
-        self._id = id(container)
-        FNBDragInfo._map[self._id] = container
-        self._pageindex = pageindex
-
-
-    def GetContainer(self):
-        """ Returns the L{FlatNotebook} page (usually a panel). """
-        
-        return FNBDragInfo._map.get(self._id, None)
-
-
-    def GetPageIndex(self):
-        """ Returns the page index associated with a page. """
-
-        return self._pageindex        
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBDropTarget
-# Simply Used To Handle The OnDrop() Method When Dragging And Dropping Between
-# Different FlatNotebooks.
-# ---------------------------------------------------------------------------- #
-
-class FNBDropTarget(wx.DropTarget):
-
-    def __init__(self, parent):
-        """ Default class constructor. """
-        
-        wx.DropTarget.__init__(self)
-
-        self._parent = parent
-        self._dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook"))
-        self.SetDataObject(self._dataobject)
-
-
-    def OnData(self, x, y, dragres):
-        """ Handles the OnData() method to call the real DnD routine. """
-        
-        if not self.GetData():
-            return wx.DragNone
-
-        draginfo = self._dataobject.GetData()
-        drginfo = cPickle.loads(draginfo)
-        
-        return self._parent.OnDropTarget(x, y, drginfo.GetPageIndex(), drginfo.GetContainer())
-
-
-# ---------------------------------------------------------------------------- #
-# Class PageInfo
-# Contains parameters for every FlatNotebook page
-# ---------------------------------------------------------------------------- #
-
-class PageInfo:
-    """
-    This class holds all the information (caption, image, etc...) belonging to a
-    single tab in L{FlatNotebook}.
-    """
-    
-    def __init__(self, caption="", imageindex=-1, tabangle=0, enabled=True):
-        """
-        Default Class Constructor.
-
-        Parameters:
-        @param caption: the tab caption;
-        @param imageindex: the tab image index based on the assigned (set) wx.ImageList (if any);
-        @param tabangle: the tab angle (only on standard tabs, from 0 to 15 degrees);
-        @param enabled: sets enabled or disabled the tab.
-        """
-
-        self._strCaption = caption
-        self._TabAngle = tabangle
-        self._ImageIndex = imageindex
-        self._bEnabled = enabled
-        self._pos = wx.Point(-1, -1)
-        self._size = wx.Size(-1, -1)
-        self._region = wx.Region()
-        self._xRect = wx.Rect()
-        self._color = None
-        self._hasFocus = False
-
-
-    def SetCaption(self, value):
-        """ Sets the tab caption. """
-        
-        self._strCaption = value
-
-
-    def GetCaption(self):
-        """ Returns the tab caption. """
-
-        return self._strCaption
-
-
-    def SetPosition(self, value):
-        """ Sets the tab position. """
-
-        self._pos = value
-
-
-    def GetPosition(self):
-        """ Returns the tab position. """
-
-        return self._pos
-
-
-    def SetSize(self, value):
-        """ Sets the tab size. """
-
-        self._size = value
-
-
-    def GetSize(self):
-        """ Returns the tab size. """
-
-        return self._size
-
-
-    def SetTabAngle(self, value):
-        """ Sets the tab header angle (0 <= tab <= 15 degrees). """
-
-        self._TabAngle = min(45, value)
-
-
-    def GetTabAngle(self):
-        """ Returns the tab angle. """
-
-        return self._TabAngle
-
-    
-    def SetImageIndex(self, value):
-        """ Sets the tab image index. """
-
-        self._ImageIndex = value
-
-
-    def GetImageIndex(self):
-        """ Returns the tab umage index. """
-
-        return self._ImageIndex
-
-
-    def GetEnabled(self):
-        """ Returns whether the tab is enabled or not. """
-
-        return self._bEnabled 
-
-
-    def EnableTab(self, enabled):
-        """ Sets the tab enabled or disabled. """
-
-        self._bEnabled = enabled 
-
-
-    def SetRegion(self, points=[]):
-        """ Sets the tab region. """
-        
-        self._region = wx.RegionFromPoints(points) 
-
-
-    def GetRegion(self):
-        """ Returns the tab region. """
-
-        return self._region  
-
-
-    def SetXRect(self, xrect):
-        """ Sets the button 'X' area rect. """
-
-        self._xRect = xrect 
-
-
-    def GetXRect(self):
-        """ Returns the button 'X' area rect. """
-
-        return self._xRect 
-
-
-    def GetColour(self):
-        """ Returns the tab colour. """
-
-        return self._color 
-
-
-    def SetColour(self, color):
-        """ Sets the tab colour. """
-
-        self._color = color 
-
-
-# ---------------------------------------------------------------------------- #
-# Class FlatNotebookEvent
-# ---------------------------------------------------------------------------- #
-
-class FlatNotebookEvent(wx.PyCommandEvent):
-    """
-    This events will be sent when a EVT_FLATNOTEBOOK_PAGE_CHANGED,
-    EVT_FLATNOTEBOOK_PAGE_CHANGING, EVT_FLATNOTEBOOK_PAGE_CLOSING,
-    EVT_FLATNOTEBOOK_PAGE_CLOSED and EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU is
-    mapped in the parent.
-    """
-        
-    def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1):
-        """ Default class constructor. """
-
-        wx.PyCommandEvent.__init__(self, eventType, id)
-        self._eventType = eventType
-
-        self.notify = wx.NotifyEvent(eventType, id)
-
-
-    def GetNotifyEvent(self):
-        """Returns the actual wx.NotifyEvent."""
-        
-        return self.notify
-
-
-    def IsAllowed(self):
-        """Returns whether the event is allowed or not."""
-
-        return self.notify.IsAllowed()
-
-
-    def Veto(self):
-        """Vetos the event."""
-
-        self.notify.Veto()
-
-
-    def Allow(self):
-        """The event is allowed."""
-
-        self.notify.Allow()
-
-
-    def SetSelection(self, nSel):
-        """ Sets event selection. """
-        
-        self._selection = nSel
-        
-
-    def SetOldSelection(self, nOldSel):
-        """ Sets old event selection. """
-        
-        self._oldselection = nOldSel
-
-
-    def GetSelection(self):
-        """ Returns event selection. """
-        
-        return self._selection
-        
-
-    def GetOldSelection(self):
-        """ Returns old event selection """
-        
-        return self._oldselection
-
-
-# ---------------------------------------------------------------------------- #
-# Class TabNavigatorWindow
-# ---------------------------------------------------------------------------- #
-
-class TabNavigatorWindow(wx.Dialog):
-    """
-    This class is used to create a modal dialog that enables "Smart Tabbing",
-    similar to what you would get by hitting Alt+Tab on Windows.
-    """
-
-    def __init__(self, parent=None, icon=None):
-        """ Default class constructor. Used internally."""
-
-        wx.Dialog.__init__(self, parent, wx.ID_ANY, "", style=0)
-
-        self._selectedItem = -1
-        self._indexMap = []
-        
-        if icon is None:
-            self._bmp = GetMondrianBitmap()
-        else:
-            self._bmp = icon
-
-        sz = wx.BoxSizer(wx.VERTICAL)
-        
-        self._listBox = wx.ListBox(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, 150), [], wx.LB_SINGLE | wx.NO_BORDER)
-        
-        mem_dc = wx.MemoryDC()
-        mem_dc.SelectObject(wx.EmptyBitmap(1,1))
-        font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        font.SetWeight(wx.BOLD)
-        mem_dc.SetFont(font)
-
-        panelHeight = mem_dc.GetCharHeight()
-        panelHeight += 4 # Place a spacer of 2 pixels
-
-        # Out signpost bitmap is 24 pixels
-        if panelHeight < 24:
-            panelHeight = 24
-        
-        self._panel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.Size(200, panelHeight))
-
-        sz.Add(self._panel)
-        sz.Add(self._listBox, 1, wx.EXPAND)
-        
-        self.SetSizer(sz)
-
-        # Connect events to the list box
-        self._listBox.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
-        self._listBox.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
-        self._listBox.Bind(wx.EVT_LISTBOX_DCLICK, self.OnItemSelected)
-        
-        # Connect paint event to the panel
-        self._panel.Bind(wx.EVT_PAINT, self.OnPanelPaint)
-        self._panel.Bind(wx.EVT_ERASE_BACKGROUND, self.OnPanelEraseBg)
-
-        self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
-        self._listBox.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
-        self.PopulateListControl(parent)
-        
-        self.GetSizer().Fit(self)
-        self.GetSizer().SetSizeHints(self)
-        self.GetSizer().Layout()
-        self.Centre()
-
-        # Set focus on the list box to avoid having to click on it to change
-        # the tab selection under GTK.
-        self._listBox.SetFocus()
-
-
-    def OnKeyUp(self, event):
-        """Handles the wx.EVT_KEY_UP for the L{TabNavigatorWindow}."""
-        
-        if event.GetKeyCode() == wx.WXK_CONTROL:
-            self.CloseDialog()
-
-
-    def OnNavigationKey(self, event):
-        """Handles the wx.EVT_NAVIGATION_KEY for the L{TabNavigatorWindow}. """
-
-        selected = self._listBox.GetSelection()
-        bk = self.GetParent()
-        maxItems = bk.GetPageCount()
-            
-        if event.GetDirection():
-        
-            # Select next page
-            if selected == maxItems - 1:
-                itemToSelect = 0
-            else:
-                itemToSelect = selected + 1
-        
-        else:
-        
-            # Previous page
-            if selected == 0:
-                itemToSelect = maxItems - 1
-            else:
-                itemToSelect = selected - 1
-        
-        self._listBox.SetSelection(itemToSelect)
-
-
-    def PopulateListControl(self, book):
-        """Populates the L{TabNavigatorWindow} listbox with a list of tabs."""
-
-        selection = book.GetSelection()
-        count = book.GetPageCount()
-        
-        self._listBox.Append(book.GetPageText(selection))
-        self._indexMap.append(selection)
-        
-        prevSel = book.GetPreviousSelection()
-        
-        if prevSel != wx.NOT_FOUND:
-        
-            # Insert the previous selection as second entry 
-            self._listBox.Append(book.GetPageText(prevSel))
-            self._indexMap.append(prevSel)
-        
-        for c in xrange(count):
-        
-            # Skip selected page
-            if c == selection:
-                continue
-
-            # Skip previous selected page as well
-            if c == prevSel:
-                continue
-
-            self._listBox.Append(book.GetPageText(c))
-            self._indexMap.append(c)
-
-        # Select the next entry after the current selection
-        self._listBox.SetSelection(0)
-        dummy = wx.NavigationKeyEvent()
-        dummy.SetDirection(True)
-        self.OnNavigationKey(dummy)
-
-
-    def OnItemSelected(self, event):
-        """Handles the wx.EVT_LISTBOX_DCLICK event for the wx.ListBox inside L{TabNavigatorWindow}. """
-
-        self.CloseDialog()
-
-
-    def CloseDialog(self):
-        """Closes the L{TabNavigatorWindow} dialog, setting selection in L{FlatNotebook}."""
-
-        bk = self.GetParent()
-        self._selectedItem = self._listBox.GetSelection()
-        iter = self._indexMap[self._selectedItem]
-        self.EndModal(wx.ID_OK)
-        wx.CallAfter(bk._pages.FireEvent, iter)
-        self.Destroy()
-        
-
-    def OnPanelPaint(self, event):
-        """Handles the wx.EVT_PAINT event for L{TabNavigatorWindow} top panel. """
-
-        dc = wx.PaintDC(self._panel)
-        rect = self._panel.GetClientRect()
-
-        bmp = wx.EmptyBitmap(rect.width, rect.height)
-
-        mem_dc = wx.MemoryDC()
-        mem_dc.SelectObject(bmp)
-
-        endColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
-        startColour = LightColour(endColour, 50)
-        PaintStraightGradientBox(mem_dc, rect, startColour, endColour)
-
-        # Draw the caption title and place the bitmap
-        # get the bitmap optimal position, and draw it
-        bmpPt, txtPt = wx.Point(), wx.Point()
-        bmpPt.y = (rect.height - self._bmp.GetHeight())/2
-        bmpPt.x = 3
-        mem_dc.DrawBitmap(self._bmp, bmpPt.x, bmpPt.y, True)
-
-        # get the text position, and draw it
-        font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        font.SetWeight(wx.BOLD)
-        mem_dc.SetFont(font)
-        fontHeight = mem_dc.GetCharHeight()
-        
-        txtPt.x = bmpPt.x + self._bmp.GetWidth() + 4
-        txtPt.y = (rect.height - fontHeight)/2
-        mem_dc.SetTextForeground(wx.WHITE)
-        mem_dc.DrawText("Opened tabs:", txtPt.x, txtPt.y)
-        mem_dc.SelectObject(wx.NullBitmap)
-        
-        dc.DrawBitmap(bmp, 0, 0)
-
-
-    def OnPanelEraseBg(self, event):
-        """Handles the wx.EVT_ERASE_BACKGROUND event for L{TabNavigatorWindow} top panel. """
-
-        pass
-
-
-# ---------------------------------------------------------------------------- #
-# Class FNBRenderer
-# ---------------------------------------------------------------------------- #
-
-class FNBRenderer:
-    """
-    Parent class for the 4 renderers defined: I{Standard}, I{VC71}, I{Fancy}
-    and I{VC8}. This class implements the common methods of all 4 renderers.
-    """
-
-    def __init__(self):
-        """Default class constructor. """
-        
-        self._tabHeight = None
-
-        if wx.Platform == "__WXMAC__":
-            # Hack to get proper highlight color for focus rectangle from
-            # current theme by creating a theme brush and getting its color.
-            # kThemeBrushFocusHighlight is available on Mac OS 8.5 and higher
-            brush = wx.BLACK_BRUSH
-            brush.MacSetTheme(Carbon.Appearance.kThemeBrushFocusHighlight)
-            self._focusPen = wx.Pen(brush.GetColour(), 2, wx.SOLID)
-        else:
-            self._focusPen = wx.Pen(wx.BLACK, 1, wx.USER_DASH)
-            self._focusPen.SetDashes([1, 1])
-            self._focusPen.SetCap(wx.CAP_BUTT)
-
-
-    def GetLeftButtonPos(self, pageContainer):
-        """ Returns the left button position in the navigation area. """
-
-        pc = pageContainer
-        style = pc.GetParent().GetWindowStyleFlag()
-        rect = pc.GetClientRect()
-        clientWidth = rect.width
-        
-        if style & FNB_NO_X_BUTTON and (style & FNB_DROPDOWN_TABS_LIST != FNB_DROPDOWN_TABS_LIST):
-            return clientWidth - 38
-        else:
-            return clientWidth - 54
-
-
-    def GetRightButtonPos(self, pageContainer):
-        """ Returns the right button position in the navigation area. """
-
-        pc = pageContainer
-        style = pc.GetParent().GetWindowStyleFlag()
-        rect = pc.GetClientRect()
-        clientWidth = rect.width
-        
-        if style & FNB_NO_X_BUTTON and (style & FNB_DROPDOWN_TABS_LIST != FNB_DROPDOWN_TABS_LIST):
-            return clientWidth - 22
-        else:
-            return clientWidth - 38
-
-
-    def GetDropArrowButtonPos(self, pageContainer):
-        """ Returns the drop down button position in the navigation area. """
-
-        pc = pageContainer
-        style = pc.GetParent().GetWindowStyleFlag()
-        rect = pc.GetClientRect()
-        clientWidth = rect.width
-
-        if style & FNB_DROPDOWN_TABS_LIST != FNB_DROPDOWN_TABS_LIST:
-            return clientWidth
-        else:
-            return clientWidth - 22
-
-
-    def GetXPos(self, pageContainer):
-        """ Returns the 'X' button position in the navigation area. """
-
-        pc = pageContainer
-        style = pc.GetParent().GetWindowStyleFlag()
-        rect = pc.GetClientRect()
-        clientWidth = rect.width
-        
-        if style & FNB_NO_X_BUTTON:
-            return clientWidth
-        else:
-            return clientWidth - 22
-
-
-    def GetButtonsAreaLength(self, pageContainer):
-        """ Returns the navigation area width. """
-
-        pc = pageContainer
-        style = pc.GetParent().GetWindowStyleFlag()
-
-        # ''
-        if style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
-            return 0
-
-        # 'x'        
-        elif style & FNB_NO_NAV_BUTTONS and not style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
-            return 22
-        
-        # '<>'
-        if not style & FNB_NO_NAV_BUTTONS and style & FNB_NO_X_BUTTON and not style & FNB_DROPDOWN_TABS_LIST:
-            return 53 - 16
-        
-        # 'vx'
-        if style & FNB_DROPDOWN_TABS_LIST and not style & FNB_NO_X_BUTTON:
-            return 22 + 16
-
-        # 'v'
-        if style & FNB_DROPDOWN_TABS_LIST and style & FNB_NO_X_BUTTON and style & FNB_NO_NAV_BUTTONS:
-            return 22
-
-        # '<>v'
-        if style & FNB_DROPDOWN_TABS_LIST and style & FNB_NO_X_BUTTON and not style & FNB_NO_NAV_BUTTONS:
-            return 53
-        
-        # '<>x'
-        return 53
-
-
-    def DrawArrowAccordingToState(self, dc, pc, rect):
-
-        lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
-        PaintStraightGradientBox(dc, rect, pc._tabAreaColor, LightColour(pc._tabAreaColor, lightFactor))
-
-    
-    def DrawLeftArrow(self, pageContainer, dc):
-        """ Draw the left navigation arrow. """
-
-        pc = pageContainer
-        
-        style = pc.GetParent().GetWindowStyleFlag()
-        if style & FNB_NO_NAV_BUTTONS:
-            return
-
-        # Make sure that there are pages in the container
-        if not pc._pagesInfoVec:
-            return
-
-        # Set the bitmap according to the button status
-        if pc._nLeftButtonStatus == FNB_BTN_HOVER:
-            arrowBmp = wx.BitmapFromXPMData(left_arrow_hilite_xpm)
-        elif pc._nLeftButtonStatus == FNB_BTN_PRESSED:
-            arrowBmp = wx.BitmapFromXPMData(left_arrow_pressed_xpm)
-        else:
-            arrowBmp = wx.BitmapFromXPMData(left_arrow_xpm)
-
-        if pc._nFrom == 0:
-            # Handle disabled arrow
-            arrowBmp = wx.BitmapFromXPMData(left_arrow_disabled_xpm)
-        
-        arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR))
-
-        # Erase old bitmap
-        posx = self.GetLeftButtonPos(pc)
-        self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14))
-        
-        # Draw the new bitmap
-        dc.DrawBitmap(arrowBmp, posx, 6, True)
-
-
-    def DrawRightArrow(self, pageContainer, dc):
-        """ Draw the right navigation arrow. """
-
-        pc = pageContainer
-        
-        style = pc.GetParent().GetWindowStyleFlag()
-        if style & FNB_NO_NAV_BUTTONS:
-            return
-
-        # Make sure that there are pages in the container
-        if not pc._pagesInfoVec:
-            return
-
-        # Set the bitmap according to the button status
-        if pc._nRightButtonStatus == FNB_BTN_HOVER:        
-            arrowBmp = wx.BitmapFromXPMData(right_arrow_hilite_xpm)
-        elif pc._nRightButtonStatus == FNB_BTN_PRESSED:
-            arrowBmp = wx.BitmapFromXPMData(right_arrow_pressed_xpm)
-        else:
-            arrowBmp = wx.BitmapFromXPMData(right_arrow_xpm)
-
-        # Check if the right most tab is visible, if it is
-        # don't rotate right anymore
-        if pc._pagesInfoVec[-1].GetPosition() != wx.Point(-1, -1):
-            arrowBmp = wx.BitmapFromXPMData(right_arrow_disabled_xpm)
-        
-        arrowBmp.SetMask(wx.Mask(arrowBmp, MASK_COLOR))
-
-        # erase old bitmap
-        posx = self.GetRightButtonPos(pc)
-        self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14))
-
-        # Draw the new bitmap
-        dc.DrawBitmap(arrowBmp, posx, 6, True)
-
-
-    def DrawDropDownArrow(self, pageContainer, dc):
-        """ Draws the drop-down arrow in the navigation area. """
-
-        pc = pageContainer
-        
-        # Check if this style is enabled
-        style = pc.GetParent().GetWindowStyleFlag()
-        if not style & FNB_DROPDOWN_TABS_LIST:
-            return
-
-        # Make sure that there are pages in the container
-        if not pc._pagesInfoVec:
-            return
-
-        if pc._nArrowDownButtonStatus == FNB_BTN_HOVER:
-            downBmp = wx.BitmapFromXPMData(down_arrow_hilite_xpm)
-        elif pc._nArrowDownButtonStatus == FNB_BTN_PRESSED:
-            downBmp = wx.BitmapFromXPMData(down_arrow_pressed_xpm)
-        else:
-            downBmp = wx.BitmapFromXPMData(down_arrow_xpm)
-
-        downBmp.SetMask(wx.Mask(downBmp, MASK_COLOR))
-
-        # erase old bitmap
-        posx = self.GetDropArrowButtonPos(pc)
-        self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14))
-
-        # Draw the new bitmap
-        dc.DrawBitmap(downBmp, posx, 6, True)
-
-
-    def DrawX(self, pageContainer, dc):
-        """ Draw the 'X' navigation button in the navigation area. """
-
-        pc = pageContainer
-        
-        # Check if this style is enabled
-        style = pc.GetParent().GetWindowStyleFlag()
-        if style & FNB_NO_X_BUTTON:
-            return
-
-        # Make sure that there are pages in the container
-        if not pc._pagesInfoVec:
-            return
-
-        # Set the bitmap according to the button status
-        if pc._nXButtonStatus == FNB_BTN_HOVER:
-            xbmp = wx.BitmapFromXPMData(x_button_hilite_xpm)
-        elif pc._nXButtonStatus == FNB_BTN_PRESSED:
-            xbmp = wx.BitmapFromXPMData(x_button_pressed_xpm)
-        else:
-            xbmp = wx.BitmapFromXPMData(x_button_xpm)
-
-        xbmp.SetMask(wx.Mask(xbmp, MASK_COLOR))
-        
-        # erase old bitmap
-        posx = self.GetXPos(pc) 
-        self.DrawArrowAccordingToState(dc, pc, wx.Rect(posx, 6, 16, 14))
-
-        # Draw the new bitmap
-        dc.DrawBitmap(xbmp, posx, 6, True)
-
-
-    def DrawTabX(self, pageContainer, dc, rect, tabIdx, btnStatus):
-        """ Draws the 'X' in the selected tab. """
-
-        pc = pageContainer
-        if not pc.HasFlag(FNB_X_ON_TAB):
-            return
-
-        # We draw the 'x' on the active tab only
-        if tabIdx != pc.GetSelection() or tabIdx < 0:
-            return
-
-        # Set the bitmap according to the button status
-        
-        if btnStatus == FNB_BTN_HOVER:
-            xBmp = wx.BitmapFromXPMData(x_button_hilite_xpm)
-        elif btnStatus == FNB_BTN_PRESSED:
-            xBmp = wx.BitmapFromXPMData(x_button_pressed_xpm)
-        else:
-            xBmp = wx.BitmapFromXPMData(x_button_xpm)
-
-        # Set the masking
-        xBmp.SetMask(wx.Mask(xBmp, MASK_COLOR))
-
-        # Draw the new bitmap
-        dc.DrawBitmap(xBmp, rect.x, rect.y, True)
-
-        # Update the vector
-        rr = wx.Rect(rect.x, rect.y, 14, 13)
-        pc._pagesInfoVec[tabIdx].SetXRect(rr)
-
-
-    def DrawTabsLine(self, pageContainer, dc, selTabX1=-1, selTabX2=-1):
-        """ Draws a line over the tabs. """
-
-        pc = pageContainer
-        
-        clntRect = pc.GetClientRect()
-        clientRect3 = wx.Rect(0, 0, clntRect.width, clntRect.height)
-
-        if pc.HasFlag(FNB_FF2):
-            if not pc.HasFlag(FNB_BOTTOM):
-                fillColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
-            else:
-                fillColor = wx.WHITE
-
-            dc.SetPen(wx.Pen(fillColor))
-
-            if pc.HasFlag(FNB_BOTTOM):
-
-                dc.DrawLine(1, 0, clntRect.width-1, 0)
-                dc.DrawLine(1, 1, clntRect.width-1, 1)
-
-                dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
-                dc.DrawLine(1, 2, clntRect.width-1, 2)
-
-                dc.SetPen(wx.Pen(fillColor))
-                dc.DrawLine(selTabX1 + 2, 2, selTabX2 - 1, 2)
-                
-            else:
-                
-                dc.DrawLine(1, clntRect.height, clntRect.width-1, clntRect.height)
-                dc.DrawLine(1, clntRect.height-1, clntRect.width-1, clntRect.height-1)
-
-                dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
-                dc.DrawLine(1, clntRect.height-2, clntRect.width-1, clntRect.height-2)
-
-                dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
-                dc.DrawLine(selTabX1 + 2, clntRect.height-2, selTabX2-1, clntRect.height-2)
-
-        else:
-            
-            if pc.HasFlag(FNB_BOTTOM):
-            
-                clientRect = wx.Rect(0, 2, clntRect.width, clntRect.height - 2)
-                clientRect2 = wx.Rect(0, 1, clntRect.width, clntRect.height - 1)
-            
-            else:
-            
-                clientRect = wx.Rect(0, 0, clntRect.width, clntRect.height - 2)
-                clientRect2 = wx.Rect(0, 0, clntRect.width, clntRect.height - 1)
-            
-            dc.SetBrush(wx.TRANSPARENT_BRUSH)
-            dc.SetPen(wx.Pen(pc.GetSingleLineBorderColour()))
-            dc.DrawRectangleRect(clientRect2)
-            dc.DrawRectangleRect(clientRect3)
-
-            dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
-            dc.DrawRectangleRect(clientRect)
-
-            if not pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
-            
-                dc.SetPen(wx.Pen((pc.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [pc._tabAreaColor])[0]))
-                dc.DrawLine(0, 0, 0, clientRect.height+1)
-                
-                if pc.HasFlag(FNB_BOTTOM):
-                
-                    dc.DrawLine(0, clientRect.height+1, clientRect.width, clientRect.height+1)
-                
-                else:
-                    
-                    dc.DrawLine(0, 0, clientRect.width, 0)
-                    
-                dc.DrawLine(clientRect.width - 1, 0, clientRect.width - 1, clientRect.height+1)
-
-
-    def CalcTabWidth(self, pageContainer, tabIdx, tabHeight):
-        """ Calculates the width of the input tab. """
-
-        pc = pageContainer
-        dc = wx.MemoryDC()
-        dc.SelectObject(wx.EmptyBitmap(1,1))
-
-        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-
-        if pc.IsDefaultTabs():
-            shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
-
-        # Calculate the text length using the bold font, so when selecting a tab
-        # its width will not change
-        dc.SetFont(boldFont)
-        width, pom = dc.GetTextExtent(pc.GetPageText(tabIdx))
-
-        # Set a minimum size to a tab
-        if width < 20:
-            width = 20
-
-        tabWidth = 2*pc._pParent.GetPadding() + width
-
-        # Style to add a small 'x' button on the top right
-        # of the tab
-        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-            # The xpm image that contains the 'x' button is 9 pixels
-            spacer = 9
-            if pc.HasFlag(FNB_VC8):
-                spacer = 4
-
-            tabWidth += pc._pParent.GetPadding() + spacer
-        
-        if pc.IsDefaultTabs():
-            # Default style
-            tabWidth += 2*shapePoints
-
-        hasImage = pc._ImageList != None and pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
-
-        # For VC71 style, we only add the icon size (16 pixels)
-        if hasImage:
-        
-            if not pc.IsDefaultTabs():
-                tabWidth += 16 + pc._pParent.GetPadding()
-            else:
-                # Default style
-                tabWidth += 16 + pc._pParent.GetPadding() + shapePoints/2
-        
-        return tabWidth
-
-
-    def CalcTabHeight(self, pageContainer):
-        """ Calculates the height of the input tab. """
-
-        if self._tabHeight:
-            return self._tabHeight
-
-        pc = pageContainer
-        dc = wx.MemoryDC()
-        dc.SelectObject(wx.EmptyBitmap(1,1))
-
-        # For GTK it seems that we must do this steps in order
-        # for the tabs will get the proper height on initialization
-        # on MSW, preforming these steps yields wierd results
-        normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont = normalFont
-
-        if "__WXGTK__" in wx.PlatformInfo:
-            boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-            dc.SetFont(boldFont)
-
-        height = dc.GetCharHeight()
-        
-        tabHeight = height + FNB_HEIGHT_SPACER # We use 8 pixels as padding
-        if "__WXGTK__" in wx.PlatformInfo:
-            # On GTK the tabs are should be larger
-            tabHeight += 6
-
-        self._tabHeight = tabHeight
-        
-        return tabHeight
-
-
-    def DrawTabs(self, pageContainer, dc):
-        """ Actually draws the tabs in L{FlatNotebook}."""
-
-        pc = pageContainer
-        if "__WXMAC__" in wx.PlatformInfo:
-            # Works well on MSW & GTK, however this lines should be skipped on MAC
-            if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec):
-                pc.Hide()
-                return
-            
-        # Get the text hight
-        tabHeight = self.CalcTabHeight(pageContainer)
-        style = pc.GetParent().GetWindowStyleFlag()
-
-        # Calculate the number of rows required for drawing the tabs
-        rect = pc.GetClientRect()
-        clientWidth = rect.width
-
-        # Set the maximum client size
-        pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight)
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-
-        if style & FNB_VC71:
-            backBrush = wx.Brush(wx.Colour(247, 243, 233))
-        else:
-            backBrush = wx.Brush(pc._tabAreaColor)
-
-        noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
-        selBrush = wx.Brush(pc._activeTabColor)
-
-        size = pc.GetSize()
-
-        # Background
-        dc.SetTextBackground((style & FNB_VC71 and [wx.Colour(247, 243, 233)] or [pc.GetBackgroundColour()])[0])
-        dc.SetTextForeground(pc._activeTextColor)
-        dc.SetBrush(backBrush)
-
-        # If border style is set, set the pen to be border pen
-        if pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
-            dc.SetPen(borderPen)
-        else:
-            colr = (pc.HasFlag(FNB_VC71) and [wx.Colour(247, 243, 233)] or [pc.GetBackgroundColour()])[0]
-            dc.SetPen(wx.Pen(colr))
-
-        if pc.HasFlag(FNB_FF2):
-            lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
-            PaintStraightGradientBox(dc, pc.GetClientRect(), pc._tabAreaColor, LightColour(pc._tabAreaColor, lightFactor))
-            dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
-        dc.DrawRectangle(0, 0, size.x, size.y)
-
-        # We always draw the bottom/upper line of the tabs
-        # regradless the style
-        dc.SetPen(borderPen)
-
-        if not pc.HasFlag(FNB_FF2):
-            self.DrawTabsLine(pc, dc)
-
-        # Restore the pen
-        dc.SetPen(borderPen)
-
-        if pc.HasFlag(FNB_VC71):
-        
-            greyLineYVal  = (pc.HasFlag(FNB_BOTTOM) and [0] or [size.y - 2])[0]
-            whiteLineYVal = (pc.HasFlag(FNB_BOTTOM) and [3] or [size.y - 3])[0]
-
-            pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))
-            dc.SetPen(pen)
-
-            # Draw thik grey line between the windows area and
-            # the tab area
-            for num in xrange(3):
-                dc.DrawLine(0, greyLineYVal + num, size.x, greyLineYVal + num)
-
-            wbPen = (pc.HasFlag(FNB_BOTTOM) and [wx.BLACK_PEN] or [wx.WHITE_PEN])[0]
-            dc.SetPen(wbPen)
-            dc.DrawLine(1, whiteLineYVal, size.x - 1, whiteLineYVal)
-
-            # Restore the pen
-            dc.SetPen(borderPen)
-        
-        # Draw labels
-        normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-        dc.SetFont(boldFont)
-
-        posx = pc._pParent.GetPadding()
-
-        # Update all the tabs from 0 to 'pc._nFrom' to be non visible
-        for i in xrange(pc._nFrom):
-        
-            pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
-            pc._pagesInfoVec[i].GetRegion().Clear()
-
-        count = pc._nFrom
-        
-        #----------------------------------------------------------
-        # Go over and draw the visible tabs
-        #----------------------------------------------------------
-        x1 = x2 = -1
-        for i in xrange(pc._nFrom, len(pc._pagesInfoVec)):
-        
-            dc.SetPen(borderPen)
-
-            if not pc.HasFlag(FNB_FF2):
-                dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0])
-
-            # Now set the font to the correct font
-            dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0])
-
-            # Add the padding to the tab width
-            # Tab width:
-            # +-----------------------------------------------------------+
-            # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
-            # +-----------------------------------------------------------+
-            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
-
-            # Check if we can draw more
-            if posx + tabWidth + self.GetButtonsAreaLength(pc) >= clientWidth:
-                break
-
-            count = count + 1
-            
-            # By default we clean the tab region
-            pc._pagesInfoVec[i].GetRegion().Clear()
-
-            # Clean the 'x' buttn on the tab.
-            # A 'Clean' rectangle, is a rectangle with width or height
-            # with values lower than or equal to 0
-            pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1))
-
-            # Draw the tab (border, text, image & 'x' on tab)
-            self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus)
-
-            if pc.GetSelection() == i:
-                x1 = posx
-                x2 = posx + tabWidth + 2
-
-            # Restore the text forground
-            dc.SetTextForeground(pc._activeTextColor)
-
-            # Update the tab position & size
-            posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0]
-
-            pc._pagesInfoVec[i].SetPosition(wx.Point(posx, posy))
-            pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight))
-            self.DrawFocusRectangle(dc, pc, pc._pagesInfoVec[i])
-
-            posx += tabWidth
-        
-        # Update all tabs that can not fit into the screen as non-visible
-        for i in xrange(count, len(pc._pagesInfoVec)):
-            pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
-            pc._pagesInfoVec[i].GetRegion().Clear()
-        
-        # Draw the left/right/close buttons
-        # Left arrow
-        self.DrawLeftArrow(pc, dc)
-        self.DrawRightArrow(pc, dc)
-        self.DrawX(pc, dc)
-        self.DrawDropDownArrow(pc, dc)
-
-        if pc.HasFlag(FNB_FF2):
-            self.DrawTabsLine(pc, dc, x1, x2)
-
-
-    def DrawFocusRectangle(self, dc, pageContainer, page):
-        """ Draws a focus rectangle like the native Notebooks. """
-        
-        if not page._hasFocus:
-            return
-
-        tabPos = wx.Point(*page.GetPosition())
-        if pageContainer.GetParent().GetWindowStyleFlag() & FNB_VC8:
-            vc8ShapeLen = self.CalcTabHeight(pageContainer) - VERTICAL_BORDER_PADDING - 2
-            tabPos.x += vc8ShapeLen
-            
-        rect = wx.RectPS(tabPos, page.GetSize())
-        rect = wx.Rect(rect.x+2, rect.y+2, rect.width-4, rect.height-8)
-
-        if wx.Platform == '__WXMAC__':
-            rect.SetWidth(rect.GetWidth() + 1)
-
-        dc.SetBrush(wx.TRANSPARENT_BRUSH)
-        dc.SetPen(self._focusPen)
-        dc.DrawRoundedRectangleRect(rect, 2)
-        
-
-    def DrawDragHint(self, pc, tabIdx):
-        """
-        Draws tab drag hint, the default implementation is to do nothing.
-        You can override this function to provide a nice feedback to user.
-        """
-        
-        pass
-
-
-    def NumberTabsCanFit(self, pageContainer, fr=-1):
-
-        pc = pageContainer
-        
-        rect = pc.GetClientRect()
-        clientWidth = rect.width
-
-        vTabInfo = []
-
-        tabHeight = self.CalcTabHeight(pageContainer)
-
-        # The drawing starts from posx 
-        posx = pc._pParent.GetPadding()
-
-        if fr < 0:
-            fr = pc._nFrom
-
-        for i in xrange(fr, len(pc._pagesInfoVec)):
-
-            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight) 
-            if posx + tabWidth + self.GetButtonsAreaLength(pc) >= clientWidth:
-                break; 
-
-            # Add a result to the returned vector 
-            tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth , tabHeight)
-            vTabInfo.append(tabRect)
-
-            # Advance posx 
-            posx += tabWidth + FNB_HEIGHT_SPACER
-
-        return vTabInfo
-
-    
-# ---------------------------------------------------------------------------- #
-# Class FNBRendererMgr
-# A manager that handles all the renderers defined below and calls the
-# appropriate one when drawing is needed
-# ---------------------------------------------------------------------------- #
-
-class FNBRendererMgr:
-    """
-    This class represents a manager that handles all the 4 renderers defined
-    and calls the appropriate one when drawing is needed.
-    """
-
-    def __init__(self):
-        """ Default class constructor. """
-        
-        # register renderers
-
-        self._renderers = {}        
-        self._renderers.update({-1: FNBRendererDefault()})
-        self._renderers.update({FNB_VC71: FNBRendererVC71()})
-        self._renderers.update({FNB_FANCY_TABS: FNBRendererFancy()})
-        self._renderers.update({FNB_VC8: FNBRendererVC8()})
-        self._renderers.update({FNB_FF2: FNBRendererFirefox2()})
-
-
-    def GetRenderer(self, style):
-        """ Returns the current renderer based on the style selected. """
-
-        if style & FNB_VC71:
-            return self._renderers[FNB_VC71]
-
-        if style & FNB_FANCY_TABS:
-            return self._renderers[FNB_FANCY_TABS]
-
-        if style & FNB_VC8:
-            return self._renderers[FNB_VC8]
-
-        if style & FNB_FF2:
-            return self._renderers[FNB_FF2]
-
-        # the default is to return the default renderer
-        return self._renderers[-1]
-
-
-#------------------------------------------
-# Default renderer 
-#------------------------------------------
-
-class FNBRendererDefault(FNBRenderer):
-    """
-    This class handles the drawing of tabs using the I{Standard} renderer.
-    """
-    
-    def __init__(self):
-        """ Default class constructor. """
-
-        FNBRenderer.__init__(self)
-        
-
-    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
-        """ Draws a tab using the I{Standard} style. """
-
-        # Default style
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-        pc = pageContainer 
-
-        tabPoints = [wx.Point() for ii in xrange(7)]
-        tabPoints[0].x = posx
-        tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
-
-        tabPoints[1].x = int(posx+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
-        tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
-        tabPoints[2].x = tabPoints[1].x+2
-        tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
-        tabPoints[3].x = int(posx+tabWidth-(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))-2
-        tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
-        tabPoints[4].x = tabPoints[3].x+2
-        tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
-        tabPoints[5].x = int(tabPoints[4].x+(tabHeight-2)*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
-        tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
-
-        tabPoints[6].x = tabPoints[0].x
-        tabPoints[6].y = tabPoints[0].y
-        
-        if tabIdx == pc.GetSelection():
-        
-            # Draw the tab as rounded rectangle
-            dc.DrawPolygon(tabPoints)
-        
-        else:
-        
-            if tabIdx != pc.GetSelection() - 1:
-            
-                # Draw a vertical line to the right of the text
-                pt1x = tabPoints[5].x
-                pt1y = (pc.HasFlag(FNB_BOTTOM) and [4] or [tabHeight - 6])[0]
-                pt2x = tabPoints[5].x
-                pt2y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 4] or [4])[0]
-                dc.DrawLine(pt1x, pt1y, pt2x, pt2y)
-
-        if tabIdx == pc.GetSelection():
-        
-            savePen = dc.GetPen()
-            whitePen = wx.Pen(wx.WHITE)
-            whitePen.SetWidth(1)
-            dc.SetPen(whitePen)
-
-            secPt = wx.Point(tabPoints[5].x + 1, tabPoints[5].y)
-            dc.DrawLine(tabPoints[0].x, tabPoints[0].y, secPt.x, secPt.y)
-
-            # Restore the pen
-            dc.SetPen(savePen)
-        
-        # -----------------------------------
-        # Text and image drawing
-        # -----------------------------------
-
-        # Text drawing offset from the left border of the
-        # rectangle
-        
-        # The width of the images are 16 pixels
-        padding = pc.GetParent().GetPadding()
-        shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
-        hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
-        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
-
-        if hasImage:
-            textOffset = 2*pc._pParent._nPadding + 16 + shapePoints/2 
-        else:
-            textOffset = pc._pParent._nPadding + shapePoints/2 
-
-        textOffset += 2
-
-        if tabIdx != pc.GetSelection():
-        
-            # Set the text background to be like the vertical lines
-            dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
-        
-        if hasImage:
-        
-            imageXOffset = textOffset - 16 - padding
-            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
-                                     posx + imageXOffset, imageYCoord,
-                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)
-        
-        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-
-        # draw 'x' on tab (if enabled)
-        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-        
-            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
-            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
-            # take a bitmap from the position of the 'x' button (the x on tab button)
-            # this bitmap will be used later to delete old buttons
-            tabCloseButtonYCoord = imageYCoord
-            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-
-            # Draw the tab
-            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)            
-        
-
-#------------------------------------------
-# Firefox2 renderer 
-#------------------------------------------
-class FNBRendererFirefox2(FNBRenderer):
-    """
-    This class handles the drawing of tabs using the I{Firefox 2} renderer.
-    """
-    
-    def __init__(self):
-        """ Default class constructor. """
-
-        FNBRenderer.__init__(self)
-
-        
-    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
-        """ Draws a tab using the I{Firefox 2} style. """
-
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-        pc = pageContainer
-
-        tabPoints = [wx.Point() for indx in xrange(7)]
-        tabPoints[0].x = posx + 2
-        tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
-
-        tabPoints[1].x = tabPoints[0].x
-        tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
-        tabPoints[2].x = tabPoints[1].x+2
-        tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
-        tabPoints[3].x = posx + tabWidth - 2
-        tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
-        tabPoints[4].x = tabPoints[3].x + 2
-        tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
-        tabPoints[5].x = tabPoints[4].x
-        tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 2])[0]
-
-        tabPoints[6].x = tabPoints[0].x
-        tabPoints[6].y = tabPoints[0].y
-
-        #------------------------------------
-        # Paint the tab with gradient
-        #------------------------------------
-        rr = wx.RectPP(tabPoints[2], tabPoints[5])
-        DrawButton(dc, rr, pc.GetSelection() == tabIdx , not pc.HasFlag(FNB_BOTTOM))
-
-        dc.SetBrush(wx.TRANSPARENT_BRUSH)
-        dc.SetPen(borderPen)
-
-        # Draw the tab as rounded rectangle
-        dc.DrawPolygon(tabPoints)
-
-        # -----------------------------------
-        # Text and image drawing
-        # -----------------------------------
-
-        # The width of the images are 16 pixels
-        padding = pc.GetParent().GetPadding()
-        shapePoints = int(tabHeight*math.tan(float(pc._pagesInfoVec[tabIdx].GetTabAngle())/180.0*math.pi))
-        hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
-        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
-
-        if hasImage:
-            textOffset = 2*padding + 16 + shapePoints/2 
-        else:
-            textOffset = padding + shapePoints/2
-            
-        textOffset += 2
-
-        if tabIdx != pc.GetSelection():
-        
-            # Set the text background to be like the vertical lines
-            dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
-
-        if hasImage:
-            imageXOffset = textOffset - 16 - padding
-            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
-                               posx + imageXOffset, imageYCoord,
-                               wx.IMAGELIST_DRAW_TRANSPARENT, True)
-        
-        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-
-        # draw 'x' on tab (if enabled)
-        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-        
-            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
-            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
-            # take a bitmap from the position of the 'x' button (the x on tab button)
-            # this bitmap will be used later to delete old buttons
-            tabCloseButtonYCoord = imageYCoord
-            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-
-            # Draw the tab
-            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
-        
-
-#------------------------------------------------------------------
-# Visual studio 7.1 
-#------------------------------------------------------------------
-
-class FNBRendererVC71(FNBRenderer):
-    """
-    This class handles the drawing of tabs using the I{VC71} renderer.
-    """
-
-    def __init__(self):
-        """ Default class constructor. """
-
-        FNBRenderer.__init__(self)
-
-
-    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
-        """ Draws a tab using the I{VC71} style. """
-
-        # Visual studio 7.1 style
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-        pc = pageContainer
-
-        dc.SetPen((tabIdx == pc.GetSelection() and [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [borderPen])[0])
-        dc.SetBrush((tabIdx == pc.GetSelection() and [wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))] or [wx.Brush(wx.Colour(247, 243, 233))])[0])
-
-        if tabIdx == pc.GetSelection():
-        
-            posy = (pc.HasFlag(FNB_BOTTOM) and [0] or [VERTICAL_BORDER_PADDING])[0]
-            tabH = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - 5] or [tabHeight - 3])[0]
-            dc.DrawRectangle(posx, posy, tabWidth, tabH) 
-
-            # Draw a black line on the left side of the
-            # rectangle
-            dc.SetPen(wx.BLACK_PEN)
-
-            blackLineY1 = VERTICAL_BORDER_PADDING
-            blackLineY2 = tabH
-            dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
-
-            # To give the tab more 3D look we do the following
-            # Incase the tab is on top,
-            # Draw a thik white line on topof the rectangle
-            # Otherwise, draw a thin (1 pixel) black line at the bottom
-
-            pen = wx.Pen((pc.HasFlag(FNB_BOTTOM) and [wx.BLACK] or [wx.WHITE])[0])
-            dc.SetPen(pen)
-            whiteLinePosY = (pc.HasFlag(FNB_BOTTOM) and [blackLineY2] or [VERTICAL_BORDER_PADDING ])[0]
-            dc.DrawLine(posx , whiteLinePosY, posx + tabWidth + 1, whiteLinePosY)
-
-            # Draw a white vertical line to the left of the tab
-            dc.SetPen(wx.WHITE_PEN)
-            if not pc.HasFlag(FNB_BOTTOM):
-                blackLineY2 += 1
-                
-            dc.DrawLine(posx, blackLineY1, posx, blackLineY2)
-        
-        else:
-        
-            # We dont draw a rectangle for non selected tabs, but only
-            # vertical line on the left
-
-            blackLineY1 = (pc.HasFlag(FNB_BOTTOM) and [VERTICAL_BORDER_PADDING + 2] or [VERTICAL_BORDER_PADDING + 1])[0]
-            blackLineY2 = pc.GetSize().y - 5 
-            dc.DrawLine(posx + tabWidth, blackLineY1, posx + tabWidth, blackLineY2)
-        
-        # -----------------------------------
-        # Text and image drawing
-        # -----------------------------------
-
-        # Text drawing offset from the left border of the
-        # rectangle
-        
-        # The width of the images are 16 pixels
-        padding = pc.GetParent().GetPadding()
-        hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
-        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [5] or [8])[0]
-
-        if hasImage:
-            textOffset = 2*pc._pParent._nPadding + 16
-        else:
-            textOffset = pc._pParent._nPadding
-
-        if tabIdx != pc.GetSelection():
-        
-            # Set the text background to be like the vertical lines
-            dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
-        
-        if hasImage:
-        
-            imageXOffset = textOffset - 16 - padding
-            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
-                                     posx + imageXOffset, imageYCoord,
-                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)
-        
-        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-        
-        # draw 'x' on tab (if enabled)
-        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-        
-            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
-            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
-            # take a bitmap from the position of the 'x' button (the x on tab button)
-            # this bitmap will be used later to delete old buttons
-            tabCloseButtonYCoord = imageYCoord
-            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-
-            # Draw the tab
-            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)                    
-
-
-#------------------------------------------------------------------
-# Fancy style
-#------------------------------------------------------------------
-
-class FNBRendererFancy(FNBRenderer):
-    """
-    This class handles the drawing of tabs using the I{Fancy} renderer.
-    """
-
-    def __init__(self):
-        """ Default class constructor. """
-
-        FNBRenderer.__init__(self)
-
-
-    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
-        """ Draws a tab using the I{Fancy} style, similar to VC71 but with gradients. """
-
-        # Fancy tabs - like with VC71 but with the following differences:
-        # - The Selected tab is colored with gradient color
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-        pc = pageContainer
-
-        pen = (tabIdx == pc.GetSelection() and [wx.Pen(pc._pParent.GetBorderColour())] or [wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE))])[0]
-
-        if tabIdx == pc.GetSelection():
-        
-            posy = (pc.HasFlag(FNB_BOTTOM) and [2] or [VERTICAL_BORDER_PADDING])[0]
-            th = tabHeight - 5
-
-            rect = wx.Rect(posx, posy, tabWidth, th)
-
-            col2 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourTo()] or [pc._pParent.GetGradientColourFrom()])[0]
-            col1 = (pc.HasFlag(FNB_BOTTOM) and [pc._pParent.GetGradientColourFrom()] or [pc._pParent.GetGradientColourTo()])[0]
-
-            PaintStraightGradientBox(dc, rect, col1, col2)
-            dc.SetBrush(wx.TRANSPARENT_BRUSH)
-            dc.SetPen(pen)
-            dc.DrawRectangleRect(rect)
-
-            # erase the bottom/top line of the rectangle
-            dc.SetPen(wx.Pen(pc._pParent.GetGradientColourFrom()))
-            if pc.HasFlag(FNB_BOTTOM):
-                dc.DrawLine(rect.x, 2, rect.x + rect.width, 2)
-            else:
-                dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1)
-        
-        else:
-        
-            # We dont draw a rectangle for non selected tabs, but only
-            # vertical line on the left
-            dc.SetPen(borderPen)
-            dc.DrawLine(posx + tabWidth, VERTICAL_BORDER_PADDING + 3, posx + tabWidth, tabHeight - 4)
-        
-
-        # -----------------------------------
-        # Text and image drawing
-        # -----------------------------------
-
-        # Text drawing offset from the left border of the
-        # rectangle
-        
-        # The width of the images are 16 pixels
-        padding = pc.GetParent().GetPadding()
-        hasImage = pc._pagesInfoVec[tabIdx].GetImageIndex() != -1
-        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
-
-        if hasImage:
-            textOffset = 2*pc._pParent._nPadding + 16
-        else:
-            textOffset = pc._pParent._nPadding 
-
-        textOffset += 2
-
-        if tabIdx != pc.GetSelection():
-        
-            # Set the text background to be like the vertical lines
-            dc.SetTextForeground(pc._pParent.GetNonActiveTabTextColour())
-        
-        if hasImage:
-        
-            imageXOffset = textOffset - 16 - padding
-            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
-                                     posx + imageXOffset, imageYCoord,
-                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)
-        
-        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-        
-        # draw 'x' on tab (if enabled)
-        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-        
-            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
-            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
-            # take a bitmap from the position of the 'x' button (the x on tab button)
-            # this bitmap will be used later to delete old buttons
-            tabCloseButtonYCoord = imageYCoord
-            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-
-            # Draw the tab
-            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)            
-        
-
-#------------------------------------------------------------------
-# Visual studio 2005 (VS8)
-#------------------------------------------------------------------
-class FNBRendererVC8(FNBRenderer):    
-    """
-    This class handles the drawing of tabs using the I{VC8} renderer.
-    """
-
-    def __init__(self):
-        """ Default class constructor. """
-
-        FNBRenderer.__init__(self)
-        self._first = True
-        self._factor = 1
-
-        
-    def DrawTabs(self, pageContainer, dc):
-        """ Draws all the tabs using VC8 style. Overloads The DrawTabs method in parent class. """
-
-        pc = pageContainer
-
-        if "__WXMAC__" in wx.PlatformInfo:
-            # Works well on MSW & GTK, however this lines should be skipped on MAC
-            if not pc._pagesInfoVec or pc._nFrom >= len(pc._pagesInfoVec):
-                pc.Hide()
-                return
-            
-        # Get the text hight
-        tabHeight = self.CalcTabHeight(pageContainer)
-
-        # Set the font for measuring the tab height
-        normalFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-        boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-
-        # Calculate the number of rows required for drawing the tabs
-        rect = pc.GetClientRect()
-
-        # Set the maximum client size
-        pc.SetSizeHints(self.GetButtonsAreaLength(pc), tabHeight)
-        borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-
-        # Create brushes
-        backBrush = wx.Brush(pc._tabAreaColor)
-        noselBrush = wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))
-        selBrush = wx.Brush(pc._activeTabColor)
-        size = pc.GetSize()
-
-        # Background
-        dc.SetTextBackground(pc.GetBackgroundColour())
-        dc.SetTextForeground(pc._activeTextColor)
-        
-        # If border style is set, set the pen to be border pen
-        if pc.HasFlag(FNB_TABS_BORDER_SIMPLE):
-            dc.SetPen(borderPen)
-        else:
-            dc.SetPen(wx.TRANSPARENT_PEN)
-
-        lightFactor = (pc.HasFlag(FNB_BACKGROUND_GRADIENT) and [70] or [0])[0]
-        
-        # For VC8 style, we color the tab area in gradient coloring
-        lightcolour = LightColour(pc._tabAreaColor, lightFactor)
-        PaintStraightGradientBox(dc, pc.GetClientRect(), pc._tabAreaColor, lightcolour)
-
-        dc.SetBrush(wx.TRANSPARENT_BRUSH)
-        dc.DrawRectangle(0, 0, size.x, size.y)
-    
-        # We always draw the bottom/upper line of the tabs
-        # regradless the style
-        dc.SetPen(borderPen)
-        self.DrawTabsLine(pc, dc)
-
-        # Restore the pen
-        dc.SetPen(borderPen)
-
-        # Draw labels
-        dc.SetFont(boldFont)
-
-        # Update all the tabs from 0 to 'pc.self._nFrom' to be non visible
-        for i in xrange(pc._nFrom):
-        
-            pc._pagesInfoVec[i].SetPosition(wx.Point(-1, -1))
-            pc._pagesInfoVec[i].GetRegion().Clear()
-        
-        # Draw the visible tabs, in VC8 style, we draw them from right to left
-        vTabsInfo = self.NumberTabsCanFit(pc)
-
-        activeTabPosx = 0
-        activeTabWidth = 0
-        activeTabHeight = 0
-
-        for cur in xrange(len(vTabsInfo)-1, -1, -1):
-        
-            # 'i' points to the index of the currently drawn tab
-            # in pc.GetPageInfoVector() vector
-            i = pc._nFrom + cur
-            dc.SetPen(borderPen)
-            dc.SetBrush((i==pc.GetSelection() and [selBrush] or [noselBrush])[0])
-
-            # Now set the font to the correct font
-            dc.SetFont((i==pc.GetSelection() and [boldFont] or [normalFont])[0])
-
-            # Add the padding to the tab width
-            # Tab width:
-            # +-----------------------------------------------------------+
-            # | PADDING | IMG | IMG_PADDING | TEXT | PADDING | x |PADDING |
-            # +-----------------------------------------------------------+
-
-            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
-            posx = vTabsInfo[cur].x
-
-            # By default we clean the tab region
-            # incase we use the VC8 style which requires
-            # the region, it will be filled by the function
-            # drawVc8Tab
-            pc._pagesInfoVec[i].GetRegion().Clear()
-            
-            # Clean the 'x' buttn on the tab 
-            # 'Clean' rectanlge is a rectangle with width or height
-            # with values lower than or equal to 0
-            pc._pagesInfoVec[i].GetXRect().SetSize(wx.Size(-1, -1))
-
-            # Draw the tab
-            # Incase we are drawing the active tab
-            # we need to redraw so it will appear on top
-            # of all other tabs
-
-            # when using the vc8 style, we keep the position of the active tab so we will draw it again later
-            if i == pc.GetSelection() and pc.HasFlag(FNB_VC8):
-            
-                activeTabPosx = posx
-                activeTabWidth = tabWidth
-                activeTabHeight = tabHeight
-            
-            else:
-            
-                self.DrawTab(pc, dc, posx, i, tabWidth, tabHeight, pc._nTabXButtonStatus)
-            
-            # Restore the text forground
-            dc.SetTextForeground(pc._activeTextColor)
-
-            # Update the tab position & size
-            pc._pagesInfoVec[i].SetPosition(wx.Point(posx, VERTICAL_BORDER_PADDING))
-            pc._pagesInfoVec[i].SetSize(wx.Size(tabWidth, tabHeight))
-        
-        # Incase we are in VC8 style, redraw the active tab (incase it is visible)
-        if pc.GetSelection() >= pc._nFrom and pc.GetSelection() < pc._nFrom + len(vTabsInfo):
-        
-            self.DrawTab(pc, dc, activeTabPosx, pc.GetSelection(), activeTabWidth, activeTabHeight, pc._nTabXButtonStatus)
-        
-        # Update all tabs that can not fit into the screen as non-visible
-        for xx in xrange(pc._nFrom + len(vTabsInfo), len(pc._pagesInfoVec)):
-        
-            pc._pagesInfoVec[xx].SetPosition(wx.Point(-1, -1))
-            pc._pagesInfoVec[xx].GetRegion().Clear()
-        
-        # Draw the left/right/close buttons 
-        # Left arrow
-        self.DrawLeftArrow(pc, dc)
-        self.DrawRightArrow(pc, dc)
-        self.DrawX(pc, dc)
-        self.DrawDropDownArrow(pc, dc)
-
-
-    def DrawTab(self, pageContainer, dc, posx, tabIdx, tabWidth, tabHeight, btnStatus):
-        """ Draws a tab using VC8 style. """
-
-        pc = pageContainer
-        borderPen = wx.Pen(pc._pParent.GetBorderColour())
-        tabPoints = [wx.Point() for ii in xrange(8)]
-
-        # If we draw the first tab or the active tab, 
-        # we draw a full tab, else we draw a truncated tab
-        #
-        #             X(2)                  X(3)
-        #        X(1)                            X(4)
-        #                                          
-        #                                           X(5)
-        #                                           
-        # X(0),(7)                                  X(6)
-        #
-        #
-
-        tabPoints[0].x = (pc.HasFlag(FNB_BOTTOM) and [posx] or [posx+self._factor])[0]
-        tabPoints[0].y = (pc.HasFlag(FNB_BOTTOM) and [2] or [tabHeight - 3])[0]
-
-        tabPoints[1].x = tabPoints[0].x + tabHeight - VERTICAL_BORDER_PADDING - 3 - self._factor
-        tabPoints[1].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - (VERTICAL_BORDER_PADDING+2)] or [(VERTICAL_BORDER_PADDING+2)])[0]
-
-        tabPoints[2].x = tabPoints[1].x + 4
-        tabPoints[2].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
-        tabPoints[3].x = tabPoints[2].x + tabWidth - 2
-        tabPoints[3].y = (pc.HasFlag(FNB_BOTTOM) and [tabHeight - VERTICAL_BORDER_PADDING] or [VERTICAL_BORDER_PADDING])[0]
-
-        tabPoints[4].x = tabPoints[3].x + 1
-        tabPoints[4].y = (pc.HasFlag(FNB_BOTTOM) and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0]
-
-        tabPoints[5].x = tabPoints[4].x + 1
-        tabPoints[5].y = (pc.HasFlag(FNB_BOTTOM) and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0]
-
-        tabPoints[6].x = tabPoints[2].x + tabWidth
-        tabPoints[6].y = tabPoints[0].y
-
-        tabPoints[7].x = tabPoints[0].x
-        tabPoints[7].y = tabPoints[0].y
-
-        pc._pagesInfoVec[tabIdx].SetRegion(tabPoints)
-
-        # Draw the polygon
-        br = dc.GetBrush()
-        dc.SetBrush(wx.Brush((tabIdx == pc.GetSelection() and [pc._activeTabColor] or [pc._colorTo])[0]))
-        dc.SetPen(wx.Pen((tabIdx == pc.GetSelection() and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0]))
-        dc.DrawPolygon(tabPoints)
-
-        # Restore the brush
-        dc.SetBrush(br)
-        rect = pc.GetClientRect()
-
-        if tabIdx != pc.GetSelection() and not pc.HasFlag(FNB_BOTTOM):
-        
-            # Top default tabs
-            dc.SetPen(wx.Pen(pc._pParent.GetBorderColour()))
-            lineY = rect.height
-            curPen = dc.GetPen()
-            curPen.SetWidth(1)
-            dc.SetPen(curPen)
-            dc.DrawLine(posx, lineY, posx+rect.width, lineY)
-        
-        # Incase we are drawing the selected tab, we draw the border of it as well
-        # but without the bottom (upper line incase of wxBOTTOM)
-        if tabIdx == pc.GetSelection():
-        
-            borderPen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW))
-            dc.SetPen(borderPen)
-            dc.SetBrush(wx.TRANSPARENT_BRUSH)
-            dc.DrawPolygon(tabPoints)
-
-            # Delete the bottom line (or the upper one, incase we use wxBOTTOM) 
-            dc.SetPen(wx.WHITE_PEN)
-            dc.DrawLine(tabPoints[0].x, tabPoints[0].y, tabPoints[6].x, tabPoints[6].y)
-
-        self.FillVC8GradientColour(pc, dc, tabPoints, tabIdx == pc.GetSelection(), tabIdx)
-
-        # Draw a thin line to the right of the non-selected tab
-        if tabIdx != pc.GetSelection():
-        
-            dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)))
-            dc.DrawLine(tabPoints[4].x-1, tabPoints[4].y, tabPoints[5].x-1, tabPoints[5].y)
-            dc.DrawLine(tabPoints[5].x-1, tabPoints[5].y, tabPoints[6].x-1, tabPoints[6].y)
-        
-        # Text drawing offset from the left border of the 
-        # rectangle
-        
-        # The width of the images are 16 pixels
-        vc8ShapeLen = tabHeight - VERTICAL_BORDER_PADDING - 2
-        if pc.TabHasImage(tabIdx):
-            textOffset = 2*pc._pParent.GetPadding() + 16 + vc8ShapeLen 
-        else:
-            textOffset = pc._pParent.GetPadding() + vc8ShapeLen
-
-        # Draw the image for the tab if any
-        imageYCoord = (pc.HasFlag(FNB_BOTTOM) and [6] or [8])[0]
-
-        if pc.TabHasImage(tabIdx):
-        
-            imageXOffset = textOffset - 16 - pc._pParent.GetPadding()
-            pc._ImageList.Draw(pc._pagesInfoVec[tabIdx].GetImageIndex(), dc,
-                                     posx + imageXOffset, imageYCoord,
-                                     wx.IMAGELIST_DRAW_TRANSPARENT, True)        
-
-        boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-            
-        # if selected tab, draw text in bold
-        if tabIdx == pc.GetSelection():
-            boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-        
-        dc.SetFont(boldFont)
-        dc.DrawText(pc.GetPageText(tabIdx), posx + textOffset, imageYCoord)
-
-        # draw 'x' on tab (if enabled)
-        if pc.HasFlag(FNB_X_ON_TAB) and tabIdx == pc.GetSelection():
-
-            textWidth, textHeight = dc.GetTextExtent(pc.GetPageText(tabIdx))
-            tabCloseButtonXCoord = posx + textOffset + textWidth + 1
-
-            # take a bitmap from the position of the 'x' button (the x on tab button)
-            # this bitmap will be used later to delete old buttons
-            tabCloseButtonYCoord = imageYCoord
-            x_rect = wx.Rect(tabCloseButtonXCoord, tabCloseButtonYCoord, 16, 16)
-            # Draw the tab
-            self.DrawTabX(pc, dc, x_rect, tabIdx, btnStatus)
-
-        self.DrawFocusRectangle(dc, pc, pc._pagesInfoVec[tabIdx])
-
-
-    def FillVC8GradientColour(self, pageContainer, dc, tabPoints, bSelectedTab, tabIdx):
-        """ Fills a tab with a gradient shading. """
-
-        # calculate gradient coefficients
-        pc = pageContainer
-
-        if self._first:
-            self._first = False
-            pc._colorTo   = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 0) 
-            pc._colorFrom = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 60)
-        
-        col2 = pc._pParent.GetGradientColourTo()
-        col1 = pc._pParent.GetGradientColourFrom()
-
-        # If colorful tabs style is set, override the tab color
-        if pc.HasFlag(FNB_COLORFUL_TABS):
-        
-            if not pc._pagesInfoVec[tabIdx].GetColour():
-            
-                # First time, generate color, and keep it in the vector
-                tabColor = RandomColour()
-                pc._pagesInfoVec[tabIdx].SetColour(tabColor)
-            
-            if pc.HasFlag(FNB_BOTTOM):
-            
-                col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50)
-                col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80)
-            
-            else:
-            
-                col1 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 50)
-                col2 = LightColour(pc._pagesInfoVec[tabIdx].GetColour(), 80)
-            
-        size = abs(tabPoints[2].y - tabPoints[0].y) - 1
-
-        rf, gf, bf = 0, 0, 0
-        rstep = float(col2.Red() - col1.Red())/float(size)
-        gstep = float(col2.Green() - col1.Green())/float(size)
-        bstep = float(col2.Blue() - col1.Blue())/float(size)
-        
-        y = tabPoints[0].y 
-
-        # If we are drawing the selected tab, we need also to draw a line 
-        # from 0.tabPoints[0].x and tabPoints[6].x . end, we achieve this
-        # by drawing the rectangle with transparent brush
-        # the line under the selected tab will be deleted by the drwaing loop
-        if bSelectedTab:
-            self.DrawTabsLine(pc, dc)
-
-        while 1:
-        
-            if pc.HasFlag(FNB_BOTTOM):
-            
-                if y > tabPoints[0].y + size:
-                    break
-            
-            else:
-            
-                if y < tabPoints[0].y - size:
-                    break
-            
-            currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf)
-
-            dc.SetPen((bSelectedTab and [wx.Pen(pc._activeTabColor)] or [wx.Pen(currCol)])[0])
-            startX = self.GetStartX(tabPoints, y, pc.GetParent().GetWindowStyleFlag()) 
-            endX = self.GetEndX(tabPoints, y, pc.GetParent().GetWindowStyleFlag())
-            dc.DrawLine(startX, y, endX, y)
-
-            # Draw the border using the 'edge' point
-            dc.SetPen(wx.Pen((bSelectedTab and [wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)] or [pc._colorBorder])[0]))
-            
-            dc.DrawPoint(startX, y)
-            dc.DrawPoint(endX, y)
-            
-            # Progress the color 
-            rf += rstep
-            gf += gstep
-            bf += bstep
-
-            if pc.HasFlag(FNB_BOTTOM):
-                y = y + 1
-            else:
-                y = y - 1
-
-
-    def GetStartX(self, tabPoints, y, style):
-        """ Returns the x start position of a tab. """
-
-        x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
-
-        # We check the 3 points to the left
-
-        bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
-        match = False
-
-        if bBottomStyle:
-        
-            for i in xrange(3):
-                
-                if y >= tabPoints[i].y and y < tabPoints[i+1].y:
-                
-                    x1 = tabPoints[i].x
-                    x2 = tabPoints[i+1].x
-                    y1 = tabPoints[i].y
-                    y2 = tabPoints[i+1].y
-                    match = True
-                    break
-                
-        else:
-        
-            for i in xrange(3):
-                
-                if y <= tabPoints[i].y and y > tabPoints[i+1].y:
-                
-                    x1 = tabPoints[i].x
-                    x2 = tabPoints[i+1].x
-                    y1 = tabPoints[i].y
-                    y2 = tabPoints[i+1].y
-                    match = True
-                    break
-                
-        if not match:
-            return tabPoints[2].x
-
-        # According to the equation y = ax + b => x = (y-b)/a
-        # We know the first 2 points
-
-        if x2 == x1:
-            return x2
-        else:
-            a = (y2 - y1)/(x2 - x1)
-
-        b = y1 - ((y2 - y1)/(x2 - x1))*x1
-
-        if a == 0:
-            return int(x1)
-
-        x = (y - b)/a
-        
-        return int(x)
-
-
-    def GetEndX(self, tabPoints, y, style):
-        """ Returns the x end position of a tab. """
-
-        x1, x2, y1, y2 = 0.0, 0.0, 0.0, 0.0
-
-        # We check the 3 points to the left
-        bBottomStyle = (style & FNB_BOTTOM and [True] or [False])[0]
-        match = False
-
-        if bBottomStyle:
-
-            for i in xrange(7, 3, -1):
-                
-                if y >= tabPoints[i].y and y < tabPoints[i-1].y:
-                
-                    x1 = tabPoints[i].x
-                    x2 = tabPoints[i-1].x
-                    y1 = tabPoints[i].y
-                    y2 = tabPoints[i-1].y
-                    match = True
-                    break
-        
-        else:
-        
-            for i in xrange(7, 3, -1):
-                
-                if y <= tabPoints[i].y and y > tabPoints[i-1].y:
-                
-                    x1 = tabPoints[i].x
-                    x2 = tabPoints[i-1].x
-                    y1 = tabPoints[i].y
-                    y2 = tabPoints[i-1].y
-                    match = True
-                    break
-
-        if not match:
-            return tabPoints[3].x
-
-        # According to the equation y = ax + b => x = (y-b)/a
-        # We know the first 2 points
-
-        # Vertical line
-        if x1 == x2:
-            return int(x1)
-        
-        a = (y2 - y1)/(x2 - x1)
-        b = y1 - ((y2 - y1)/(x2 - x1))*x1
-
-        if a == 0:
-            return int(x1)
-
-        x = (y - b)/a
-
-        return int(x)
-
-
-    def NumberTabsCanFit(self, pageContainer, fr=-1):
-        """ Returns the number of tabs that can fit in the visible area. """
-
-        pc = pageContainer
-        
-        rect = pc.GetClientRect()
-        clientWidth = rect.width
-
-        # Empty results
-        vTabInfo = []
-        tabHeight = self.CalcTabHeight(pageContainer)
-
-        # The drawing starts from posx
-        posx = pc._pParent.GetPadding()
-        
-        if fr < 0:
-            fr = pc._nFrom
-
-        for i in xrange(fr, len(pc._pagesInfoVec)):
-        
-            vc8glitch = tabHeight + FNB_HEIGHT_SPACER
-            tabWidth = self.CalcTabWidth(pageContainer, i, tabHeight)
-
-            if posx + tabWidth + vc8glitch + self.GetButtonsAreaLength(pc) >= clientWidth:
-                break
-
-            # Add a result to the returned vector
-            tabRect = wx.Rect(posx, VERTICAL_BORDER_PADDING, tabWidth, tabHeight)
-            vTabInfo.append(tabRect)
-
-            # Advance posx
-            posx += tabWidth + FNB_HEIGHT_SPACER
-        
-        return vTabInfo
-    
-
-# ---------------------------------------------------------------------------- #
-# Class FlatNotebook
-# ---------------------------------------------------------------------------- #
-
-class FlatNotebook(wx.PyPanel):
-    """
-    Display one or more windows in a notebook.
-    
-    B{Events}:
-        - B{EVT_FLATNOTEBOOK_PAGE_CHANGING}: sent when the active 
-            page in the notebook is changing
-        - B{EVT_FLATNOTEBOOK_PAGE_CHANGED}: sent when the active 
-            page in the notebook has changed
-        - B{EVT_FLATNOTEBOOK_PAGE_CLOSING}: sent when a page in the 
-            notebook is closing
-        - B{EVT_FLATNOTEBOOK_PAGE_CLOSED}: sent when a page in the 
-            notebook has been closed
-        - B{EVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU}: sent when the user
-            clicks a tab in the notebook with the right mouse
-            button
-    """
-    
-    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
-                 style=0, name="FlatNotebook"):
-        """
-        Default class constructor.
-
-        All the parameters are as in wxPython class construction, except the
-        'style': this can be assigned to whatever combination of FNB_* styles.
-        
-        """
-
-        self._bForceSelection = False
-        self._nPadding = 6
-        self._nFrom = 0
-        style |= wx.TAB_TRAVERSAL
-        self._pages = None
-        self._windows = []
-        self._popupWin = None
-        self._naviIcon = None
-
-        wx.PyPanel.__init__(self, parent, id, pos, size, style)
-        
-        self._pages = PageContainer(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, style)
-
-        self.Bind(wx.EVT_NAVIGATION_KEY, self.OnNavigationKey)
-
-        self.Init()
-
-
-    def Init(self):
-        """ Initializes all the class attributes. """
-        
-        self._pages._colorBorder = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)
-
-        self._mainSizer = wx.BoxSizer(wx.VERTICAL)
-        self.SetSizer(self._mainSizer)
-
-        # The child panels will inherit this bg color, so leave it at the default value
-        #self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_APPWORKSPACE))
-
-        # Set default page height
-        dc = wx.ClientDC(self)
-        
-        if "__WXGTK__" in wx.PlatformInfo:
-            # For GTK it seems that we must do this steps in order
-            # for the tabs will get the proper height on initialization
-            # on MSW, preforming these steps yields wierd results
-            boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-            boldFont.SetWeight(wx.FONTWEIGHT_BOLD)
-            dc.SetFont(boldFont)
-        
-        height = dc.GetCharHeight()
-
-        tabHeight = height + FNB_HEIGHT_SPACER         # We use 8 pixels as padding
-        
-        if "__WXGTK__" in wx.PlatformInfo:
-            tabHeight += 6
-            
-        self._pages.SetSizeHints(-1, tabHeight)
-        # Add the tab container to the sizer
-        self._mainSizer.Insert(0, self._pages, 0, wx.EXPAND)
-        self._mainSizer.Layout()
-
-        self._pages._nFrom = self._nFrom
-        self._pDropTarget = FNBDropTarget(self)
-        self.SetDropTarget(self._pDropTarget)
-
-
-    def DoGetBestSize(self):
-        """ Overrides DoGetBestSize to handle sizers nicely. """
-
-        if not self._windows:
-            # Something is better than nothing... no pages!
-            return wx.Size(20, 20)
-
-        maxWidth = maxHeight = 0
-        tabHeight = self.GetPageBestSize().height
-
-        for win in self._windows:
-            # Loop over all the windows to get their best size
-            width, height = win.GetBestSize()
-            maxWidth, maxHeight = max(maxWidth, width), max(maxHeight, height)
-
-        return wx.Size(maxWidth, maxHeight+tabHeight)
-    
-
-    def SetActiveTabTextColour(self, textColour):
-        """ Sets the text colour for the active tab. """
-
-        self._pages._activeTextColor = textColour
-
-
-    def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
-        """ Handles the drop action from a DND operation. """
-
-        return self._pages.OnDropTarget(x, y, nTabPage, wnd_oldContainer)
-
-
-    def GetPreviousSelection(self):
-        """ Returns the previous selection. """
-
-        return self._pages._iPreviousActivePage
-
-
-    def AddPage(self, page, text, select=True, imageId=-1):
-        """
-        Add a page to the L{FlatNotebook}.
-
-        @param page: Specifies the new page.
-        @param text: Specifies the text for the new page.
-        @param select: Specifies whether the page should be selected.
-        @param imageId: Specifies the optional image index for the new page.
-        
-        Return value:
-        True if successful, False otherwise.
-        """
-
-        # sanity check
-        if not page:
-            return False
-
-        # reparent the window to us
-        page.Reparent(self)
-
-        # Add tab
-        bSelected = select or len(self._windows) == 0
-
-        if bSelected:
-            
-            bSelected = False
-            
-            # Check for selection and send events
-            oldSelection = self._pages._iActivePage
-            tabIdx = len(self._windows)
-            
-            event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
-            event.SetSelection(tabIdx)
-            event.SetOldSelection(oldSelection)
-            event.SetEventObject(self)
-            
-            if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
-                bSelected = True            
-        
-        curSel = self._pages.GetSelection()
-
-        if not self._pages.IsShown():
-            self._pages.Show()
-
-        self._pages.AddPage(text, bSelected, imageId)
-        self._windows.append(page)
-
-        self.Freeze()
-
-        # Check if a new selection was made
-        if bSelected:
-        
-            if curSel >= 0:
-            
-                # Remove the window from the main sizer
-                self._mainSizer.Detach(self._windows[curSel])
-                self._windows[curSel].Hide()
-            
-            if self.GetWindowStyleFlag() & FNB_BOTTOM:
-            
-                self._mainSizer.Insert(0, page, 1, wx.EXPAND)
-            
-            else:
-            
-                # We leave a space of 1 pixel around the window
-                self._mainSizer.Add(page, 1, wx.EXPAND)
-
-            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
-            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
-            event.SetOldSelection(oldSelection)
-            self.GetEventHandler().ProcessEvent(event)
-            
-        else:
-
-            # Hide the page
-            page.Hide()
-
-        self.Thaw()        
-        self._mainSizer.Layout()
-        self.Refresh()
-
-        return True        
-
-
-    def SetImageList(self, imageList):
-        """ Sets the image list for the page control. """
-
-        self._pages.SetImageList(imageList)
-
-
-    def AssignImageList(self, imageList):
-        """ Assigns the image list for the page control. """
-
-        self._pages.AssignImageList(imageList)
-
-
-    def GetImageList(self):
-        """ Returns the associated image list. """
-        
-        return self._pages.GetImageList()
-
-
-    def InsertPage(self, indx, page, text, select=True, imageId=-1):
-        """
-        Inserts a new page at the specified position.
-
-        @param indx: Specifies the position of the new page.
-        @param page: Specifies the new page.
-        @param text: Specifies the text for the new page.
-        @param select: Specifies whether the page should be selected.
-        @param imageId: Specifies the optional image index for the new page.
-        
-        Return value:
-        True if successful, False otherwise.
-        """     
-
-        # sanity check
-        if not page:
-            return False
-
-        # reparent the window to us
-        page.Reparent(self)
-
-        if not self._windows:
-        
-            self.AddPage(page, text, select, imageId)
-            return True
-
-        # Insert tab
-        bSelected = select or not self._windows
-        curSel = self._pages.GetSelection()
-        
-        indx = max(0, min(indx, len(self._windows)))
-
-        if indx <= len(self._windows):
-        
-            self._windows.insert(indx, page)
-        
-        else:
-        
-            self._windows.append(page)
-
-        if bSelected:
-        
-            bSelected = False
-            
-            # Check for selection and send events
-            oldSelection = self._pages._iActivePage
-            
-            event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetId())
-            event.SetSelection(indx)
-            event.SetOldSelection(oldSelection)
-            event.SetEventObject(self)
-            
-            if not self.GetEventHandler().ProcessEvent(event) or event.IsAllowed() or len(self._windows) == 0:
-                bSelected = True            
-        
-        self._pages.InsertPage(indx, text, bSelected, imageId)
-        
-        if indx <= curSel:
-            curSel = curSel + 1
-
-        self.Freeze()
-
-        # Check if a new selection was made
-        if bSelected:
-        
-            if curSel >= 0:
-            
-                # Remove the window from the main sizer
-                self._mainSizer.Detach(self._windows[curSel])
-                self._windows[curSel].Hide()
-            
-            self._pages.SetSelection(indx)
-
-            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
-            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
-            event.SetOldSelection(oldSelection)
-            self.GetEventHandler().ProcessEvent(event)
-        
-        else:
-        
-            # Hide the page
-            page.Hide()
-
-        self.Thaw()
-        self._mainSizer.Layout()        
-        self.Refresh()
-
-        return True
-
-
-    def SetSelection(self, page):
-        """
-        Sets the selection for the given page.
-        The call to this function generates the page changing events
-        """
-
-        if page >= len(self._windows) or not self._windows:
-            return
-
-        # Support for disabed tabs
-        if not self._pages.GetEnabled(page) and len(self._windows) > 1 and not self._bForceSelection:
-            return
-
-        curSel = self._pages.GetSelection()
-
-        # program allows the page change
-        self.Freeze()
-        if curSel >= 0:
-        
-            # Remove the window from the main sizer
-            self._mainSizer.Detach(self._windows[curSel])
-            self._windows[curSel].Hide()
-        
-        if self.GetWindowStyleFlag() & FNB_BOTTOM:
-        
-            self._mainSizer.Insert(0, self._windows[page], 1, wx.EXPAND)
-        
-        else:
-        
-            # We leave a space of 1 pixel around the window
-            self._mainSizer.Add(self._windows[page], 1, wx.EXPAND)
-        
-        self._windows[page].Show()
-        self.Thaw()
-        
-        self._mainSizer.Layout()
-        
-        if page != self._pages._iActivePage:
-            # there is a real page changing
-            self._pages._iPreviousActivePage = self._pages._iActivePage
-
-        self._pages._iActivePage = page
-        self._pages.DoSetSelection(page)
-
-    def DeletePage(self, page):
-        """
-        Deletes the specified page, and the associated window.
-        The call to this function generates the page changing events.
-        """
-
-        if page >= len(self._windows) or page < 0:
-            return
-
-        # Fire a closing event
-        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
-        event.SetSelection(page)
-        event.SetEventObject(self)
-        self.GetEventHandler().ProcessEvent(event)
-
-        # The event handler allows it?
-        if not event.IsAllowed():
-            return
-
-        self.Freeze()
-
-        # Delete the requested page
-        pageRemoved = self._windows[page]
-
-        # If the page is the current window, remove it from the sizer
-        # as well
-        if page == self._pages.GetSelection():
-            self._mainSizer.Detach(pageRemoved)
-        
-        # Remove it from the array as well
-        self._windows.pop(page)
-
-        # Now we can destroy it in wxWidgets use Destroy instead of delete
-        pageRemoved.Destroy()
-
-        self.Thaw()
-
-        self._pages.DoDeletePage(page)
-        self.Refresh()
-        self.Update()  
-
-        # Fire a closed event
-        closedEvent = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSED, self.GetId())
-        closedEvent.SetSelection(page)
-        closedEvent.SetEventObject(self)
-        self.GetEventHandler().ProcessEvent(closedEvent)
-
-
-    def DeleteAllPages(self):
-        """ Deletes all the pages. """
-
-        if not self._windows:
-            return False
-
-        self.Freeze()
-        
-        for page in self._windows:
-            page.Destroy()
-        
-        self._windows = []
-        self.Thaw()
-
-        # Clear the container of the tabs as well
-        self._pages.DeleteAllPages()
-        return True
-
-
-    def GetCurrentPage(self):
-        """ Returns the currently selected notebook page or None. """
-        
-        sel = self._pages.GetSelection()
-        if sel < 0:
-            return None
-
-        return self._windows[sel]
-
-
-    def GetPage(self, page):
-        """ Returns the window at the given page position, or None. """
-
-        if page >= len(self._windows):
-            return None
-
-        return self._windows[page]
-
-
-    def GetPageIndex(self, win):
-        """ Returns the index at which the window is found. """
-
-        try:
-            return self._windows.index(win)
-        except:
-            return -1
-
-
-    def GetSelection(self):
-        """ Returns the currently selected page, or -1 if none was selected. """
-        
-        return self._pages.GetSelection()
-
-
-    def AdvanceSelection(self, forward=True):
-        """
-        Cycles through the tabs.
-        The call to this function generates the page changing events.
-        """
-
-        self._pages.AdvanceSelection(forward)
-
-
-    def GetPageCount(self):
-        """ Returns the number of pages in the L{FlatNotebook} control. """
-
-        return self._pages.GetPageCount()
-
-    def SetNavigatorIcon(self, bmp):
-        """ Set the icon used by the L{TabNavigatorWindow} """
-        if isinstance(bmp, wx.Bitmap) and bmp.IsOk():
-            # Make sure image is proper size
-            if bmp.GetSize() != (16, 16):
-                img = bmp.ConvertToImage()
-                img.Rescale(16, 16, wx.IMAGE_QUALITY_HIGH)
-                bmp = wx.BitmapFromImage(img)
-            self._naviIcon = bmp
-        else:
-            raise TypeError, "SetNavigatorIcon requires a valid bitmap"
-
-    def Navigation(self, direction=True):
-        if len(self._windows) >= 1:
-            if not self._popupWin:
-                self._popupWin = TabNavigatorWindow(self, self._naviIcon)
-                self._popupWin.SetReturnCode(wx.ID_OK)
-                self._popupWin.ShowModal()
-                self._popupWin.Destroy()
-                self._popupWin = None
-            else:
-                # a dialog is already opened
-                self._popupWin.Navigation(direction)
-
-    def OnNavigationKey(self, event):
-        """ Handles the wx.EVT_NAVIGATION_KEY event for L{FlatNotebook}. """
-
-        if event.IsWindowChange():
-            if len(self._windows) == 0:
-                return
-            # change pages
-            if self.HasFlag(FNB_SMART_TABS):
-                if not self._popupWin:
-                    self._popupWin = TabNavigatorWindow(self, self._naviIcon)
-                    self._popupWin.SetReturnCode(wx.ID_OK)
-                    self._popupWin.ShowModal()
-                    self._popupWin.Destroy()
-                    self._popupWin = None
-                else:
-                    # a dialog is already opened
-                    self._popupWin.OnNavigationKey(event)
-                    return
-            else:
-                # change pages
-                self.AdvanceSelection(event.GetDirection())
-
-        else:
-            event.Skip()
-            
-
-    def GetPageShapeAngle(self, page_index):
-        """ Returns the angle associated to a tab. """
-
-        if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
-            return None, False
-        
-        result = self._pages._pagesInfoVec[page_index].GetTabAngle()
-        return result, True
-
-
-    def SetPageShapeAngle(self, page_index, angle):
-        """ Sets the angle associated to a tab. """
-
-        if page_index < 0 or page_index >= len(self._pages._pagesInfoVec):
-            return
-
-        if angle > 15:
-            return
-
-        self._pages._pagesInfoVec[page_index].SetTabAngle(angle)
-
-
-    def SetAllPagesShapeAngle(self, angle):
-        """ Sets the angle associated to all the tab. """
-
-        if angle > 15:
-            return
-
-        for ii in xrange(len(self._pages._pagesInfoVec)):
-            self._pages._pagesInfoVec[ii].SetTabAngle(angle)
-        
-        self.Refresh()
-
-
-    def GetPageBestSize(self):
-        """ Return the page best size. """
-
-        return self._pages.GetClientSize()
-
-
-    def SetPageText(self, page, text):
-        """ Sets the text for the given page. """
-
-        bVal = self._pages.SetPageText(page, text)
-        self._pages.EnsureVisible(page, False)
-        self._pages.Refresh()
-
-        return bVal
-
-
-    def SetPadding(self, padding):
-        """
-        Sets the amount of space around each page's icon and label, in pixels.
-        NB: only the horizontal padding is considered.
-        """
-
-        self._nPadding = padding.GetWidth()
-
-
-    def GetTabArea(self):
-        """ Returns the associated page. """
-
-        return self._pages
-
-
-    def GetPadding(self):
-        """ Returns the amount of space around each page's icon and label, in pixels. """
-        
-        return self._nPadding 
-
-
-    def SetWindowStyleFlag(self, style):
-        """ Sets the L{FlatNotebook} window style flags. """
-            
-        wx.PyPanel.SetWindowStyleFlag(self, style)
-        renderer = self._pages._mgr.GetRenderer(self.GetWindowStyleFlag())
-        renderer._tabHeight = None
-
-        if self._pages:
-        
-            # For changing the tab position (i.e. placing them top/bottom)
-            # refreshing the tab container is not enough
-            self.SetSelection(self._pages._iActivePage)
-
-        if not self._pages.HasFlag(FNB_HIDE_ON_SINGLE_TAB):
-            #For Redrawing the Tabs once you remove the Hide tyle
-            self._pages._ReShow()
-
-
-    def RemovePage(self, page):
-        """ Deletes the specified page, without deleting the associated window. """
-
-        if page >= len(self._windows):
-            return False
-
-        # Fire a closing event
-        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CLOSING, self.GetId())
-        event.SetSelection(page)
-        event.SetEventObject(self)
-        self.GetEventHandler().ProcessEvent(event)
-
-        # The event handler allows it?
-        if not event.IsAllowed():
-            return False
-
-        self.Freeze()
-
-        # Remove the requested page
-        pageRemoved = self._windows[page]
-
-        # If the page is the current window, remove it from the sizer
-        # as well
-        if page == self._pages.GetSelection():
-            self._mainSizer.Detach(pageRemoved)
-        
-        # Remove it from the array as well
-        self._windows.pop(page)
-        self.Thaw()
-
-        self._pages.DoDeletePage(page)
-
-        return True
-
-
-    def SetRightClickMenu(self, menu):
-        """ Sets the popup menu associated to a right click on a tab. """
-
-        self._pages._pRightClickMenu = menu
-
-
-    def GetPageText(self, nPage):
-        """ Returns the tab caption. """
-
-        return self._pages.GetPageText(nPage)
-
-
-    def SetGradientColours(self, fr, to, border):
-        """ Sets the gradient colours for the tab. """
-
-        self._pages._colorFrom = fr
-        self._pages._colorTo   = to
-        self._pages._colorBorder = border
-
-
-    def SetGradientColourFrom(self, fr):
-        """ Sets the starting colour for the gradient. """
-
-        self._pages._colorFrom = fr
-
-
-    def SetGradientColourTo(self, to):
-        """ Sets the ending colour for the gradient. """
-
-        self._pages._colorTo = to
-
-
-    def SetGradientColourBorder(self, border):
-        """ Sets the tab border colour. """
-
-        self._pages._colorBorder = border
-
-
-    def GetGradientColourFrom(self):
-        """ Gets first gradient colour. """
-
-        return self._pages._colorFrom
-
-
-    def GetGradientColourTo(self):
-        """ Gets second gradient colour. """
-
-        return self._pages._colorTo
-
-
-    def GetGradientColourBorder(self):
-        """ Gets the tab border colour. """
-
-        return self._pages._colorBorder
-
-
-    def GetBorderColour(self):
-        """ Returns the border colour. """
-
-        return self._pages._colorBorder
-    
-
-    def GetActiveTabTextColour(self):
-        """ Get the active tab text colour. """
-
-        return self._pages._activeTextColor
-
-
-    def SetPageImage(self, page, image):
-        """
-        Sets the image index for the given page. Image is an index into the
-        image list which was set with SetImageList.
-        """
-
-        self._pages.SetPageImage(page, image)
-
-
-    def GetPageImage(self, nPage):
-        """
-        Returns the image index for the given page. Image is an index into the
-        image list which was set with SetImageList.
-        """
-
-        return self._pages.GetPageImage(nPage)
-
-
-    def GetEnabled(self, page):
-        """ Returns whether a tab is enabled or not. """
-
-        return self._pages.GetEnabled(page)
-
-
-    def EnableTab(self, page, enabled=True):
-        """ Enables or disables a tab. """
-
-        if page >= len(self._windows):
-            return
-
-        self._windows[page].Enable(enabled)
-        self._pages.EnableTab(page, enabled)
-
-
-    def GetNonActiveTabTextColour(self):
-        """ Returns the non active tabs text colour. """
-
-        return self._pages._nonActiveTextColor
-
-
-    def SetNonActiveTabTextColour(self, color):
-        """ Sets the non active tabs text colour. """
-
-        self._pages._nonActiveTextColor = color
-
-
-    def SetTabAreaColour(self, color):
-        """ Sets the area behind the tabs colour. """
-
-        self._pages._tabAreaColor = color
-
-
-    def GetTabAreaColour(self):
-        """ Returns the area behind the tabs colour. """
-
-        return self._pages._tabAreaColor
-
-
-    def SetActiveTabColour(self, color):
-        """ Sets the active tab colour. """
-
-        self._pages._activeTabColor = color
-
-
-    def GetActiveTabColour(self):
-        """ Returns the active tab colour. """
-
-        return self._pages._activeTabColor
-
-
-    def EnsureVisible(self, page):
-       """ Ensures that a tab is visible. """
-
-       self._pages.DoSetSelection(page)
-
-       
-# ---------------------------------------------------------------------------- #
-# Class PageContainer
-# Acts as a container for the pages you add to FlatNotebook
-# ---------------------------------------------------------------------------- #
-
-class PageContainer(wx.Panel):
-    """
-    This class acts as a container for the pages you add to L{FlatNotebook}.
-    """
-
-    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
-                 size=wx.DefaultSize, style=0):
-        """ Default class constructor. """
-        
-        self._ImageList = None
-        self._iActivePage = -1
-        self._pDropTarget = None
-        self._nLeftClickZone = FNB_NOWHERE
-        self._iPreviousActivePage = -1
-
-        self._pRightClickMenu = None
-        self._nXButtonStatus = FNB_BTN_NONE
-        self._nArrowDownButtonStatus = FNB_BTN_NONE
-        self._pParent = parent
-        self._nRightButtonStatus = FNB_BTN_NONE
-        self._nLeftButtonStatus = FNB_BTN_NONE
-        self._nTabXButtonStatus = FNB_BTN_NONE
-
-        self._pagesInfoVec = []        
-
-        self._colorTo = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
-        self._colorFrom = wx.WHITE
-        self._activeTabColor = wx.WHITE
-        self._activeTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
-        self._nonActiveTextColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
-        self._tabAreaColor = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)
-
-        self._nFrom = 0
-        self._isdragging = False
-
-        # Set default page height, this is done according to the system font
-        memDc = wx.MemoryDC()
-        memDc.SelectObject(wx.EmptyBitmap(1,1))
-    
-        if "__WXGTK__" in wx.PlatformInfo:
-            boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
-            boldFont.SetWeight(wx.BOLD)
-            memDc.SetFont(boldFont)
-
-        height = memDc.GetCharHeight()
-        tabHeight = height + FNB_HEIGHT_SPACER # We use 10 pixels as padding
-
-        wx.Panel.__init__(self, parent, id, pos, wx.Size(size.x, tabHeight),
-                          style|wx.NO_BORDER|wx.NO_FULL_REPAINT_ON_RESIZE|wx.WANTS_CHARS)
-
-        self._pDropTarget = FNBDropTarget(self)
-        self.SetDropTarget(self._pDropTarget)
-        self._mgr = FNBRendererMgr()
-
-        self.Bind(wx.EVT_PAINT, self.OnPaint)
-        self.Bind(wx.EVT_SIZE, self.OnSize)
-        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
-        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
-        self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
-        self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
-        self.Bind(wx.EVT_MOTION, self.OnMouseMove)
-        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
-        self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
-        self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
-        self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
-        self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
-        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
-        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
-        
-
-    def OnEraseBackground(self, event):
-        """ Handles the wx.EVT_ERASE_BACKGROUND event for L{PageContainer} (does nothing)."""
-
-        pass
-
-    
-    def _ReShow(self):
-        """ Handles the Redraw of the tabs when the FNB_HIDE_ON_SINGLE_TAB has been removed """
-        self.Show()
-        self.GetParent()._mainSizer.Layout()
-        self.Refresh()
-
-
-    def OnPaint(self, event):
-        """ Handles the wx.EVT_PAINT event for L{PageContainer}."""
-
-        dc = wx.BufferedPaintDC(self)
-        renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
-        renderer.DrawTabs(self, dc)
-
-        if self.HasFlag(FNB_HIDE_ON_SINGLE_TAB) and len(self._pagesInfoVec) <= 1:
-            self.Hide()
-            self.GetParent()._mainSizer.Layout()
-            self.Refresh()
-
-
-    def AddPage(self, caption, selected=True, imgindex=-1):
-        """
-        Add a page to the L{FlatNotebook}.
-
-        @param window: Specifies the new page.
-        @param caption: Specifies the text for the new page.
-        @param selected: Specifies whether the page should be selected.
-        @param imgindex: Specifies the optional image index for the new page.
-        
-        Return value:
-        True if successful, False otherwise.
-        """
-
-        if selected:
-
-            self._iPreviousActivePage = self._iActivePage        
-            self._iActivePage = len(self._pagesInfoVec)
-        
-        # Create page info and add it to the vector
-        pageInfo = PageInfo(caption, imgindex)
-        self._pagesInfoVec.append(pageInfo)
-        self.Refresh()
-
-
-    def InsertPage(self, indx, text, selected=True, imgindex=-1):
-        """
-        Inserts a new page at the specified position.
-
-        @param indx: Specifies the position of the new page.
-        @param page: Specifies the new page.
-        @param text: Specifies the text for the new page.
-        @param select: Specifies whether the page should be selected.
-        @param imgindex: Specifies the optional image index for the new page.
-        
-        Return value:
-        True if successful, False otherwise.
-        """     
-
-        if selected:
-
-            self._iPreviousActivePage = self._iActivePage        
-            self._iActivePage = len(self._pagesInfoVec)
-        
-        self._pagesInfoVec.insert(indx, PageInfo(text, imgindex))
-        
-        self.Refresh()
-        return True
-
-
-    def OnSize(self, event):
-        """ Handles the wx.EVT_SIZE events for L{PageContainer}. """
-
-        # When resizing the control, try to fit to screen as many tabs as we can 
-        style = self.GetParent().GetWindowStyleFlag() 
-        renderer = self._mgr.GetRenderer(style)
-        
-        fr = 0
-        page = self.GetSelection()
-        
-        for fr in xrange(self._nFrom):
-            vTabInfo = renderer.NumberTabsCanFit(self, fr)
-            if page - fr >= len(vTabInfo):
-                continue
-            break
-
-        self._nFrom = fr
-
-        self.EnsureVisible(page, False)
-        self.Refresh() # Call on paint
-        event.Skip()
-
-
-    def OnMiddleDown(self, event):
-        """ Handles the wx.EVT_MIDDLE_DOWN events for L{PageContainer}. """
-
-        # Test if this style is enabled
-        style = self.GetParent().GetWindowStyleFlag()
-        
-        if not style & FNB_MOUSE_MIDDLE_CLOSES_TABS:
-            return
-
-        where, tabIdx = self.HitTest(event.GetPosition())
-        
-        if where == FNB_TAB:
-            self.DeletePage(tabIdx)
-        
-        event.Skip()
-
-
-    def OnRightDown(self, event):
-        """ Handles the wx.EVT_RIGHT_DOWN events for L{PageContainer}. """
-        
-        where, tabIdx = self.HitTest(event.GetPosition())
-
-        if where in [FNB_TAB, FNB_TAB_X]:
-
-            if self._pagesInfoVec[tabIdx].GetEnabled():
-                # Fire events and eventually (if allowed) change selection
-                self.FireEvent(tabIdx)
-
-                # send a message to popup a custom menu
-                event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CONTEXT_MENU, self.GetParent().GetId())
-                event.SetSelection(tabIdx)
-                event.SetOldSelection(self._iActivePage)
-                event.SetEventObject(self.GetParent())
-                self.GetParent().GetEventHandler().ProcessEvent(event)
-
-                if self._pRightClickMenu:
-                    self.PopupMenu(self._pRightClickMenu)
-            
-        event.Skip()
-
-
-    def OnLeftDown(self, event):
-        """ Handles the wx.EVT_LEFT_DOWN events for L{PageContainer}. """
-
-        # Reset buttons status
-        self._nXButtonStatus     = FNB_BTN_NONE
-        self._nLeftButtonStatus  = FNB_BTN_NONE
-        self._nRightButtonStatus = FNB_BTN_NONE
-        self._nTabXButtonStatus  = FNB_BTN_NONE
-        self._nArrowDownButtonStatus = FNB_BTN_NONE
-
-        self._nLeftClickZone, tabIdx = self.HitTest(event.GetPosition())
-
-        if self._nLeftClickZone == FNB_DROP_DOWN_ARROW:
-            self._nArrowDownButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
-        elif self._nLeftClickZone == FNB_LEFT_ARROW:
-            self._nLeftButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
-        elif self._nLeftClickZone == FNB_RIGHT_ARROW:
-            self._nRightButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
-        elif self._nLeftClickZone == FNB_X:
-            self._nXButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
-        elif self._nLeftClickZone == FNB_TAB_X:
-            self._nTabXButtonStatus = FNB_BTN_PRESSED
-            self.Refresh()
-
-        elif self._nLeftClickZone == FNB_TAB:
-            
-            if self._iActivePage != tabIdx:
-                
-                # In case the tab is disabled, we dont allow to choose it
-                if self._pagesInfoVec[tabIdx].GetEnabled():
-                    self.FireEvent(tabIdx)
-
-
-    def RotateLeft(self):
-
-        if self._nFrom == 0:
-            return
-
-        # Make sure that the button was pressed before
-        if self._nLeftButtonStatus != FNB_BTN_PRESSED:
-            return
-
-        self._nLeftButtonStatus = FNB_BTN_HOVER
-
-        # We scroll left with bulks of 5
-        scrollLeft = self.GetNumTabsCanScrollLeft()
-
-        self._nFrom -= scrollLeft
-        if self._nFrom < 0:
-            self._nFrom = 0
-
-        self.Refresh()
-
-
-    def RotateRight(self):
-
-        if self._nFrom >= len(self._pagesInfoVec) - 1:
-            return
-
-        # Make sure that the button was pressed before
-        if self._nRightButtonStatus != FNB_BTN_PRESSED:
-            return
-
-        self._nRightButtonStatus = FNB_BTN_HOVER
-
-        # Check if the right most tab is visible, if it is
-        # don't rotate right anymore
-        if self._pagesInfoVec[len(self._pagesInfoVec)-1].GetPosition() != wx.Point(-1, -1):
-            return
-
-        self._nFrom += 1
-        self.Refresh()
-
-
-    def OnLeftUp(self, event):
-        """ Handles the wx.EVT_LEFT_UP events for L{PageContainer}. """
-
-        # forget the zone that was initially clicked
-        self._nLeftClickZone = FNB_NOWHERE
-
-        where, tabIdx = self.HitTest(event.GetPosition())
-        
-        # Make sure selected tab has focus
-#        self.SetFocus()
-
-        if where == FNB_LEFT_ARROW:
-            self.RotateLeft()
-            
-        elif where == FNB_RIGHT_ARROW:
-            self.RotateRight()
-            
-        elif where == FNB_X:
-            
-            # Make sure that the button was pressed before
-            if self._nXButtonStatus != FNB_BTN_PRESSED:
-                return
-
-            self._nXButtonStatus = FNB_BTN_HOVER
-
-            self.DeletePage(self._iActivePage)
-            
-        elif where == FNB_TAB_X:
-            
-            # Make sure that the button was pressed before
-            if self._nTabXButtonStatus != FNB_BTN_PRESSED:
-                return 
-
-            self._nTabXButtonStatus = FNB_BTN_HOVER
-
-            self.DeletePage(self._iActivePage)
-
-        elif where == FNB_DROP_DOWN_ARROW:
-
-            # Make sure that the button was pressed before
-            if self._nArrowDownButtonStatus != FNB_BTN_PRESSED:
-                return
-
-            self._nArrowDownButtonStatus = FNB_BTN_NONE
-
-            # Refresh the button status
-            renderer = self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag())
-            dc = wx.ClientDC(self)
-            renderer.DrawDropDownArrow(self, dc)
-
-            self.PopupTabsMenu()
-
-        event.Skip()
-        
-
-    def HitTest(self, pt):
-        """
-        HitTest method for L{PageContainer}.
-        Returns the flag (if any) and the hit page (if any).
-        """
-
-        style = self.GetParent().GetWindowStyleFlag()
-        render = self._mgr.GetRenderer(style)
-
-        fullrect = self.GetClientRect()
-        btnLeftPos = render.GetLeftButtonPos(self)
-        btnRightPos = render.GetRightButtonPos(self)
-        btnDropdownPos = render.GetDropArrowButtonPos(self)
-        btnXPos = render.GetXPos(self)
-        
-        tabIdx = -1
-        
-        if len(self._pagesInfoVec) == 0:
-            return FNB_NOWHERE, tabIdx
-
-        rect = wx.Rect(btnXPos, 8, 16, 16)
-        if rect.Contains(pt):
-            return (style & FNB_NO_X_BUTTON and [FNB_NOWHERE] or [FNB_X])[0], tabIdx
-
-        rect = wx.Rect(btnDropdownPos, 8, 16, 16)
-        if style & FNB_DROPDOWN_TABS_LIST:
-            rect = wx.Rect(render.GetDropArrowButtonPos(self), 8, 16, 16)
-            if rect.Contains(pt):
-                return FNB_DROP_DOWN_ARROW, tabIdx
-
-        rect = wx.Rect(btnRightPos, 8, 16, 16)
-        if rect.Contains(pt):
-            return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_RIGHT_ARROW])[0], tabIdx
-
-        rect = wx.Rect(btnLeftPos, 8, 16, 16)
-        if rect.Contains(pt):
-            return (style & FNB_NO_NAV_BUTTONS and [FNB_NOWHERE] or [FNB_LEFT_ARROW])[0], tabIdx
-
-        # Test whether a left click was made on a tab
-        bFoundMatch = False
-        
-        for cur in xrange(self._nFrom, len(self._pagesInfoVec)):
-
-            pgInfo = self._pagesInfoVec[cur]
-
-            if pgInfo.GetPosition() == wx.Point(-1, -1):
-                continue
-
-            if style & FNB_X_ON_TAB and cur == self.GetSelection():
-                # 'x' button exists on a tab
-                if self._pagesInfoVec[cur].GetXRect().Contains(pt):
-                    return FNB_TAB_X, cur
-                    
-            if style & FNB_VC8:
-
-                if self._pagesInfoVec[cur].GetRegion().Contains(pt.x, pt.y):
-                    if bFoundMatch or cur == self.GetSelection():    
-                        return FNB_TAB, cur
-
-                    tabIdx = cur
-                    bFoundMatch = True
-                    
-            else:
-
-                tabRect = wx.Rect(pgInfo.GetPosition().x, pgInfo.GetPosition().y,
-                                  pgInfo.GetSize().x, pgInfo.GetSize().y)
-                
-                if tabRect.Contains(pt):
-                    # We have a match
-                    return FNB_TAB, cur
-
-        if bFoundMatch:
-            return FNB_TAB, tabIdx
-
-        if self._isdragging:
-            # We are doing DND, so check also the region outside the tabs
-            # try before the first tab
-            pgInfo = self._pagesInfoVec[0]
-            tabRect = wx.Rect(0, pgInfo.GetPosition().y, pgInfo.GetPosition().x, self.GetParent().GetSize().y)
-            if tabRect.Contains(pt):
-                return FNB_TAB, 0
-
-            # try after the last tab
-            pgInfo = self._pagesInfoVec[-1]
-            startpos = pgInfo.GetPosition().x+pgInfo.GetSize().x
-            tabRect = wx.Rect(startpos, pgInfo.GetPosition().y, fullrect.width-startpos, self.GetParent().GetSize().y)
-
-            if tabRect.Contains(pt):
-                return FNB_TAB, len(self._pagesInfoVec)        
-
-        # Default
-        return FNB_NOWHERE, -1
-
-
-    def SetSelection(self, page):
-        """ Sets the selected page. """
-
-        book = self.GetParent()
-        book.SetSelection(page)
-        self.DoSetSelection(page)
-
-
-    def DoSetSelection(self, page):
-        """ Does the actual selection of a page. """
-
-        if page < len(self._pagesInfoVec):
-            #! fix for tabfocus
-            da_page = self._pParent.GetPage(page)
-    
-#            if da_page != None:
-#                da_page.SetFocus()
-#        
-        self.EnsureVisible(page)
-
-    def EnsureVisible(self, page, refresh=True):
-        if not self.IsTabVisible(page):
-            # Try to remove one tab from start and try again
-            
-            if not self.CanFitToScreen(page):
-
-                if self._nFrom > page:
-                    self._nFrom = page
-                else:
-                    while self._nFrom < page:
-                        self._nFrom += 1
-                        if self.CanFitToScreen(page):
-                            break
-        if refresh:
-            self.Refresh()
-
-
-    def DeletePage(self, page):
-        """ Delete the specified page from L{FlatNotebook}. """
-
-        book = self.GetParent()
-        book.DeletePage(page)
-        book.Refresh()
-
-
-    def IsTabVisible(self, page):
-        """ Returns whether a tab is visible or not. """
-
-        iLastVisiblePage = self.GetLastVisibleTab()
-        return page <= iLastVisiblePage and page >= self._nFrom
-
-
-    def DoDeletePage(self, page):
-        """ Does the actual page deletion. """
-
-        # Remove the page from the vector
-        book = self.GetParent()
-        self._pagesInfoVec.pop(page)
-
-        # Thanks to Yiaanis AKA Mandrav
-        if self._iActivePage >= page:
-            self._iActivePage = self._iActivePage - 1
-            self._iPreviousActivePage = -1
-
-        # The delete page was the last first on the array,
-        # but the book still has more pages, so we set the
-        # active page to be the first one (0)
-        if self._iActivePage < 0 and len(self._pagesInfoVec) > 0:
-            self._iActivePage = 0
-            self._iPreviousActivePage = -1
-
-        # Refresh the tabs
-        if self._iActivePage >= 0:
-        
-            book._bForceSelection = True
-
-            # Check for selection and send event
-            event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
-            event.SetSelection(self._iActivePage)
-            event.SetOldSelection(self._iPreviousActivePage)
-            event.SetEventObject(self.GetParent())
-            self.GetParent().GetEventHandler().ProcessEvent(event)            
-
-            book.SetSelection(self._iActivePage)
-            book._bForceSelection = False
-
-            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
-            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
-            event.SetOldSelection(self._iPreviousActivePage)
-            self.GetParent().GetEventHandler().ProcessEvent(event)            
-        
-        if not self._pagesInfoVec:        
-            # Erase the page container drawings
-            dc = wx.ClientDC(self)
-            dc.Clear()
-        
-
-    def DeleteAllPages(self):
-        """ Deletes all the pages. """
-
-        self._iActivePage = -1
-        self._iPreviousActivePage = -1
-        self._nFrom = 0
-        self._pagesInfoVec = []
-
-        # Erase the page container drawings
-        dc = wx.ClientDC(self)
-        dc.Clear()
-
-
-    def OnMouseMove(self, event):
-        """ Handles the wx.EVT_MOTION for L{PageContainer}. """
-
-        if self._pagesInfoVec and self.IsShown():
-        
-            xButtonStatus = self._nXButtonStatus
-            xTabButtonStatus = self._nTabXButtonStatus
-            rightButtonStatus = self._nRightButtonStatus
-            leftButtonStatus = self._nLeftButtonStatus
-            dropDownButtonStatus = self._nArrowDownButtonStatus
-            
-            style = self.GetParent().GetWindowStyleFlag()
-
-            self._nXButtonStatus = FNB_BTN_NONE
-            self._nRightButtonStatus = FNB_BTN_NONE
-            self._nLeftButtonStatus = FNB_BTN_NONE
-            self._nTabXButtonStatus = FNB_BTN_NONE
-            self._nArrowDownButtonStatus = FNB_BTN_NONE
-
-            where, tabIdx = self.HitTest(event.GetPosition())
-            
-            if where == FNB_X:
-                if event.LeftIsDown():
-                
-                    self._nXButtonStatus = (self._nLeftClickZone==FNB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-                
-                else:
-                
-                    self._nXButtonStatus = FNB_BTN_HOVER
-
-            elif where == FNB_DROP_DOWN_ARROW:
-                if event.LeftIsDown():
-
-                    self._nArrowDownButtonStatus = (self._nLeftClickZone==FNB_DROP_DOWN_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-
-                else:
-
-                    self._nArrowDownButtonStatus = FNB_BTN_HOVER
-
-            elif where == FNB_TAB_X:
-                if event.LeftIsDown():
-                
-                    self._nTabXButtonStatus = (self._nLeftClickZone==FNB_TAB_X and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-                
-                else:
-
-                    self._nTabXButtonStatus = FNB_BTN_HOVER
-                
-            elif where == FNB_RIGHT_ARROW:
-                if event.LeftIsDown():
-                
-                    self._nRightButtonStatus = (self._nLeftClickZone==FNB_RIGHT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-                
-                else:
-                
-                    self._nRightButtonStatus = FNB_BTN_HOVER
-                
-            elif where == FNB_LEFT_ARROW:
-                if event.LeftIsDown():
-                
-                    self._nLeftButtonStatus = (self._nLeftClickZone==FNB_LEFT_ARROW and [FNB_BTN_PRESSED] or [FNB_BTN_NONE])[0]
-                
-                else:
-                
-                    self._nLeftButtonStatus = FNB_BTN_HOVER
-                
-            elif where == FNB_TAB:
-                # Call virtual method for showing tooltip
-                self.ShowTabTooltip(tabIdx)
-                
-                if not self.GetEnabled(tabIdx):                
-                    # Set the cursor to be 'No-entry'
-                    wx.SetCursor(wx.StockCursor(wx.CURSOR_NO_ENTRY))
-                
-                # Support for drag and drop
-                if event.Dragging() and not (style & FNB_NODRAG):
-
-                    self._isdragging = True                
-                    draginfo = FNBDragInfo(self, tabIdx)
-                    drginfo = cPickle.dumps(draginfo)
-                    dataobject = wx.CustomDataObject(wx.CustomDataFormat("FlatNotebook"))
-                    dataobject.SetData(drginfo)
-                    dragSource = FNBDropSource(self)
-                    dragSource.SetData(dataobject)
-                    dragSource.DoDragDrop(wx.Drag_DefaultMove)
-                    
-            bRedrawX = self._nXButtonStatus != xButtonStatus
-            bRedrawRight = self._nRightButtonStatus != rightButtonStatus
-            bRedrawLeft = self._nLeftButtonStatus != leftButtonStatus
-            bRedrawTabX = self._nTabXButtonStatus != xTabButtonStatus
-            bRedrawDropArrow = self._nArrowDownButtonStatus != dropDownButtonStatus
-
-            render = self._mgr.GetRenderer(style)
-        
-            if (bRedrawX or bRedrawRight or bRedrawLeft or bRedrawTabX or bRedrawDropArrow):
-
-                dc = wx.ClientDC(self)
-                
-                if bRedrawX:
-                                
-                    render.DrawX(self, dc)
-                
-                if bRedrawLeft:
-                
-                    render.DrawLeftArrow(self, dc)
-                
-                if bRedrawRight:
-                
-                    render.DrawRightArrow(self, dc)
-                
-                if bRedrawTabX:
-                
-                    self.Refresh()
-
-                if bRedrawDropArrow:
-
-                    render.DrawDropDownArrow(self, dc)
-
-        event.Skip()
-
-
-    def GetLastVisibleTab(self):
-        """ Returns the last visible tab. """
-
-        if self._nFrom < 0:
-            return -1
-
-        ii = 0
-        
-        for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
-        
-            if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
-                break
-        
-        return ii-1
-
-
-    def GetNumTabsCanScrollLeft(self):
-        """ Returns the number of tabs than can be scrolled left. """
-
-        if self._nFrom - 1 >= 0:
-            return 1
-
-        return 0
-
-
-    def IsDefaultTabs(self):
-        """ Returns whether a tab has a default style. """
-
-        style = self.GetParent().GetWindowStyleFlag()
-        res = (style & FNB_VC71) or (style & FNB_FANCY_TABS) or (style & FNB_VC8)
-        return not res
-
-
-    def AdvanceSelection(self, bForward=True):
-        """
-        Cycles through the tabs.
-        The call to this function generates the page changing events.
-        """
-
-        nSel = self.GetSelection()
-
-        if nSel < 0:
-            return
-
-        nMax = self.GetPageCount() - 1
-        
-        if bForward:
-            newSelection = (nSel == nMax and [0] or [nSel + 1])[0]
-        else:
-            newSelection = (nSel == 0 and [nMax] or [nSel - 1])[0]
-
-        if not self._pagesInfoVec[newSelection].GetEnabled():
-            return
-
-        self.FireEvent(newSelection)
-
-
-    def OnMouseLeave(self, event):
-        """ Handles the wx.EVT_LEAVE_WINDOW event for L{PageContainer}. """
-
-        self._nLeftButtonStatus = FNB_BTN_NONE
-        self._nXButtonStatus = FNB_BTN_NONE
-        self._nRightButtonStatus = FNB_BTN_NONE
-        self._nTabXButtonStatus = FNB_BTN_NONE
-        self._nArrowDownButtonStatus = FNB_BTN_NONE
-
-        style = self.GetParent().GetWindowStyleFlag()        
-        render = self._mgr.GetRenderer(style)
-        
-        dc = wx.ClientDC(self)
-
-        render.DrawX(self, dc)
-        render.DrawLeftArrow(self, dc)
-        render.DrawRightArrow(self, dc)
-
-        selection = self.GetSelection()
-
-        if selection == -1:
-            event.Skip()
-            return
-        
-        if not self.IsTabVisible(selection):
-            if selection == len(self._pagesInfoVec) - 1:
-                if not self.CanFitToScreen(selection):
-                    event.Skip()
-                    return
-            else:
-                event.Skip()
-                return
-                    
-        render.DrawTabX(self, dc, self._pagesInfoVec[selection].GetXRect(), selection, self._nTabXButtonStatus)
-        render.DrawFocusRectangle(dc, self, self._pagesInfoVec[selection])
-
-        event.Skip()
-
-
-    def OnMouseEnterWindow(self, event):
-        """ Handles the wx.EVT_ENTER_WINDOW event for L{PageContainer}. """
-
-        self._nLeftButtonStatus = FNB_BTN_NONE
-        self._nXButtonStatus = FNB_BTN_NONE
-        self._nRightButtonStatus = FNB_BTN_NONE
-        self._nLeftClickZone = FNB_BTN_NONE
-        self._nArrowDownButtonStatus = FNB_BTN_NONE
-
-        event.Skip()
-
-
-    def ShowTabTooltip(self, tabIdx):
-        """ Shows a tab tooltip. """
-
-        pWindow = self._pParent.GetPage(tabIdx)
-        
-        if pWindow:        
-            pToolTip = pWindow.GetToolTip()
-            if pToolTip and pToolTip.GetWindow() == pWindow:
-                self.SetToolTipString(pToolTip.GetTip())
-        
-
-    def SetPageImage(self, page, imgindex):
-        """ Sets the image index associated to a page. """
-
-        if page < len(self._pagesInfoVec):
-        
-            self._pagesInfoVec[page].SetImageIndex(imgindex)
-            self.Refresh()
-
-
-    def GetPageImage(self, page):
-        """ Returns the image index associated to a page. """
-
-        if page < len(self._pagesInfoVec):
-        
-            return self._pagesInfoVec[page].GetImageIndex()
-        
-        return -1
-
-
-    def OnDropTarget(self, x, y, nTabPage, wnd_oldContainer):
-        """ Handles the drop action from a DND operation. """
-
-        # Disable drag'n'drop for disabled tab
-        if not wnd_oldContainer._pagesInfoVec[nTabPage].GetEnabled():
-            return wx.DragCancel
-
-        self._isdragging = True
-        oldContainer = wnd_oldContainer
-        nIndex = -1
-
-        where, nIndex = self.HitTest(wx.Point(x, y))
-
-        oldNotebook = oldContainer.GetParent()
-        newNotebook = self.GetParent()
-
-        if oldNotebook == newNotebook:
-        
-            if nTabPage >= 0:
-            
-                if where == FNB_TAB:
-                    self.MoveTabPage(nTabPage, nIndex)
-                           
-        elif self.GetParent().GetWindowStyleFlag() & FNB_ALLOW_FOREIGN_DND:
-        
-            if wx.Platform in ["__WXMSW__", "__WXGTK__", "__WXMAC__"]:
-                if nTabPage >= 0:
-                
-                    window = oldNotebook.GetPage(nTabPage)
-
-                    if window:
-                        where, nIndex = newNotebook._pages.HitTest(wx.Point(x, y))
-                        caption = oldContainer.GetPageText(nTabPage)
-                        imageindex = oldContainer.GetPageImage(nTabPage)
-                        oldNotebook.RemovePage(nTabPage)
-                        window.Reparent(newNotebook)
-
-                        if imageindex >= 0:
-
-                            bmp = oldNotebook.GetImageList().GetBitmap(imageindex)
-                            newImageList = newNotebook.GetImageList()
-    
-                            if not newImageList:
-                                xbmp, ybmp = bmp.GetWidth(), bmp.GetHeight()
-                                newImageList = wx.ImageList(xbmp, ybmp)                                
-                                imageindex = 0
-                            else:
-                                imageindex = newImageList.GetImageCount()
-
-                            newImageList.Add(bmp)
-                            newNotebook.SetImageList(newImageList)
-                                
-                        newNotebook.InsertPage(nIndex, window, caption, True, imageindex)
-
-        self._isdragging = False
-        
-        return wx.DragMove
-
-
-    def MoveTabPage(self, nMove, nMoveTo):
-        """ Moves a tab inside the same L{FlatNotebook}. """
-
-        if nMove == nMoveTo:
-            return
-
-        elif nMoveTo < len(self._pParent._windows):
-            nMoveTo = nMoveTo + 1
-
-        self._pParent.Freeze()
-        
-        # Remove the window from the main sizer
-        nCurSel = self._pParent._pages.GetSelection()
-        self._pParent._mainSizer.Detach(self._pParent._windows[nCurSel])
-        self._pParent._windows[nCurSel].Hide()
-
-        pWindow = self._pParent._windows[nMove]
-        self._pParent._windows.pop(nMove)
-        self._pParent._windows.insert(nMoveTo-1, pWindow)
-
-        pgInfo = self._pagesInfoVec[nMove]
-
-        self._pagesInfoVec.pop(nMove)
-        self._pagesInfoVec.insert(nMoveTo - 1, pgInfo)
-
-        # Add the page according to the style
-        pSizer = self._pParent._mainSizer
-        style = self.GetParent().GetWindowStyleFlag()
-
-        if style & FNB_BOTTOM:
-        
-            pSizer.Insert(0, pWindow, 1, wx.EXPAND)
-        
-        else:
-        
-            # We leave a space of 1 pixel around the window
-            pSizer.Add(pWindow, 1, wx.EXPAND)
-        
-        pWindow.Show()
-
-        pSizer.Layout()
-        self._iActivePage = nMoveTo - 1
-        self._iPreviousActivePage = -1
-        self.DoSetSelection(self._iActivePage)
-        self.Refresh()
-        self._pParent.Thaw()
-
-
-    def CanFitToScreen(self, page):
-        """ Returns wheter a tab can fit in the left space in the screen or not. """
-
-        # Incase the from is greater than page,
-        # we need to reset the self._nFrom, so in order
-        # to force the caller to do so, we return false
-        if self._nFrom > page:
-            return False
-
-        style = self.GetParent().GetWindowStyleFlag()
-        render = self._mgr.GetRenderer(style)
-
-        vTabInfo = render.NumberTabsCanFit(self)
-
-        if page - self._nFrom >= len(vTabInfo):
-            return False
-        
-        return True
-
-
-    def GetNumOfVisibleTabs(self):
-        """ Returns the number of visible tabs. """
-
-        count = 0
-        for ii in xrange(self._nFrom, len(self._pagesInfoVec)):
-            if self._pagesInfoVec[ii].GetPosition() == wx.Point(-1, -1):
-                break
-            count = count + 1
-
-        return count
-
-
-    def GetEnabled(self, page):
-        """ Returns whether a tab is enabled or not. """
-
-        if page >= len(self._pagesInfoVec):
-            return True # Seems strange, but this is the default
-        
-        return self._pagesInfoVec[page].GetEnabled()
-
-
-    def EnableTab(self, page, enabled=True):
-        """ Enables or disables a tab. """
-
-        if page >= len(self._pagesInfoVec):
-            return
-        
-        self._pagesInfoVec[page].EnableTab(enabled)
-        
-
-    def GetSingleLineBorderColour(self):
-        """ Returns the colour for the single line border. """
-
-        if self.HasFlag(FNB_FANCY_TABS):
-            return self._colorFrom
-        
-        return wx.WHITE
-
-
-    def HasFlag(self, flag):
-        """ Returns whether a flag is present in the L{FlatNotebook} style. """
-
-        style = self.GetParent().GetWindowStyleFlag()
-        res = (style & flag and [True] or [False])[0]
-        return res
-
-
-    def ClearFlag(self, flag):
-        """ Deletes a flag from the L{FlatNotebook} style. """
-
-        style = self.GetParent().GetWindowStyleFlag()
-        style &= ~flag 
-        self.SetWindowStyleFlag(style)
-
-
-    def TabHasImage(self, tabIdx):
-        """ Returns whether a tab has an associated image index or not. """
-
-        if self._ImageList:
-            return self._pagesInfoVec[tabIdx].GetImageIndex() != -1
-        
-        return False
-
-
-    def OnLeftDClick(self, event):
-        """ Handles the wx.EVT_LEFT_DCLICK event for L{PageContainer}. """
-
-        where, tabIdx = self.HitTest(event.GetPosition())
-        
-        if where == FNB_RIGHT_ARROW:
-            self.RotateRight()
-
-        elif where == FNB_LEFT_ARROW:
-            self.RotateLeft()
-
-        elif self.HasFlag(FNB_DCLICK_CLOSES_TABS):
-        
-            if where == FNB_TAB:
-                self.DeletePage(tabIdx)
-        
-        else:
-        
-            event.Skip()
-        
-
-    def OnSetFocus(self, event):
-        """ Handles the wx.EVT_SET_FOCUS event for L{PageContainer}. """
-
-        if self._iActivePage < 0:
-            event.Skip()
-            return
-
-        self.SetFocusedPage(self._iActivePage)
-
-
-    def OnKillFocus(self, event):
-        """ Handles the wx.EVT_KILL_FOCUS event for L{PageContainer}. """
-
-        self.SetFocusedPage()
-
-
-    def OnKeyDown(self, event):
-        """
-        When the PageContainer has the focus tabs can be changed with
-        the left/right arrow keys.
-        """
-        key = event.GetKeyCode()
-        if key == wx.WXK_LEFT:
-            self.GetParent().AdvanceSelection(False)
-        elif key == wx.WXK_RIGHT:
-            self.GetParent().AdvanceSelection(True)
-        elif key == wx.WXK_TAB and not event.ControlDown():
-            flags = 0
-            if not event.ShiftDown(): flags |= wx.NavigationKeyEvent.IsForward
-            if event.CmdDown():       flags |= wx.NavigationKeyEvent.WinChange
-            self.Navigate(flags)
-        else:
-            event.Skip()
-
-            
-    def SetFocusedPage(self, pageIndex=-1):
-        """
-        Sets/Unsets the focus on the appropriate page.
-        If pageIndex is defaulted, we have lost focus and no focus indicator is drawn.
-        """
-
-        for indx, page in enumerate(self._pagesInfoVec):
-            if indx == pageIndex:
-                page._hasFocus = True
-            else:
-                page._hasFocus = False
-            
-        self.Refresh()
-                
-
-    def PopupTabsMenu(self):
-        """ Pops up the menu activated with the drop down arrow in the navigation area. """
-
-        popupMenu = wx.Menu()
-
-        for i in xrange(len(self._pagesInfoVec)):
-            pi = self._pagesInfoVec[i]
-            item = wx.MenuItem(popupMenu, i+1, pi.GetCaption(), pi.GetCaption(), wx.ITEM_NORMAL)
-            self.Bind(wx.EVT_MENU, self.OnTabMenuSelection, item)
-
-            # There is an alignment problem with wx2.6.3 & Menus so only use
-            # images for versions above 2.6.3
-            if wx.VERSION > (2, 6, 3, 0) and self.TabHasImage(i):
-                item.SetBitmap(self.GetImageList().GetBitmap(pi.GetImageIndex()))
-
-            popupMenu.AppendItem(item)
-            item.Enable(pi.GetEnabled())
-            
-        self.PopupMenu(popupMenu)
-
-
-    def OnTabMenuSelection(self, event):
-        """ Handles the wx.EVT_MENU event for L{PageContainer}. """
-
-        selection = event.GetId() - 1
-        self.FireEvent(selection)
-
-
-    def FireEvent(self, selection):
-        """
-        Fires the wxEVT_FLATNOTEBOOK_PAGE_CHANGING and wxEVT_FLATNOTEBOOK_PAGE_CHANGED events
-        called from other methods (from menu selection or Smart Tabbing).
-        Utility function.
-        """
-
-        if selection == self._iActivePage:
-            # No events for the same selection
-            return
-        
-        oldSelection = self._iActivePage
-
-        event = FlatNotebookEvent(wxEVT_FLATNOTEBOOK_PAGE_CHANGING, self.GetParent().GetId())
-        event.SetSelection(selection)
-        event.SetOldSelection(oldSelection)
-        event.SetEventObject(self.GetParent())
-        
-        if not self.GetParent().GetEventHandler().ProcessEvent(event) or event.IsAllowed():
-        
-            self.SetSelection(selection)
-
-            # Fire a wxEVT_FLATNOTEBOOK_PAGE_CHANGED event
-            event.SetEventType(wxEVT_FLATNOTEBOOK_PAGE_CHANGED)
-            event.SetOldSelection(oldSelection)
-            self.GetParent().GetEventHandler().ProcessEvent(event)
-#            self.SetFocus()
-            
-
-    def SetImageList(self, imglist):
-        """ Sets the image list for the page control. """
-
-        self._ImageList = imglist
-
-
-    def AssignImageList(self, imglist):
-        """ Assigns the image list for the page control. """
-
-        self._ImageList = imglist
-
-
-    def GetImageList(self):
-        """ Returns the image list for the page control. """
-
-        return self._ImageList
-
-
-    def GetSelection(self):
-        """ Returns the current selected page. """
-
-        return self._iActivePage 
-
-
-    def GetPageCount(self):
-        """ Returns the number of tabs in the L{FlatNotebook} control. """
-
-        return len(self._pagesInfoVec)
-
-
-    def GetPageText(self, page):
-        """ Returns the tab caption of the page. """
-
-        return self._pagesInfoVec[page].GetCaption() 
-
-
-    def SetPageText(self, page, text):
-        """ Sets the tab caption of the page. """
-
-        self._pagesInfoVec[page].SetCaption(text)
-        return True 
-
-
-    def DrawDragHint(self):
-        """ Draws small arrow at the place that the tab will be placed. """
-
-        # get the index of tab that will be replaced with the dragged tab
-        pt = wx.GetMousePosition()
-        client_pt = self.ScreenToClient(pt)
-        where, tabIdx = self.HitTest(client_pt)
-        self._mgr.GetRenderer(self.GetParent().GetWindowStyleFlag()).DrawDragHint(self, tabIdx)
-
-
diff --git a/utils/PyoDoc.py b/utils/PyoDoc.py
index 03e145f..9628f9a 100644
--- a/utils/PyoDoc.py
+++ b/utils/PyoDoc.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # encoding: utf-8
 from __future__ import with_statement
-import subprocess, threading, os
+import subprocess, threading, os, sys, unicodedata
 import wx
 import wx.stc  as  stc
 from wx.lib.embeddedimage import PyEmbeddedImage
@@ -9,6 +9,10 @@ from pyo import *
 
 DOC_AS_SINGLE_APP = False
 
+PLATFORM = sys.platform
+DEFAULT_ENCODING = sys.getdefaultencoding()
+ENCODING = sys.getfilesystemencoding()
+
 TEMP_PATH = os.path.join(os.path.expanduser('~'), '.epyo')
 if not os.path.isdir(TEMP_PATH):
     os.mkdir(TEMP_PATH)
@@ -19,14 +23,14 @@ DOC_STYLES = {'Default': {'default': '#000000', 'comment': '#007F7F', 'commentbl
                     'number': '#005000', 'string': '#7F007F', 'triple': '#7F0000', 'keyword': '#00007F', 'keyword2': '#007F9F',
                     'class': '#0000FF', 'function': '#007F7F', 'identifier': '#000000', 'caret': '#00007E',
                     'background': '#EEEEEE', 'linenumber': '#000000', 'marginback': '#B0B0B0', 'markerfg': '#CCCCCC',
-                      'markerbg': '#000000', 'bracelight': '#AABBDD', 'bracebad': '#DD0000', 'lineedge': '#CCCCCC'}}
+                    'markerbg': '#000000', 'bracelight': '#AABBDD', 'bracebad': '#DD0000', 'lineedge': '#CCCCCC'}}
 
 if wx.Platform == '__WXMSW__':
   DOC_FACES = {'face': 'Verdana', 'size' : 8, 'size2': 7}
 elif wx.Platform == '__WXMAC__':
   DOC_FACES = {'face': 'Monaco', 'size' : 12, 'size2': 9}
 else:
-  DOC_FACES = {'face': 'Courier New', 'size' : 8, 'size2': 7}
+  DOC_FACES = {'face': 'Monospace', 'size' : 8, 'size2': 7}
 DOC_FACES['size3'] = DOC_FACES['size2'] + 4
 for key, value in DOC_STYLES['Default'].items():
   DOC_FACES[key] = value
@@ -206,11 +210,10 @@ functions : Miscellaneous functions.
 """ % PYO_VERSION
 
 _DOC_KEYWORDS = ['Attributes', 'Examples', 'Methods', 'Notes', 'Methods details', 
-                 'Parentclass', 'Overview', 'Initline', 'Description']
+                 'Parentclass', 'Overview', 'Initline', 'Description', 'Parameters']
 _HEADERS = ["Server", "PyoObjectBase", "Map", "Stream", "TableStream", "functions"]
-_KEYWORDS_LIST = ['Parameters']
+_KEYWORDS_LIST = ['SLMap']
 _KEYWORDS_LIST.extend(_HEADERS)
-_KEYWORDS_LIST.append("SLMap")
 _NUM_PAGES = 1
 _NUM_PAGES += len(_HEADERS)
 for k1 in _HEADERS:
@@ -786,7 +789,7 @@ class ManualPanel(wx.Treebook):
                 if not panel.isLoad:
                     panel.isLoad = True
                     panel.win = stc.StyledTextCtrl(panel, -1, size=panel.GetSize(), style=wx.SUNKEN_BORDER)
-                    panel.win.LoadFile(os.path.join(DOC_PATH, word))
+                    panel.win.LoadFile(os.path.join(ensureNFD(DOC_PATH), word))
                     panel.win.SetMarginWidth(1, 0)
                     panel.win.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
                     if self.searchKey != None:
@@ -925,7 +928,8 @@ class ManualFrame(wx.Frame):
             self.searchMenu.Append(id, txt)
             self.Bind(wx.EVT_MENU, self.onSearchScope, id=id)
 
-        self.search = wx.SearchCtrl(self.toolbar, 200, size=(200,-1), style=wx.WANTS_CHARS | wx.TE_PROCESS_ENTER)
+        tw, th = self.GetTextExtent("Q")
+        self.search = wx.SearchCtrl(self.toolbar, 200, size=(200,th+6), style=wx.WANTS_CHARS | wx.TE_PROCESS_ENTER)
         self.search.ShowCancelButton(True)
         self.search.SetMenu(self.searchMenu)
         self.toolbar.AddControl(self.search)
@@ -1080,6 +1084,42 @@ class RunningThread(threading.Thread):
         while self.proc.poll() == None and not self.terminated:
             time.sleep(.25)
 
+def ensureNFD(unistr):
+    if PLATFORM in ['linux2', 'win32']:
+        encodings = [DEFAULT_ENCODING, ENCODING,
+                     'cp1252', 'iso-8859-1', 'utf-16']
+        format = 'NFC'
+    else:
+        encodings = [DEFAULT_ENCODING, ENCODING,
+                     'macroman', 'iso-8859-1', 'utf-16']
+        format = 'NFC'
+    decstr = unistr
+    if type(decstr) != UnicodeType:
+        for encoding in encodings:
+            try:
+                decstr = decstr.decode(encoding)
+                break
+            except UnicodeDecodeError:
+                continue
+            except:
+                decstr = "UnableToDecodeString"
+                print "Unicode encoding not in a recognized format..."
+                break
+    if decstr == "UnableToDecodeString":
+        return unistr
+    else:
+        return unicodedata.normalize(format, decstr)
+
+def toSysEncoding(unistr):
+    try:
+        if PLATFORM == "win32":
+            unistr = unistr.encode(ENCODING)
+        else:
+            unistr = unicode(unistr)
+    except:
+        pass
+    return unistr
+
 if __name__ == "__main__":
     DOC_AS_SINGLE_APP = True
     app = wx.PySimpleApp()
diff --git a/utils/epyo_builder_OSX.sh b/utils/epyo_builder_OSX.sh
index a715ead..463cbf8 100755
--- a/utils/epyo_builder_OSX.sh
+++ b/utils/epyo_builder_OSX.sh
@@ -1,6 +1,5 @@
 mkdir Resources
 cp PyoDoc.py Resources/
-cp FlatNoteBook.py Resources/
 cp Tutorial_01_RingMod.py Resources/
 cp Tutorial_02_Flanger.py Resources/
 cp Tutorial_03_TriTable.py Resources/
@@ -27,20 +26,19 @@ else
     exit;
 fi
 
-ditto --rsrc --arch i386 E-Pyo.app E-Pyo-i386.app
+# keep only 64-bit arch
+ditto --rsrc --arch x86_64 E-Pyo.app E-Pyo-x86_64.app
 rm -rf E-Pyo.app
-mv E-Pyo-i386.app E-Pyo.app
+mv E-Pyo-x86_64.app E-Pyo.app
 
 cd ..
 cp -R E-Pyo_OSX/E-Pyo.app .
 
-# Fixed wrong path in Info.plist
-cd E-Pyo.app/Contents
-awk '{gsub("Library/Frameworks/Python.framework/Versions/2.6/Resources/Python.app/Contents/MacOS/Python", "@executable_path/../Frameworks/Python.framework/Versions/2.6/Python")}1' Info.plist > Info.plist_tmp && mv Info.plist_tmp Info.plist
+# Fixed wrong path in Info.plist (no more needed python 2.7.8, py2app 0.9)
+#cd E-Pyo.app/Contents
+#awk '{gsub("Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python", "@executable_path/../Frameworks/Python.framework/Versions/2.7/Python")}1' Info.plist > Info.plist_tmp && mv Info.plist_tmp Info.plist
+#cd ../..
 
-cd ../..
-#tar -cjvf E-Pyo_OSX-0.6.1.tar.bz2 E-Pyo.app
-#rm -rf E-Pyo.app
 rm -rf E-Pyo_OSX
 rm -rf Resources
 rm -rf examples
diff --git a/utils/epyo_builder_win32.py b/utils/epyo_builder_win32.py
index e4265c3..8241966 100644
--- a/utils/epyo_builder_win32.py
+++ b/utils/epyo_builder_win32.py
@@ -4,7 +4,6 @@ version = sys.version_info[:2]
 
 os.mkdir("Resources")
 shutil.copy("PyoDoc.py", "Resources")
-shutil.copy("FlatNoteBook.py", "Resources")
 shutil.copy("Tutorial_01_RingMod.py", "Resources")
 shutil.copy("Tutorial_02_Flanger.py", "Resources")
 shutil.copy("Tutorial_03_TriTable.py", "Resources")
@@ -15,9 +14,9 @@ os.system("svn export ../examples Resources/examples/")
 os.system("svn export snippets Resources/snippets/")
 os.system("svn export styles Resources/styles/")
 
-os.system("C:\Python%d%d\python ..\..\pyinstaller\Configure.py" % version)
-os.system('C:\Python%d%d\python ..\..\pyinstaller\Makespec.py -F -c --icon=Resources\E-PyoIcon.ico "E-Pyo.py"' % version)
-os.system('C:\Python%d%d\python ..\..\pyinstaller\Build.py "E-Pyo.spec"' % version)
+#os.system("C:\Python%d%d\python ..\..\pyinstaller\Configure.py" % version)
+os.system('C:\Python%d%d\Scripts\pyi-makespec -F -c --icon=Resources\E-PyoIcon.ico "E-Pyo.py"' % version)
+os.system('C:\Python%d%d\Scripts\pyi-build "E-Pyo.spec"' % version)
 
 os.mkdir("E-Pyo_py%d%d" % version)
 shutil.copytree("Resources", "E-Pyo_py%d%d/Resources" % version)
diff --git a/utils/info.plist b/utils/info.plist
index b43497a..0abb41b 100644
--- a/utils/info.plist
+++ b/utils/info.plist
@@ -32,17 +32,17 @@
 	<key>CFBundleIdentifier</key>
 	<string>org.pythonmac.unspecified.E-Pyo</string>
 	<key>CFBundleInfoDictionaryVersion</key>
-	<string>0.6.8</string>
+	<string>0.7.4</string>
 	<key>CFBundleName</key>
 	<string>E-Pyo</string>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>0.6.8</string>
+	<string>0.7.4</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>0.6.8</string>
+	<string>0.7.4</string>
 	<key>LSHasLocalizedDisplayName</key>
 	<false/>
 	<key>NSAppleScriptEnabled</key>
@@ -78,17 +78,16 @@
 	<array/>
 	<key>PyRuntimeLocations</key>
 	<array>
-		<string>@executable_path/../Frameworks/Python.framework/Versions/2.6/Python</string>
+		<string>@executable_path/../Frameworks/Python.framework/Versions/2.7/Python</string>
 	</array>
 	<key>PythonInfoDict</key>
 	<dict>
 		<key>PythonExecutable</key>
-		<string>@executable_path/../Frameworks/Python.framework/Versions/2.6/Python</string>
+		<string>@executable_path/../Frameworks/Python.framework/Versions/2.7/Python</string>
 		<key>PythonLongVersion</key>
-		<string>2.6.5 (r265:79359, Mar 24 2010, 01:32:55) 
-[GCC 4.0.1 (Apple Inc. build 5493)]</string>
+		<string>2.7.8 (v2.7.8:ee879c0ffa11, Jun 29 2014, 21:07:35) \n[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]</string>
 		<key>PythonShortVersion</key>
-		<string>2.6</string>
+		<string>2.7</string>
 		<key>py2app</key>
 		<dict>
 			<key>alias</key>
@@ -96,7 +95,7 @@
 			<key>template</key>
 			<string>app</string>
 			<key>version</key>
-			<string>0.4.4</string>
+			<string>0.9</string>
 		</dict>
 	</dict>
 </dict>

-- 
python-pyo packaging



More information about the pkg-multimedia-commits mailing list