[SCM] python-pyo/master: New upstream release.

tiago at users.alioth.debian.org tiago at users.alioth.debian.org
Tue Dec 13 20:35:47 UTC 2016


The following commit has been merged in the master branch:
commit 14ccf066f17510e555887c7fb0e2c0dd54002147
Author: Tiago Bortoletto Vaz <tiago at debian.org>
Date:   Mon Mar 7 15:13:41 2016 -0500

    New upstream release.

diff --git a/ChangeLog b/ChangeLog
index 4d9772e..27a003c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2016-03-01 belangeo <belangeo at gmail.com>
+
+    * Final revision for version 0.7.9.
+    - SHA: 7ddbeacd14cd78ce4930c845a82745bb58f4a26c
+
+2016-03-01 belangeo <belangeo at gmail.com>
+
+    *  Upgraded version number to 0.7.9.
+
+2016-03-01 belangeo <belangeo at gmail.com>
+
+    *  Pyo now uses its own PRNG to avoid conflicts with other libs or 
+    modules that use rand()/srand() in the same process. This fixed the 
+    Server's global seed behaviour.
+
+2016-02-29 belangeo <belangeo at gmail.com>
+
+    * Fixed a bug, introduced by unicode addresses handler, in Open Sound 
+    Control objects.
+
+2016-02-29 belangeo <belangeo at gmail.com>
+
+    * Exposed internal GUI widgets in the official API. New objects are
+    PyoGuiControlSlider, PyoGuiVuMeter, PyoGuiGrapher, PyoGuiMultiSlider,
+    PyoGuiSpectrum, PyoGuiScope and PyoGuiSndView.
+
+2016-02-17 belangeo <belangeo at gmail.com>
+
+    * E-Pyo: Added a warning before quitting the application.
+
+2016-02-12 belangeo <belangeo at gmail.com>
+
+    * Fixed a bug in Notein voice assignation.
+
+2016-02-12 belangeo <belangeo at gmail.com>
+
+    * Added readyToDetect() method to AttackDetector object.
+
+2016-01-29 belangeo <belangeo at gmail.com>
+
+    * Fixed segfault in Server dealloc function.
+
 2016-01-08 belangeo <belangeo at gmail.com>
 
     * Final revision for version 0.7.8.
diff --git a/debian/changelog b/debian/changelog
index 93f2b18..1075c0f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+python-pyo (0.7.9-1) unstable; urgency=medium
+
+  * New upstream release.
+
+ -- Tiago Bortoletto Vaz <tiago at debian.org>  Mon, 07 Mar 2016 15:13:08 -0500
+
 python-pyo (0.7.8+git20160129-1) unstable; urgency=medium
 
   * Fix segfault when rendering.
diff --git a/doc-sphinx/source/api/classes/expression.rst b/doc-sphinx/source/api/classes/expression.rst
index c2e5e3a..4d544b6 100644
--- a/doc-sphinx/source/api/classes/expression.rst
+++ b/doc-sphinx/source/api/classes/expression.rst
@@ -94,7 +94,7 @@ Builtin functions
 Comments
 --------
 
-A comment start with two slashs ( // ) and ends at the end of the line::
+A comment starts with two slashs ( // ) and ends at the end of the line::
     
     // This is a comment!
 
diff --git a/doc-sphinx/source/api/classes/index.rst b/doc-sphinx/source/api/classes/index.rst
index 3fb9d7c..95836a9 100644
--- a/doc-sphinx/source/api/classes/index.rst
+++ b/doc-sphinx/source/api/classes/index.rst
@@ -31,4 +31,5 @@ Classes by category
    tables
    matrices
    map
+   wxgui
 
diff --git a/doc-sphinx/source/api/classes/wxgui.rst b/doc-sphinx/source/api/classes/wxgui.rst
new file mode 100644
index 0000000..2214a23
--- /dev/null
+++ b/doc-sphinx/source/api/classes/wxgui.rst
@@ -0,0 +1,52 @@
+Additional WxPython widgets 
+===============================
+
+.. module:: pyo
+
+The classes in this module are based on internal classes that where 
+originally designed to help the creation of graphical tools for the
+control and the visualization of audio signals. WxPython must be installed
+under the current Python distribution to access these classes.
+
+
+*PyoGuiControlSlider*
+-----------------------------------
+
+.. autoclass:: PyoGuiControlSlider
+   :members:
+
+*PyoGuiVuMeter*
+-----------------------------------
+
+.. autoclass:: PyoGuiVuMeter
+   :members:
+
+*PyoGuiGrapher*
+-----------------------------------
+
+.. autoclass:: PyoGuiGrapher
+   :members:
+
+*PyoGuiMultiSlider*
+-----------------------------------
+
+.. autoclass:: PyoGuiMultiSlider
+   :members:
+
+*PyoGuiSpectrum*
+-----------------------------------
+
+.. autoclass:: PyoGuiSpectrum
+   :members:
+
+*PyoGuiScope*
+-----------------------------------
+
+.. autoclass:: PyoGuiScope
+   :members:
+
+*PyoGuiSndView*
+-----------------------------------
+
+.. autoclass:: PyoGuiSndView
+   :members:
diff --git a/doc-sphinx/source/index.rst b/doc-sphinx/source/index.rst
index a07f281..64e0d41 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.7.8 documentation
+Welcome to the Pyo 0.7.9 documentation
 ===================================================
 
 Pyo is a Python module written in C to help digital signal processing script 
diff --git a/embedded/puredata/pyo~-help.pd b/embedded/puredata/pyo~-help.pd
index 9ba3bef..f2101a2 100644
--- a/embedded/puredata/pyo~-help.pd
+++ b/embedded/puredata/pyo~-help.pd
@@ -234,7 +234,7 @@ in pyo~ inputs).;
 #N canvas 193 300 450 300 README 0;
 #X text 14 33 Author : Olivier Belanger;
 #X text 14 81 Last update : October 2015;
-#X text 14 57 Version : 0.7.8;
+#X text 14 57 Version : 0.7.9;
 #X text 15 108 pyo website : http://ajaxsoundstudio.com/software/pyo/
 ;
 #X text 15 10 pyo~ : Embedded pyo scripting inside puredata.;
diff --git a/examples/effects/04_harmonizer.py b/examples/effects/04_harmonizer.py
index 98d9113..43676fc 100644
--- a/examples/effects/04_harmonizer.py
+++ b/examples/effects/04_harmonizer.py
@@ -10,7 +10,7 @@ s = Server(sr=44100, nchnls=2, buffersize=512, duplex=0).boot()
 
 sf = SfPlayer('../snds/flute.aif', speed=1, loop=True, mul=.5).out()
 
-env = WinTable(7)
+env = WinTable(8)
 
 wsize = .1
 trans = -7
diff --git a/examples/effects/05_fuzz_disto.py b/examples/effects/05_fuzz_disto.py
index 1976ff8..e4f9a90 100644
--- a/examples/effects/05_fuzz_disto.py
+++ b/examples/effects/05_fuzz_disto.py
@@ -34,7 +34,7 @@ boost = Sig(bp, mul=BOOST)
 sig = Lookup(table, boost)
 
 # Lowpass filter on distorted signal
-lp = Tone(sig, freq=LP_CUTOFF_FREQ, mul=.7)
+lp = ButLP(sig, freq=LP_CUTOFF_FREQ, mul=.7)
 
 # Balance between dry and wet signals
 out = Interp(src, lp, interp=BALANCE).out()
diff --git a/examples/wxgui/01_gui_widgets_example.py b/examples/wxgui/01_gui_widgets_example.py
new file mode 100644
index 0000000..a196501
--- /dev/null
+++ b/examples/wxgui/01_gui_widgets_example.py
@@ -0,0 +1,236 @@
+"""
+Demo script for showing how GUI classes from pyo can be used to build
+audio programs with graphical interface.
+
+"""
+import wx, time, random
+from pyo import *
+
+NCHNLS = 2
+
+server = Server(nchnls=NCHNLS).boot().start()
+
+### A basic audio process ###
+snd = SndTable([SNDS_PATH+"/transparent.aif"]*NCHNLS)
+m = Metro(.125, poly=1).play()
+am = Iter(m, [1,0,0,0]*4)
+t2 = ExpTable([(0,1),(4096,10),(8191,10)], exp=4)
+q = TrigEnv(m, t2, m.time)
+pos = TrigLinseg(m, [(0.0,0.0), (m.time, 1,0)])
+n = Pointer(snd, pos, mul=am)
+fr = SigTo(1000, time=0.05, init=1000)
+f = ButBP(n, freq=fr, q=q).out()
+#pa = PeakAmp(f)
+sp = Spectrum(f)
+sc = Scope(f)
+
+class MyFrame(wx.Frame):
+    def __init__(self, parent, title, pos=(50, 50), size=(850, 600)):
+        wx.Frame.__init__(self, parent, -1, title, pos, size)
+        self.panel = wx.Panel(self)
+        vmainsizer = wx.BoxSizer(wx.VERTICAL)
+        mainsizer = wx.BoxSizer(wx.HORIZONTAL)
+        leftbox = wx.BoxSizer(wx.VERTICAL)
+        midbox = wx.BoxSizer(wx.VERTICAL)
+        rightbox = wx.BoxSizer(wx.VERTICAL)
+
+        ### PyoGuiControlSlider - logarithmic scale ###
+        sizer1 = self.createFreqSlider()
+
+        ### PyoGuiControlSlider - dB scale & VuMeter ###
+        sizer2 = self.createOutputBox()
+
+        ### PyoGuiGrapher - Filter's Q automation ###
+        sizer3 = self.createGrapher()
+
+        ### PyoGuiMultiSlider - Step Sequencer ###
+        sizer4 = self.createMultiSlider()
+
+        ### PyoGuiSpectrum - Frequency display ###
+        sizer5 = self.createSpectrum()
+
+        ### PyoGuiScope - oscilloscope display ###
+        sizer6 = self.createScope()
+
+        ### PyoGuiSndView - Soundfile display ###
+        sizer7 = self.createSndView()
+
+        leftbox.Add(sizer1, 0, wx.ALL | wx.EXPAND, 5)
+        leftbox.Add(sizer3, 1, wx.ALL | wx.EXPAND, 5)
+        leftbox.Add(sizer4, 1, wx.ALL | wx.EXPAND, 5)
+
+        midbox.Add(sizer5, 1, wx.ALL | wx.EXPAND, 5)
+        midbox.Add(sizer6, 1, wx.ALL | wx.EXPAND, 5)
+
+        rightbox.Add(sizer2, 1, wx.ALL | wx.EXPAND, 5)
+        
+        mainsizer.Add(leftbox, 1, wx.ALL | wx.EXPAND, 5)
+        mainsizer.Add(midbox, 1, wx.ALL | wx.EXPAND, 5)
+        mainsizer.Add(rightbox, 0, wx.ALL | wx.EXPAND, 5)
+        vmainsizer.Add(mainsizer, 1, wx.ALL | wx.EXPAND, 5)
+        vmainsizer.Add(sizer7, 1, wx.ALL | wx.EXPAND, 5)
+        self.panel.SetSizerAndFit(vmainsizer)
+
+    def createFreqSlider(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        label = wx.StaticText(self.panel, -1, "PyoGuiControlSlider: filter's center frequency (log scale)")
+        sizer.Add(label, 0, wx.CENTER|wx.ALL, 5) 
+        self.freq = PyoGuiControlSlider(parent=self.panel, 
+                                        minvalue=20, 
+                                        maxvalue=20000, 
+                                        init=1000, 
+                                        pos=(0, 0), 
+                                        size=(200, 16),
+                                        log=True, 
+                                        integer=False,
+                                        powoftwo=False,
+                                        orient=wx.HORIZONTAL)
+        #print self.freq.getRange()
+        #print self.freq.isPowOfTwo()
+        self.freq.Bind(EVT_PYO_GUI_CONTROL_SLIDER, self.changeFreq)
+        sizer.Add(self.freq, 0, wx.ALL | wx.EXPAND, 5)
+        return sizer
+
+    def createOutputBox(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        label = wx.StaticText(self.panel, -1, "dB slider - PyoGuiVuMeter")
+        sizer.Add(label, 0, wx.CENTER|wx.ALL, 5) 
+        sizer1 = wx.BoxSizer(wx.HORIZONTAL)
+        self.amp = PyoGuiControlSlider(parent=self.panel, 
+                                        minvalue=-60, 
+                                        maxvalue=18, 
+                                        init=-12, 
+                                        pos=(0, 0), 
+                                        size=(200, 16),
+                                        log=False, 
+                                        integer=False,
+                                        powoftwo=False,
+                                        orient=wx.VERTICAL)
+        self.amp.Bind(EVT_PYO_GUI_CONTROL_SLIDER, self.changeGain)
+        self.meter = PyoGuiVuMeter(parent=self.panel, 
+                                   nchnls=NCHNLS, 
+                                   pos=(0, 0), 
+                                   size=(5*NCHNLS, 200),
+                                   orient=wx.VERTICAL,
+                                   style=0)
+        self.meter.setNchnls(8)
+        # Register the VuMeter in the Server object.
+        server.setMeter(self.meter)
+        # or register its `setRms` method in a PeakAmp object.
+        # pa.setFunction(self.meter.setRms)
+
+        sizer1.Add(self.amp, 0, wx.ALL | wx.EXPAND, 5)
+        sizer1.Add(self.meter, 0, wx.ALL | wx.EXPAND, 5)
+        sizer.Add(sizer1, 1, wx.CENTER | wx.ALL, 5)
+        return sizer
+
+    def createGrapher(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        label = wx.StaticText(self.panel, -1, "PyoGuiGrapher: Filter's Q automation")
+        sizer.Add(label, 0, wx.CENTER|wx.ALL, 5)
+        self.graph = PyoGuiGrapher(parent=self.panel, 
+                                    xlen=8192, 
+                                    yrange=(1.0, 10.0), 
+                                    init=[(0.0, 0.0), (1.0, 1.0)], 
+                                    mode=2, 
+                                    exp=t2.exp,
+                                    inverse=True, 
+                                    tension=0.75,
+                                    bias=8.0,
+                                    size=(300,100),
+                                    style=0)
+        self.graph.setValues(t2.getPoints())
+        self.graph.setYrange((0.1, 20))
+        self.graph.setInverse(False)
+        self.graph.Bind(EVT_PYO_GUI_GRAPHER, self.changeGraph)
+        sizer.Add(self.graph, 1, wx.ALL | wx.EXPAND, 5)
+        return sizer
+
+    def createMultiSlider(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        label = wx.StaticText(self.panel, -1, "PyoGuiMultiSlider: Step Sequencer")
+        sizer.Add(label, 0, wx.CENTER|wx.ALL, 5)
+        self.steps = PyoGuiMultiSlider(parent=self.panel, 
+                                    xlen=16, 
+                                    yrange=(0, 1), 
+                                    init=[1,0,0,0]*4,
+                                    size=(300,100),
+                                    style=0)
+        self.steps.setYrange((0, 2))
+        self.steps.setValues([random.uniform(0, 2) for i in range(16)])
+        self.steps.Bind(EVT_PYO_GUI_MULTI_SLIDER, self.changeSteps)
+        sizer.Add(self.steps, 1, wx.ALL | wx.EXPAND, 5)
+        return sizer
+
+    def createSpectrum(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        label = wx.StaticText(self.panel, -1, "PyoGuiSpectrum: Frequency display")
+        sizer.Add(label, 0, wx.CENTER|wx.ALL, 5)
+        self.spectrum = PyoGuiSpectrum(parent=self.panel, 
+                                    lowfreq=0,
+                                    highfreq=22050,
+                                    fscaling=1,
+                                    mscaling=1,
+                                    size=(300,150),
+                                    style=0)
+        self.spectrum.setAnalyzer(sp)
+        sizer.Add(self.spectrum, 1, wx.ALL | wx.EXPAND, 5)
+        return sizer
+
+    def createScope(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        label = wx.StaticText(self.panel, -1, "PyoGuiScope: Oscilloscope display")
+        sizer.Add(label, 0, wx.CENTER|wx.ALL, 5)
+        self.scope = PyoGuiScope(parent=self.panel, 
+                                    length=0.05,
+                                    gain=1,
+                                    size=(300,150),
+                                    style=0)
+        self.scope.setAnalyzer(sc)
+        self.scope.setLength(0.05)
+        self.scope.setGain(0.67)
+        sizer.Add(self.scope, 1, wx.ALL | wx.EXPAND, 5)
+        return sizer
+
+    def createSndView(self):
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        label = wx.StaticText(self.panel, -1, "PyoGuiSndView: Soundfile display")
+        sizer.Add(label, 0, wx.CENTER|wx.ALL, 5)
+        self.sndview = PyoGuiSndView(parent=self.panel, 
+                                    size=(300,200),
+                                    style=0)
+        self.sndview.setTable(snd)
+        self.sndview.setSelection(0.51, 0.76)
+        self.sndview.Bind(EVT_PYO_GUI_SNDVIEW_MOUSE_POSITION, self.mousePos)
+        self.sndview.Bind(EVT_PYO_GUI_SNDVIEW_SELECTION, self.sndSelection)
+        sizer.Add(self.sndview, 1, wx.ALL | wx.EXPAND, 5)
+        return sizer
+
+    def changeFreq(self, evt):
+        fr.value = evt.value
+
+    def changeGain(self, evt):
+        am.mul = pow(10, evt.value * 0.05)
+
+    def changeGraph(self, evt):
+        t2.replace(evt.value)
+
+    def changeSteps(self, evt):
+        am.setChoice(evt.value)
+
+    def mousePos(self, evt):
+        print(evt.value)
+
+    def sndSelection(self, evt):
+        pos.replace([(0.0, evt.value[0]), (m.time, evt.value[1])])
+
+app = wx.App(False)
+mainFrame = MyFrame(None, title='Test Pyo GUI objects')
+mainFrame.Show()
+app.MainLoop()
+
+# Clean up...
+server.stop()
+time.sleep(0.25)
+server.shutdown()
+time.sleep(0.25)
\ No newline at end of file
diff --git a/include/pyomodule.h b/include/pyomodule.h
index b5ba8b5..4b61140 100644
--- a/include/pyomodule.h
+++ b/include/pyomodule.h
@@ -21,7 +21,7 @@
 #include "Python.h"
 #include <math.h>
 
-#define PYO_VERSION "0.7.8"
+#define PYO_VERSION "0.7.9"
 
 #ifndef __MYFLT_DEF
 #define __MYFLT_DEF
@@ -494,8 +494,10 @@ extern PyTypeObject ExprType;
 #define PI M_PI
 #define TWOPI (2 * M_PI)
 
+#define PYO_RAND_MAX 4294967295
+
 /* random uniform (0.0 -> 1.0) */
-#define RANDOM_UNIFORM rand()/((MYFLT)(RAND_MAX)+1)
+#define RANDOM_UNIFORM (pyorand()/((MYFLT)(PYO_RAND_MAX)+1))
 
 /* random objects identifier */
 #define BEATER_ID 0
diff --git a/include/servermodule.h b/include/servermodule.h
index 31f22a1..255f674 100644
--- a/include/servermodule.h
+++ b/include/servermodule.h
@@ -141,10 +141,11 @@ typedef struct {
     /* Properties */
     int verbosity; /* a sum of values to display different levels: 1 = error */
                    /* 2 = message, 4 = warning , 8 = debug. Default 7.*/
-    int globalSeed; /* initial seed for random objects. If -1, objects are seeded with the clock. */
+    int globalSeed; /* initial seed for random objects. If <= 0, objects are seeded with the clock. */
 } Server;
 
 PyObject * PyServer_get_server();
+extern unsigned int pyorand();
 extern PyObject * Server_removeStream(Server *self, int sid);
 extern MYFLT * Server_getInputBuffer(Server *self);
 extern PmEvent * Server_getMidiEventBuffer(Server *self);
diff --git a/installers/osx/PkgResources_x86_64/ReadMe.rtf b/installers/osx/PkgResources_x86_64/ReadMe.rtf
index 4d01517..23774ec 100755
--- a/installers/osx/PkgResources_x86_64/ReadMe.rtf
+++ b/installers/osx/PkgResources_x86_64/ReadMe.rtf
@@ -1,84 +1,88 @@
-{\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\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\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{\author olivier }{\creatim\yr0\mo0\dy0\hr0\min0}{\author olivier }{\revtim\yr2015\mo3\dy5\hr17\min29}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern67306242}}\deftab720
+{\rtf1\ansi\deff4\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\froman\fprq0\fcharset128 Times New Roman;}{\f5\froman\fprq0\fcharset128 Liberation Serif{\*\falt Times New Roman};}{\f6\froman\fprq0\fcharset128 LucidaGrande;}{\f7\froman\fprq0\fcharset128 Liberation Sans{\*\falt Arial};}{\f8\fnil\fprq2\fcharset0 FreeSans;}{\f9\fnil\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}}
+{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}
+{\stylesheet{\s0\snext0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084 Normal;}
+{\s1\sbasedon15\snext1\ql\nowidctlpar\sb240\sa120\keepn\ltrpar\cf1\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f7\fs28\lang3084 Heading 1;}
+{\s2\sbasedon15\snext2\ql\nowidctlpar\sb240\sa120\keepn\ltrpar\cf1\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f7\fs28\lang3084 Heading 2;}
+{\s3\sbasedon15\snext3\ql\nowidctlpar\sb240\sa120\keepn\ltrpar\cf1\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f7\fs28\lang3084 Heading 3;}
+{\s15\sbasedon0\snext16\ql\nowidctlpar\sb240\sa120\keepn\ltrpar\cf1\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f7\fs28\lang3084 Heading;}
+{\s16\sbasedon0\snext16\sl288\slmult1\ql\nowidctlpar\sb0\sa140\ltrpar\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\loch\f5\fs24\lang3084 Text Body;}
+{\s17\sbasedon16\snext17\sl288\slmult1\ql\nowidctlpar\sb0\sa140\ltrpar\cf1\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f5\fs24\lang3084 List;}
+{\s18\sbasedon0\snext18\ql\nowidctlpar\sb120\sa120\ltrpar\cf1\i\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f5\fs24\lang3084 Caption;}
+{\s19\sbasedon0\snext19\ql\nowidctlpar\ltrpar\cf1\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f5\fs24\lang3084 Index;}
+{\s20\sbasedon0\snext20\ql\nowidctlpar\ltrpar\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\loch\f5\fs24\lang3084 Quotations;}
+{\s21\sbasedon15\snext21\ql\nowidctlpar\sb240\sa120\keepn\ltrpar\cf1\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f7\fs28\lang3084 Title;}
+{\s22\sbasedon15\snext22\ql\nowidctlpar\sb240\sa120\keepn\ltrpar\cf1\kerning1\dbch\af8\langfe1081\dbch\af9\afs24\loch\f7\fs28\lang3084 Subtitle;}
+}{\*\generator LibreOffice/5.0.2.2$Linux_X86_64 LibreOffice_project/00m0$Build-2}{\info{\author olivier }{\creatim\yr0\mo0\dy0\hr0\min0}{\author Olivier }{\revtim\yr2016\mo2\dy3\hr18\min50}{\printim\yr0\mo0\dy0\hr0\min0}}\deftab720
 \viewscale100
 {\*\pgdsctbl
 {\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
-{\*\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
-5}{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
+{\*\ftnsep}\pgndec\pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\rtlch \ltrch\loch\fs26\loch\f6
+Python-pyo (version 0.7}{\rtlch \ltrch\loch\fs26\loch\f6
+.8}{\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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.}{\cf1\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-10}
-\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\rtlch \ltrch\loch\fs26\loch\f6
+System requirements : OS X 10.6 to 10.10}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\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 (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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\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\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b\rtlch \ltrch\loch\fs26\loch\f6
 1. pyo extension:}
-\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\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\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 _pyo.so}
-\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 _pyo64.so}
-\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 pyo.py}
-\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 pyo64.py}
-\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 pyolib (folder)}
-\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b\rtlch \ltrch\loch\fs26\loch\f6
 2. Support libraries (i386 and x86_64):}
-\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\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\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b\rtlch \ltrch\loch\fs26\loch\f6
+Warning:}{\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\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 liblo.7.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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 libportaudio.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
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 libportmidi.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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 libsndfile.1.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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 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
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 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
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 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
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
 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\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ltrpar\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{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-Olivier B\u233\'e9langer, 201}{\cf1\b0\kerning1\dbch\af6\langfe1081\rtlch \ltrch\loch\fs26\lang3084\loch\f5
-5}
+\par \pard\plain \s0\ql\nowidctlpar\ltrpar\hyphpar0\cf1\kerning1\dbch\af9\langfe1081\dbch\af9\afs24\alang1081\loch\f5\fs24\lang3084\ql\nowidctlpar\ltrpar{\b0\rtlch \ltrch\loch\fs26\loch\f6
+Olivier B\u233\'3flanger, 2015}
 \par }
\ No newline at end of file
diff --git a/installers/osx/release_x86_64.sh b/installers/osx/release_x86_64.sh
index 1a8eadb..bcd1103 100644
--- a/installers/osx/release_x86_64.sh
+++ b/installers/osx/release_x86_64.sh
@@ -7,9 +7,9 @@
 # 3. cd utils and build E-Pyo
 # 4. cd installers/osx and build the realease, only x86_64 version
 
-export PACKAGE_NAME=pyo_0.7.8_x86_64.pkg
-export DMG_DIR="pyo 0.7.8 Universal"
-export DMG_NAME="pyo_0.7.8_OSX-universal.dmg"
+export PACKAGE_NAME=pyo_0.7.9_x86_64.pkg
+export DMG_DIR="pyo 0.7.9 Universal"
+export DMG_NAME="pyo_0.7.9_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
diff --git a/installers/win/win_installer_py26.iss b/installers/win/win_installer_py26.iss
index 3fe3d1c..e4ee877 100644
--- a/installers/win/win_installer_py26.iss
+++ b/installers/win/win_installer_py26.iss
@@ -3,7 +3,7 @@
 
 #define appName "pyo"
 #define pyVer "2.6"
-#define appVer "0.7.8"
+#define appVer "0.7.9"
 
 [Setup]
 ; NOTE: The value of AppId uniquely identifies this application.
diff --git a/installers/win/win_installer_py27.iss b/installers/win/win_installer_py27.iss
index 2c55a83..809431f 100644
--- a/installers/win/win_installer_py27.iss
+++ b/installers/win/win_installer_py27.iss
@@ -3,7 +3,7 @@
 
 #define appName "pyo"
 #define pyVer "2.7"
-#define appVer "0.7.8"
+#define appVer "0.7.9"
 
 [Setup]
 ; NOTE: The value of AppId uniquely identifies this application.
diff --git a/pyo.py b/pyo.py
index b0fb79c..59f18b0 100644
--- a/pyo.py
+++ b/pyo.py
@@ -63,6 +63,8 @@ from pyolib.fourier import *
 import pyolib.phasevoc as phasevoc
 from pyolib.phasevoc import *
 from pyolib._core import *
+from pyolib.wxgui import *
+import pyolib.wxgui as wxgui
 if WITH_EXTERNALS:
     import pyolib.external as external
     from pyolib.external import *
@@ -119,11 +121,13 @@ OBJECTS_TREE = {'functions': sorted(['pa_count_devices', 'pa_get_default_input',
                                                     'TranspoToCents', 'MToF', 'FToM', 'MToT', 'TrackHold', 'Resample', 'Expr']),
                                   'expression': sorted(['Expr']),
                                   'fourier': sorted(['FFT', 'IFFT', 'CarToPol', 'PolToCar', 'FrameDelta', 'FrameAccum', 'Vectral', 'CvlVerb'])}},
-        'Map': {'SLMap': sorted(['SLMapFreq', 'SLMapMul', 'SLMapPhase', 'SLMapQ', 'SLMapDur', 'SLMapPan'])},
-        'Server': [],
-        'MidiListener': [],
-        'OscListener': [],
-        'Stream': [],
-        'TableStream': []}
+                'Map': {'SLMap': sorted(['SLMapFreq', 'SLMapMul', 'SLMapPhase', 'SLMapQ', 'SLMapDur', 'SLMapPan'])},
+                'Server': [],
+                'MidiListener': [],
+                'OscListener': [],
+                'Stream': [],
+                'TableStream': [],
+                'PyoGui': ['PyoGuiControlSlider', 'PyoGuiVuMeter', 'PyoGuiGrapher', 'PyoGuiMultiSlider', 'PyoGuiSpectrum', 'PyoGuiScope',
+                           'PyoGuiSndView']}
 
 DOC_KEYWORDS = ['Attributes', 'Examples', 'Parameters', 'Methods', 'Notes', 'Methods details', 'See also', 'Parentclass']
\ No newline at end of file
diff --git a/pyolib/_widgets.py b/pyolib/_widgets.py
index 2cfb089..63459eb 100644
--- a/pyolib/_widgets.py
+++ b/pyolib/_widgets.py
@@ -73,10 +73,8 @@ MATRIXWINDOWS = []
 SPECTRUMWINDOWS = []
 SCOPEWINDOWS = []
 EXPREDITORWINDOWS = []
-WX_APP = False
 
 def createRootWindow():
-    global WX_APP
     if not PYO_USE_WX:
         if len(WINDOWS) == 0:
             root = Tk()
@@ -85,9 +83,8 @@ def createRootWindow():
         else:
             return None
     else:
-        if not WX_APP:
-            win = wx.App(False)
-            WX_APP = True
+        if wx.GetApp() is None:
+            win = wx.App()
             return win
         else:
             return None
@@ -130,7 +127,7 @@ def wxDisplayWindow(f, title):
 def wxShowWindow(f, title, root):
     f.SetTitle(title)
     f.Show()
-    if root != None:
+    if root is not None:
         root.MainLoop()
 
 def wxCreateDelayedCtrlWindows():
@@ -215,7 +212,7 @@ def createCtrlWindow(obj, map_list, title, wxnoserver=False):
         if title == None: title = obj.__class__.__name__
         win.title(title)
     else:
-        if wxnoserver or WX_APP:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             f = PyoObjectControl(None, obj, map_list)
             if title == None: title = obj.__class__.__name__
@@ -227,7 +224,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_APP:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             f = TableGrapher(None, obj, mode, xlen, yrange)
             if title == None: title = obj.__class__.__name__
@@ -239,12 +236,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_APP:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             f = DataTableGrapher(None, obj, yrange)
             if title == None: title = obj.__class__.__name__
-            wxShowWindow(f, title, root)
             obj._setGraphFrame(f)
+            wxShowWindow(f, title, root)
         else:
             DATAGRAPHWINDOWS.append([obj, yrange, title])
 
@@ -257,12 +254,12 @@ def createViewTableWindow(samples, title="Table waveform", wxnoserver=False, tab
         win.resizable(False, False)
         win.title(title)
     else:
-        if wxnoserver or WX_APP:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             f = ViewTable(None, samples, tableclass, object)
-            wxShowWindow(f, title, root)
             if object != None:
                 object._setViewFrame(f)
+            wxShowWindow(f, title, root)
         else:
             TABLEWINDOWS.append([samples, tableclass, title, object])
 
@@ -275,12 +272,12 @@ def createSndViewTableWindow(obj, title="Table waveform", wxnoserver=False, tabl
         win.resizable(False, False)
         win.title(title)
     else:
-        if wxnoserver or WX_APP:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             f = SndViewTable(None, obj, tableclass, mouse_callback)
             if title == None: title = obj.__class__.__name__
-            wxShowWindow(f, title, root)
             obj._setViewFrame(f)
+            wxShowWindow(f, title, root)
         else:
             SNDTABLEWINDOWS.append([obj, tableclass, title, mouse_callback])
 
@@ -295,13 +292,13 @@ It helps a lot to speed up matrix drawing!"""
         win.resizable(False, False)
         win.title(title)
     else:
-        if wxnoserver or WX_APP:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             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)
+            wxShowWindow(f, title, root)
         else:
             MATRIXWINDOWS.append([samples,size,title, object])
 
@@ -309,13 +306,13 @@ 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_APP:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             f = SpectrumDisplay(None, object)
             if title == None: title = object.__class__.__name__
-            wxShowWindow(f, title, root)
             if object != None:
                 object._setViewFrame(f)
+            wxShowWindow(f, title, root)
         else:
             SPECTRUMWINDOWS.append([object, title])
 
@@ -323,13 +320,13 @@ 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:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             f = ScopeDisplay(None, object)
             if title == None: title = object.__class__.__name__
-            wxShowWindow(f, title, root)
             if object != None:
                 object._setViewFrame(f)
+            wxShowWindow(f, title, root)
         else:
             SCOPEWINDOWS.append([object, title])
 
@@ -337,7 +334,7 @@ def createExprEditorWindow(object, title, wxnoserver=False):
     if not PYO_USE_WX:
         print "WxPython must be installed to use the Expr editor display."
     else:
-        if wxnoserver or WX_APP:
+        if wxnoserver or wx.GetApp() is not None:
             root = createRootWindow()
             f = ExprEditorFrame(None, object)
             if title == None: title = object.__class__.__name__
diff --git a/pyolib/_wxwidgets.py b/pyolib/_wxwidgets.py
index 50a81b5..4f8a6d4 100644
--- a/pyolib/_wxwidgets.py
+++ b/pyolib/_wxwidgets.py
@@ -18,7 +18,7 @@ You should have received a copy of the GNU Lesser General Public
 License along with pyo.  If not, see <http://www.gnu.org/licenses/>.
 """
 import wx, os, sys, math, time, random, unicodedata
-from types import ListType, FloatType, IntType, UnicodeType
+from types import ListType, FloatType, IntType, UnicodeType, TupleType
 import wx.stc as stc
 
 try:
@@ -400,6 +400,8 @@ class ControlSlider(wx.Panel):
 
         evt.Skip()
 
+# TODO: key, command and slmap should be removed from the multislider widget.
+# It should work in the same way as the ControlSlider widget.
 class MultiSlider(wx.Panel):
     def __init__(self, parent, init, key, command, slmap):
         wx.Panel.__init__(self, parent, size=(250,250))
@@ -480,12 +482,13 @@ class MultiSlider(wx.Panel):
             self.Refresh()
 
 class VuMeter(wx.Panel):
-    def __init__(self, parent, size=(200,11), numSliders=2, orient=wx.HORIZONTAL):
+    def __init__(self, parent, size=(200,11), numSliders=2, orient=wx.HORIZONTAL, 
+                 pos=wx.DefaultPosition, style=0):
         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)
+        wx.Panel.__init__(self, parent, -1, pos=pos, size=size, style=style)
         self.parent = parent
         self.orient = orient
         self.SetBackgroundColour("#000000")
@@ -589,8 +592,11 @@ class VuMeter(wx.Panel):
             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)
+                if i < len(self.amplitude):
+                    db = math.log10(self.amplitude[i]+0.00001) * 0.2 + 1.
+                    width = int(db*w)
+                else:
+                    width = 0
                 dc.DrawBitmap(self.backBitmap, 0, y)
                 if width > 0:
                     dc.SetClippingRegion(0, y, width, height)
@@ -600,8 +606,11 @@ class VuMeter(wx.Panel):
             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)
+                if i < len(self.amplitude):
+                    db = math.log10(self.amplitude[i]+0.00001) * 0.2 + 1.
+                    height = int(db*h)
+                else:
+                    height = 0
                 dc.DrawBitmap(self.backBitmap, y, 0)
                 if height > 0:
                     dc.SetClippingRegion(y, h-height, width, height)
@@ -612,12 +621,17 @@ class VuMeter(wx.Panel):
     def OnClose(self, evt):
         self.Destroy()
 
+# TODO: BACKGROUND_COLOUR hard-coded all over the place in this class.
 class RangeSlider(wx.Panel):
     def __init__(self, parent, minvalue, maxvalue, init=None, pos=(0,0), size=(200,15),
-                 valtype='int', log=False, function=None):
+                 valtype='int', log=False, function=None, backColour=None):
         wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY, pos=pos, size=size, style=wx.NO_BORDER)
+        if backColour:
+            self.backgroundColour = backColour
+        else:
+            self.backgroundColour = BACKGROUND_COLOUR
         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
-        self.SetBackgroundColour(BACKGROUND_COLOUR)
+        self.SetBackgroundColour(self.backgroundColour)
         self.SetMinSize(self.GetSize())
         self.sliderHeight = 15
         self.borderWidth = 1
@@ -653,8 +667,8 @@ class RangeSlider(wx.Panel):
         w, h = self.GetSize()
         b = wx.EmptyBitmap(w,h)
         dc = wx.MemoryDC(b)
-        dc.SetPen(wx.Pen(BACKGROUND_COLOUR, width=1))
-        dc.SetBrush(wx.Brush(BACKGROUND_COLOUR))
+        dc.SetPen(wx.Pen(self.backgroundColour, width=1))
+        dc.SetBrush(wx.Brush(self.backgroundColour))
         dc.DrawRectangle(0,0,w,h)
         dc.SetBrush(wx.Brush("#777777"))
         dc.SetPen(wx.Pen("#FFFFFF", width=1))
@@ -749,9 +763,10 @@ class RangeSlider(wx.Panel):
 
 class HRangeSlider(RangeSlider):
     def __init__(self, parent, minvalue, maxvalue, init=None, pos=(0,0), size=(200,15),
-                 valtype='int', log=False, function=None):
-        RangeSlider.__init__(self, parent, minvalue, maxvalue, init, pos, size, valtype, log, function)
+                 valtype='int', log=False, function=None, backColour=None):
+        RangeSlider.__init__(self, parent, minvalue, maxvalue, init, pos, size, valtype, log, function, backColour)
         self.SetMinSize((50, 15))
+
         self.createSliderBitmap()
         #self.createBackgroundBitmap()
         self.clampHandlePos()
@@ -767,11 +782,11 @@ class HRangeSlider(RangeSlider):
         self.backgroundBitmap = wx.EmptyBitmap(w,h)
         dc = wx.MemoryDC(self.backgroundBitmap)
 
-        dc.SetBrush(wx.Brush(BACKGROUND_COLOUR, wx.SOLID))
+        dc.SetBrush(wx.Brush(self.backgroundColour, wx.SOLID))
         dc.Clear()
 
         # Draw background
-        dc.SetPen(wx.Pen(BACKGROUND_COLOUR, width=self.borderWidth, style=wx.SOLID))
+        dc.SetPen(wx.Pen(self.backgroundColour, width=self.borderWidth, style=wx.SOLID))
         dc.DrawRectangle(0, 0, w, h)
 
         # Draw inner part
@@ -831,9 +846,9 @@ class HRangeSlider(RangeSlider):
         dc = wx.AutoBufferedPaintDC(self)
 
         # Draw background
-        dc.SetBrush(wx.Brush(BACKGROUND_COLOUR))
+        dc.SetBrush(wx.Brush(self.backgroundColour))
         dc.Clear()
-        dc.SetPen(wx.Pen(BACKGROUND_COLOUR))
+        dc.SetPen(wx.Pen(self.backgroundColour))
         dc.DrawRectangle(0, 0, w, h)
 
         #dc.DrawBitmap(self.backgroundBitmap, 0, 0)
@@ -991,7 +1006,6 @@ class ViewTablePanel(wx.Panel):
         else:
             self.dcref = wx.PaintDC
 
-
     def draw(self, samples):
         self.samples = samples
         self.Refresh()
@@ -1050,25 +1064,61 @@ class SndViewTable(wx.Frame):
         self.Destroy()
 
 class SndViewTablePanel(wx.Panel):
-    def __init__(self, parent, obj, mouse_callback=None):
+    def __init__(self, parent, obj=None, mouse_callback=None, select_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_RIGHT_DOWN, self.OnRightDown)
+        self.Bind(wx.EVT_RIGHT_UP, self.OnMouseUp)
         self.Bind(wx.EVT_MOTION, self.OnMotion)
         self.Bind(wx.EVT_SIZE, self.OnSize)
+        self.refresh_from_selection = False
+        self.background_bitmap = None
         self.obj = obj
-        self.chnls = len(self.obj)
+        self.selstart = self.selend = self.movepos = None
+        self.moveSelection = False
+        self.createSelection = False
         self.begin = 0
-        self.end = self.obj.getDur(False)
+        if self.obj is not None:
+            self.chnls = len(self.obj)
+            self.end = self.obj.getDur(False)
+        else:
+            self.chnls = 1
+            self.end = 1.0
+        self.img = [[]]
         self.mouse_callback = mouse_callback
+        self.select_callback = select_callback
         if sys.platform == "win32":
             self.dcref = wx.BufferedPaintDC
         else:
             self.dcref = wx.PaintDC
         self.setImage()
 
+    def getDur(self):
+        if self.obj is not None:
+            return self.obj.getDur(False)
+        else:
+            return 1.0
+
+    def resetSelection(self):
+        self.selstart = self.selend = None
+        if self.background_bitmap is not None:
+            self.refresh_from_selection = True
+        self.Refresh()
+        if self.select_callback != None:
+            self.select_callback((0.0, 1.0))
+
+    def setSelection(self, start, stop):
+        self.selstart = start
+        self.selend = stop
+        if self.background_bitmap is not None:
+            self.refresh_from_selection = True
+        self.Refresh()
+        if self.select_callback != None:
+            self.select_callback((self.selstart, self.selend))
+        
     def setBegin(self, x):
         self.begin = x
 
@@ -1076,8 +1126,9 @@ class SndViewTablePanel(wx.Panel):
         self.end = x
 
     def setImage(self):
-        self.img = self.obj.getViewTable(self.GetSize(), self.begin, self.end)
-        self.Refresh()
+        if self.obj is not None:
+            self.img = self.obj.getViewTable(self.GetSize(), self.begin, self.end)
+            self.Refresh()
 
     def clipPos(self, pos):
         if pos[0] < 0.0: x = 0.0
@@ -1086,7 +1137,8 @@ class SndViewTablePanel(wx.Panel):
         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))
+        if self.obj is not None:
+            x = x * ((self.end - self.begin) / self.obj.getDur(False)) + (self.begin / self.obj.getDur(False))
         return (x, y)
 
     def OnMouseDown(self, evt):
@@ -1101,6 +1153,29 @@ class SndViewTablePanel(wx.Panel):
             self.mouse_callback(pos)
         self.CaptureMouse()
 
+    def OnRightDown(self, evt):
+        size = self.GetSize()
+        pos = evt.GetPosition()
+        if pos[1] <= 0:
+            pos = (float(pos[0])/size[0], 1.0)
+        else:
+            pos = (float(pos[0])/size[0], 1.-(float(pos[1])/size[1]))
+        pos = self.clipPos(pos)
+        if evt.ShiftDown():
+            if self.selstart is not None and self.selend is not None:
+                self.moveSelection = True
+                self.movepos = pos[0]
+        elif evt.CmdDown():
+            self.selstart = self.selend = None
+            self.refresh_from_selection = True
+            self.Refresh()
+            if self.select_callback != None:
+                self.select_callback((0.0, 1.0))
+        else:
+            self.createSelection = True
+            self.selstart = pos[0]
+        self.CaptureMouse()
+
     def OnMotion(self, evt):
         if self.HasCapture():
             size = self.GetSize()
@@ -1110,20 +1185,40 @@ class SndViewTablePanel(wx.Panel):
             else:
                 pos = (float(pos[0])/size[0], 1.-(float(pos[1])/size[1]))
             pos = self.clipPos(pos)
-            if self.mouse_callback != None:
-                self.mouse_callback(pos)
+            if evt.LeftIsDown():
+                if self.mouse_callback != None:
+                    self.mouse_callback(pos)
+            elif evt.RightIsDown():
+                refresh = False
+                if self.createSelection:
+                    self.selend = pos[0]
+                    refresh = True
+                elif self.moveSelection:
+                    diff = pos[0] - self.movepos 
+                    self.movepos = pos[0]
+                    self.selstart += diff
+                    self.selend += diff
+                    refresh = True
+                if refresh:
+                    self.refresh_from_selection = True
+                    self.Refresh()
+                    if self.select_callback != None:
+                        self.select_callback((self.selstart, self.selend))
 
     def OnMouseUp(self, evt):
         if self.HasCapture():
             self.ReleaseMouse()
+        self.createSelection = self.moveSelection = False
 
-    def OnPaint(self, evt):
+    def create_background(self):
         w,h = self.GetSize()
-        dc = self.dcref(self)
+        self.background_bitmap = wx.EmptyBitmap(w, h)
+        dc = wx.MemoryDC(self.background_bitmap)
         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))
@@ -1132,7 +1227,7 @@ class SndViewTablePanel(wx.Panel):
             font, ptsize = dc.GetFont(), dc.GetFont().GetPointSize()
             font.SetPointSize(ptsize - 3)
             dc.SetFont(font)
-        elif sys.platform == "win32":
+        else:
             font = dc.GetFont()
             font.SetPointSize(8)
             dc.SetFont(font)
@@ -1159,6 +1254,42 @@ class SndViewTablePanel(wx.Panel):
             dc.SetPen(wx.Pen('#000000', width=1))
             dc.DrawLine(0, h-y, w, h-y)
 
+        dc.SelectObject(wx.NullBitmap)
+
+    def OnPaint(self, evt):
+        w,h = self.GetSize()
+        dc = self.dcref(self)
+        gc = wx.GraphicsContext_Create(dc)
+        dc.SetBrush(wx.Brush("#FFFFFF"))
+        dc.Clear()
+        dc.DrawRectangle(0,0,w,h)
+
+        if not self.refresh_from_selection:
+            self.create_background()
+
+        dc.DrawBitmap(self.background_bitmap, 0, 0)
+
+        if self.selstart is not None and self.selend is not None:
+            gc.SetPen(wx.Pen(wx.Colour(0, 0, 0, 64)))
+            gc.SetBrush(wx.Brush(wx.Colour(0, 0, 0, 64)))
+            if self.obj is not None:
+                dur = self.obj.getDur(False)
+            else:
+                dur = 1.0
+            selstartabs = min(self.selstart, self.selend) * dur
+            selendabs = max(self.selstart, self.selend) * dur
+            if selstartabs < self.begin:
+                startpix = 0
+            else:
+                startpix = ((selstartabs - self.begin) / (self.end - self.begin)) * w
+            if selendabs > self.end:
+                endpix = w
+            else:
+                endpix = ((selendabs - self.begin) / (self.end - self.begin)) * w
+            gc.DrawRectangle(startpix, 0, endpix - startpix, h)
+
+        self.refresh_from_selection = False
+
     def OnSize(self, evt):
         wx.CallAfter(self.setImage)
 
@@ -1364,39 +1495,48 @@ class SpectrumDisplay(wx.Frame):
         self.obj._setViewFrame(None)
         self.Destroy()
 
+# TODO: Adjust the font size according to the size of the panel.
 class SpectrumPanel(wx.Panel):
-    def __init__(self, parent, chnls, lowfreq, highfreq, fscaling, mscaling):
-        wx.Panel.__init__(self, parent)
+    def __init__(self, parent, chnls, lowfreq, highfreq, fscaling, mscaling, 
+                 pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):
+        wx.Panel.__init__(self, parent, pos=pos, size=size, style=style)
         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
         self.Bind(wx.EVT_PAINT, self.OnPaint)
         self.Bind(wx.EVT_SIZE, self.OnSize)
-        self.chnls = chnls
+        #self.chnls = chnls
         self.img = None
+        self.obj = None
         self.lowfreq = lowfreq
         self.highfreq = highfreq
         self.fscaling = fscaling
         self.mscaling = mscaling
-        if self.chnls == 1:
-            self.pens = [wx.Pen(wx.Colour(100,0,0))]
-            self.brushes = [wx.Brush(wx.Colour(166,4,0))]
-        else:
-            self.pens = [wx.Pen(wx.Colour(166,4,0)), wx.Pen(wx.Colour(8,11,116)), wx.Pen(wx.Colour(0,204,0)),
-                        wx.Pen(wx.Colour(255,167,0)), wx.Pen(wx.Colour(133,0,75)), wx.Pen(wx.Colour(255,236,0)),
-                        wx.Pen(wx.Colour(1,147,154)), wx.Pen(wx.Colour(162,239,0))]
-            self.brushes = [wx.Brush(wx.Colour(166,4,0,128)), wx.Brush(wx.Colour(8,11,116,128)), wx.Brush(wx.Colour(0,204,0,128)),
-                            wx.Brush(wx.Colour(255,167,0,128)), wx.Brush(wx.Colour(133,0,75,128)), wx.Brush(wx.Colour(255,236,0,128)),
-                            wx.Brush(wx.Colour(1,147,154,128)), wx.Brush(wx.Colour(162,239,0,128))]
+        self.pens = [wx.Pen(wx.Colour(166,4,0)), wx.Pen(wx.Colour(8,11,116)), wx.Pen(wx.Colour(0,204,0)),
+                    wx.Pen(wx.Colour(255,167,0)), wx.Pen(wx.Colour(133,0,75)), wx.Pen(wx.Colour(255,236,0)),
+                    wx.Pen(wx.Colour(1,147,154)), wx.Pen(wx.Colour(162,239,0))]
+        self.brushes = [wx.Brush(wx.Colour(166,4,0,128)), wx.Brush(wx.Colour(8,11,116,128)), wx.Brush(wx.Colour(0,204,0,128)),
+                        wx.Brush(wx.Colour(255,167,0,128)), wx.Brush(wx.Colour(133,0,75,128)), wx.Brush(wx.Colour(255,236,0,128)),
+                        wx.Brush(wx.Colour(1,147,154,128)), wx.Brush(wx.Colour(162,239,0,128))]
         if sys.platform == "win32":
             self.dcref = wx.BufferedPaintDC
         else:
             self.dcref = wx.PaintDC
 
     def OnSize(self, evt):
-        self.GetParent().GetParent().setDisplaySize(self.GetSize())
+        try:
+            self.GetParent().GetParent().setDisplaySize(self.GetSize())
+        except:
+            pass
+        try:
+            size = self.GetSize()
+            self.obj.setWidth(size[0])
+            self.obj.setHeight(size[1])
+        except:
+            pass
+
         self.Refresh()
 
     def setImage(self, points):
-        self.img = [points[i] for i in range(self.chnls)]
+        self.img = [points[i] for i in range(len(points))]
         self.Refresh()
 
     def setFscaling(self, x):
@@ -1416,10 +1556,10 @@ class SpectrumPanel(wx.Panel):
         dc = self.dcref(self)
         gc = wx.GraphicsContext_Create(dc)
         tw, th = dc.GetTextExtent("0")
-
+        
         # background
         background = gc.CreatePath()
-        background.AddRectangle(0,0,w,h)
+        background.AddRectangle(0,0,w-1,h-1)
         gc.SetPen(wx.BLACK_PEN)
         gc.SetBrush(wx.WHITE_BRUSH)
         gc.DrawPath(background)
@@ -1531,18 +1671,18 @@ class SpectrumPanel(wx.Panel):
                 dc.DrawLine(0, pos, w-mw-6, pos)
                 i += 1
 
-        last_tw = tw
-        # legend
-        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+th+7)
-
         # spectrum
         if self.img != None:
+            last_tw = tw
+            # legend
+            tw, th = dc.GetTextExtent("chan 8")
+            for i in range(len(self.img)):
+                dc.SetTextForeground(self.pens[i%8].GetColour())
+                dc.DrawText("chan %d" % (i+1), w-tw-20-last_tw, i*th+th+7)
+            # channel spectrums
             for i, samples in enumerate(self.img):
-                gc.SetPen(self.pens[i])
-                gc.SetBrush(self.brushes[i])
+                gc.SetPen(self.pens[i%8])
+                gc.SetBrush(self.brushes[i%8])
                 gc.DrawLines(samples)
 
 ######################################################################
@@ -1613,22 +1753,24 @@ class ScopeDisplay(wx.Frame):
         self.Destroy()
 
 class ScopePanel(wx.Panel):
-    def __init__(self, parent, obj):
-        wx.Panel.__init__(self, parent)
+    def __init__(self, parent, obj=None, pos=wx.DefaultPosition, 
+                 size=wx.DefaultSize, style=0):
+        wx.Panel.__init__(self, parent, pos=pos, size=size, style=style)
         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)]
+        if self.obj is not None:
+            self.gain = self.obj.gain
+            self.length = self.obj.length
         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)]
+            self.gain = 1
+            self.length = 0.05
+        #self.chnls = len(self.obj)
+        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
@@ -1636,9 +1778,12 @@ class ScopePanel(wx.Panel):
             self.dcref = wx.PaintDC
 
     def OnSize(self, evt):
-        size = self.GetSize()
-        self.obj.setWidth(size[0])
-        self.obj.setHeight(size[1])
+        try:
+            size = self.GetSize()
+            self.obj.setWidth(size[0])
+            self.obj.setHeight(size[1])
+        except:
+            pass
 
     def setGain(self, gain):
         self.gain = gain
@@ -1691,21 +1836,21 @@ class ScopePanel(wx.Panel):
             dc.DrawText("%.3f" % (j*timestep), j*tickstep+2, h-12)
         # draw waveforms
         for i, samples in enumerate(self.img):
-            gc.SetPen(self.pens[i])
+            gc.SetPen(self.pens[i%8])
             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())
+        for i in range(len(self.img)):
+            dc.SetTextForeground(self.pens[i%8].GetColour())
             dc.DrawText("chan %d" % (i+1), w-tw-20-last_tw, i*th+10)
 
 ######################################################################
 ## Grapher window for PyoTableObject control
 ######################################################################
-OFF = 15
+OFF = 10
 OFF2 = OFF*2
 RAD = 3
 RAD2 = RAD*2
@@ -1713,8 +1858,9 @@ AREA = RAD+2
 AREA2 = AREA*2
 class Grapher(wx.Panel):
     def __init__(self, parent, xlen=8192, yrange=(0.0, 1.0), init=[(0.0,0.0),(1.0,1.0)], mode=0,
-                 exp=10.0, inverse=True, tension=0.0, bias=0.0, outFunction=None):
-        wx.Panel.__init__(self, parent, size=(500,250), style=wx.SUNKEN_BORDER)
+                 exp=10.0, inverse=True, tension=0.0, bias=0.0, outFunction=None, pos=(0, 0),
+                 size=(300, 200), style=0):
+        wx.Panel.__init__(self, parent, pos=pos, size=size, style=style)
         self.backgroundColour = BACKGROUND_COLOUR
         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
         self.SetBackgroundColour(self.backgroundColour)
@@ -1736,7 +1882,7 @@ class Grapher(wx.Panel):
         self.xlen = xlen
         self.yrange = yrange
         self.init = [tup for tup in init]
-        self.points = init
+        self.points = [tup for tup in init]
         self.outFunction = outFunction
 
         if sys.platform == "win32":
@@ -1750,6 +1896,7 @@ class Grapher(wx.Panel):
         self.init = [(p[0],p[1]) for p in pts]
         self.points = [(p[0],p[1]) for p in pts]
         self.selected = None
+        self.sendValues()
         self.Refresh()
 
     def pointToPixels(self, pt):
@@ -1773,6 +1920,11 @@ class Grapher(wx.Panel):
         y = pt[1] * (self.yrange[1]-self.yrange[0]) + self.yrange[0]
         return x, y
 
+    def valuesToPoint(self, val):
+        x = val[0] / float(self.xlen)
+        y = (val[1] - self.yrange[0]) / float(self.yrange[1]-self.yrange[0])
+        return x, y
+
     def borderClip(self, pos):
         w,h = self.GetSize()
         if pos[0] < (OFF+RAD): pos[0] = (OFF+RAD)
@@ -1801,7 +1953,7 @@ class Grapher(wx.Panel):
         return pos
 
     def reset(self):
-        self.points = self.init
+        self.points = [tup for tup in self.init]
         self.Refresh()
 
     def getPoints(self):
@@ -2046,10 +2198,10 @@ class Grapher(wx.Panel):
                 dc.DrawText(t, xpos+2, h-OFF-10)
             if i < 9:
                 t = "%.2f" % ((9-i) * 0.1 * (self.yrange[1]-self.yrange[0]) + self.yrange[0])
-                dc.DrawText(t, OFF+1, ypos+ystep-10)
+                dc.DrawText(t, OFF+2, ypos+ystep-10)
             else:
                 t = "%.2f" % ((9-i) * 0.1 * (self.yrange[1]-self.yrange[0]) + self.yrange[0])
-                dc.DrawText(t, OFF+1, h-OFF-10)
+                dc.DrawText(t, OFF+2, h-OFF-10)
 
         dc.SetPen(wx.Pen("#000000", 1))
         dc.SetBrush(wx.Brush("#000000"))
@@ -2229,8 +2381,9 @@ class TableGrapher(wx.Frame):
         self.graph.reset()
 
 class DataMultiSlider(wx.Panel):
-    def __init__(self, parent, init, yrange=(0,1), outFunction=None):
-        wx.Panel.__init__(self, parent, size=(250,250), style=wx.SUNKEN_BORDER)
+    def __init__(self, parent, init, yrange=(0,1), outFunction=None,
+                pos=(0, 0), size=(300, 200), style=0):
+        wx.Panel.__init__(self, parent, pos=pos, size=size, style=style)
         self.backgroundColour = BACKGROUND_COLOUR
         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
         self.SetBackgroundColour(self.backgroundColour)
@@ -2239,9 +2392,9 @@ class DataMultiSlider(wx.Panel):
         self.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
         self.Bind(wx.EVT_LEFT_UP, self.MouseUp)
         self.Bind(wx.EVT_MOTION, self.MouseMotion)
-        self.values = init
+        self.values = [v for v in init]
         self.len = len(self.values)
-        self.yrange = yrange
+        self.yrange = (float(yrange[0]), float(yrange[1]))
         self.outFunction = outFunction
         if sys.platform == "win32":
             self.dcref = wx.BufferedPaintDC
diff --git a/pyolib/analysis.py b/pyolib/analysis.py
index 81f1db6..5188da3 100644
--- a/pyolib/analysis.py
+++ b/pyolib/analysis.py
@@ -726,6 +726,13 @@ class AttackDetector(PyoObject):
         x, lmax = convertArgsToLists(x)
         [obj.setReltime(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
 
+    def readyToDetect(self):
+        """
+        Initializes variables in the ready state to detect an attack.
+
+        """
+        [obj.readyToDetect() for obj in self._base_objs]
+        
     def out(self, chnl=0, inc=1, dur=0, delay=0):
         return self.play(dur, delay)
 
@@ -846,9 +853,9 @@ class Spectrum(PyoObject):
         self._in_fader = InputFader(input)
         in_fader, size, wintype, lmax = convertArgsToLists(self._in_fader, size, wintype)
         self._base_objs = [Spectrum_base(wrap(in_fader,i), wrap(size,i), wrap(wintype,i)) for i in range(lmax)]
+        self._timer = Pattern(self.refreshView, 0.05).play()
         if function == None:
             self.view()
-        self._timer = Pattern(self.refreshView, 0.05).play()
 
     def setInput(self, x, fadetime=0.05):
         """
@@ -942,6 +949,38 @@ class Spectrum(PyoObject):
         pyoArgsAssert(self, "N", time)
         self._timer.time = time
 
+    def setLowFreq(self, x):
+        """
+        Sets the lower frequency, in Hz, returned by the analysis.
+
+        :Args:
+
+            x : float
+                New low frequency in Hz. Adjusts the `lowbound` attribute, as `x / sr`.
+
+        """
+        pyoArgsAssert(self, "n", x)
+        x /= self.getServer().getSamplingRate()
+        self._lowbound = x
+        x, lmax = convertArgsToLists(x)
+        tmp = [obj.setLowbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
+    def setHighFreq(self, x):
+        """
+        Sets the higher frequency, in Hz, returned by the analysis.
+
+        :Args:
+
+            x : float
+                New high frequency in Hz. Adjusts the `highbound` attribute, as `x / sr`.
+
+        """
+        pyoArgsAssert(self, "n", x)
+        x /= self.getServer().getSamplingRate()
+        self._highbound = x
+        x, lmax = convertArgsToLists(x)
+        tmp = [obj.setHighbound(wrap(x,i)) for i, obj in enumerate(self._base_objs)]
+
     def setLowbound(self, x):
         """
         Sets the lower frequency, as multiplier of sr, returned by the analysis.
@@ -1131,7 +1170,6 @@ class Spectrum(PyoObject):
         if self.viewFrame != None:
             self.viewFrame.update(self.points)
 
-
     @property
     def input(self):
         """PyoObject. Input signal to process."""
@@ -1221,6 +1259,11 @@ class Scope(PyoObject):
         gain : float, optional
             Linear gain applied to the signal to be displayed.
             Can't be a list. Defaults to 0.67.
+        function : python callable, optional
+            If set, this function will be called with samples (as
+            list of lists, one list per channel). Useful if someone
+            wants to save the analysis data into a text file.
+            Defaults to None.
 
     .. note::
 
@@ -1235,21 +1278,23 @@ class Scope(PyoObject):
     >>> scope = Scope(a+b)
 
     """
-    def __init__(self, input, length=0.05, gain=0.67):
-        pyoArgsAssert(self, "oNN", input, length, gain)
+    def __init__(self, input, length=0.05, gain=0.67, function=None):
+        pyoArgsAssert(self, "oNNC", input, length, gain, function)
         PyoObject.__init__(self)
         self.points = None
         self.viewFrame = None
         self._input = input
         self._length = length
         self._gain = gain
+        self._function = function
         self._width = 500
         self._height = 400
         self._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()
+        if function == None:
+            self.view()
 
     def setInput(self, x, fadetime=0.05):
         """
@@ -1369,6 +1414,21 @@ class Scope(PyoObject):
         pyoArgsAssert(self, "SB", title, wxnoserver)
         createScopeWindow(self, title, wxnoserver)
 
+    def setFunction(self, function):
+        """
+        Sets the function to be called to retrieve the analysis data.
+
+        :Args:
+
+            function : python callable
+                The function called by the internal timer to retrieve the
+                analysis data. The function must be created with one argument
+                and will receive the data as a list of lists (one list per channel).
+
+        """
+        pyoArgsAssert(self, "C", function)
+        self._function = getWeakMethodRef(function)
+
     def _setViewFrame(self, frame):
         self.viewFrame = frame
 
@@ -1382,7 +1442,8 @@ class Scope(PyoObject):
         self.points = [obj.display() for obj in self._base_objs]
         if self.viewFrame != None:
             self.viewFrame.update(self.points)
-
+        if self._function is not None:
+            self._function(self.points)
 
     @property
     def input(self):
diff --git a/pyolib/expression.py b/pyolib/expression.py
index 87369ca..f6adf66 100644
--- a/pyolib/expression.py
+++ b/pyolib/expression.py
@@ -86,7 +86,7 @@ Constants:
 Comments
 --------
 
-A comment start with two slashs ( // ) and ends at the end of the line:
+A comment starts with two slashs ( // ) and ends at the end of the line:
     
     // This is a comment!
 
diff --git a/pyolib/tables.py b/pyolib/tables.py
index aeed3c1..e182910 100644
--- a/pyolib/tables.py
+++ b/pyolib/tables.py
@@ -1463,6 +1463,7 @@ class SndTable(PyoTableObject):
             else:
                 [obj.setSound(path, (i%_snd_chnls), start, stop) for i, obj in enumerate(self._base_objs)]
         self.refreshView()
+        self._resetView()
 
     def append(self, path, crossfade=0, start=0, stop=None):
         """
@@ -1693,6 +1694,11 @@ class SndTable(PyoTableObject):
         if self.viewFrame != None:
             self.viewFrame.update()
 
+    def _resetView(self):
+        if self.viewFrame != None:
+            if hasattr(self.viewFrame, "_setZoom"):
+                self.viewFrame._setZoom()
+
     @property
     def sound(self):
         """string. Full path of the sound."""
diff --git a/pyolib/wxgui.py b/pyolib/wxgui.py
new file mode 100644
index 0000000..08bae20
--- /dev/null
+++ b/pyolib/wxgui.py
@@ -0,0 +1,968 @@
+"""
+The classes in this module are based on internal classes that where 
+originally designed to help the creation of graphical tools for the
+control and the visualization of audio signals. WxPython must be installed
+under the current Python distribution to access these classes.
+
+"""
+from _widgets import PYO_USE_WX
+
+if not PYO_USE_WX:
+    NO_WX_MESSAGE = "WxPython must be installed on the system to use pyo's wx widgets."
+    class PyoGuiControlSlider:
+        def __init__(self, *args, **kwargs):
+            raise Exception(NO_WX_MESSAGE)
+    class PyoGuiVuMeter:
+        def __init__(self, *args, **kwargs):
+            raise Exception(NO_WX_MESSAGE)
+    class PyoGuiGrapher:
+        def __init__(self, *args, **kwargs):
+            raise Exception(NO_WX_MESSAGE)
+    class PyoGuiMultiSlider:
+        def __init__(self, *args, **kwargs):
+            raise Exception(NO_WX_MESSAGE)
+    class PyoGuiSpectrum:
+        def __init__(self, *args, **kwargs):
+            raise Exception(NO_WX_MESSAGE)
+    class PyoGuiScope:
+        def __init__(self, *args, **kwargs):
+            raise Exception(NO_WX_MESSAGE)
+    class PyoGuiSndView:
+        def __init__(self, *args, **kwargs):
+            raise Exception(NO_WX_MESSAGE)
+else:
+    import wx
+    import wx.lib.newevent
+    from _wxwidgets import ControlSlider, VuMeter, Grapher, DataMultiSlider
+    from _wxwidgets import SpectrumPanel, ScopePanel, SndViewTablePanel, HRangeSlider
+    
+    # Custom events
+    PyoGuiControlSliderEvent, EVT_PYO_GUI_CONTROL_SLIDER = wx.lib.newevent.NewEvent()
+    PyoGuiGrapherEvent, EVT_PYO_GUI_GRAPHER = wx.lib.newevent.NewEvent()
+    PyoGuiMultiSliderEvent, EVT_PYO_GUI_MULTI_SLIDER = wx.lib.newevent.NewEvent()
+    PyoGuiSndViewMousePositionEvent, EVT_PYO_GUI_SNDVIEW_MOUSE_POSITION = wx.lib.newevent.NewEvent()
+    PyoGuiSndViewSelectionEvent, EVT_PYO_GUI_SNDVIEW_SELECTION = wx.lib.newevent.NewEvent()
+
+    class PyoGuiControlSlider(ControlSlider):
+        """
+        Floating-point control slider.
+
+        :Parent: wx.Panel
+        
+        :Events:
+            
+            EVT_PYO_GUI_CONTROL_SLIDER
+                Sent after any change of the slider position. The current 
+                value of the slider can be retrieve with the `value` 
+                attribute of the generated event.
+
+        :Args:
+
+            parent : wx.Window
+                The parent window.
+            minvalue : float
+                The minimum value of the slider.
+            maxvalue : float
+                The maximum value of the slider.
+            init : float, optional
+                The initial value of the slider. If None, the slider
+                inits to the minimum value. Defaults to None.
+            pos : tuple, optional
+                The slider's position in pixel (x, y). Defaults to (0, 0).
+            size : tuple, optional
+                The slider's size in pixel (x, y). Defaults to (200, 16).
+            log : boolean, optional
+                If True, creates a logarithmic slider (minvalue must be
+                greater than 0). Defaults to False.
+            integer : boolean, optional
+                If True, creates an integer slider. Defaults to False.
+            powoftwo : boolean, optional
+                If True, creates a power-of-two slider (log is automatically
+                False and integer is True). If True, minvalue and maxvalue
+                must be exponents to base 2 but init is a real power-of-two
+                value. Defaults to False.
+            orient : {wx.HORIZONTAL or wx.VERTICAL}, optional
+                The slider's orientation. Defaults to wx.HORIZONTAL.
+        
+        """
+        def __init__(self, parent, minvalue, maxvalue, init=None, pos=(0, 0),
+                     size=(200, 16), log=False, integer=False, powoftwo=False,
+                     orient=wx.HORIZONTAL):
+            super(PyoGuiControlSlider, self).__init__(parent, minvalue, maxvalue, 
+                                                      init, pos, size, log,
+                                                      self._outFunction, integer, 
+                                                      powoftwo, 
+                                                      parent.GetBackgroundColour(), 
+                                                      orient)
+
+        def _outFunction(self, value):
+            evt = PyoGuiControlSliderEvent(value=value)
+            wx.PostEvent(self, evt)
+
+        def enable(self):
+            """
+            Enable the slider for user input.
+
+            """
+            super(PyoGuiControlSlider, self).Enable()
+
+        def disable(self):
+            """
+            Disable the slider for user input.
+            
+            """
+            super(PyoGuiControlSlider, self).Disable()
+
+        def setValue(self, x, propagate=True):
+            """
+            Sets a new value to the slider.
+
+            :Args:
+
+                x : int or float
+                    The controller number.
+                propagate : boolean, optional
+                    If True, an event will be sent after the call.
+
+            """
+            super(PyoGuiControlSlider, self).SetValue(x, propagate)
+            
+        def setMidiCtl(self, x, propagate=True):
+            """
+            Sets the midi controller number to show on the slider.
+
+            :Args:
+
+                x : int
+                    The controller number.
+                propagate : boolean, optional
+                    If True, an event will be sent after the call.
+
+            """
+            super(PyoGuiControlSlider, self).setMidiCtl(x, propagate)
+
+        def setRange(self, minvalue, maxvalue):
+            """
+            Sets new minimum and maximum values.
+
+            :Args:
+
+                minvalue : int or float
+                    The new minimum value.
+                maxvalue : int or float
+                    The new maximum value.
+
+            """
+            super(PyoGuiControlSlider, self).setRange(minvalue, maxvalue)
+
+        def getValue(self):
+            """
+            Returns the current value of the slider.
+            
+            """
+            return super(PyoGuiControlSlider, self).GetValue()
+
+        def getMidiCtl(self):
+            """
+            Returns the midi controller number, if any, assigned to the slider.
+            
+            """
+            return super(PyoGuiControlSlider, self).getMidiCtl()
+
+        def getMinValue(self):
+            """
+            Returns the current minimum value.
+            
+            """
+            return super(PyoGuiControlSlider, self).getMinValue()
+
+        def getMaxValue(self):
+            """
+            Returns the current maximum value.
+            
+            """
+            return super(PyoGuiControlSlider, self).getMaxValue()
+
+        def getInit(self):
+            """
+            Returns the initial value.
+            
+            """
+            return super(PyoGuiControlSlider, self).getInit()
+
+        def getRange(self):
+            """
+            Returns minimum and maximum values as a list.
+            
+            """
+            return super(PyoGuiControlSlider, self).getRange()
+
+        def isInteger(self):
+            """
+            Returns True if the slider manage only integer, False otherwise.
+            
+            """
+            return self.integer
+
+        def isLog(self):
+            """
+            Returns True if the slider is logarithmic, False otherwise.
+            
+            """
+            return self.log
+
+        def isPowOfTwo(self):
+            """
+            Returns True if the slider manage only power-of-two values, False otherwise.
+            
+            """
+            return self.powoftwo
+
+    class PyoGuiVuMeter(VuMeter):
+        """
+        Multi-channels Vu Meter.
+        
+        When registered as the Server's meter, its internal method `setRms`
+        will be called each buffer size with a list of normalized amplitudes
+        as argument. The `setRms` method can also be registered as the 
+        function callback of a PeakAmp object.
+
+        :Parent: wx.Panel
+
+        :Args:
+
+            parent : wx.Window
+                The parent window.
+            nchnls : int, optional
+                The initial number of channels of the meter. Defaults to 2.
+            pos : wx.Point, optional
+                Window position in pixels. Defaults to (0, 0).
+            size : tuple, optional
+                The meter's size in pixels (x, y). Defaults to (200, 11).
+            orient : {wx.HORIZONTAL or wx.VERTICAL}, optional
+                The meter's orientation. Defaults to wx.HORIZONTAL.
+            style : int, optional
+                Window style (see wx.Window documentation). Defaults to 0.
+                
+        """
+        def __init__(self, parent, nchnls=2, pos=(0, 0), size=(200, 11),
+                     orient=wx.HORIZONTAL, style=0):
+            super(PyoGuiVuMeter, self).__init__(parent, size, nchnls, orient,
+                                                pos, style)
+
+        def setNchnls(self, nchnls):
+            """
+            Sets the number of channels of the meter.
+
+            :Args:
+
+                nchnls : int
+                    The number of channels.
+
+            """
+            super(PyoGuiVuMeter, self).setNumSliders(nchnls)
+
+    class PyoGuiGrapher(Grapher):
+        """
+        Multi-modes break-points function editor.
+
+        :Parent: wx.Panel
+        
+        :Events:
+            
+            EVT_PYO_GUI_GRAPHER
+                Sent after any change of the grapher function. The current 
+                list of points of the grapher can be retrieve with the `value` 
+                attribute of the generated event.
+
+        :Args:
+
+            parent : wx.Window
+                The parent window.
+            xlen : int, optional
+                The length, in samples, of the grapher. Defaults to 8192.
+            yrange : two-values tuple, optional
+                A tuple indicating the minimum and maximum values of the Y-axis.
+                Defaults to (0, 1).
+            init : list of two-values tuples, optional
+                The initial break-points function set as normalized values. 
+                A point is defined with its X and Y positions as a tuple. 
+                Defaults to [(0.0, 0.0), (1.0, 1.0)].
+            mode : int, optional
+                The grapher mode definning how line segments will be draw. 
+                Possible modes are:
+                    0. linear (default)
+                    1. cosine
+                    2. exponential (uses `exp` and `inverse` arguments)
+                    3. curve       (uses `tension` and `bias` arguments)
+                    4. logarithmic
+                    5. logarithmic cosine
+            exp : int or float, optional
+                The exponent factor for an exponential graph. Defaults to 10.0.
+            inverse : boolean, optional
+                If True, downward slope will be inversed. Useful to create
+                biexponential curves. Defaults to True.
+            tension : int or float, optional
+                Curvature at the known points. 1 is high, 0 normal, -1 is low.
+                Defaults to 0.
+            bias : int or float, optional
+                Curve attraction (for each segments) toward bundary points.
+                0 is even, positive is towards first point, negative is towards
+                the second point. Defaults to 0.
+            pos : wx.Point, optional
+                Window position in pixels. Defaults to (0, 0).
+            size : wx.Size, optional
+                Window size in pixels. Defaults to (300, 200).
+            style : int, optional
+                Window style (see wx.Window documentation). Defaults to 0.
+
+        """
+        def __init__(self, parent, xlen=8192, yrange=(0, 1), init=[(0.0, 0.0), (1.0, 1.0)],
+                     mode=0, exp=10, inverse=True, tension=0, bias=0, pos=(0, 0),
+                     size=(300, 200), style=0):
+            super(PyoGuiGrapher, self).__init__(parent, xlen, yrange, init, mode,
+                                                exp, inverse, tension, bias, 
+                                                self._outFunction, pos, size, style)
+
+        def _outFunction(self, value):
+            evt = PyoGuiGrapherEvent(value=value)
+            wx.PostEvent(self, evt)
+
+        def _refresh(self):
+            self.Refresh()
+            self.sendValues()
+
+        def reset(self):
+            """
+            Resets the points to the initial state.
+
+            """
+            super(PyoGuiGrapher, self).reset()
+
+        def getPoints(self):
+            """
+            Returns the current normalized points of the grapher.
+            
+            """
+            return super(PyoGuiGrapher, self).getPoints()
+
+        def getValues(self):
+            """
+            Returns the current points, according to Y-axis range, of the grapher.
+            
+            """
+            return super(PyoGuiGrapher, self).getValues()
+
+        def setPoints(self, pts):
+            """
+            Sets a new group of normalized points in the grapher.
+
+            :Args:
+
+                pts : list of two-values tuples
+                    New normalized (between 0 and 1) points.
+
+            """
+            self.points = [pt for pt in pts]
+            self._refresh()
+
+        def setValues(self, vals):
+            """
+            Sets a new group of points, according to Y-axis range, in the grapher.
+
+            :Args:
+
+                vals : list of two-values tuples
+                    New real points.
+
+            """
+            self.points = [self.valuesToPoint(val) for val in vals]
+            self._refresh()
+
+        def setYrange(self, yrange):
+            """
+            Sets a new Y-axis range to the grapher.
+
+            :Args:
+
+                yrange : two-values tuple
+                    New Y-axis range.
+
+            """
+            vals = self.getValues()
+            self.yrange = yrange
+            self.setValues(vals)
+
+        def setInitPoints(self, pts):
+            """
+            Sets a new initial normalized points list to the grapher.
+
+            :Args:
+
+                pts : list of two-values tuples
+                    New normalized (between 0 and 1) initial points.
+
+            """
+            super(PyoGuiGrapher, self).setInitPoints(pts)
+
+        def setMode(self, x):
+            """
+            Changes the grapher's mode.
+
+            :Args:
+
+                x : int
+                    New mode. Possible modes are:
+                        0. linear (default)
+                        1. cosine
+                        2. exponential (uses `exp` and `inverse` arguments)
+                        3. curve       (uses `tension` and `bias` arguments)
+                        4. logarithmic
+                        5. logarithmic cosine
+
+            """
+            self.mode = x
+            self._refresh()
+
+        def setExp(self, x):
+            """
+            Changes the grapher's exponent factor for exponential graph.
+
+            :Args:
+
+                x : float
+                    New exponent factor.
+
+            """
+            self.exp = x
+            self._refresh()
+
+        def setInverse(self, x):
+            """
+            Changes the grapher's inverse boolean for exponential graph.
+
+            :Args:
+
+                x : boolean
+                    New inverse factor.
+
+            """
+            self.inverse = x
+            self._refresh()
+
+        def setTension(self, x):
+            """
+            Changes the grapher's tension factor for curved graph.
+
+            :Args:
+
+                x : float
+                    New tension factor.
+
+            """
+            self.tension = x
+            self._refresh()
+
+        def setBias(self, x):
+            """
+            Changes the grapher's bias factor for curved graph.
+
+            :Args:
+
+                x : float
+                    New bias factor.
+
+            """
+            self.bias = x
+            self._refresh()
+
+    class PyoGuiMultiSlider(DataMultiSlider):
+        """
+        Data multi-sliders editor.
+
+        :Parent: wx.Panel
+        
+        :Events:
+            
+            EVT_PYO_GUI_MULTI_SLIDER
+                Sent after any change of the multi-sliders values. The current 
+                list of values of the multi-sliders can be retrieve with the 
+                `value` attribute of the generated event.
+
+        :Args:
+
+            parent : wx.Window
+                The parent window.
+            xlen : int, optional
+                The number of sliders in the multi-sliders. Defaults to 16.
+            yrange : two-values tuple
+                A tuple indicating the minimum and maximum values of the Y-axis.
+                Defaults to (0, 1).
+            init : list values, optional
+                The initial list of values of the multi-sliders. 
+                Defaults to None, meaning all sliders initialized to the 
+                minimum value.
+            pos : wx.Point, optional
+                Window position in pixels. Defaults to (0, 0).
+            size : wx.Size, optional
+                Window size in pixels. Defaults to (300, 200).
+            style : int, optional
+                Window style (see wx.Window documentation). Defaults to 0.
+
+        """
+        def __init__(self, parent, xlen=16, yrange=(0, 1), init=None,
+                    pos=(0, 0), size=(300, 200), style=0):
+            if init is None:
+                init = [yrange[0]] * xlen
+            else:
+                if len(init) < xlen:
+                    init += [yrange[0]] * (xlen - len(init))
+                elif len(init) > xlen:
+                    init = init[:xlen]
+            super(PyoGuiMultiSlider, self).__init__(parent, init, yrange, 
+                                                    self._outFunction, pos,
+                                                    size, style)
+
+        def _outFunction(self, value):
+            evt = PyoGuiMultiSliderEvent(value=value)
+            wx.PostEvent(self, evt)
+
+        def reset(self):
+            """
+            Resets the sliders to their initial state.
+            
+            """
+            super(PyoGuiMultiSlider, self).reset()
+
+        def getValues(self):
+            """
+            Returns the current values of the sliders.
+            
+            """
+            return [v for v in self.values]
+
+        def setValues(self, vals):
+            """
+            Sets new values to the sliders.
+
+            :Args:
+
+                vals : list of values
+                    New values.
+
+            """
+            wx.CallAfter(super(PyoGuiMultiSlider, self).update, vals)
+
+        def setYrange(self, yrange):
+            """
+            Sets a new Y-axis range to the multi-sliders.
+
+            :Args:
+
+                yrange : two-values tuple
+                    New Y-axis range.
+
+            """
+            self.yrange = (float(yrange[0]), float(yrange[1]))
+            self.Refresh()
+
+    class PyoGuiSpectrum(SpectrumPanel):
+        """
+        Frequency spectrum display.
+
+        This widget should be used with the Spectrum object, which 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.
+        
+        To create the bridge between the analyzer and the display, the
+        Spectrum object must be registered in the PyoGuiSpectrum object
+        with the setAnalyzer(obj) method. The Spectrum object will 
+        automatically call the update(points) method to refresh the display.
+
+        :Parent: wx.Panel
+
+        :Args:
+
+            parent : wx.Window
+                The parent window.
+            lowfreq : int or float, optional
+                The lowest frequency, in Hz, to display on the X-axis.
+                Defaults to 0.
+            highfreq : int or float, optional
+                The highest frequency, in Hz, to display on the X-axis.
+                Defaults to 22050.
+            fscaling : int, optional
+                The frequency scaling on the X-axis. 0 means linear, 1 means 
+                logarithmic. Defaults to 0.
+            mscaling : int, optional
+                The magnitude scaling on the Y-axis. 0 means linear, 1 means 
+                logarithmic. Defaults to 0.
+            pos : wx.Point, optional
+                Window position in pixels. Defaults to (0, 0).
+            size : wx.Size, optional
+                Window size in pixels. Defaults to (300, 200).
+            style : int, optional
+                Window style (see wx.Window documentation). Defaults to 0.
+
+        """
+        def __init__(self, parent, lowfreq=0, highfreq=22050, fscaling=0, 
+                     mscaling=0, pos=(0, 0), size=(300, 200), style=0):
+            super(PyoGuiSpectrum, self).__init__(parent, 1, lowfreq, highfreq, 
+                                                 fscaling, mscaling, pos, size, style)
+
+        def update(self, points):
+            """
+            Display updating method.
+            
+            This method is automatically called by the audio analyzer
+            object (Spectrum) with points to draw as arguments. The points
+            are already formatted for the current drawing surface to save
+            CPU cycles.
+            
+            The method setAnalyzer(obj) must be used to register the audio
+            analyzer object.
+            
+            :Args:
+                
+                points : list of list of tuples
+                    A list containing n-channels list of tuples. A tuple
+                    is a point (X-Y coordinates) to draw.
+
+            """
+            wx.CallAfter(self.setImage, points)
+        
+        def setAnalyzer(self, object):
+            """
+            Register an audio analyzer object (Spectrum).
+
+            :Args:
+                
+                object : Spectrum object
+                    The audio object performing the frequency analysis.
+
+            """
+            self.obj = object
+            self.obj.setFunction(self.update)
+            self.obj.setLowFreq(self.lowfreq)
+            self.obj.setHighFreq(self.highfreq)
+            self.obj.setFscaling(self.fscaling)
+            self.obj.setMscaling(self.mscaling)
+
+        def setLowFreq(self, x):
+            """
+            Changes the lowest frequency of the display.
+
+            This method propagates the value to the audio analyzer.
+
+            :Args:
+                
+                x : int or float
+                    New lowest frequency.
+
+            """
+            if self.obj is not None:
+                self.obj.setLowFreq(x)
+            super(PyoGuiSpectrum, self).setLowFreq(x)
+
+        def setHighFreq(self, x):
+            """
+            Changes the highest frequency of the display.
+
+            This method propagates the value to the audio analyzer.
+
+            :Args:
+                
+                x : int or float
+                    New highest frequency.
+
+            """
+            if self.obj is not None:
+                self.obj.setHighFreq(x)
+            super(PyoGuiSpectrum, self).setHighFreq(x)
+
+        def setFscaling(self, x):
+            """
+            Changes the frequency scaling (X-axis) of the display.
+
+            This method propagates the value to the audio analyzer.
+
+            :Args:
+                
+                x : int
+                    0 means linear scaling, 1 means logarithmic scaling.
+
+            """
+            if self.obj is not None:
+                self.obj.setFscaling(x)
+            super(PyoGuiSpectrum, self).setFscaling(x)
+
+        def setMscaling(self, x):
+            """
+            Changes the magnitude scaling (Y-axis) of the display.
+
+            This method propagates the value to the audio analyzer.
+
+            :Args:
+                
+                x : int
+                    0 means linear scaling, 1 means logarithmic scaling.
+
+            """
+            if self.obj is not None:
+                self.obj.setMscaling(x)
+            super(PyoGuiSpectrum, self).setMscaling(x)
+
+    class PyoGuiScope(ScopePanel):
+        """
+        Oscilloscope display.
+
+        This widget should be used with the Scope object, which computes
+        the waveform of an input signal to display on a GUI. 
+        
+        To create the bridge between the analyzer and the display, the
+        Scope object must be registered in the PyoGuiScope object with 
+        the setAnalyzer(obj) method. The Scope object will automatically 
+        call the update(points) method to refresh the display.
+
+        :Parent: wx.Panel
+
+        :Args:
+
+            parent : wx.Window
+                The parent window.
+            length : float, optional
+                Length, in seconds, of the waveform segment displayed on
+                the window. Defaults to 0.05.
+            gain : float, optional
+                Linear gain applied to the signal to be displayed.
+                Defaults to 0.67.
+            pos : wx.Point, optional
+                Window position in pixels. Defaults to (0, 0).
+            size : wx.Size, optional
+                Window size in pixels. Defaults to (300, 200).
+            style : int, optional
+                Window style (see wx.Window documentation). Defaults to 0.
+
+        """
+        def __init__(self, parent, length=0.05, gain=0.67, pos=(0, 0), 
+                     size=(300, 200), style=0):
+            super(PyoGuiScope, self).__init__(parent, None, pos, size, style)
+            super(PyoGuiScope, self).setLength(length)
+            super(PyoGuiScope, self).setGain(gain)
+
+        def update(self, points):
+            """
+            Display updating method.
+            
+            This method is automatically called by the audio analyzer
+            object (Scope) with points to draw as arguments. The points
+            are already formatted for the current drawing surface to save
+            CPU cycles.
+            
+            The method setAnalyzer(obj) must be used to register the audio
+            analyzer object.
+            
+            :Args:
+                
+                points : list of list of tuples
+                    A list containing n-channels list of tuples. A tuple
+                    is a point (X-Y coordinates) to draw.
+
+            """
+            wx.CallAfter(self.setImage, points)
+        
+        def setAnalyzer(self, object):
+            """
+            Register an audio analyzer object (Scope).
+
+            :Args:
+                
+                object : Scope object
+                    The audio object performing the waveform analysis.
+
+            """
+            self.obj = object
+            self.obj.setFunction(self.update)
+            self.obj.setLength(self.length)
+            self.obj.setGain(self.gain)
+
+        def setLength(self, x):
+            """
+            Changes the length, in seconds, of the displayed audio segment.
+
+            This method propagates the value to the audio analyzer.
+
+            :Args:
+                
+                x : float
+                    New segment length in seconds.
+
+            """
+            if self.obj is not None:
+                self.obj.setLength(x)
+            super(PyoGuiScope, self).setLength(x)
+
+        def setGain(self, x):
+            """
+            Changes the gain applied to the input signal.
+
+            This method propagates the value to the audio analyzer.
+
+            :Args:
+                
+                x : float
+                    New linear gain.
+
+            """
+            if self.obj is not None:
+                self.obj.setGain(x)
+            super(PyoGuiScope, self).setGain(x)
+
+    # left-click + drag ===> event position
+    # right-click + drag ===> highlight a selection + event selection (start, end)
+    # Shift + right-click + drag ===> move the selection + event selection (start, end)
+    # Ctrl + right-click ===> delete the selection + event selection (0.0, 1.0)
+    class PyoGuiSndView(wx.Panel):
+        """
+        Soundfile display.
+
+        This widget should be used with the SndTable object, which keeps
+        soundfile in memory and computes the waveform to display on the GUI. 
+        
+        To create the bridge between the audio memory and the display, the
+        SndTable object must be registered in the PyoGuiSndView object with 
+        the setTable(object) method. 
+        
+        The SndTable object will automatically call the update() method to 
+        refresh the display when the table is modified.
+
+        :Parent: wx.Panel
+
+        :Events:
+            
+            EVT_PYO_GUI_SNDVIEW_MOUSE_POSITION
+                Sent when the mouse is moving on the panel with the left
+                button pressed. The `value` attribute of the event will
+                hold the normalized position of the mouse into the sound.
+                For X-axis value, 0.0 is the beginning of the sound and 1.0
+                is the end of the sound. For the Y-axis, 0.0 is the bottom 
+                of the panel and 1.0 is the top.
+            EVT_PYO_GUI_SNDVIEW_SELECTION
+                Sent when a new region is selected on the panel. A new 
+                selection is created with a Right-click and drag on the panel. 
+                The current selection can be moved with Shift+Right-click and 
+                drag. Ctrl+Right-click (Cmd on OSX) remove the selected region.
+                The `value` attribute of the event will hold the normalized 
+                selection as a tuple (min, max). 0.0 means the beginning of 
+                the sound and 1.0 means the end of the sound.
+
+        :Args:
+
+            parent : wx.Window
+                The parent window.
+            pos : wx.Point, optional
+                Window position in pixels. Defaults to (0, 0).
+            size : wx.Size, optional
+                Window size in pixels. Defaults to (300, 200).
+            style : int, optional
+                Window style (see wx.Window documentation). Defaults to 0.
+
+        """
+        def __init__(self, parent, pos=(0, 0), size=(300, 200), style=0):
+            wx.Panel.__init__(self, parent, pos=pos, size=size, style=style)
+            box = wx.BoxSizer(wx.VERTICAL)
+            self._curzoom = (0.0, 1.0)
+            self.sndview = SndViewTablePanel(self, None, 
+                                             self._position_callback, 
+                                             self._select_callback)
+            box.Add(self.sndview, 1, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 5)
+            self.zoom = HRangeSlider(self, minvalue=0, maxvalue=1, 
+                                     valtype='float', function=self._setZoom,
+                                     backColour=parent.GetBackgroundColour())
+            box.Add(self.zoom, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 5)
+            self.SetSizer(box)
+
+        def _setZoom(self, values=None):
+            if values is None:
+                values = self._curzoom
+            dur = self.sndview.getDur()
+            self.sndview.setBegin(dur * values[0])
+            self.sndview.setEnd(dur * values[1])
+            self._curzoom = values
+            self.update()
+
+        def _position_callback(self, pos):
+            evt = PyoGuiSndViewMousePositionEvent(value=pos)
+            wx.PostEvent(self, evt)
+
+        def _select_callback(self, selection):
+            selection = (max(0.0, min(selection)), min(max(selection), 1.0))
+            evt = PyoGuiSndViewSelectionEvent(value=selection)
+            wx.PostEvent(self, evt)
+
+        def __del__(self):
+            if self.sndview.obj is not None:
+                self.sndview.obj._setViewFrame(None)
+            self.Destroy()
+
+        def update(self):
+            """
+            Display updating method.
+            
+            This method is automatically called by the audio memory
+            object (SndTable) when the table is modified.
+            
+            The method setTable(obj) must be used to register the audio
+            memory object.
+
+            """
+            wx.CallAfter(self.sndview.setImage)
+        
+        def setTable(self, object):
+            """
+            Register an audio memory object (SndTable).
+
+            :Args:
+                
+                object : SndTable object
+                    The audio table keeping the sound in memory.
+
+            """
+            object._setViewFrame(self)
+            self.sndview.obj = object
+            self.sndview.setBegin(0.0)
+            self.sndview.setEnd(object.getDur(False))
+            self.sndview.chnls = len(object)
+            self.update()
+
+        def setSelection(self, start, stop):
+            """
+            Changes the selected region.
+
+            This method will trigger a EVT_PYO_GUI_SNDVIEW_SELECTION event
+            with a tuple (start, stop) as value.
+
+            :Args:
+                
+                start : float
+                    The starting point of the selected region. This value
+                    must be normalized between 0 and 1 (0 is the beginning
+                    of the sound, 1 is the end).
+                stop : float
+                    The ending point of the selected region. This value
+                    must be normalized between 0 and 1 (0 is the beginning
+                    of the sound, 1 is the end).
+
+            """
+            self.sndview.setSelection(start, stop)
+                
+        def resetSelection(self):
+            """
+            Removes the selected region.
+            
+            This method will trigger a EVT_PYO_GUI_SNDVIEW_SELECTION event
+            with a tuple (0.0, 1.0) as value.
+
+            """
+            self.sndview.resetSelection()
\ No newline at end of file
diff --git a/scripts/release_doc_src.sh b/scripts/release_doc_src.sh
index 320ea79..964ec49 100755
--- 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.7.8
+version=0.7.9
 replace=XXX
 
 doc_rep=pyo_XXX-doc
diff --git a/setup.py b/setup.py
index d770190..f9456f2 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.7.8"
+pyo_version = "0.7.9"
 build_osx_with_jack_support = False
 compile_externals = False
 
diff --git a/src/engine/pyomodule.c b/src/engine/pyomodule.c
index f4a69d3..82db41b 100644
--- a/src/engine/pyomodule.c
+++ b/src/engine/pyomodule.c
@@ -30,7 +30,7 @@
 #include "tablemodule.h"
 #include "matrixmodule.h"
 
-/** Note :
+/** TODO:
  ** Add an argument to pa_get_* and pm_get_* functions to allow printing to the console
  **/
 
diff --git a/src/engine/servermodule.c b/src/engine/servermodule.c
index a7b8e31..b020ff1 100644
--- a/src/engine/servermodule.c
+++ b/src/engine/servermodule.c
@@ -54,6 +54,12 @@ static int Server_start_rec_internal(Server *self, char *filename);
 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,2203,2207};
+static unsigned int PYO_RAND_SEED = 1;
+/* Linear congruential pseudo-random generator. */
+unsigned int pyorand() {
+    PYO_RAND_SEED = (PYO_RAND_SEED * 1664525 + 1013904223) % PYO_RAND_MAX;
+    return PYO_RAND_SEED;
+}
 
 #ifdef USE_COREAUDIO
 static int coreaudio_stop_callback(Server *self);
@@ -1966,21 +1972,20 @@ Server_setGlobalSeed(Server *self, PyObject *arg)
 int
 Server_generateSeed(Server *self, int oid)
 {
-    int curseed, seed, count, mult;
-    long ltime;
+    unsigned int curseed, count, mult, ltime;
 
     count = ++rnd_objs_count[oid];
     mult = rnd_objs_mult[oid];
 
     if (self->globalSeed > 0) {
-        curseed = self->globalSeed + ((count * mult) % 32768);
+        curseed = (self->globalSeed + count * mult) % PYO_RAND_MAX;
     }
     else {
-        ltime = time(NULL);
-        seed = (unsigned) (ltime / 2) % 32768;
-        curseed = seed + ((count * mult) % 32768);
+        ltime = (unsigned int)time(NULL);
+        curseed = (ltime * ltime + count * mult) % PYO_RAND_MAX;
     }
-    srand(curseed);
+
+    PYO_RAND_SEED = curseed;
 
     return 0;
 }
diff --git a/src/objects/analysismodule.c b/src/objects/analysismodule.c
index 944570b..5244129 100644
--- a/src/objects/analysismodule.c
+++ b/src/objects/analysismodule.c
@@ -2289,6 +2289,14 @@ AttackDetector_setReltime(AttackDetector *self, PyObject *arg)
 	Py_RETURN_NONE;
 }
 
+static PyObject *
+AttackDetector_readyToDetect(AttackDetector *self)
+{
+    self->overminok = 1;
+    self->timer = self->maxtime;
+	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."},
@@ -2308,6 +2316,7 @@ static PyMethodDef AttackDetector_methods[] = {
 {"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)."},
+{"readyToDetect", (PyCFunction)AttackDetector_readyToDetect, METH_NOARGS, "Initializes thresholds."},
 {"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."},
diff --git a/src/objects/freeverbmodule.c b/src/objects/freeverbmodule.c
index e2ef257..a0c6b0a 100644
--- a/src/objects/freeverbmodule.c
+++ b/src/objects/freeverbmodule.c
@@ -673,7 +673,7 @@ Freeverb_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
     Server_generateSeed((Server *)self->server, FREEVERB_ID);
 
-    rndSamps = (rand()/(MYFLT)(RAND_MAX) * 20 + 10) / DEFAULT_SRATE;
+    rndSamps = (RANDOM_UNIFORM * 20 + 10) / DEFAULT_SRATE;
     for(i=0; i<NUM_COMB; i++) {
         nsamps = Freeverb_calc_nsamples((Freeverb *)self, comb_delays[i] + rndSamps);
         self->comb_buf[i] = (MYFLT *)realloc(self->comb_buf[i], (nsamps+1) * sizeof(MYFLT));
diff --git a/src/objects/granulatormodule.c b/src/objects/granulatormodule.c
index 4470e82..f07b6cb 100644
--- a/src/objects/granulatormodule.c
+++ b/src/objects/granulatormodule.c
@@ -754,7 +754,7 @@ Granulator_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     Server_generateSeed((Server *)self->server, GRANULATOR_ID);
 
     for (i=0; i<self->ngrains; i++) {
-        phase = ((MYFLT)i/self->ngrains) * (1.0 + ((rand()/((MYFLT)(RAND_MAX)+1)*2.0-1.0) * 0.01));
+        phase = ((MYFLT)i/self->ngrains) * (1.0 + ((RANDOM_UNIFORM * 2.0 - 1.0) * 0.01));
         if (phase < 0.0)
             phase = 0.0;
         else if (phase >= 1.0)
@@ -949,7 +949,7 @@ Granulator_setGrains(Granulator *self, PyObject *arg)
         self->lastppos = (MYFLT *)realloc(self->lastppos, self->ngrains * sizeof(MYFLT));
 
         for (i=0; i<self->ngrains; i++) {
-            phase = ((MYFLT)i/self->ngrains) * (1.0 + ((rand()/((MYFLT)(RAND_MAX)+1)*2.0-1.0) * 0.01));
+            phase = ((MYFLT)i/self->ngrains) * (1.0 + ((RANDOM_UNIFORM * 2.0 - 1.0) * 0.01));
             if (phase < 0.0)
                 phase = 0.0;
             else if (phase >= 1.0)
@@ -2246,7 +2246,7 @@ Granule_transform_i(Granule *self) {
             }
         } else {
             /* asynchronous */
-            if ((rand() * self->srOnRandMax) < dens)
+            if ((pyorand() * self->srOnRandMax) < dens)
                 flag = 1;
         }
 
@@ -2337,7 +2337,7 @@ Granule_transform_a(Granule *self) {
             }
         } else {
             /* asynchronous */
-            if ((rand() * self->srOnRandMax) < density[i])
+            if ((pyorand() * self->srOnRandMax) < density[i])
                 flag = 1;
         }
 
@@ -2537,7 +2537,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;
+    self->srOnRandMax = self->sr / (MYFLT)PYO_RAND_MAX;
 
     Stream_setFunctionPtr(self->stream, Granule_compute_next_data_frame);
     self->mode_func_ptr = Granule_setProcMode;
@@ -3029,7 +3029,7 @@ MainParticle_transform_mono_i(MainParticle *self) {
                         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;
+                    self->devFactor = (RANDOM_UNIFORM * 2.0 - 1.0) * dev + 1.0;
                     break;
                 }
             }
@@ -3129,7 +3129,7 @@ MainParticle_transform_mono_a(MainParticle *self) {
                         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;
+                    self->devFactor = (RANDOM_UNIFORM * 2.0 - 1.0) * dev + 1.0;
                     break;
                 }
             }
@@ -3237,7 +3237,7 @@ MainParticle_transform_i(MainParticle *self) {
                         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;
+                    self->devFactor = (RANDOM_UNIFORM * 2.0 - 1.0) * dev + 1.0;
                     if (self->chnls == 2) {
                         self->k1[j] = 0;
                         self->k2[j] = self->bufsize;
@@ -3371,7 +3371,7 @@ MainParticle_transform_a(MainParticle *self) {
                         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;
+                    self->devFactor = (RANDOM_UNIFORM * 2.0 - 1.0) * dev + 1.0;
                     if (self->chnls == 2) {
                         self->k1[j] = 0;
                         self->k2[j] = self->bufsize;
@@ -3548,7 +3548,7 @@ MainParticle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     INIT_OBJECT_COMMON
 
     self->oneOnSr = 1.0 / self->sr;
-    self->srOnRandMax = self->sr / (MYFLT)RAND_MAX;
+    self->srOnRandMax = self->sr / (MYFLT)PYO_RAND_MAX;
 
     Stream_setFunctionPtr(self->stream, MainParticle_compute_next_data_frame);
     self->mode_func_ptr = MainParticle_setProcMode;
diff --git a/src/objects/lfomodule.c b/src/objects/lfomodule.c
index ef9be04..1017756 100644
--- a/src/objects/lfomodule.c
+++ b/src/objects/lfomodule.c
@@ -175,7 +175,7 @@ LFO_generates_ii(LFO *self) {
                     self->pointerPos -= 1.0;
                     self->sahPointerPos = 0.0;
                     self->sahLastValue = self->sahCurrentValue;
-                    self->sahCurrentValue = rand()/((MYFLT)(RAND_MAX)*0.5) - 1.0;
+                    self->sahCurrentValue = RANDOM_UNIFORM * 2.0 - 1.0;
                 }
                 if (self->sahPointerPos < 1.0) {
                     fade = 0.5 * MYSIN(PI * (self->sahPointerPos+0.5)) + 0.5;
@@ -354,7 +354,7 @@ LFO_generates_ai(LFO *self) {
                     self->pointerPos -= 1.0;
                     self->sahPointerPos = 0.0;
                     self->sahLastValue = self->sahCurrentValue;
-                    self->sahCurrentValue = rand()/((MYFLT)(RAND_MAX)*0.5) - 1.0;
+                    self->sahCurrentValue = RANDOM_UNIFORM * 2.0 - 1.0;
                 }
                 if (self->sahPointerPos < 1.0) {
                     fade = 0.5 * MYSIN(PI * (self->sahPointerPos+0.5)) + 0.5;
@@ -553,7 +553,7 @@ LFO_generates_ia(LFO *self) {
                     self->pointerPos -= 1.0;
                     self->sahPointerPos = 0.0;
                     self->sahLastValue = self->sahCurrentValue;
-                    self->sahCurrentValue = rand()/((MYFLT)(RAND_MAX)*0.5) - 1.0;
+                    self->sahCurrentValue = RANDOM_UNIFORM * 2.0 - 1.0;
                 }
                 if (self->sahPointerPos < 1.0) {
                     fade = 0.5 * MYSIN(PI * (self->sahPointerPos+0.5)) + 0.5;
@@ -768,7 +768,7 @@ LFO_generates_aa(LFO *self) {
                     self->pointerPos -= 1.0;
                     self->sahPointerPos = 0.0;
                     self->sahLastValue = self->sahCurrentValue;
-                    self->sahCurrentValue = rand()/((MYFLT)(RAND_MAX)*0.5) - 1.0;
+                    self->sahCurrentValue = RANDOM_UNIFORM * 2.0 - 1.0;
                 }
                 if (self->sahPointerPos < 1.0) {
                     fade = 0.5 * MYSIN(PI * (self->sahPointerPos+0.5)) + 0.5;
@@ -961,7 +961,7 @@ LFO_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
     Server_generateSeed((Server *)self->server, LFO_ID);
 
-    self->sahCurrentValue = self->sahLastValue = rand()/((MYFLT)(RAND_MAX)*0.5) - 1.0;
+    self->sahCurrentValue = self->sahLastValue = RANDOM_UNIFORM * 2.0 - 1.0;
 
     (*self->mode_func_ptr)(self);
 
diff --git a/src/objects/metromodule.c b/src/objects/metromodule.c
index 4913b0b..57dec3f 100644
--- a/src/objects/metromodule.c
+++ b/src/objects/metromodule.c
@@ -992,7 +992,7 @@ Clouder_generate_i(Clouder *self) {
 
     dens *= 0.5;
     for (i=0; i<self->bufsize; i++) {
-        rnd = (int)(rand() / (MYFLT)RAND_MAX * self->sr);
+        rnd = (int)(RANDOM_UNIFORM * self->sr);
         if (rnd < dens) {
             self->buffer_streams[i + self->voiceCount++ * self->bufsize] = 1.0;
             if (self->voiceCount == self->poly)
@@ -1020,7 +1020,7 @@ Clouder_generate_a(Clouder *self) {
             dens = self->sr;
 
         dens *= 0.5;
-        rnd = (int)(rand() / (MYFLT)RAND_MAX * self->sr);
+        rnd = (int)(RANDOM_UNIFORM * self->sr);
         if (rnd < dens) {
             self->buffer_streams[i + self->voiceCount++ * self->bufsize] = 1.0;
             if (self->voiceCount == self->poly)
@@ -1759,11 +1759,11 @@ typedef struct {
 static MYFLT
 Beater_defineAccent(int n) {
 	if (n == 1)
-		return (MYFLT)((rand() % 15) + 112) / 127.; // 112 -> 127
+		return (MYFLT)((pyorand() % 15) + 112) / 127.; // 112 -> 127
 	else if (n == 2)
-		return (MYFLT)((rand() % 20) + 70) / 127.; // 70 -> 90
+		return (MYFLT)((pyorand() % 20) + 70) / 127.; // 70 -> 90
 	else if (n == 3)
-		return (MYFLT)((rand() % 20) + 40) / 127.; // 40 -> 60
+		return (MYFLT)((pyorand() % 20) + 40) / 127.; // 40 -> 60
     else
         return 0.5;
 }
@@ -1906,7 +1906,7 @@ Beater_makeSequence(Beater *self) {
 
 	j = 0;
 	for (i=0; i < self->taps; i++) {
-		if ((rand() % 100) < self->tapProb[i]) {
+		if ((pyorand() % 100) < self->tapProb[i]) {
 			self->sequence[i] = 1;
 			self->tapList[j++] = i;
 		}
diff --git a/src/objects/midimodule.c b/src/objects/midimodule.c
index 6849296..480c982 100644
--- a/src/objects/midimodule.c
+++ b/src/objects/midimodule.c
@@ -1919,7 +1919,7 @@ int firstEmpty(int *buf, int len) {
 int nextEmptyVoice(int *buf, int voice, int len) {
     int i, tmp;
     int next = -1;
-    for (i=0; i<len; i++) {
+    for (i=1; i<=len; i++) {
         tmp = (i + voice) % len;
         if (buf[tmp*2+1] == 0) {
             next = tmp;
diff --git a/src/objects/noisemodule.c b/src/objects/noisemodule.c
index 728e3b8..9cfad4d 100644
--- a/src/objects/noisemodule.c
+++ b/src/objects/noisemodule.c
@@ -37,7 +37,7 @@ Noise_generate(Noise *self) {
     int i;
 
     for (i=0; i<self->bufsize; i++) {
-        self->data[i] = rand()/((MYFLT)(RAND_MAX)+1)*1.98-0.99;
+        self->data[i] = RANDOM_UNIFORM * 1.98 - 0.99;
     }
 }
 
@@ -168,7 +168,7 @@ Noise_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
     Server_generateSeed((Server *)self->server, NOISE_ID);
 
-    self->seed = rand();
+    self->seed = pyorand();
 
     (*self->mode_func_ptr)(self);
 
@@ -335,7 +335,7 @@ PinkNoise_generate(PinkNoise *self) {
     int i;
 
     for (i=0; i<self->bufsize; i++) {
-        in = rand()/((MYFLT)(RAND_MAX)+1)*1.98-0.99;
+        in = RANDOM_UNIFORM * 1.98 - 0.99;
         self->c0 = self->c0 * 0.99886 + in * 0.0555179;
         self->c1 = self->c1 * 0.99332 + in * 0.0750759;
         self->c2 = self->c2 * 0.96900 + in * 0.1538520;
@@ -601,7 +601,7 @@ BrownNoise_generate(BrownNoise *self) {
     int i;
 
     for (i=0; i<self->bufsize; i++) {
-        rnd = rand()/((MYFLT)(RAND_MAX)+1)*1.98-0.99;
+        rnd = RANDOM_UNIFORM * 1.98 - 0.99;
         val = self->c1 * rnd + self->c2 * self->y1;
         self->y1 = val;
         self->data[i] = val * 20.0; /* gain compensation */
diff --git a/src/objects/oscbankmodule.c b/src/objects/oscbankmodule.c
index bc0bee1..ccf5f91 100644
--- a/src/objects/oscbankmodule.c
+++ b/src/objects/oscbankmodule.c
@@ -89,7 +89,7 @@ OscBank_setFrequencies(OscBank *self, MYFLT freq, MYFLT spread) {
     MYFLT scl = freq * spread;
 
     if (self->fjit == 1) {
-        seed = rand();
+        seed = pyorand();
         for (i=0; i<self->stages; i++) {
             seed = (seed * 15625 + 1) & 0xFFFF;
             rnd = seed * 1.52587890625e-07 - 0.005 + 1.0;
@@ -115,7 +115,7 @@ OscBank_pickNewFrnds(OscBank *self, MYFLT frndf, MYFLT frnda) {
     else if (frnda > 1.0)
         frnda = 1.0;
 
-    seed = rand();
+    seed = pyorand();
     for (i=0; i<self->stages; i++) {
         self->fOldValues[i] = self->fValues[i];
         seed = (seed * 15625 + 1) & 0xFFFF;
@@ -134,7 +134,7 @@ OscBank_pickNewArnds(OscBank *self, MYFLT arndf, MYFLT arnda) {
     else if (arnda > 1.0)
         arnda = 1.0;
 
-    seed = rand();
+    seed = pyorand();
     for (i=0; i<self->stages; i++) {
         self->aOldValues[i] = self->aValues[i];
         seed = (seed * 15625 + 1) & 0xFFFF;
diff --git a/src/objects/oscmodule.c b/src/objects/oscmodule.c
index 9f28225..937a395 100644
--- a/src/objects/oscmodule.c
+++ b/src/objects/oscmodule.c
@@ -970,7 +970,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=NULL, *address=NULL;
+    PyObject *tup, *result=NULL;
     lo_blob *blob = NULL;
     char *blobdata = NULL;
     uint32_t blobsize = 0;
@@ -980,13 +980,17 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
 
     Py_ssize_t lsize = PyList_Size(self->address_path);
     for (i=0; i<lsize; i++) {
-        if (PyString_Check(PyList_GET_ITEM(self->address_path, i))) 
-            address = PyList_GET_ITEM(self->address_path, i);
-        else
-            address = PyUnicode_AsASCIIString(PyList_GET_ITEM(self->address_path, i));
-        if (lo_pattern_match(path, PyString_AsString(address))) {
-            ok = 1;
-            break;
+        if (PyString_Check(PyList_GET_ITEM(self->address_path, i))) {
+            if (lo_pattern_match(path, PyString_AsString(PyList_GET_ITEM(self->address_path, i)))) {
+                ok = 1;
+                break;
+            }
+        }
+        else {
+            if (lo_pattern_match(path, PyString_AsString(PyUnicode_AsASCIIString(PyList_GET_ITEM(self->address_path, i))))) {
+                ok = 1;
+                break;
+            }
         }
     }
     if (ok) {
@@ -1051,7 +1055,6 @@ int OscDataReceive_handler(const char *path, const char *types, lo_arg **argv, i
     Py_XDECREF(tup);
     Py_XDECREF(result);
     Py_XDECREF(charlist);
-    Py_XDECREF(address);
     return 0;
 }
 
diff --git a/src/objects/randommodule.c b/src/objects/randommodule.c
index aa3e085..fc25ac6 100644
--- a/src/objects/randommodule.c
+++ b/src/objects/randommodule.c
@@ -58,7 +58,7 @@ Randi_generate_iii(Randi *self) {
         else if (self->time >= 1.0) {
             self->time -= 1.0;
             self->oldValue = self->value;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             self->diff = self->value - self->oldValue;
         }
         self->data[i] = self->oldValue + self->diff * self->time;
@@ -82,7 +82,7 @@ Randi_generate_aii(Randi *self) {
         else if (self->time >= 1.0) {
             self->time -= 1.0;
             self->oldValue = self->value;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
             self->diff = self->value - self->oldValue;
         }
         self->data[i] = self->oldValue + self->diff * self->time;
@@ -106,7 +106,7 @@ Randi_generate_iai(Randi *self) {
         else if (self->time >= 1.0) {
             self->time -= 1.0;
             self->oldValue = self->value;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             self->diff = self->value - self->oldValue;
         }
         self->data[i] = self->oldValue + self->diff * self->time;
@@ -130,7 +130,7 @@ Randi_generate_aai(Randi *self) {
         else if (self->time >= 1.0) {
             self->time -= 1.0;
             self->oldValue = self->value;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
             self->diff = self->value - self->oldValue;
         }
         self->data[i] = self->oldValue + self->diff * self->time;
@@ -154,7 +154,7 @@ Randi_generate_iia(Randi *self) {
         else if (self->time >= 1.0) {
             self->time -= 1.0;
             self->oldValue = self->value;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             self->diff = self->value - self->oldValue;
         }
         self->data[i] = self->oldValue + self->diff * self->time;
@@ -178,7 +178,7 @@ Randi_generate_aia(Randi *self) {
         else if (self->time >= 1.0) {
             self->time -= 1.0;
             self->oldValue = self->value;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
             self->diff = self->value - self->oldValue;
         }
         self->data[i] = self->oldValue + self->diff * self->time;
@@ -202,7 +202,7 @@ Randi_generate_iaa(Randi *self) {
         else if (self->time >= 1.0) {
             self->time -= 1.0;
             self->oldValue = self->value;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             self->diff = self->value - self->oldValue;
         }
         self->data[i] = self->oldValue + self->diff * self->time;
@@ -226,7 +226,7 @@ Randi_generate_aaa(Randi *self) {
         else if (self->time >= 1.0) {
             self->time -= 1.0;
             self->oldValue = self->value;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
             self->diff = self->value - self->oldValue;
         }
         self->data[i] = self->oldValue + self->diff * self->time;
@@ -673,7 +673,7 @@ Randh_generate_iii(Randh *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
         }
         self->data[i] = self->value;
     }
@@ -695,7 +695,7 @@ Randh_generate_aii(Randh *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
         }
         self->data[i] = self->value;
     }
@@ -717,7 +717,7 @@ Randh_generate_iai(Randh *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
         }
         self->data[i] = self->value;
     }
@@ -739,7 +739,7 @@ Randh_generate_aai(Randh *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
         }
         self->data[i] = self->value;
     }
@@ -761,7 +761,7 @@ Randh_generate_iia(Randh *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
         }
         self->data[i] = self->value;
     }
@@ -783,7 +783,7 @@ Randh_generate_aia(Randh *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
         }
         self->data[i] = self->value;
     }
@@ -805,7 +805,7 @@ Randh_generate_iaa(Randh *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
         }
         self->data[i] = self->value;
     }
@@ -827,7 +827,7 @@ Randh_generate_aaa(Randh *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
         }
         self->data[i] = self->value;
     }
@@ -1268,7 +1268,7 @@ Choice_generate_i(Choice *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = self->choice[(int)((rand()/((MYFLT)(RAND_MAX))) * self->chSize)];
+            self->value = self->choice[(int)(RANDOM_UNIFORM * self->chSize)];
         }
         self->data[i] = self->value;
     }
@@ -1287,7 +1287,7 @@ Choice_generate_a(Choice *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = self->choice[(int)((rand()/((MYFLT)(RAND_MAX))) * self->chSize)];
+            self->value = self->choice[(int)(RANDOM_UNIFORM * self->chSize)];
         }
         self->data[i] = self->value;
     }
@@ -1644,7 +1644,7 @@ RandInt_generate_ii(RandInt *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = (MYFLT)((int)(rand()/((MYFLT)(RAND_MAX)+1)*ma));
+            self->value = (MYFLT)((int)(RANDOM_UNIFORM * ma));
         }
         self->data[i] = self->value;
     }
@@ -1664,7 +1664,7 @@ RandInt_generate_ai(RandInt *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = (MYFLT)((int)(rand()/((MYFLT)(RAND_MAX)+1)*ma[i]));
+            self->value = (MYFLT)((int)(RANDOM_UNIFORM * ma[i]));
         }
         self->data[i] = self->value;
     }
@@ -1684,7 +1684,7 @@ RandInt_generate_ia(RandInt *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = (MYFLT)((int)(rand()/((MYFLT)(RAND_MAX)+1)*ma));
+            self->value = (MYFLT)((int)(RANDOM_UNIFORM * ma));
         }
         self->data[i] = self->value;
     }
@@ -1704,7 +1704,7 @@ RandInt_generate_aa(RandInt *self) {
             self->time += 1.0;
         else if (self->time >= 1.0) {
             self->time -= 1.0;
-            self->value = (MYFLT)((int)(rand()/((MYFLT)(RAND_MAX)+1)*ma[i]));
+            self->value = (MYFLT)((int)(RANDOM_UNIFORM * ma[i]));
         }
         self->data[i] = self->value;
     }
@@ -2084,7 +2084,7 @@ RandDur_generate_ii(RandDur *self) {
             range = ma - mi;
             if (range < 0.0)
                 range = 0.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             self->inc = (1.0 / self->value) / self->sr;
         }
         self->data[i] = self->value;
@@ -2110,7 +2110,7 @@ RandDur_generate_ai(RandDur *self) {
             range = ma - mi;
             if (range < 0.0)
                 range = 0.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             self->inc = (1.0 / self->value) / self->sr;
         }
         self->data[i] = self->value;
@@ -2135,7 +2135,7 @@ RandDur_generate_ia(RandDur *self) {
             range = ma[i] - mi;
             if (range < 0.0)
                 range = 0.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             self->inc = (1.0 / self->value) / self->sr;
         }
         self->data[i] = self->value;
@@ -2161,7 +2161,7 @@ RandDur_generate_aa(RandDur *self) {
             range = ma[i] - mi;
             if (range < 0.0)
                 range = 0.0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             self->inc = (1.0 / self->value) / self->sr;
         }
         self->data[i] = self->value;
@@ -2633,7 +2633,7 @@ Xnoise_cauchy(Xnoise *self) {
     }
     while (rnd == 0.5);
 
-    if (rand() < (RAND_MAX / 2))
+    if (pyorand() < (PYO_RAND_MAX / 2))
         dir = -1;
     else
         dir = 1;
@@ -2694,7 +2694,7 @@ Xnoise_poisson(Xnoise *self) {
             }
         }
     }
-    val = self->poisson_buffer[rand() % self->poisson_tab] / 12.0 * self->xx2;
+    val = self->poisson_buffer[pyorand() % self->poisson_tab] / 12.0 * self->xx2;
 
     if (val < 0.0) return 0.0;
     else if (val > 1.0) return 1.0;
@@ -2709,12 +2709,12 @@ Xnoise_walker(Xnoise *self) {
     if (self->xx2 < 0.002) self->xx2 = 0.002;
 
     modulo = (int)(self->xx2 * 1000.0);
-    dir = rand() % 2;
+    dir = pyorand() % 2;
 
     if (dir == 0)
-        self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
     else
-        self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
     if (self->walkerValue > self->xx1)
         self->walkerValue = self->xx1;
@@ -2736,12 +2736,12 @@ Xnoise_loopseg(Xnoise *self) {
         if (self->xx2 < 0.002) self->xx2 = 0.002;
 
         modulo = (int)(self->xx2 * 1000.0);
-        dir = rand() % 2;
+        dir = pyorand() % 2;
 
         if (dir == 0)
-            self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
         else
-            self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
         if (self->walkerValue > self->xx1)
             self->walkerValue = self->xx1;
@@ -2754,7 +2754,7 @@ Xnoise_loopseg(Xnoise *self) {
             self->loopChoice = 0;
         else {
             self->loopChoice = 1;
-            self->loopStop = (rand() % 4) + 1;
+            self->loopStop = (pyorand() % 4) + 1;
         }
     }
     else {
@@ -2771,7 +2771,7 @@ Xnoise_loopseg(Xnoise *self) {
 
         if (self->loopTime == self->loopStop) {
             self->loopChoice = 0;
-            self->loopLen = (rand() % 10) + 3;
+            self->loopLen = (pyorand() % 10) + 3;
         }
     }
 
@@ -3149,7 +3149,7 @@ Xnoise_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         self->loop_buffer[i] = 0.0;
     }
     self->loopChoice = self->loopCountPlay = self->loopTime = self->loopCountRec = self->loopStop = 0;
-    self->loopLen = (rand() % 10) + 3;
+    self->loopLen = (pyorand() % 10) + 3;
 
     Stream_setFunctionPtr(self->stream, Xnoise_compute_next_data_frame);
     self->mode_func_ptr = Xnoise_setProcMode;
@@ -3565,7 +3565,7 @@ XnoiseMidi_cauchy(XnoiseMidi *self) {
     }
     while (rnd == 0.5);
 
-    if (rand() < (RAND_MAX / 2))
+    if (pyorand() < (PYO_RAND_MAX / 2))
         dir = -1;
     else
         dir = 1;
@@ -3626,7 +3626,7 @@ XnoiseMidi_poisson(XnoiseMidi *self) {
             }
         }
     }
-    val = self->poisson_buffer[rand() % self->poisson_tab] / 12.0 * self->xx2;
+    val = self->poisson_buffer[pyorand() % self->poisson_tab] / 12.0 * self->xx2;
 
     if (val < 0.0) return 0.0;
     else if (val > 1.0) return 1.0;
@@ -3641,12 +3641,12 @@ XnoiseMidi_walker(XnoiseMidi *self) {
     if (self->xx2 < 0.002) self->xx2 = 0.002;
 
     modulo = (int)(self->xx2 * 1000.0);
-    dir = rand() % 2;
+    dir = pyorand() % 2;
 
     if (dir == 0)
-        self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
     else
-        self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
     if (self->walkerValue > self->xx1)
         self->walkerValue = self->xx1;
@@ -3668,12 +3668,12 @@ XnoiseMidi_loopseg(XnoiseMidi *self) {
         if (self->xx2 < 0.002) self->xx2 = 0.002;
 
         modulo = (int)(self->xx2 * 1000.0);
-        dir = rand() % 2;
+        dir = pyorand() % 2;
 
         if (dir == 0)
-            self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
         else
-            self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
         if (self->walkerValue > self->xx1)
             self->walkerValue = self->xx1;
@@ -3686,7 +3686,7 @@ XnoiseMidi_loopseg(XnoiseMidi *self) {
             self->loopChoice = 0;
         else {
             self->loopChoice = 1;
-            self->loopStop = (rand() % 4) + 1;
+            self->loopStop = (pyorand() % 4) + 1;
         }
     }
     else {
@@ -3703,7 +3703,7 @@ XnoiseMidi_loopseg(XnoiseMidi *self) {
 
         if (self->loopTime == self->loopStop) {
             self->loopChoice = 0;
-            self->loopLen = (rand() % 10) + 3;
+            self->loopLen = (pyorand() % 10) + 3;
         }
     }
 
@@ -4093,7 +4093,7 @@ XnoiseMidi_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         self->loop_buffer[i] = 0.0;
     }
     self->loopChoice = self->loopCountPlay = self->loopTime = self->loopCountRec = self->loopStop = 0;
-    self->loopLen = (rand() % 10) + 3;
+    self->loopLen = (pyorand() % 10) + 3;
 
     Stream_setFunctionPtr(self->stream, XnoiseMidi_compute_next_data_frame);
     self->mode_func_ptr = XnoiseMidi_setProcMode;
@@ -4531,7 +4531,7 @@ XnoiseDur_cauchy(XnoiseDur *self) {
     }
     while (rnd == 0.5);
 
-    if (rand() < (RAND_MAX / 2))
+    if (pyorand() < (PYO_RAND_MAX / 2))
         dir = -1;
     else
         dir = 1;
@@ -4592,7 +4592,7 @@ XnoiseDur_poisson(XnoiseDur *self) {
             }
         }
     }
-    val = self->poisson_buffer[rand() % self->poisson_tab] / 12.0 * self->xx2;
+    val = self->poisson_buffer[pyorand() % self->poisson_tab] / 12.0 * self->xx2;
 
     if (val < 0.0) return 0.0;
     else if (val > 1.0) return 1.0;
@@ -4607,12 +4607,12 @@ XnoiseDur_walker(XnoiseDur *self) {
     if (self->xx2 < 0.002) self->xx2 = 0.002;
 
     modulo = (int)(self->xx2 * 1000.0);
-    dir = rand() % 2;
+    dir = pyorand() % 2;
 
     if (dir == 0)
-        self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
     else
-        self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
     if (self->walkerValue > self->xx1)
         self->walkerValue = self->xx1;
@@ -4634,12 +4634,12 @@ XnoiseDur_loopseg(XnoiseDur *self) {
         if (self->xx2 < 0.002) self->xx2 = 0.002;
 
         modulo = (int)(self->xx2 * 1000.0);
-        dir = rand() % 2;
+        dir = pyorand() % 2;
 
         if (dir == 0)
-            self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
         else
-            self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
         if (self->walkerValue > self->xx1)
             self->walkerValue = self->xx1;
@@ -4652,7 +4652,7 @@ XnoiseDur_loopseg(XnoiseDur *self) {
             self->loopChoice = 0;
         else {
             self->loopChoice = 1;
-            self->loopStop = (rand() % 4) + 1;
+            self->loopStop = (pyorand() % 4) + 1;
         }
     }
     else {
@@ -4669,7 +4669,7 @@ XnoiseDur_loopseg(XnoiseDur *self) {
 
         if (self->loopTime == self->loopStop) {
             self->loopChoice = 0;
-            self->loopLen = (rand() % 10) + 3;
+            self->loopLen = (pyorand() % 10) + 3;
         }
     }
 
@@ -4891,7 +4891,7 @@ XnoiseDur_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         self->loop_buffer[i] = 0.0;
     }
     self->loopChoice = self->loopCountPlay = self->loopTime = self->loopCountRec = self->loopStop = 0;
-    self->loopLen = (rand() % 10) + 3;
+    self->loopLen = (pyorand() % 10) + 3;
 
     Stream_setFunctionPtr(self->stream, XnoiseDur_compute_next_data_frame);
     self->mode_func_ptr = XnoiseDur_setProcMode;
@@ -5258,9 +5258,9 @@ Urn_choose(Urn *self) {
     int value = 0;
     int i, pick;
 
-    pick = rand() % self->length;
+    pick = pyorand() % self->length;
     while (pick == self->lastvalue)
-        pick = rand() % self->length;
+        pick = pyorand() % self->length;
 
     for (i=0; i<self->length; i++) {
         if (i != pick)
diff --git a/src/objects/sfplayermodule.c b/src/objects/sfplayermodule.c
index f9f332a..50b1e9e 100644
--- a/src/objects/sfplayermodule.c
+++ b/src/objects/sfplayermodule.c
@@ -1015,7 +1015,7 @@ SfMarkerShuffler_chooseNewMark(SfMarkerShuffler *self, int dir)
     int mark;
     if (dir == 1) {
         if (self->startPos == -1) {
-            mark = (int)(self->markers_size * (rand()/((MYFLT)(RAND_MAX)+1)));
+            mark = (int)(self->markers_size * RANDOM_UNIFORM);
             self->startPos = self->markers[mark] * self->srScale;
             self->endPos = self->markers[mark+1] * self->srScale;
         }
@@ -1024,13 +1024,13 @@ SfMarkerShuffler_chooseNewMark(SfMarkerShuffler *self, int dir)
             self->endPos = self->nextEndPos;
         }
 
-        mark = (int)(self->markers_size * (rand()/((MYFLT)(RAND_MAX)+1)));
+        mark = (int)(self->markers_size * RANDOM_UNIFORM);
         self->nextStartPos = self->markers[mark] * self->srScale;
         self->nextEndPos = self->markers[mark+1] * self->srScale;
     }
     else {
         if (self->startPos == -1) {
-            mark = self->markers_size - (int)(self->markers_size * (rand()/((MYFLT)(RAND_MAX)+1)));
+            mark = self->markers_size - (int)(self->markers_size * RANDOM_UNIFORM);
             self->startPos = self->markers[mark] * self->srScale;
             self->endPos = self->markers[mark-1] * self->srScale;
         }
@@ -1039,7 +1039,7 @@ SfMarkerShuffler_chooseNewMark(SfMarkerShuffler *self, int dir)
             self->endPos = self->nextEndPos;
         }
 
-        mark = self->markers_size - (int)(self->markers_size * (rand()/((MYFLT)(RAND_MAX)+1)));
+        mark = self->markers_size - (int)(self->markers_size * RANDOM_UNIFORM);
         self->nextStartPos = self->markers[mark] * self->srScale;
         self->nextEndPos = self->markers[mark-1] * self->srScale;
     }
diff --git a/src/objects/trigmodule.c b/src/objects/trigmodule.c
index df50c6d..c00d825 100644
--- a/src/objects/trigmodule.c
+++ b/src/objects/trigmodule.c
@@ -45,7 +45,7 @@ TrigRandInt_generate_i(TrigRandInt *self) {
 
     for (i=0; i<self->bufsize; i++) {
         if (in[i] == 1)
-            self->value = (MYFLT)((int)(rand()/((MYFLT)(RAND_MAX)+1)*ma));
+            self->value = (MYFLT)((int)(RANDOM_UNIFORM * ma));
 
         self->data[i] = self->value;
     }
@@ -59,7 +59,7 @@ TrigRandInt_generate_a(TrigRandInt *self) {
 
     for (i=0; i<self->bufsize; i++) {
         if (in[i] == 1)
-            self->value = (MYFLT)((int)(rand()/((MYFLT)(RAND_MAX)+1)*ma[i]));
+            self->value = (MYFLT)((int)(RANDOM_UNIFORM * ma[i]));
 
         self->data[i] = self->value;
     }
@@ -204,7 +204,7 @@ TrigRandInt_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         ma = PyFloat_AsDouble(self->max);
     else
         ma = Stream_getData((Stream *)self->max_stream)[0];
-    self->value = (MYFLT)((int)(rand()/((MYFLT)(RAND_MAX)+1)*ma));
+    self->value = (MYFLT)((int)(RANDOM_UNIFORM * ma));
 
     (*self->mode_func_ptr)(self);
 
@@ -398,7 +398,7 @@ TrigRand_generate_ii(TrigRand *self) {
     for (i=0; i<self->bufsize; i++) {
         if (in[i] == 1) {
             self->timeCount = 0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             if (self->time <= 0.0)
                 self->currentValue = self->value;
             else
@@ -429,7 +429,7 @@ TrigRand_generate_ai(TrigRand *self) {
         MYFLT range = ma - mi[i];
         if (in[i] == 1) {
             self->timeCount = 0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
             if (self->time <= 0.0)
                 self->currentValue = self->value;
             else
@@ -460,7 +460,7 @@ TrigRand_generate_ia(TrigRand *self) {
         MYFLT range = ma[i] - mi;
         if (in[i] == 1) {
             self->timeCount = 0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi;
+            self->value = range * RANDOM_UNIFORM + mi;
             if (self->time <= 0.0)
                 self->currentValue = self->value;
             else
@@ -491,7 +491,7 @@ TrigRand_generate_aa(TrigRand *self) {
         MYFLT range = ma[i] - mi[i];
         if (in[i] == 1) {
             self->timeCount = 0;
-            self->value = range * (rand()/((MYFLT)(RAND_MAX)+1)) + mi[i];
+            self->value = range * RANDOM_UNIFORM + mi[i];
             if (self->time <= 0.0)
                 self->currentValue = self->value;
             else
@@ -912,7 +912,7 @@ TrigChoice_generate(TrigChoice *self) {
     for (i=0; i<self->bufsize; i++) {
         if (in[i] == 1) {
             self->timeCount = 0;
-            self->value = self->choice[(int)((rand()/((MYFLT)(RAND_MAX))) * self->chSize)];
+            self->value = self->choice[(int)(RANDOM_UNIFORM * self->chSize)];
             if (self->time <= 0.0)
                 self->currentValue = self->value;
             else
@@ -2830,7 +2830,7 @@ TrigXnoise_cauchy(TrigXnoise *self) {
     }
     while (rnd == 0.5);
 
-    if (rand() < (RAND_MAX / 2))
+    if (pyorand() < (PYO_RAND_MAX / 2))
         dir = -1;
     else
         dir = 1;
@@ -2891,7 +2891,7 @@ TrigXnoise_poisson(TrigXnoise *self) {
             }
         }
     }
-    val = self->poisson_buffer[rand() % self->poisson_tab] / 12.0 * self->xx2;
+    val = self->poisson_buffer[pyorand() % self->poisson_tab] / 12.0 * self->xx2;
 
     if (val < 0.0) return 0.0;
     else if (val > 1.0) return 1.0;
@@ -2906,12 +2906,12 @@ TrigXnoise_walker(TrigXnoise *self) {
     if (self->xx2 < 0.002) self->xx2 = 0.002;
 
     modulo = (int)(self->xx2 * 1000.0);
-    dir = rand() % 2;
+    dir = pyorand() % 2;
 
     if (dir == 0)
-        self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
     else
-        self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
     if (self->walkerValue > self->xx1)
         self->walkerValue = self->xx1;
@@ -2933,12 +2933,12 @@ TrigXnoise_loopseg(TrigXnoise *self) {
         if (self->xx2 < 0.002) self->xx2 = 0.002;
 
         modulo = (int)(self->xx2 * 1000.0);
-        dir = rand() % 2;
+        dir = pyorand() % 2;
 
         if (dir == 0)
-            self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
         else
-            self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
         if (self->walkerValue > self->xx1)
             self->walkerValue = self->xx1;
@@ -2951,7 +2951,7 @@ TrigXnoise_loopseg(TrigXnoise *self) {
             self->loopChoice = 0;
         else {
             self->loopChoice = 1;
-            self->loopStop = (rand() % 4) + 1;
+            self->loopStop = (pyorand() % 4) + 1;
         }
     }
     else {
@@ -2968,7 +2968,7 @@ TrigXnoise_loopseg(TrigXnoise *self) {
 
         if (self->loopTime == self->loopStop) {
             self->loopChoice = 0;
-            self->loopLen = (rand() % 10) + 3;
+            self->loopLen = (pyorand() % 10) + 3;
         }
     }
 
@@ -3218,7 +3218,7 @@ TrigXnoise_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         self->loop_buffer[i] = 0.0;
     }
     self->loopChoice = self->loopCountPlay = self->loopTime = self->loopCountRec = self->loopStop = 0;
-    self->loopLen = (rand() % 10) + 3;
+    self->loopLen = (pyorand() % 10) + 3;
 
     Stream_setFunctionPtr(self->stream, TrigXnoise_compute_next_data_frame);
     self->mode_func_ptr = TrigXnoise_setProcMode;
@@ -3600,7 +3600,7 @@ TrigXnoiseMidi_cauchy(TrigXnoiseMidi *self) {
     }
     while (rnd == 0.5);
 
-    if (rand() < (RAND_MAX / 2))
+    if (pyorand() < (PYO_RAND_MAX / 2))
         dir = -1;
     else
         dir = 1;
@@ -3661,7 +3661,7 @@ TrigXnoiseMidi_poisson(TrigXnoiseMidi *self) {
             }
         }
     }
-    val = self->poisson_buffer[rand() % self->poisson_tab] / 12.0 * self->xx2;
+    val = self->poisson_buffer[pyorand() % self->poisson_tab] / 12.0 * self->xx2;
 
     if (val < 0.0) return 0.0;
     else if (val > 1.0) return 1.0;
@@ -3676,12 +3676,12 @@ TrigXnoiseMidi_walker(TrigXnoiseMidi *self) {
     if (self->xx2 < 0.002) self->xx2 = 0.002;
 
     modulo = (int)(self->xx2 * 1000.0);
-    dir = rand() % 2;
+    dir = pyorand() % 2;
 
     if (dir == 0)
-        self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
     else
-        self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+        self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
     if (self->walkerValue > self->xx1)
         self->walkerValue = self->xx1;
@@ -3703,12 +3703,12 @@ TrigXnoiseMidi_loopseg(TrigXnoiseMidi *self) {
         if (self->xx2 < 0.002) self->xx2 = 0.002;
 
         modulo = (int)(self->xx2 * 1000.0);
-        dir = rand() % 2;
+        dir = pyorand() % 2;
 
         if (dir == 0)
-            self->walkerValue = self->walkerValue + (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue + (((pyorand() % modulo) - (modulo / 2)) * 0.001);
         else
-            self->walkerValue = self->walkerValue - (((rand() % modulo) - (modulo / 2)) * 0.001);
+            self->walkerValue = self->walkerValue - (((pyorand() % modulo) - (modulo / 2)) * 0.001);
 
         if (self->walkerValue > self->xx1)
             self->walkerValue = self->xx1;
@@ -3721,7 +3721,7 @@ TrigXnoiseMidi_loopseg(TrigXnoiseMidi *self) {
             self->loopChoice = 0;
         else {
             self->loopChoice = 1;
-            self->loopStop = (rand() % 4) + 1;
+            self->loopStop = (pyorand() % 4) + 1;
         }
     }
     else {
@@ -3738,7 +3738,7 @@ TrigXnoiseMidi_loopseg(TrigXnoiseMidi *self) {
 
         if (self->loopTime == self->loopStop) {
             self->loopChoice = 0;
-            self->loopLen = (rand() % 10) + 3;
+            self->loopLen = (pyorand() % 10) + 3;
         }
     }
 
@@ -3997,7 +3997,7 @@ TrigXnoiseMidi_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         self->loop_buffer[i] = 0.0;
     }
     self->loopChoice = self->loopCountPlay = self->loopTime = self->loopCountRec = self->loopStop = 0;
-    self->loopLen = (rand() % 10) + 3;
+    self->loopLen = (pyorand() % 10) + 3;
 
     Stream_setFunctionPtr(self->stream, TrigXnoiseMidi_compute_next_data_frame);
     self->mode_func_ptr = TrigXnoiseMidi_setProcMode;
@@ -5088,7 +5088,7 @@ Percent_generates_i(Percent *self) {
     for (i=0; i<self->bufsize; i++) {
         self->data[i] = 0.0;
         if (in[i] == 1.0) {
-            guess = (rand()/((MYFLT)(RAND_MAX)+1)) * 100.0;
+            guess = RANDOM_UNIFORM * 100.0;
             if (guess <= perc)
                 self->data[i] = 1.0;
         }
@@ -5105,7 +5105,7 @@ Percent_generates_a(Percent *self) {
     for (i=0; i<self->bufsize; i++) {
         self->data[i] = 0.0;
         if (in[i] == 1.0) {
-            guess = (rand()/((MYFLT)(RAND_MAX)+1)) * 100.0;
+            guess = RANDOM_UNIFORM * 100.0;
             if (guess <= perc[i])
                 self->data[i] = 1.0;
         }
diff --git a/src/objects/utilsmodule.c b/src/objects/utilsmodule.c
index 390622d..6442876 100644
--- a/src/objects/utilsmodule.c
+++ b/src/objects/utilsmodule.c
@@ -2580,9 +2580,9 @@ PyTypeObject BetweenType = {
 /* Denorm */
 /************/
 #ifndef USE_DOUBLE
-#define DENORM_RAND  ((MYFLT) ((rand()/((MYFLT)(RAND_MAX)*0.5+1) - 1.0) * (MYFLT)(1.0e-24)))
+#define DENORM_RAND  ((MYFLT) ((pyorand()/((MYFLT)(PYO_RAND_MAX)*0.5+1) - 1.0) * (MYFLT)(1.0e-24)))
 #else
-#define DENORM_RAND  ((MYFLT) ((rand()/((MYFLT)(RAND_MAX)*0.5+1) - 1.0) * (MYFLT)(1.0e-60)))
+#define DENORM_RAND  ((MYFLT) ((pyorand()/((MYFLT)(PYO_RAND_MAX)*0.5+1) - 1.0) * (MYFLT)(1.0e-60)))
 #endif
 
 typedef struct {
diff --git a/src/objects/wgverbmodule.c b/src/objects/wgverbmodule.c
index 3b55070..ba280e4 100644
--- a/src/objects/wgverbmodule.c
+++ b/src/objects/wgverbmodule.c
@@ -105,7 +105,7 @@ WGVerb_process_ii(WGVerb *self) {
             else if (self->rnd_time[j] >= 1.0) {
                 self->rnd_time[j] -= 1.0;
                 self->rnd_oldValue[j] = self->rnd_value[j];
-                self->rnd_value[j] = self->rnd_range[j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[j];
+                self->rnd_value[j] = self->rnd_range[j] * RANDOM_UNIFORM - self->rnd_halfRange[j];
                 self->rnd_diff[j] = self->rnd_value[j] - self->rnd_oldValue[j];
             }
             self->rnd[j] = self->rnd_oldValue[j] + self->rnd_diff[j] * self->rnd_time[j];
@@ -165,7 +165,7 @@ WGVerb_process_ai(WGVerb *self) {
             else if (self->rnd_time[j] >= 1.0) {
                 self->rnd_time[j] -= 1.0;
                 self->rnd_oldValue[j] = self->rnd_value[j];
-                self->rnd_value[j] = self->rnd_range[j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[j];
+                self->rnd_value[j] = self->rnd_range[j] * RANDOM_UNIFORM - self->rnd_halfRange[j];
                 self->rnd_diff[j] = self->rnd_value[j] - self->rnd_oldValue[j];
             }
             self->rnd[j] = self->rnd_oldValue[j] + self->rnd_diff[j] * self->rnd_time[j];
@@ -225,7 +225,7 @@ WGVerb_process_ia(WGVerb *self) {
             else if (self->rnd_time[j] >= 1.0) {
                 self->rnd_time[j] -= 1.0;
                 self->rnd_oldValue[j] = self->rnd_value[j];
-                self->rnd_value[j] = self->rnd_range[j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[j];
+                self->rnd_value[j] = self->rnd_range[j] * RANDOM_UNIFORM - self->rnd_halfRange[j];
                 self->rnd_diff[j] = self->rnd_value[j] - self->rnd_oldValue[j];
             }
             self->rnd[j] = self->rnd_oldValue[j] + self->rnd_diff[j] * self->rnd_time[j];
@@ -285,7 +285,7 @@ WGVerb_process_aa(WGVerb *self) {
             else if (self->rnd_time[j] >= 1.0) {
                 self->rnd_time[j] -= 1.0;
                 self->rnd_oldValue[j] = self->rnd_value[j];
-                self->rnd_value[j] = self->rnd_range[j] * (rand()/((MYFLT)(RAND_MAX)+1)) - self->rnd_halfRange[j];
+                self->rnd_value[j] = self->rnd_range[j] * RANDOM_UNIFORM - self->rnd_halfRange[j];
                 self->rnd_diff[j] = self->rnd_value[j] - self->rnd_oldValue[j];
             }
             self->rnd[j] = self->rnd_oldValue[j] + self->rnd_diff[j] * self->rnd_time[j];
@@ -916,7 +916,7 @@ STReverb_process_ii(STReverb *self) {
                 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_value[k][j] = self->rnd_range[k][j] * RANDOM_UNIFORM - 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];
@@ -1037,7 +1037,7 @@ STReverb_process_ai(STReverb *self) {
                 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_value[k][j] = self->rnd_range[k][j] * RANDOM_UNIFORM - 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];
@@ -1159,7 +1159,7 @@ STReverb_process_ia(STReverb *self) {
                 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_value[k][j] = self->rnd_range[k][j] * RANDOM_UNIFORM - 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];
@@ -1281,7 +1281,7 @@ STReverb_process_aa(STReverb *self) {
                 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_value[k][j] = self->rnd_range[k][j] * RANDOM_UNIFORM - 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];
diff --git a/utils/E-Pyo.py b/utils/E-Pyo.py
index dc85faa..203c256 100755
--- a/utils/E-Pyo.py
+++ b/utils/E-Pyo.py
@@ -3316,6 +3316,11 @@ class MainFrame(wx.Frame):
         wx.AboutBox(info)
 
     def OnClose(self, event):
+	msg = "You are about to leave E-Pyo. Is this really what you want to do?"
+	dlg = wx.MessageDialog(self, msg, "Warning!", wx.YES_NO|wx.ICON_QUESTION)
+	if dlg.ShowModal() != wx.ID_YES:
+	    event.StopPropagation()
+	    return
         if self.back_server_started == True:
             try:
                 self.startStopBackgroundServer(None)
diff --git a/utils/PyoDoc.py b/utils/PyoDoc.py
index 9628f9a..262891d 100644
--- a/utils/PyoDoc.py
+++ b/utils/PyoDoc.py
@@ -209,9 +209,17 @@ functions : Miscellaneous functions.
 
 """ % PYO_VERSION
 
+PYOGUI_DOC = """
+The classes in this module are based on internal classes that where 
+originally designed to help the creation of graphical tools for the
+control and the visualization of audio signals. WxPython must be installed
+under the current Python distribution to access these classes.
+
+"""
+
 _DOC_KEYWORDS = ['Attributes', 'Examples', 'Methods', 'Notes', 'Methods details', 
                  'Parentclass', 'Overview', 'Initline', 'Description', 'Parameters']
-_HEADERS = ["Server", "PyoObjectBase", "Map", "Stream", "TableStream", "functions"]
+_HEADERS = ["Server", "PyoObjectBase", "Map", "Stream", "TableStream", "functions", "PyoGui"]
 _KEYWORDS_LIST = ['SLMap']
 _KEYWORDS_LIST.extend(_HEADERS)
 _NUM_PAGES = 1
@@ -240,6 +248,7 @@ PYOTABLEOBJECT_METHODS_FILTER = [x[0] for x in inspect.getmembers(PyoTableObject
 PYOPVOBJECT_METHODS_FILTER = [x[0] for x in inspect.getmembers(PyoPVObject, inspect.ismethod)]
 MAP_METHODS_FILTER = [x[0] for x in inspect.getmembers(Map, inspect.ismethod)]
 SLMAP_METHODS_FILTER = [x[0] for x in inspect.getmembers(SLMap, inspect.ismethod)]
+WXPANEL_METHODS_FILTER = [x[0] for x in inspect.getmembers(wx.Panel, inspect.ismethod)]
 
 def _ed_set_style(editor, searchKey=None):
     editor.SetLexer(stc.STC_LEX_PYTHON)
@@ -623,13 +632,18 @@ class ManualPanel(wx.Treebook):
                 else:
                     try:
                         text = eval(obj).__doc__
-                        text = text.replace(".. note::", "Notes:").replace(".. seealso::", "See also:").replace(":Args:", "Parameters:")
+                        text = text.replace(".. note::", "Notes:").replace(".. seealso::", "See also:").replace(":Args:", "Parameters:").replace(":Events:", "Events:")
                     except:
                         if obj == "functions":
                             text = "Miscellaneous functions...\n\n"
                             text += "\nOverview:\n"
                             for o in OBJECTS_TREE["functions"]:
                                 text += o + ": " + self.getDocFirstLine(o)
+                        elif obj == "PyoGui":
+                            text = PYOGUI_DOC
+                            text += "\nOverview:\n"
+                            for o in OBJECTS_TREE["PyoGui"]:
+                                text += o + ": " + self.getDocFirstLine(o)
                         else:
                             text = "\nNot documented yet...\n\n"
                     if obj in OBJECTS_TREE["PyoObjectBase"]["PyoObject"].keys():
@@ -711,6 +725,8 @@ class ManualPanel(wx.Treebook):
             filter = MAP_METHODS_FILTER
         elif parentclass == "SLMap":
             filter = SLMAP_METHODS_FILTER
+        elif parentclass == "wx.Panel":
+            filter = WXPANEL_METHODS_FILTER
         else:
             filter = []
         obj_meths = [x[0] for x in inspect.getmembers(eval(obj), inspect.ismethod) if x[0] not in filter]
diff --git a/utils/info.plist b/utils/info.plist
index 843e284..fd258f1 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.7.8</string>
+	<string>0.7.9</string>
 	<key>CFBundleName</key>
 	<string>E-Pyo</string>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-	<string>0.7.8</string>
+	<string>0.7.9</string>
 	<key>CFBundleSignature</key>
 	<string>????</string>
 	<key>CFBundleVersion</key>
-	<string>0.7.8</string>
+	<string>0.7.9</string>
 	<key>LSHasLocalizedDisplayName</key>
 	<false/>
 	<key>NSAppleScriptEnabled</key>

-- 
python-pyo packaging



More information about the pkg-multimedia-commits mailing list